From 2f24ef71bc9f6255c0f02db42b90184a843c468c Mon Sep 17 00:00:00 2001 From: Michael Webster Date: Tue, 18 Feb 2025 18:49:47 +0000 Subject: [PATCH 1/2] Rebase onto gjs-1.82.1 (from debian 13/trixie) - mozjs 128 support. --- .clangd | 6 + .eslintrc.yml | 7 +- .gitignore | 10 + .gitlab-ci.yml | 118 +- .gitmodules | 6 + .reuse/dep5 | 19 - NEWS | 336 + README.MSVC.md | 167 + README.md | 39 +- build/choose-tests-locale.sh | 0 build/compile-gschemas.py | 16 - build/maintainer-upload-release.sh | 5 +- build/{symlink-gjs.py => symlink-cjs.py} | 13 +- cjs/byteArray.cpp | 47 +- cjs/byteArray.h | 3 +- cjs/{gjs.stp.in => cjs.stp.in} | 8 +- cjs/{gjs_pch.hh => cjs_pch.hh} | 4 + cjs/context-private.h | 31 +- cjs/context.cpp | 191 +- cjs/deprecation.cpp | 19 +- cjs/deprecation.h | 12 +- cjs/engine.cpp | 109 +- cjs/engine.h | 5 + cjs/error-types.cpp | 2 + cjs/global.cpp | 72 +- cjs/global.h | 4 +- cjs/importer.cpp | 43 +- cjs/internal.cpp | 55 +- cjs/jsapi-class.h | 28 +- cjs/jsapi-dynamic-class.cpp | 33 +- cjs/jsapi-util-args.h | 1 + cjs/jsapi-util-error.cpp | 39 +- cjs/jsapi-util-root.h | 169 +- cjs/jsapi-util-string.cpp | 13 +- cjs/jsapi-util.cpp | 65 +- cjs/jsapi-util.h | 5 +- cjs/mem-private.h | 2 + cjs/mem.cpp | 2 + cjs/module.cpp | 110 +- cjs/native.cpp | 28 +- cjs/native.h | 17 +- cjs/objectbox.cpp | 2 +- cjs/profiler-private.h | 6 + cjs/profiler.cpp | 138 +- cjs/promise.cpp | 6 +- cjs/stack.cpp | 45 +- cjs/text-encoding.cpp | 32 +- debian/changelog | 6 + debian/control | 121 +- debian/copyright | 127 +- debian/gbp.conf | 17 + debian/libcjs0.acc.in | 20 - debian/libcjs0.symbols | 160 +- debian/not-installed | 9 + debian/rules | 20 +- debian/shlibs.local | 2 +- debian/tests/acc | 18 - debian/tests/build | 8 +- debian/tests/control | 12 +- debian/tests/installed-tests | 0 debian/tests/testsuite | 4 - debian/watch | 4 + debian/watch.devel | 4 + doc/CPP_Style_Guide.md | 90 +- doc/Hacking.md | 57 +- doc/Mainloop.md | 2 +- doc/Overrides.md | 34 +- doc/Signals.md | 2 +- doc/SpiderMonkey_Memory.md | 26 +- doc/Style_Guide.md | 16 +- doc/Understanding-SpiderMonkey-code.md | 10 +- doc/cairo.md | 30 +- examples/dbus-client.js | 14 +- examples/dbus-service.js | 6 +- examples/gtk-application.js | 2 +- examples/http-server.js | 12 +- gi/arg-cache.cpp | 742 +- gi/arg-cache.h | 8 +- gi/arg-inl.h | 38 +- gi/arg-types-inl.h | 10 + gi/arg.cpp | 495 +- gi/arg.h | 84 +- gi/boxed.cpp | 107 +- gi/boxed.h | 4 +- gi/{gjs_gi_probes.d => cjs_gi_probes.d} | 0 gi/{gjs_gi_trace.h => cjs_gi_trace.h} | 2 +- gi/closure.cpp | 4 +- gi/closure.h | 13 +- gi/cwrapper.h | 1 + gi/enumeration.cpp | 4 +- gi/foreign.cpp | 157 +- gi/foreign.h | 48 +- gi/function.cpp | 128 +- gi/fundamental.cpp | 6 +- gi/gerror.cpp | 11 +- gi/gobject.cpp | 10 +- gi/gobject.h | 2 + gi/gtype.cpp | 2 - gi/interface.cpp | 49 +- gi/js-value-inl.h | 73 +- gi/ns.cpp | 62 + gi/ns.h | 2 + gi/object.cpp | 391 +- gi/object.h | 40 +- gi/param.cpp | 28 +- gi/private.cpp | 46 +- gi/repo.cpp | 99 +- gi/repo.h | 3 + gi/toggle.cpp | 4 + gi/toggle.h | 4 +- gi/utils-inl.h | 1 + gi/value.cpp | 222 +- gi/value.h | 3 +- gi/wrapperutils.h | 3 +- gjs.doap | 16 - installed-tests/debugger-test.sh | 0 .../debugger/backtrace.debugger.output | 28 +- .../debugger/breakpoint.debugger.output | 12 +- .../debugger/continue.debugger.output | 4 +- .../debugger/delete.debugger.output | 16 +- .../debugger/down-up.debugger.output | 18 +- .../debugger/finish.debugger.output | 12 +- .../debugger/frame.debugger.output | 6 +- installed-tests/debugger/keys.debugger | 5 + installed-tests/debugger/keys.debugger.output | 18 +- .../debugger/lastvalues.debugger.output | 2 +- installed-tests/debugger/list.debugger.output | 4 +- installed-tests/debugger/next.debugger.output | 20 +- .../debugger/print.debugger.output | 2 +- installed-tests/debugger/return.debugger | 7 +- .../debugger/return.debugger.output | 26 +- installed-tests/debugger/set.debugger.output | 2 +- installed-tests/debugger/step.debugger.output | 32 +- .../debugger/throw-ignored.debugger.output | 2 +- installed-tests/debugger/throw.debugger | 7 +- .../debugger/throw.debugger.output | 28 +- .../debugger/until.debugger.output | 10 +- installed-tests/js/.eslintrc.yml | 3 + installed-tests/js/jsunit.gresources.xml | 17 +- .../js/libgjstesttools/gjs-test-tools.cpp | 39 + .../js/libgjstesttools/gjs-test-tools.h | 64 +- .../js/libgjstesttools/meson.build | 14 +- installed-tests/js/meson.build | 141 +- installed-tests/js/minijasmine-executor.js | 8 +- installed-tests/js/minijasmine.js | 4 +- installed-tests/js/modules/greet.js | 9 + installed-tests/js/modules/sideEffect.js | 5 + installed-tests/js/modules/sideEffect2.js | 5 + installed-tests/js/modules/sideEffect3.js | 5 + installed-tests/js/modules/sideEffect4.js | 7 + installed-tests/js/testAsyncMainloop.js | 2 +- installed-tests/js/testByteArray.js | 108 - installed-tests/js/testConsole.js | 24 + installed-tests/js/testESModules.js | 86 +- installed-tests/js/testEncoding.js | 15 +- installed-tests/js/testExceptions.js | 68 +- installed-tests/js/testGDBus.js | 96 +- installed-tests/js/testGIMarshalling.js | 521 +- installed-tests/js/testGLib.js | 141 +- installed-tests/js/testGObject.js | 28 + installed-tests/js/testGObjectClass.js | 74 +- .../js/testGObjectDestructionAccess.js | 285 +- installed-tests/js/testGObjectInterface.js | 2 +- installed-tests/js/testGio.js | 18 +- installed-tests/js/testGtk3.js | 65 +- installed-tests/js/testGtk4.js | 150 +- installed-tests/js/testImporter.js | 12 +- installed-tests/js/testImporter2.js | 4 +- installed-tests/js/testIntrospection.js | 61 +- installed-tests/js/testLegacyByteArray.js | 122 +- installed-tests/js/testLegacyGObject.js | 4 +- installed-tests/js/testLegacyGtk.js | 42 +- installed-tests/js/testParamSpec.js | 5 + installed-tests/js/testPrint.js | 44 + installed-tests/js/testPromise.js | 4 +- installed-tests/js/testRegress.js | 66 +- installed-tests/js/testSignals.js | 6 +- installed-tests/js/testWarnLib.js | 4 + installed-tests/js/testWeakRef.js | 79 + installed-tests/meson.build | 15 +- installed-tests/minijasmine.cpp | 6 +- installed-tests/script.test.in | 2 +- installed-tests/scripts/common.sh | 0 installed-tests/scripts/testCommandLine.sh | 10 +- .../scripts/testCommandLineModules.sh | 0 installed-tests/scripts/testExamples.sh | 0 installed-tests/scripts/testWarnings.sh | 2 +- js.gresource.xml | 2 +- libgjs.map => libcjs.map | 0 libgjs.symbols => libcjs.symbols | 0 libgjs-private/gjs-gdbus-wrapper.c | 2 + libgjs-private/gjs-match-info.c | 357 + libgjs-private/gjs-match-info.h | 93 + meson.build | 284 +- meson_options.txt | 4 +- modules/cairo-context.cpp | 35 +- modules/cairo-pdf-surface.cpp | 14 +- modules/cairo-ps-surface.cpp | 14 +- modules/cairo-region.cpp | 15 +- modules/cairo-surface.cpp | 20 +- modules/cairo-svg-surface.cpp | 14 +- modules/cairo.cpp | 9 +- modules/console.cpp | 19 +- modules/core/_common.js | 32 +- modules/core/overrides/GLib.js | 72 +- modules/core/overrides/GObject.js | 209 +- modules/core/overrides/Gtk.js | 157 +- modules/esm/_encoding/encoding.js | 2 + modules/esm/console.js | 11 +- modules/internal/loader.js | 29 +- modules/modules.cpp | 25 - modules/modules.h | 10 - modules/script/_bootstrap/debugger.js | 105 +- modules/script/_bootstrap/default.js | 30 +- modules/script/_legacy.js | 8 +- modules/script/lang.js | 2 +- modules/script/package.js | 1 + subprojects/cairo.wrap | 13 + subprojects/gobject-introspection-tests.wrap | 11 + .../gobject-introspection-tests/.clang-format | 12 + .../gobject-introspection-tests/.editorconfig | 14 + .../gobject-introspection-tests/COPYING | 13 + .../gobject-introspection-tests/COPYING.GPL | 340 + .../gobject-introspection-tests/COPYING.LGPL | 481 ++ .../gobject-introspection-tests/README.md | 77 + .../gobject-introspection-tests/annotation.c | 841 ++ .../gobject-introspection-tests/annotation.h | 313 + .../docs/provenance.txt | 103 + .../gobject-introspection-tests/drawable.c | 64 + .../gobject-introspection-tests/drawable.h | 47 + subprojects/gobject-introspection-tests/foo.c | 853 ++ subprojects/gobject-introspection-tests/foo.h | 563 ++ .../gimarshallingtests.c | 7316 +++++++++++++++++ .../gimarshallingtests.h | 2325 ++++++ .../gitestmacros.h | 9 + .../gobject-introspection-tests.doap | 111 + .../gobject-introspection-tests/meson.build | 223 + .../meson_options.txt | 5 + .../regress-unix.c | 39 + .../regress-unix.h | 31 + .../gobject-introspection-tests/regress.c | 5100 ++++++++++++ .../gobject-introspection-tests/regress.h | 1713 ++++ .../tools/iwyu.imp | 9 + .../tools/run_clang_format.sh | 9 + .../tools/run_iwyu.sh | 10 + .../gobject-introspection-tests/utility.c | 55 + .../gobject-introspection-tests/utility.h | 105 + .../gobject-introspection-tests/warnlib.c | 48 + .../gobject-introspection-tests/warnlib.h | 52 + test/check-headers.sh | 181 + test/check-pch.sh | 18 +- test/extra/Dockerfile | 15 +- test/extra/Dockerfile.debug | 30 +- test/extra/do_environment.sh | 0 test/gjs-test-common.h | 2 + test/gjs-test-coverage.cpp | 52 +- test/gjs-test-jsapi-utils.cpp | 100 +- test/gjs-test-no-introspection-object.cpp | 2 + test/gjs-test-no-introspection-object.h | 2 + test/gjs-test-rooting.cpp | 32 +- test/gjs-test-toggle-queue.cpp | 4 +- test/gjs-test-utils.h | 4 +- test/gjs-tests.cpp | 118 +- test/meson.build | 22 +- test/mock-js-resources.gresource.xml | 2 +- test/test-ci.sh | 17 +- tools/apply-format | 3 +- tools/cppcheck.cfg | 16 +- tools/git-pre-commit-format | 0 tools/gjs-private-iwyu.imp | 1 + tools/gjs-public-iwyu.imp | 2 +- tools/heapdot.py | 2 +- tools/heapgraph.py | 79 +- tools/package-lock.json | 1266 +-- tools/package.json | 4 +- tools/process_iwyu.py | 33 +- tools/run_coverage.sh | 8 +- tools/run_cppcheck.sh | 32 +- tools/run_eslint.sh | 0 tools/run_iwyu.sh | 2 +- util/console.h | 2 + util/log.cpp | 10 +- util/log.h | 2 + util/misc.cpp | 2 + util/misc.h | 2 + 285 files changed, 28463 insertions(+), 4680 deletions(-) create mode 100644 .clangd create mode 100644 .gitmodules delete mode 100644 .reuse/dep5 create mode 100644 README.MSVC.md mode change 100755 => 100644 build/choose-tests-locale.sh delete mode 100644 build/compile-gschemas.py mode change 100755 => 100644 build/maintainer-upload-release.sh rename build/{symlink-gjs.py => symlink-cjs.py} (60%) rename cjs/{gjs.stp.in => cjs.stp.in} (60%) rename cjs/{gjs_pch.hh => cjs_pch.hh} (97%) create mode 100644 debian/gbp.conf delete mode 100644 debian/libcjs0.acc.in create mode 100644 debian/not-installed delete mode 100755 debian/tests/acc mode change 100755 => 100644 debian/tests/build mode change 100755 => 100644 debian/tests/installed-tests delete mode 100755 debian/tests/testsuite create mode 100644 debian/watch create mode 100644 debian/watch.devel rename gi/{gjs_gi_probes.d => cjs_gi_probes.d} (100%) rename gi/{gjs_gi_trace.h => cjs_gi_trace.h} (95%) mode change 100755 => 100644 installed-tests/debugger-test.sh create mode 100644 installed-tests/js/modules/greet.js create mode 100644 installed-tests/js/modules/sideEffect.js create mode 100644 installed-tests/js/modules/sideEffect2.js create mode 100644 installed-tests/js/modules/sideEffect3.js create mode 100644 installed-tests/js/modules/sideEffect4.js delete mode 100644 installed-tests/js/testByteArray.js create mode 100644 installed-tests/js/testWeakRef.js mode change 100755 => 100644 installed-tests/scripts/common.sh mode change 100755 => 100644 installed-tests/scripts/testCommandLine.sh mode change 100755 => 100644 installed-tests/scripts/testCommandLineModules.sh mode change 100755 => 100644 installed-tests/scripts/testExamples.sh mode change 100755 => 100644 installed-tests/scripts/testWarnings.sh rename libgjs.map => libcjs.map (100%) rename libgjs.symbols => libcjs.symbols (100%) create mode 100644 libgjs-private/gjs-match-info.c create mode 100644 libgjs-private/gjs-match-info.h delete mode 100644 modules/modules.cpp delete mode 100644 modules/modules.h create mode 100644 subprojects/cairo.wrap create mode 100644 subprojects/gobject-introspection-tests.wrap create mode 100644 subprojects/gobject-introspection-tests/.clang-format create mode 100644 subprojects/gobject-introspection-tests/.editorconfig create mode 100644 subprojects/gobject-introspection-tests/COPYING create mode 100644 subprojects/gobject-introspection-tests/COPYING.GPL create mode 100644 subprojects/gobject-introspection-tests/COPYING.LGPL create mode 100644 subprojects/gobject-introspection-tests/README.md create mode 100644 subprojects/gobject-introspection-tests/annotation.c create mode 100644 subprojects/gobject-introspection-tests/annotation.h create mode 100644 subprojects/gobject-introspection-tests/docs/provenance.txt create mode 100644 subprojects/gobject-introspection-tests/drawable.c create mode 100644 subprojects/gobject-introspection-tests/drawable.h create mode 100644 subprojects/gobject-introspection-tests/foo.c create mode 100644 subprojects/gobject-introspection-tests/foo.h create mode 100644 subprojects/gobject-introspection-tests/gimarshallingtests.c create mode 100644 subprojects/gobject-introspection-tests/gimarshallingtests.h create mode 100644 subprojects/gobject-introspection-tests/gitestmacros.h create mode 100644 subprojects/gobject-introspection-tests/gobject-introspection-tests.doap create mode 100644 subprojects/gobject-introspection-tests/meson.build create mode 100644 subprojects/gobject-introspection-tests/meson_options.txt create mode 100644 subprojects/gobject-introspection-tests/regress-unix.c create mode 100644 subprojects/gobject-introspection-tests/regress-unix.h create mode 100644 subprojects/gobject-introspection-tests/regress.c create mode 100644 subprojects/gobject-introspection-tests/regress.h create mode 100644 subprojects/gobject-introspection-tests/tools/iwyu.imp create mode 100644 subprojects/gobject-introspection-tests/tools/run_clang_format.sh create mode 100644 subprojects/gobject-introspection-tests/tools/run_iwyu.sh create mode 100644 subprojects/gobject-introspection-tests/utility.c create mode 100644 subprojects/gobject-introspection-tests/utility.h create mode 100644 subprojects/gobject-introspection-tests/warnlib.c create mode 100644 subprojects/gobject-introspection-tests/warnlib.h create mode 100644 test/check-headers.sh mode change 100755 => 100644 test/check-pch.sh mode change 100755 => 100644 test/extra/do_environment.sh mode change 100755 => 100644 test/test-ci.sh mode change 100755 => 100644 tools/apply-format mode change 100755 => 100644 tools/git-pre-commit-format mode change 100755 => 100644 tools/heapgraph.py mode change 100755 => 100644 tools/process_iwyu.py mode change 100755 => 100644 tools/run_coverage.sh mode change 100755 => 100644 tools/run_cppcheck.sh mode change 100755 => 100644 tools/run_eslint.sh mode change 100755 => 100644 tools/run_iwyu.sh diff --git a/.clangd b/.clangd new file mode 100644 index 000000000..ede073eae --- /dev/null +++ b/.clangd @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MIT OR LGPL-2.0-or-later +# SPDX-FileCopyrightText: 2024 Philip Chimento + +Diagnostics: + ClangTidy: + Remove: bugprone-sizeof-expression # Interferes with g_clear_pointer() diff --git a/.eslintrc.yml b/.eslintrc.yml index 97e728f96..aabe6e193 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -30,6 +30,7 @@ rules: - error - arrays: always-multiline objects: always-multiline + imports: always-multiline functions: never comma-spacing: - error @@ -68,12 +69,16 @@ rules: jsdoc/check-tag-names: error jsdoc/check-types: error jsdoc/implements-on-classes: error - jsdoc/newline-after-description: error jsdoc/require-jsdoc: error jsdoc/require-param: error jsdoc/require-param-description: error jsdoc/require-param-name: error jsdoc/require-param-type: error + jsdoc/tag-lines: + - error + - always + - count: 0 + startLines: 1 key-spacing: - error - beforeColon: false diff --git a/.gitignore b/.gitignore index 346fde5be..a65980eb5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,13 @@ /tools/node_modules # artifact from ci-templates: /container-build-report.xml +debian/tmp +debian/libcjs0 +debian/libcjs-dbg +debian/libcjs-dev +debian/cjs +debian/.debhelper +debian/*.substvars +debian/*.debhelper.log +debian/debhelper-build-stamp +debian/files \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bf2ecdea8..e9e2d662a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,7 +14,7 @@ stages: .gjs-alpine: variables: - FDO_DISTRIBUTION_TAG: '2022-11-02.0' + FDO_DISTRIBUTION_TAG: '2024-07-28.0' FDO_UPSTREAM_REPO: GNOME/gjs build-alpine-image: @@ -23,16 +23,17 @@ build-alpine-image: - .gjs-alpine stage: prepare variables: - FDO_DISTRIBUTION_PACKAGES: cppcheck git python3 npm bash grep + FDO_DISTRIBUTION_PACKAGES: | + bash cppcheck git grep npm py3-codespell python3 reuse FDO_DISTRIBUTION_EXEC: | - python3 -m ensurepip && - rm -r /usr/lib/python*/ensurepip && - pip3 install --no-cache --upgrade cpplint reuse codespell && - mkdir -p /cwd + mkdir -p /cwd && + apk add cpplint \ + --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing/ .coverage: &coverage - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs115-debug + image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug variables: + GIT_SUBMODULE_STRATEGY: normal coverage: '/^ lines.*(\d+\.\d+\%)/' script: - export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig @@ -61,7 +62,13 @@ build-alpine-image: when: always paths: - _build/compile_commands.json + - _build/installed-tests/js/jsunit-resources.c + - _build/installed-tests/js/jsunit-resources.h + - _build/js-resources.c + - _build/js-resources.h - _build/meson-logs/*log*.txt + - _build/test/mock-js-resources.c + - _build/test/mock-js-resources.h script: - test/test-ci.sh SETUP - test/test-ci.sh BUILD @@ -74,8 +81,9 @@ build-alpine-image: build_recommended: <<: *build stage: source_check - image: registry.gitlab.gnome.org/gnome/gjs:job-3012153_fedora.mozjs115-debug # pinned on purpose + image: registry.gitlab.gnome.org/gnome/gjs:job-4161430_fedora.mozjs128-debug # pinned on purpose variables: + GIT_SUBMODULE_STRATEGY: normal TEST_OPTS: --verbose --no-stdsplit --print-errorlogs --setup=verbose except: - schedules @@ -85,13 +93,13 @@ sanitizer_gcc: stage: test tags: - asan # LSAN needs CAP_SYS_PTRACE - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs115-debug + image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug variables: + GIT_SUBMODULE_STRATEGY: normal CONFIG_OPTS: -Db_sanitize=address,undefined TEST_OPTS: --timeout-multiplier=3 # Override these during build, but they are overridden by meson anyways ASAN_OPTIONS: start_deactivated=true,detect_leaks=0 - USE_UNSTABLE_GNOME_PREFIX: 'true' except: - schedules @@ -102,11 +110,11 @@ sanitizer_thread_gcc: allow_failure: true tags: - asan # TSAN needs CAP_SYS_PTRACE - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs115-debug + image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug variables: + GIT_SUBMODULE_STRATEGY: normal CONFIG_OPTS: -Db_sanitize=thread TEST_OPTS: --timeout-multiplier=3 --setup=verbose - USE_UNSTABLE_GNOME_PREFIX: 'true' except: - schedules @@ -116,11 +124,11 @@ sanitizer_thread_gcc: build_maximal: when: on_success stage: test - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs115-debug + image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug variables: + GIT_SUBMODULE_STRATEGY: normal CC: clang CXX: clang++ - USE_UNSTABLE_GNOME_PREFIX: 'true' CONFIG_OPTS: >- -Ddtrace=true -Dsystemtap=true -Dverbose_logs=true -Db_pch=false ENABLE_GTK: "yes" @@ -143,11 +151,10 @@ build_maximal: build_minimal: <<: *build stage: test - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs115 + image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128 variables: - CONFIG_OPTS: >- - -Dbuildtype=release - -Dcairo=disabled -Dreadline=disabled -Dprofiler=disabled + GIT_SUBMODULE_STRATEGY: normal + CONFIG_OPTS: -Dbuildtype=release -Dreadline=disabled -Dprofiler=disabled TEST_OPTS: --setup=verbose except: - schedules @@ -155,8 +162,9 @@ build_minimal: build_unity: <<: *build stage: test - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs115 + image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128 variables: + GIT_SUBMODULE_STRATEGY: normal # unity-size here is forced to use an high number to check whether we can # join all the sources together, but should not be used in real world to # not to break multi-jobs compilation @@ -205,10 +213,22 @@ cppcheck: extends: - .fdo.distribution-image@alpine - .gjs-alpine - stage: source_check + stage: test # so that we have compile_commands.json and generated C files script: - cppcheck --version - - cppcheck . -v -f -q -UHAVE_PRINTF_ALTERNATIVE_INT --error-exitcode=1 --inline-suppr --library=gtk,tools/cppcheck.cfg --enable=warning,performance,portability + # Create fake g-i test files, we are not analyzing them anyway + - mkdir -p subprojects/gobject-introspection-tests + - | + touch \ + subprojects/gobject-introspection-tests/annotation.{c,h} \ + subprojects/gobject-introspection-tests/drawable.{c,h} \ + subprojects/gobject-introspection-tests/foo.{c,h} \ + subprojects/gobject-introspection-tests/gimarshallingtests.{c,h} \ + subprojects/gobject-introspection-tests/regress.{c,h} \ + subprojects/gobject-introspection-tests/regress-unix.{c,h} \ + subprojects/gobject-introspection-tests/warnlib.{c,h} \ + subprojects/gobject-introspection-tests/utility.{c,h} + - ./tools/run_cppcheck.sh -q except: refs: - schedules @@ -265,7 +285,7 @@ eslint: - .eslintrc.yml - '**/.eslintrc.yml' -pch_check: +headers_check: when: on_success stage: source_check extends: @@ -273,13 +293,15 @@ pch_check: - .gjs-alpine script: - env SELFTEST=1 test/check-pch.sh + - env SELFTEST=1 test/check-headers.sh - test/check-pch.sh + - test/check-headers.sh except: refs: - schedules - tags variables: - - $CI_COMMIT_MESSAGE =~ /\[skip pch_check\]/ + - $CI_COMMIT_MESSAGE =~ /\[skip headers_check\]/ only: changes: - "**/*.c" @@ -287,11 +309,14 @@ pch_check: - "**/*.h" - "**/*.hh" - test/check-pch.sh + - test/check-headers.sh iwyu: when: on_success stage: source_check - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs115-debug + image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug + variables: + GIT_SUBMODULE_STRATEGY: normal script: - test/test-ci.sh UPSTREAM_BASE - meson setup _build -Db_pch=false @@ -301,8 +326,11 @@ iwyu: refs: - branches except: - - schedules - - /^gnome-\d+-\d+$/ + refs: + - schedules + - /^gnome-[-\d]+$/ + variables: + - $CI_COMMIT_MESSAGE =~ /\[skip iwyu\]/ codespell: when: on_success @@ -316,7 +344,7 @@ codespell: codespell -S "*.png,*.po,*.jpg,*.wrap,.git,LICENSES" -f \ --builtin "code,usage,clear" \ --skip="./build/maintainer-upload-release.sh,./installed-tests/js/jasmine.js,./README.md,./build/flatpak/*.json,./tools/package-lock.json" \ - --ignore-words-list="afterall,deque,falsy,files',filetest,gir,inout,musl,nmake,stdio,uint,upto,xdescribe" + --ignore-words-list="aas,afterall,deque,falsy,files',filetest,gir,inout,musl,nmake,stdio,uint,upto,ws,xdescribe" except: - schedules @@ -346,7 +374,9 @@ coverage: iwyu-full: when: manual stage: manual - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs115-debug + image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug + variables: + GIT_SUBMODULE_STRATEGY: normal script: - meson setup _build - ./tools/run_iwyu.sh @@ -358,11 +388,11 @@ sanitizer_clang: stage: manual tags: - asan # LSAN needs CAP_SYS_PTRACE - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs115-debug + image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug variables: + GIT_SUBMODULE_STRATEGY: normal CC: clang CXX: clang++ - USE_UNSTABLE_GNOME_PREFIX: 'true' # Override these during build, but they are overridden by meson anyways ASAN_OPTIONS: start_deactivated=true,detect_leaks=0 CONFIG_OPTS: -Db_sanitize=address,undefined -Db_lundef=false @@ -374,8 +404,9 @@ sanitizer_clang: installed_tests: <<: *build stage: manual - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs115-debug + image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug variables: + GIT_SUBMODULE_STRATEGY: normal CONFIG_OPTS: -Dinstalled_tests=true -Dprefix=/usr TEST: skip when: manual @@ -390,9 +421,9 @@ installed_tests: valgrind: <<: *build stage: manual - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs115-debug + image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug variables: - USE_UNSTABLE_GNOME_PREFIX: 'true' + GIT_SUBMODULE_STRATEGY: normal TEST_OPTS: --setup=valgrind allow_failure: true when: manual @@ -403,8 +434,9 @@ valgrind: zeal_2: <<: *build stage: manual - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs115-debug + image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug variables: + GIT_SUBMODULE_STRATEGY: normal TEST_OPTS: --setup=extra_gc when: manual except: @@ -413,8 +445,9 @@ zeal_2: zeal_4: <<: *build stage: manual - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs115-debug + image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug variables: + GIT_SUBMODULE_STRATEGY: normal TEST_OPTS: --setup=pre_verify when: manual except: @@ -423,8 +456,9 @@ zeal_4: zeal_11: <<: *build stage: manual - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs115-debug + image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug variables: + GIT_SUBMODULE_STRATEGY: normal TEST_OPTS: --setup=post_verify when: manual except: @@ -465,28 +499,28 @@ zeal_11: BUILDAH_FORMAT: docker BUILDAH_ISOLATION: chroot -fedora.mozjs102: +fedora.mozjs115: <<: *create_docker_image variables: <<: *docker_variables DOCKERFILE: test/extra/Dockerfile -fedora.mozjs102-debug: +fedora.mozjs115-debug: <<: *create_docker_image variables: <<: *docker_variables DOCKERFILE: test/extra/Dockerfile.debug -fedora.mozjs115: +fedora.mozjs128: <<: *create_docker_image variables: <<: *docker_variables DOCKERFILE: test/extra/Dockerfile - ARGS: --build-arg MOZJS_BRANCH=mozjs115 --build-arg MOZJS_BUILDDEPS=mozjs102 + ARGS: --build-arg MOZJS_BRANCH=mozjs128 --build-arg MOZJS_BUILDDEPS=mozjs115 -fedora.mozjs115-debug: +fedora.mozjs128-debug: <<: *create_docker_image variables: <<: *docker_variables DOCKERFILE: test/extra/Dockerfile.debug - ARGS: --build-arg MOZJS_BRANCH=mozjs115 --build-arg MOZJS_BUILDDEPS=mozjs102 + ARGS: --build-arg MOZJS_BRANCH=mozjs128 --build-arg MOZJS_BUILDDEPS=mozjs115 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..292b0b1a4 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2024 Philip Chimento +[submodule "subprojects/gobject-introspection-tests"] + path = subprojects/gobject-introspection-tests + url = ../gobject-introspection-tests.git + shallow = true diff --git a/.reuse/dep5 b/.reuse/dep5 deleted file mode 100644 index be58e75f1..000000000 --- a/.reuse/dep5 +++ /dev/null @@ -1,19 +0,0 @@ -Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ - -Files: .gitlab/issue_templates/* build/flatpak/org.gnome.*.json - doc/* CONTRIBUTING.md NEWS *README* tools/heapgraph.md - tools/package-lock.json installed-tests/js/modules/data.txt -Copyright: No rights reserved -License: CC0-1.0 - -Files: tools/package.json -Copyright: 2020 Evan Welsh -License: MIT OR LGPL-2.0-or-later - -Files: installed-tests/js/modules/encodings.json -Copyright: WHATWG (Apple, Google, Mozilla, Microsoft) -License: BSD-3-Clause - -Files: jsconfig.json -Copyright: 2021 Evan Welsh -License: MIT OR LGPL-2.0-or-later diff --git a/NEWS b/NEWS index 2a7485c0f..36cd3070a 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,339 @@ +Version 1.82.1 +-------------- + +- Closed bugs and merge requests: + + * gnome-shell crash when switching user after upgrade from Fedora 40 to Fedora + 41 [#647, !955, Philip Chimento] + +Version 1.82.0 +-------------- + +- Closed bugs and merge requests: + + * installed tests are failing because they can't load internal typelibs from + parent directory [#639, !953, Simon McVittie] + * GIMarshalling test has 3 failures with 1.81.90 on i686 [#642, !954, Philip + Chimento] + +Version 1.81.90 +--------------- + +- Closed bugs and merge requests: + + * callbacks: fix sweeping check for incremental GC [!859, !950, Evan Welsh, + Gary Li] + * GJS doesn't handle query parameters in imports [#618, !944, Gary Li] + * Integrate gobject-introspection-tests as submodule [!946, Philip Chimento] + * module: Include full module specifier in import.meta.url [!947, Philip + Chimento] + * doap: Remove invalid maintainer entry [!948, Sophie Herold] + * installed tests have the wrong libexecdir [#636, !949, Jeremy Bicha] + * Inheriting final class crashes GJS [#640, !951, Gary Li] + * Various maintenance [!952, Philip Chimento] + +Version 1.81.2 +-------------- + +- New JavaScript features! This version of GJS is based on SpiderMonkey 128, an + upgrade from the previous ESR (Extended Support Release) of SpiderMonkey 115. + Here are the highlights of the new JavaScript features. + For more information, look them up on MDN or devdocs.io. + + * New APIs + + The new `Object.groupBy()` and `Map.groupBy()` static methods group the + elements of an iterable according to the return value of a key function. + + The new `Promise.withResolvers()` static method returns a Promise as well + as its resolve and reject functions, shorthand for a common pattern used + when promisifying event-based APIs. + + Strings have gained the `isWellFormed()` and `toWellFormed()` methods + which help when interoperating with strings that may have unpaired + Unicode surrogates. This usually does not come up in the GNOME platform. + + ArrayBuffers have gained the `transfer()` and `transferToFixedLength()` + methods, which transfer ownership of a data buffer to a new ArrayBuffer + object, without copying it, and invalidating ("detaching") any existing + references to the buffer. There is also a new property, `detached`, which + allows checking whether an ArrayBuffer is in the detached state. + + The new `Intl.Segmenter` class allows splitting a string into graphemes, + words, or sentences, in a locale-aware way. + + `Intl.NumberFormat` has gained `formatRange()` and `formatRangeToParts()` + methods, which allow formatting number ranges, like "3–5". + + `Intl.PluralRules` has gained a `selectRange()` method, which allows + selecting the proper plural form based on a range of numbers, like + "30–50 feral hogs". + + * New behaviour + + The `Intl.NumberFormat` and `Intl.PluralRules` constructors support new + options: `roundingIncrement`, `roundingMode`, `roundingPriority`, and + `trailingZeroDisplay`. + + The `Intl.NumberFormat` constructor also supports the new option + `useGrouping`. + + * Backwards-incompatible changes + + The behaviour of `Date.parse()` has been changed to be more consistent + with other JavaScript engines. (But don't use `Date.parse()`.) + +- Closed bugs and merge requests: + * Invalid search paths cause failed assertions when printing imports.gi + [#629, !935, Gary Li] + * SpiderMonkey 128 [#630, !936, !945, Philip Chimento] + * Pretty-printing byte array in cjs-console throws a type conversion + error [#434, !937, Gary Li] + * js: Add gjs_debug_callable() debug function [!940, Philip Chimento] + * build: Build Cairo from subproject if not found [!941, Philip + Chimento] + * Bump CI image to Fedora 40 [!942, Philip Chimento] + * CI tools updates [!943, Philip Chimento] + +Version 1.81.1 +-------------- + +- Breaking change: When creating a GObject with the `new` operator, the + constructor takes a single argument consisting of a property bag with + GObject construct properties and their values. + This was often confused with the `new` static method that may take + arguments that are not interpreted as property bags. + For example, Gio.FileIcon was one of the many affected APIs: + + new Gio.FileIcon({file: myFile}) + + vs + + Gio.FileIcon.new(myFile) + + Confusion between the two often lead to bug reports when confusing + these two and calling `new Gio.FileIcon(myFile)` - the constructor + would look for a nonexistent `file` property on `myFile`, causing an + improperly initialized object. + + This is now no longer allowed. The argument to `new Gio.FileIcon(...)` + must be a plain JS object, not a GObject. + + It's possible that existing code legitimately used a GObject here. If + your code does this and a quick migration is impractical, please get + in touch and we will revert this change before 1.82.0 in favour of a + longer deprecation period. + +- The `get_data()`, `get_qdata()`, `set_data()`, `steal_data()`, + `steal_qdata()`, `ref()`, `unref()`, `ref_sink()`, and + `force_floating()` methods of GObject now throw if called. + These methods never worked, but sometimes they would silently appear + to succeed, then cause crashes or memory leaks later. + + If you were trying to use the `get_data()` family of methods, just set + a JS property instead. If you were trying to modify the refcount of a + GObject in JS, instead set the object as the value of a JS property on + some other object. + +- Closed bugs and merge requests: + * doc: Document how to get a stack trace [!864, Sonny Piers] + * TextDecoder should accept GBytes [#587, !903, Sriyansh Shivam] + * Possible use-after-free with GLib.Regex.match/GLib.MatchInfo [#589, + !920, Philip Chimento] + * method `get_line` of `Pango.Layout` doesn't work. [#547, !921, + Philip Chimento] + * Block calls to g_object_get_data and friends [#423, !922, Philip + Chimento] + * Crash when calling Pango.Layout.get_pixel_size() with a badly + init:ed Pango.Layout [#580, !923, Philip Chimento] + * doc: avoid reference to Gio.UnixInputStream [!925, Andy Holmes] + * Add a CI check for config.h, and some other useful checks [#447, + !926, Philip Chimento] + * Incorrect UnixOutputStream warning [#610, !928, Philip Chimento] + * Various maintenance [!929, !931, Philip Chimento] + * Docs: Various markdown fixes [!930, Frank Dana] + * Some build fixes for the main (and gnome-46) branches for Visual + Studio [!932, Chun-wei Fan] + * GJS doesn't log undefined values [#621, !933, Gary Li] + * property objects are printed as empty js objects [#622, !934, Gary + Li] + +Version 1.80.2 +-------------- + +- Quick follow-up release to fix crash on ppc64. + +- Closed bugs and merge requests: + * 1.79.90 failing tests on ppc64 [#605, !927, Daniel Kolesa] + +Version 1.80.1 +-------------- + +- Quick follow-up release to fix build failure on MacPorts and Homebrew. + +- Closed bugs and merge requests: + * 1.79.90: gi/arg-inl.h: expression is not assignable [#608, !924, + Philip Chimento] + +Version 1.78.5 +-------------- + +- You may have noticed that WeakRef and FinalizationRegistry... never + actually worked as they were supposed to. They work now! + +- Closed bugs and merge requests: + * Workspace switching performance degradation due to leaked WeakRefs + in JS [#600, !913, Philip Chimento] + +Version 1.80.0 +-------------- + +- In GNOME 46 and later, platform-specific GLib and Gio APIs have moved + to the separate libraries GLibUnix, GioUnix, GLibWin32, and GioWin32. + They are still available in the main GLib and Gio libraries, so your + code will continue to work, but you will get a deprecation message. + + To migrate your code, import the new libraries (e.g., + `import GioUnix from 'gi://GioUnix';`) and consider the 'Unix' or + 'Win32' prefix part of the namespace, rather than class or function + name: e.g., + * Gio.UnixInputStream -> GioUnix.InputStream + * GLib.unix_open_pipe -> GLibUnix.open_pipe + + Exceptions to the above rule are Gio.UnixConnection, + Gio.UnixCredentialsMessage, Gio.UnixFDList, Gio.UnixSocketAddress, and + Gio.UnixSocketAddressType. These remain in Gio, because they are + actually cross-platform despite being named "Unix". + +- Closed bugs and merge requests: + * meson: fix automagic dependency lookup for cairo [!917, Eli + Schwartz] + * Deprecate accessing GLibUnix/GLibWin32 APIs through GLib [#599, + !918, Philip Chimento] + * CI: Build newer GLib in debug Docker image [!919, Philip Chimento] + +Version 1.79.90 +--------------- + +- You may have noticed that WeakRef and FinalizationRegistry... never + actually worked as they were supposed to. They work now! + +- Closed bugs and merge requests: + * Workspace switching performance degradation due to leaked WeakRefs + in JS [#600, !913, Philip Chimento] + * GTop.glibtop_get_mountlist invocation causes GNOME Shell Crash + [#601, !914, Philip Chimento] + * Progress towards some performance improvements in accessing GObject + properties [!915, Marco Trevisan] + * Various maintenance [!916, Philip Chimento] + +Version 1.79.3 +-------------- + +- Closed bugs and merge requests: + * Various maintenance [!912, Philip Chimento] + +Version 1.78.4 +-------------- + +- Closed bugs and merge requests: + * package: Specify GIRepository version [!910, !911, Florian Müllner] + +Version 1.76.3 +-------------- + +- Various fixes ported from the development branch. + +- Closed bugs and merge requests: + * gi/gerror: Fix version of the GIRepository typelib import [!906, Jordan + Petridis] + * package: Specify GIRepository version [!910, !911, Florian Müllner] + +Version 1.79.2 +-------------- + +- Progress towards some performance improvements in accessing GObject + properties [Marco Trevisan] + +- Regression fix also released in 1.78.3 [Philip Chimento] + +- Closed bugs and merge requests: + * value, object: Honor signal arguments transfer annotation [!862, + Marco Trevisan] + +Version 1.78.3 +-------------- + +- Closed bugs and merge requests: + * GJS 1.78.2 causes all Gnome extensions preference settings windows + to disappears after 3-7 seconds [#598, !909, Philip Chimento] + +Version 1.79.1 +-------------- + +- Closed bugs and merge requests: + * Improve console output [#511, !890, Sriyansh Shivam] + * Name the GC source [!897, Ivan Molodetskikh] + * Various maintenance [!898, !907, Philip Chimento] + * build: Fix meson deprecations [Rick Calixte] + * doc: fix broken link in Mainloop.md [!899, Andy Holmes] + * overrides: Make class object a parameter of register type hooks [!900, + Philip Chimento] + * Display correct stack trace on SyntaxError [#584, !901, Philip Chimento] + * HTTP server stops listening [#569, !904, Akshay Warrier] + +Version 1.78.2 +-------------- + +- Closed bugs and merge requests: + * Uninitialized memory in float out values can lead to crashes in mozjs gc + code later on [#591, !902, Philip Chimento] + * Garbage collection of Gdk surfaces [#592, !905, Philip Chimento] + * gi/gerror: Fix version of the GIRepository typelib import [!906, Jordan + Petridis] + +Version 1.78.1 +-------------- + +- Closed bugs and merge requests: + * Gtk template signals cause a reference cycle that is not detected [#576, + !891, James Westman] + * Modules from resources may get loaded twice [#577, !892, Philip Chimento] + * docs: add examples for creating cairo image surfaces [!894, Andy Holmes] + * Deadlocks between GJS GC and dconf gsettings when a setting value is changed + [#558, !895, msizanoen] + * Gtk3: Fix leak in GtkBuilder template signal connections [!896, Philip + Chimento] + +Version 1.78.0 +-------------- + +- Closed bugs and merge requests: + * Improved Console.log Output [!886, Sriyansh Shivam] + * `gjs:dbus / Gtk4` unit test fails: Function Gtk.SectionModel.get_section() + cannot be called [#575, !889, Matt Turner] + +Version 1.77.90 +--------------- + +- Building GJS with -fno-exceptions is now the default. To retain the previous + behaviour, invoke Meson with -Dcpp_eh=default. + +- Closed bugs and merge requests: + * testEverything fails make check [#95, !858, Marco Trevisan] + * Using a Gio.Appinfo().launch with context may crash gjs [#553, !858, Marco + Trevisan] + * Fixed-size and Zero-terminated arrays are leaked when used as in or inout + arguments with transfer none [#561, !858, Marco Trevisan] + * Crash due to bad memory usage when calling a function taking an inout array + with length parameter and transfer full [#562, !858, Marco Trevisan] + * Various maintenance [!875, !888, Philip Chimento, Marco Trevisan, Andy + Holmes] + * README.MSVC.md: Update for SpiderMonkey-115.x [!877, Chun-wei Fan] + * GJS returns pointers instead of numbers for function with output parameters + [#570, !878, Philip Chimento, Marco Trevisan] + * Profiler spuriously records GJS.boxed_instance and GJS.boxed_prototype + [#551, !879, Philip Chimento] + * installed-tests/js/meson: Add tests dependencies to dbus tests [!880, Marco + Trevisan] + * eslint: Make multi-line imports to always include a trailing comma [!881, + Marco Trevisan] + * Make console.error format GError correctly [#572, !883, Sriyansh Shivam] + * Gtk: Throw an error for an invalid Template string [!884, Andy Holmes] + * Gtk: Attempt to load Template from a string, if it appears valid [!885, Andy + Holmes] + * global: Really enable non-mutating Array methods [!887, Philip Chimento] + Version 1.77.2 -------------- diff --git a/README.MSVC.md b/README.MSVC.md new file mode 100644 index 000000000..2880cbe77 --- /dev/null +++ b/README.MSVC.md @@ -0,0 +1,167 @@ +Instructions for building GJS on Visual Studio or clang-cl +========================================================== +Building the GJS on Windows is now supported using Visual Studio +versions 2019 16.5.x or later with or without clang-cl in both 32-bit +and 64-bit (x64) flavors, via Meson. It should be noted that a +recent-enough Windows SDK from Microsoft is still required if using +clang-cl, as we will still use items from the Windows SDK. + +Recent official binary installers of CLang (which contains clang-cl) +from the LLVM website are known to work to build SpiderMonkey 128 and +GJS. + +You will need the following items to build GJS using Visual Studio +or clang-cl (they can be built with Visual Studio 2015 or later, +unless otherwise noted): +- SpiderMonkey 128.x (mozjs-128). This must be built with clang-cl as + the Visual Studio compiler is no longer supported for building this. + Please see the below section carefully on this... +- GObject-Introspection (G-I) 1.66.x or later +- GLib 2.66.x or later, (which includes GIO, GObject, and the + associated tools) +- Cairo including Cairo-GObject support (Optional) +- GTK+-4.x or later (Optional) +- and anything that the above items depend on. + +Note again that SpiderMonkey must be built using Visual Studio with +clang-cl, and the rest should preferably be built with Visual Studio +or clang-cl as well. The Visual Studio version used for building the +other dependencies should preferably be the same across the board, or, +if using Visual Studio 2015 or later, Visual Studio 2015 through 2022. + +Please also be aware that the Rust MSVC toolchains that correspond to +the platform you are building for must also be present to build +SpiderMonkey. Please refer to the Rust website on how to install the +Rust compilers and toolchains for MSVC. This applies to clang-cl +builds as well. + +Be aware that it is often hard to find a suitable source release for +SpiderMonkey nowadays, so it may be helpful to look in + +ftp://ftp.gnome.org/pub/gnome/teams/releng/tarballs-needing-help/mozjs/ + +for the suitable release series of SpiderMonkey that corresponds to +the GJS version that is being built, as GJS depends on ESR (Extended +Service Release, a.k.a Long-term support) releases of SpiderMonkey. + +You may also be able to obtain the SpiderMonkey 128.x sources via the +FireFox (ESR) or Thunderbird 128.x sources, in $(srcroot)/js. + +Please do note that the build must be done carefully, in addition to the +official instructions that are posted on the Mozilla website: + +https://firefox-source-docs.mozilla.org/js/build.html + +You will need to create a .mozconfig file that will describe your build +options for the build in the root directory of the Firefox/ThunderBird 128.x +sources. A sample content of the .mozconfig file can be added as follows: + +``` +ac_add_options --enable-application=js +mk_add_options MOZ_MAKE_FLAGS=-j12 +ac_add_options --target=x86_64-pc-mingw32 +ac_add_options --host=x86_64-pc-mingw32 +ac_add_options --disable-tests +ac_add_options --enable-optimize +ac_add_options --disable-debug +ac_add_options --disable-jemalloc +ac_add_options --prefix=c:/software.b/mozjs128.bin +``` + +An explanation of the lines above: +* `ac_add_options --enable-application=js`: This line is absolutely required, to build SpiderMonkey standalone +* `mk_add_options MOZ_MAKE_FLAGS=-j12`: MOZ_MAKE_FLAGS=-jX means X number of parallel processes for the build +* `ac_add_options --target=x86_64-pc-mingw32`: Target architecture, replace `x86_64` with `aarch64` for ARM64 builds, and with `i686` for 32-bit x86 builds. +* `ac_add_options --host=x86_64-pc-mingw32`: Use this as-is, unless building on a 32-bit compiler (replace `x86_64` with `i686`; not recommended) +* `ac_add_options --disable-tests`: Save some build time +* `ac_add_options --enable-optimize`: Use for release builds of SpiderMonkey. Use `--disable-optimize` instead if building with `--enable-debug` +* `ac_add_options --enable-debug`: Include debugging functions, for debug builds. Use `--disable-debug` instead if building with `--enable-optimize` +* `ac_add_options --disable-jemalloc`: This is absolutely needed, otherwise GJS will not build and run correctly +* `ac_add_options --prefix=c:/software.b/mozjs128.bin`: Some installation path, change as needed + +If your GJS build crashes upon launch, use Dependency Walker to ensure that +mozjs-128.dll does not depend on mozglue.dll! If it does, or if GJS fails to +link with missing arena_malloc() and friends symbols, you have built SpiderMoney +incorrectly and will need to rebuild SpiderMonkey (with the build options as +noted above) and retry the build. + +Please also check that `--enable-optimize` is *not* used with `--enable-debug`. +You should explicitly enable one and disable the other, as `--enable-debug` +will make the resulting build depend on the debug CRT, and mixing between +the release and debug CRT in the same DLL is often a sign of trouble when using +with GJS, meaning that you will need to rebuild SpiderMonkey with the appropriate +options set in your `.mozconfig` file. Please note that for SpiderMonkey builds, +PDB files are generated even if `--disable-debug` is used. + +You will need to check that `js-config.h` has the correct entries that correspond +to your SpiderMonkey build, especially the following items: + +* `JS_64BIT`, `JS_PUNBOX64`: Should be defined for 64-bit builds, not 32-bit builds +* `JS_NUNBOX32`: Should be defined for 32-bit builds, not 64-bit builds +* `JS_DEBUG`, `JS_GC_ZEAL`: Should only be defined if `--enable-debug` is used + +Note in particular that a mozglue.dll should *not* be in $(builddir)/dist/bin, +although there will be a mozglue.lib somewhere in the build tree (which, you can +safely delete after building SpiderMonkey). The --host=... and --target=... +are absolutely required for all builds, as per the Mozilla's SpiderMonkey build +instructions, as Rust is being involved here. + +Run `./mach build` to carry out the build, and then `./mach build install` to copy +the completed build to the directory specified by `ac_add_options --prefix=xxx`. + +If `./mach build install` does not work for you for some reason, the DLLs you +need and js.exe can be found in $(buildroot)/dist/bin (you need *all* the DLLs, +make sure that there is no mozglue.dll, otherwise you will need to redo your +build as noted above), and the required headers are found in +$(buildroot)/dist/include. Note that for PDB files and .lib files, +you will need to search for them in $(buildroot), +where the PDB file names match the filenames for the DLLs/EXEs in +$(buildroot)/dist/bin, and you will need to look for the following .lib files: +-mozjs-128.lib +-js_static.lib (optional) + +You may want to put the .lib's and DLLs/EXEs into $(PREFIX)\lib and +$(PREFIX)\bin respectively, and put the headers into +$(PREFIX)\include\mozjs-128 for convenience. + +You will need to place the generated mozjs-128.pc pkg-config file into +$(PREFIX)\lib\pkgconfig and ensure that pkg-config can find it by +setting PKG_CONFIG_PATH. Ensure that the 'includedir' and 'libdir' +in there is correct so that the mozjs-128.pc can be used correctly in +Visual Studio/clang-cl builds, and replace the `-isystem` with `-I` if +building GJS with Visual Studio. You will also need to ensure that the +existing GObject-Introspection installation (if used) is on the same +drive where the GJS sources are (and therefore where the GJS build +is being carried out). + +To carry out the build +====================== +If using clang-cl, you will need to set *both* the environment variables CC +and CXX to: 'clang-cl [--target=]' (without the quotes); please +see https://clang.llvm.org/docs/CrossCompilation.html on how the target triplet +can be defined, which is used if using the cross-compilation capabilities of CLang. +In this case, you need to ensure that 'clang-cl.exe' and 'lld-link.exe' (i.e. your +LLVM bindir) are present in your PATH. + +You need to install Python 3.6.x or later, as well as the +pkg-config tool, Meson (via pip) and Ninja. Perform a build by doing the +following, in an appropriate Visual Studio command prompt +in an empty build directory: + +``` +meson --buildtype=... --prefix= -Dskip_dbus_tests=true -Dprofiler=disabled +``` + +(Note that -Dskip_dbus_tests=true is required for MSVC/clang-cl builds; please +see the Meson documentation for the values accepted by buildtype) + +You may want to view the build options after the configuration succeeds +by using 'meson configure'. You may need to set the envvar: +`SETUPTOOLS_USE_DISTUTILS=stdlib` for the introspection step to proceed +successfully. A fix for this is being investigated. + +When the configuration succeeds, run: +ninja + +You may choose to install the build results using 'ninja install' +or running the 'install' project when the build succeeds. diff --git a/README.md b/README.md index 60bc65299..12fe00793 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,45 @@ +[![Build Status](https://gitlab.gnome.org/GNOME/gjs/badges/master/pipeline.svg)](https://gitlab.gnome.org/GNOME/gjs/pipelines) +[![Coverage report](https://gitlab.gnome.org/GNOME/gjs/badges/master/coverage.svg)](https://gnome.pages.gitlab.gnome.org/gjs/) +[![Contributors](https://img.shields.io/github/contributors/GNOME/gjs.svg)](https://gitlab.gnome.org/GNOME/gjs/-/graphs/HEAD) +[![Last commit](https://img.shields.io/github/last-commit/GNOME/gjs.svg)](https://gitlab.gnome.org/GNOME/gjs/commits/HEAD) +[![Search hit](https://img.shields.io/github/search/GNOME/gjs/goto.svg?label=github%20hits)](https://github.com/search?utf8=%E2%9C%93&q=gjs&type=) [![License](https://img.shields.io/badge/License-LGPL%20v2%2B-blue.svg)](https://gitlab.gnome.org/GNOME/gjs/blob/HEAD/COPYING) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitlab.gnome.org/GNOME/gjs/blob/HEAD/COPYING) -CJS fork of GJS for Cinnamon. It is functionally identical, and is only -to maintain stability with the Cinnamon release cycle, and between various -distributions. +GNOME JavaScript +============================= -CJS is a JavaScript runtime built on +GJS is a JavaScript runtime built on [Firefox's SpiderMonkey JavaScript engine](https://spidermonkey.dev/) and the [GNOME platform libraries](https://developer.gnome.org/). +Use the GNOME platform libraries in your JavaScript programs. +GJS powers GNOME Shell, Maps, Characters, Sound Recorder and many other apps. + +If you would like to learn more or get started with GJS, head over to the [documentation](./doc/Home.md). + +## Installation + +Available as part of your GNOME distribution by default. +In most package managers the package will be called `gjs`. + ## Usage -CJS includes a command-line interpreter, usually installed in -`/usr/bin/cjs`. -Type `cjs` to start it and test out your JavaScript statements +GJS includes a command-line interpreter, usually installed in +`/usr/bin/gjs`. +Type `gjs` to start it and test out your JavaScript statements interactively. Hit Ctrl+D to exit. -`cjs filename.js` runs a whole program. -`cjs -d filename.js` does that and starts a debugger as well. +`gjs filename.js` runs a whole program. +`gjs -d filename.js` does that and starts a debugger as well. There are also facilities for generating code coverage reports. -Type `cjs --help` for more information. +Type `gjs --help` for more information. -_______ -. -# Upstream +`-d` only available in gjs >= 1.53.90 ## Contributing -[![Contributors](https://img.shields.io/github/contributors/GNOME/gjs.svg)](https://gitlab.gnome.org/GNOME/gjs/-/graphs/HEAD) For instructions on how to get started contributing to GJS, please read the contributing guide, diff --git a/build/choose-tests-locale.sh b/build/choose-tests-locale.sh old mode 100755 new mode 100644 diff --git a/build/compile-gschemas.py b/build/compile-gschemas.py deleted file mode 100644 index f1800767b..000000000 --- a/build/compile-gschemas.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: MIT OR LGPL-2.0-or-later -# SPDX-FileCopyrightText: 2019 Philip Chimento - -import os -import subprocess -import sys - -if len(sys.argv) < 2: - sys.exit("usage: compile-gschemas.py ") - -schemadir = sys.argv[1] - -if os.environ.get('DESTDIR') is None: - print('Compiling GSettings schemas...') - subprocess.call(['glib-compile-schemas', schemadir]) diff --git a/build/maintainer-upload-release.sh b/build/maintainer-upload-release.sh old mode 100755 new mode 100644 index 60a610948..011df8cf2 --- a/build/maintainer-upload-release.sh +++ b/build/maintainer-upload-release.sh @@ -24,6 +24,9 @@ case $project_version in 1.7[34].*) gnome_series=43 ;; 1.7[56].*) gnome_series=44 ;; 1.7[78].*) gnome_series=45 ;; + 1.79.* | 1.80.*) gnome_series=46 ;; + 1.8[12].*) gnome_series=47 ;; + 1.8[34].*) gnome_series=48 ;; *) echo "Version $project_version not handled by this script" exit 1 @@ -54,4 +57,4 @@ popd scp "$tarball_path" "master.gnome.org:" # shellcheck disable=SC2029 -ssh -t "master.gnome.org" ftpadmin install "$tarball_basename" +ssh -t "master.gnome.org" ftpadmin install --unattended "$tarball_basename" diff --git a/build/symlink-gjs.py b/build/symlink-cjs.py similarity index 60% rename from build/symlink-gjs.py rename to build/symlink-cjs.py index af54428e0..213b73536 100644 --- a/build/symlink-gjs.py +++ b/build/symlink-cjs.py @@ -9,17 +9,8 @@ assert(len(sys.argv) == 2) -destdir = os.environ.get('DESTDIR') -install_prefix = os.environ.get('MESON_INSTALL_PREFIX') -bindir = sys.argv[1] -if destdir is not None: - # os.path.join() doesn't concat paths if one of them is absolute - if install_prefix[0] == '/' and os.name != 'nt': - installed_bin_dir = os.path.join(destdir, install_prefix[1:], bindir) - else: - installed_bin_dir = os.path.join(destdir, install_prefix, bindir) -else: - installed_bin_dir = os.path.join(install_prefix, bindir) +installed_bin_dir = os.path.join(os.environ.get('MESON_INSTALL_DESTDIR_PREFIX'), + sys.argv[1]) if os.name == 'nt': # Using symlinks on Windows often require administrative privileges, diff --git a/cjs/byteArray.cpp b/cjs/byteArray.cpp index 6b395ce7d..20b0258a9 100644 --- a/cjs/byteArray.cpp +++ b/cjs/byteArray.cpp @@ -6,11 +6,14 @@ #include +#include // for copy_n + #include #include #include #include +#include #include #include #include @@ -28,15 +31,6 @@ #include "cjs/jsapi-util.h" #include "cjs/macros.h" #include "cjs/text-encoding.h" -#include "util/misc.h" // for _gjs_memdup2 - -// Callback to use with JS::NewExternalArrayBuffer() - -static void bytes_unref_arraybuffer(void* contents [[maybe_unused]], - void* user_data) { - auto* gbytes = static_cast(user_data); - g_bytes_unref(gbytes); -} GJS_JSAPI_RETURN_CONVENTION static bool to_string_func(JSContext* cx, unsigned argc, JS::Value* vp) { @@ -145,15 +139,18 @@ from_gbytes_func(JSContext *context, return true; } - JS::RootedObject array_buffer( - context, - JS::NewExternalArrayBuffer( - context, len, - const_cast(data), // the ArrayBuffer won't modify the data - bytes_unref_arraybuffer, gbytes)); + JS::RootedObject array_buffer{context, JS::NewArrayBuffer(context, len)}; if (!array_buffer) return false; - g_bytes_ref(gbytes); // now owned by both ArrayBuffer and BoxedBase + + // Copy the data into the ArrayBuffer so that the copy is aligned, and + // because the GBytes data pointer may point into immutable memory. + { + JS::AutoCheckCannotGC nogc; + bool unused; + uint8_t* storage = JS::GetArrayBufferData(array_buffer, &unused, nogc); + std::copy_n(static_cast(data), len, storage); + } JS::RootedObject obj( context, JS_NewUint8ArrayWithBuffer(context, array_buffer, 0, -1)); @@ -164,14 +161,20 @@ from_gbytes_func(JSContext *context, return true; } -JSObject* gjs_byte_array_from_data(JSContext* cx, size_t nbytes, void* data) { +JSObject* gjs_byte_array_from_data_copy(JSContext* cx, size_t nbytes, + void* data) { JS::RootedObject array_buffer(cx); // a null data pointer takes precedence over whatever `nbytes` says - if (data) - array_buffer = JS::NewArrayBufferWithContents( - cx, nbytes, _gjs_memdup2(data, nbytes)); - else + if (data) { + array_buffer = JS::NewArrayBuffer(cx, nbytes); + + JS::AutoCheckCannotGC nogc{}; + bool unused; + uint8_t* storage = JS::GetArrayBufferData(array_buffer, &unused, nogc); + std::copy_n(static_cast(data), nbytes, storage); + } else { array_buffer = JS::NewArrayBuffer(cx, 0); + } if (!array_buffer) return nullptr; @@ -186,7 +189,7 @@ JSObject* gjs_byte_array_from_data(JSContext* cx, size_t nbytes, void* data) { } JSObject* gjs_byte_array_from_byte_array(JSContext* cx, GByteArray* array) { - return gjs_byte_array_from_data(cx, array->len, array->data); + return gjs_byte_array_from_data_copy(cx, array->len, array->data); } GBytes* gjs_byte_array_get_bytes(JSObject* obj) { diff --git a/cjs/byteArray.h b/cjs/byteArray.h index 342f54898..958f57213 100644 --- a/cjs/byteArray.h +++ b/cjs/byteArray.h @@ -20,7 +20,8 @@ bool gjs_define_byte_array_stuff(JSContext *context, JS::MutableHandleObject module); GJS_JSAPI_RETURN_CONVENTION -JSObject* gjs_byte_array_from_data(JSContext* cx, size_t nbytes, void* data); +JSObject* gjs_byte_array_from_data_copy(JSContext* cx, size_t nbytes, + void* data); GJS_JSAPI_RETURN_CONVENTION JSObject * gjs_byte_array_from_byte_array (JSContext *context, diff --git a/cjs/gjs.stp.in b/cjs/cjs.stp.in similarity index 60% rename from cjs/gjs.stp.in rename to cjs/cjs.stp.in index d0b51ad34..423334918 100644 --- a/cjs/gjs.stp.in +++ b/cjs/cjs.stp.in @@ -3,20 +3,20 @@ * SPDX-FileCopyrightText: 2010 Red Hat, Inc. */ -probe gjs.object_wrapper_new = process("@EXPANDED_LIBDIR@/libgjs-gi.so.0.0.0").mark("object__wrapper__new") +probe cjs.object_wrapper_new = process("@EXPANDED_LIBDIR@/libcjs-gi.so.0.0.0").mark("object__wrapper__new") { wrapper_address = $arg1; gobject_address = $arg2; gi_namespace = user_string($arg3); gi_name = user_string($arg4); - probestr = sprintf("gjs.object_wrapper_new(%p, %s, %s)", wrapper_address, gi_namespace, gi_name); + probestr = sprintf("cjs.object_wrapper_new(%p, %s, %s)", wrapper_address, gi_namespace, gi_name); } -probe gjs.object_wrapper_finalize = process("@EXPANDED_LIBDIR@/libgjs-gi.so.0.0.0").mark("object__wrapper__finalize") +probe cjs.object_wrapper_finalize = process("@EXPANDED_LIBDIR@/libcjs-gi.so.0.0.0").mark("object__wrapper__finalize") { wrapper_address = $arg1; gobject_address = $arg2; gi_namespace = user_string($arg3); gi_name = user_string($arg4); - probestr = sprintf("gjs.object_wrapper_finalize(%p, %s, %s)", wrapper_address, gi_namespace, gi_name); + probestr = sprintf("cjs.object_wrapper_finalize(%p, %s, %s)", wrapper_address, gi_namespace, gi_name); } diff --git a/cjs/gjs_pch.hh b/cjs/cjs_pch.hh similarity index 97% rename from cjs/gjs_pch.hh rename to cjs/cjs_pch.hh index f74e65918..298c62a7f 100644 --- a/cjs/gjs_pch.hh +++ b/cjs/cjs_pch.hh @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,8 @@ #include #include #include +#include +#include #include #include #include @@ -95,6 +98,7 @@ #include #include #include +#include #include #include #include diff --git a/cjs/context-private.h b/cjs/context-private.h index 7e31d0f64..79064b821 100644 --- a/cjs/context-private.h +++ b/cjs/context-private.h @@ -32,12 +32,14 @@ #include #include #include +#include // for UniqueChars, FreePolicy #include #include // for ScriptEnvironmentPreparer #include "gi/closure.h" #include "cjs/context.h" #include "cjs/jsapi-util.h" +#include "cjs/jsapi-util-root.h" #include "cjs/macros.h" #include "cjs/mainloop.h" #include "cjs/profiler.h" @@ -51,11 +53,12 @@ using JobQueueStorage = using ObjectInitList = JS::GCVector, 0, js::SystemAllocPolicy>; using FundamentalTable = - JS::GCHashMap, js::DefaultHasher, + JS::GCHashMap, js::DefaultHasher, js::SystemAllocPolicy>; using GTypeTable = - JS::GCHashMap, js::DefaultHasher, + JS::GCHashMap, js::DefaultHasher, js::SystemAllocPolicy>; +using FunctionVector = JS::GCVector; class GjsContextPrivate : public JS::JobQueue { public: @@ -87,7 +90,8 @@ class GjsContextPrivate : public JS::JobQueue { std::vector> m_destroy_notifications; std::vector m_async_closures; - std::unordered_map m_unhandled_rejection_stacks; + std::unordered_map m_unhandled_rejection_stacks; + FunctionVector m_cleanup_tasks; GjsProfiler* m_profiler; @@ -117,7 +121,6 @@ class GjsContextPrivate : public JS::JobQueue { /* flags */ std::atomic_bool m_destroying = ATOMIC_VAR_INIT(false); - bool m_in_gc_sweep : 1; bool m_should_exit : 1; bool m_force_gc : 1; bool m_draining_job_queue : 1; @@ -126,13 +129,6 @@ class GjsContextPrivate : public JS::JobQueue { bool m_unhandled_exception : 1; bool m_should_listen_sigusr2 : 1; - // If profiling is enabled, we record the durations and reason for GC mark - // and sweep - int64_t m_gc_begin_time; - int64_t m_sweep_begin_time; - int64_t m_group_sweep_begin_time; - const char* m_gc_reason; // statically allocated - void schedule_gc_internal(bool force_gc); static gboolean trigger_gc_if_needed(void* data); void on_garbage_collection(JSGCStatus, JS::GCReason); @@ -192,7 +188,6 @@ class GjsContextPrivate : public JS::JobQueue { [[nodiscard]] GjsProfiler* profiler() const { return m_profiler; } [[nodiscard]] const GjsAtoms& atoms() const { return *m_atoms; } [[nodiscard]] bool destroying() const { return m_destroying.load(); } - [[nodiscard]] bool sweeping() const { return m_in_gc_sweep; } [[nodiscard]] const char* program_name() const { return m_program_name; } void set_program_name(char* value) { m_program_name = value; } GJS_USE const char* program_path(void) const { return m_program_path; } @@ -256,12 +251,19 @@ class GjsContextPrivate : public JS::JobQueue { JS::HandleObject incumbent_global) override; void runJobs(JSContext* cx) override; [[nodiscard]] bool empty() const override { return m_job_queue.empty(); } + [[nodiscard]] bool isDrainingStopped() const override { + return !m_draining_job_queue; + } js::UniquePtr saveJobQueue( JSContext* cx) override; GJS_JSAPI_RETURN_CONVENTION bool run_jobs_fallible(); - void register_unhandled_promise_rejection(uint64_t id, GjsAutoChar&& stack); + void register_unhandled_promise_rejection(uint64_t id, + JS::UniqueChars&& stack); void unregister_unhandled_promise_rejection(uint64_t id); + GJS_JSAPI_RETURN_CONVENTION bool queue_finalization_registry_cleanup( + JSFunction* cleanup_task); + GJS_JSAPI_RETURN_CONVENTION bool run_finalization_registry_cleanup(); void register_notifier(DestroyNotify notify_func, void* data); void unregister_notifier(DestroyNotify notify_func, void* data); @@ -270,9 +272,6 @@ class GjsContextPrivate : public JS::JobQueue { [[nodiscard]] bool register_module(const char* identifier, const char* filename, GError** error); - void set_gc_status(JSGCStatus status, JS::GCReason reason); - void set_finalize_status(JSFinalizeStatus status); - static void trace(JSTracer* trc, void* data); void free_profiler(void); diff --git a/cjs/context.cpp b/cjs/context.cpp index 79e2c9225..bcd59ae44 100644 --- a/cjs/context.cpp +++ b/cjs/context.cpp @@ -12,13 +12,13 @@ #ifdef HAVE_UNISTD_H # include // for getpid -#elif defined (_WIN32) -# include #endif -#ifdef DEBUG -# include // for find +#ifdef G_OS_WIN32 +# include +# include #endif + #include #include // for u16string #include // for get_id @@ -31,10 +31,6 @@ #include #include -#ifdef G_OS_WIN32 -#include -#endif - #include // for SystemAllocPolicy #include // for Call, JS_CallFunctionValue #include // for UndefinedHandleValue @@ -48,7 +44,7 @@ #include // for WeakCache #include // for RootedVector #include // for CurrentGlobalOrNull -#include // for DefaultHasher via WeakCache +#include // for ExposeObjectToActiveJS #include #include #include // for JobQueue::SavedJobQueue @@ -67,6 +63,7 @@ #include #include // for JS_GetFunctionObject, JS_Ge... #include // for ScriptEnvironmentPreparer +#include // for UniquePtr::get #include "gi/closure.h" // for Closure::Ptr, Closure #include "gi/function.h" @@ -93,7 +90,10 @@ #include "cjs/profiler.h" #include "cjs/promise.h" #include "cjs/text-encoding.h" -#include "modules/modules.h" +#include "modules/cairo-module.h" +#include "modules/console.h" +#include "modules/print.h" +#include "modules/system.h" #include "util/log.h" namespace mozilla { @@ -127,8 +127,6 @@ struct _GjsContext { G_DEFINE_TYPE_WITH_PRIVATE(GjsContext, gjs_context, G_TYPE_OBJECT); -Gjs::NativeModuleRegistry& registry = Gjs::NativeModuleRegistry::get(); - GjsContextPrivate* GjsContextPrivate::from_object(GObject* js_context) { g_return_val_if_fail(GJS_IS_CONTEXT(js_context), nullptr); return static_cast( @@ -336,13 +334,16 @@ gjs_context_class_init(GjsContextClass *klass) #endif g_irepository_prepend_search_path(priv_typelib_dir); } + auto& registry = Gjs::NativeModuleDefineFuncs::get(); registry.add("_promiseNative", gjs_define_native_promise_stuff); registry.add("_byteArrayNative", gjs_define_byte_array_stuff); registry.add("_encodingNative", gjs_define_text_encoding_stuff); registry.add("_gi", gjs_define_private_gi_stuff); registry.add("gi", gjs_define_repo); - - gjs_register_static_modules(); + registry.add("cairoNative", gjs_js_define_cairo_stuff); + registry.add("system", gjs_js_define_system_stuff); + registry.add("console", gjs_define_console_stuff); + registry.add("_print", gjs_define_print_stuff); } void GjsContextPrivate::trace(JSTracer* trc, void* data) { @@ -353,12 +354,13 @@ void GjsContextPrivate::trace(JSTracer* trc, void* data) { JS::TraceEdge(trc, &gjs->m_main_loop_hook, "GJS main loop hook"); gjs->m_atoms->trace(trc); gjs->m_job_queue.trace(trc); + gjs->m_cleanup_tasks.trace(trc); gjs->m_object_init_list.trace(trc); } void GjsContextPrivate::warn_about_unhandled_promise_rejections(void) { for (auto& kv : m_unhandled_rejection_stacks) { - const char *stack = kv.second; + const char* stack = kv.second.get(); g_warning("Unhandled promise rejection. To suppress this warning, add " "an error handler to your promise chain with .catch() or a " "try-catch block around your await expression. %s%s", @@ -533,10 +535,8 @@ static bool on_context_module_rejected_log_exception(JSContext* cx, JS::Value* vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - JSString* id = - JS_GetFunctionDisplayId(JS_GetObjectFunction(&args.callee())); gjs_debug(GJS_DEBUG_IMPORTER, "Module evaluation promise rejected: %s", - gjs_debug_string(id).c_str()); + gjs_debug_callable(&args.callee()).c_str()); JS::HandleValue error = args.get(0); @@ -555,10 +555,8 @@ static bool on_context_module_resolved(JSContext* cx, unsigned argc, JS::Value* vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - JSString* id = - JS_GetFunctionDisplayId(JS_GetObjectFunction(&args.callee())); gjs_debug(GJS_DEBUG_IMPORTER, "Module evaluation promise resolved: %s", - gjs_debug_string(id).c_str()); + gjs_debug_callable(&args.callee()).c_str()); args.rval().setUndefined(); @@ -619,11 +617,9 @@ static void load_context_module(JSContext* cx, const char* uri, [](JSContext* cx, unsigned argc, JS::Value* vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - JSString* id = - JS_GetFunctionDisplayId(JS_GetObjectFunction(&args.callee())); gjs_debug(GJS_DEBUG_IMPORTER, "Module evaluation promise rejected: %s", - gjs_debug_string(id).c_str()); + gjs_debug_callable(&args.callee()).c_str()); JS::HandleValue error = args.get(0); // Abort because this module is required. @@ -759,7 +755,7 @@ GjsContextPrivate::GjsContextPrivate(JSContext* cx, GjsContext* public_context) { Gjs::AutoMainRealm ar{this}; load_context_module( - cx, "resource:///org/gnome/gjs/modules/esm/_bootstrap/default.js", + cx, "resource:///org/cinnamon/cjs/modules/esm/_bootstrap/default.js", "ESM bootstrap"); } @@ -886,6 +882,11 @@ void GjsContextPrivate::schedule_gc_internal(bool force_gc) { m_auto_gc_id = g_timeout_add_seconds_full(G_PRIORITY_LOW, 10, trigger_gc_if_needed, this, nullptr); + + if (force_gc) + g_source_set_name_by_id(m_auto_gc_id, "[gjs] Garbage Collection (Big Hammer)"); + else + g_source_set_name_by_id(m_auto_gc_id, "[gjs] Garbage Collection"); } /* @@ -903,17 +904,14 @@ void GjsContextPrivate::schedule_gc_if_needed(void) { } void GjsContextPrivate::on_garbage_collection(JSGCStatus status, JS::GCReason reason) { - int64_t now = 0; if (m_profiler) - now = g_get_monotonic_time() * 1000L; + _gjs_profiler_set_gc_status(m_profiler, status, reason); switch (status) { case JSGC_BEGIN: - m_gc_begin_time = now; - m_gc_reason = gjs_explain_gc_reason(reason); gjs_debug_lifecycle(GJS_DEBUG_CONTEXT, "Begin garbage collection because of %s", - m_gc_reason); + gjs_explain_gc_reason(reason)); // We finalize any pending toggle refs before doing any garbage // collection, so that we can collect the JS wrapper objects, and in @@ -925,14 +923,6 @@ void GjsContextPrivate::on_garbage_collection(JSGCStatus status, JS::GCReason re m_async_closures.shrink_to_fit(); break; case JSGC_END: - if (m_profiler && m_gc_begin_time != 0) { - _gjs_profiler_add_mark(m_profiler, m_gc_begin_time, - now - m_gc_begin_time, "GJS", - "Garbage collection", m_gc_reason); - } - m_gc_begin_time = 0; - m_gc_reason = nullptr; - m_destroy_notifications.shrink_to_fit(); gjs_debug_lifecycle(GJS_DEBUG_CONTEXT, "End garbage collection"); break; @@ -941,73 +931,6 @@ void GjsContextPrivate::on_garbage_collection(JSGCStatus status, JS::GCReason re } } -void GjsContextPrivate::set_finalize_status(JSFinalizeStatus status) { - // Implementation note for mozjs-24: - // - // Sweeping happens in two phases, in the first phase all GC things from the - // allocation arenas are queued for sweeping, then the actual sweeping - // happens. The first phase is marked by JSFINALIZE_GROUP_START, the second - // one by JSFINALIZE_GROUP_END, and finally we will see - // JSFINALIZE_COLLECTION_END at the end of all GC. (see jsgc.cpp, - // BeginSweepPhase/BeginSweepingZoneGroup and SweepPhase, all called from - // IncrementalCollectSlice). - // - // Incremental GC muddies the waters, because BeginSweepPhase is always run - // to entirety, but SweepPhase can be run incrementally and mixed with JS - // code runs or even native code, when MaybeGC/IncrementalGC return. - // - // Luckily for us, objects are treated specially, and are not really queued - // for deferred incremental finalization (unless they are marked for - // background sweeping). Instead, they are finalized immediately during - // phase 1, so the following guarantees are true (and we rely on them): - // - phase 1 of GC will begin and end in the same JSAPI call (i.e., our - // callback will be called with GROUP_START and the triggering JSAPI call - // will not return until we see a GROUP_END) - // - object finalization will begin and end in the same JSAPI call - // - therefore, if there is a finalizer frame somewhere in the stack, - // GjsContextPrivate::sweeping() will return true. - // - // Comments in mozjs-24 imply that this behavior might change in the future, - // but it hasn't changed in mozilla-central as of 2014-02-23. In addition to - // that, the mozilla-central version has a huge comment in a different - // portion of the file, explaining why finalization of objects can't be - // mixed with JS code, so we can probably rely on this behavior. - - int64_t now = 0; - - if (m_profiler) - now = g_get_monotonic_time() * 1000L; - - switch (status) { - case JSFINALIZE_GROUP_PREPARE: - m_in_gc_sweep = true; - m_sweep_begin_time = now; - break; - case JSFINALIZE_GROUP_START: - m_group_sweep_begin_time = now; - break; - case JSFINALIZE_GROUP_END: - if (m_profiler && m_group_sweep_begin_time != 0) { - _gjs_profiler_add_mark(m_profiler, m_group_sweep_begin_time, - now - m_group_sweep_begin_time, "GJS", - "Group sweep", nullptr); - } - m_group_sweep_begin_time = 0; - break; - case JSFINALIZE_COLLECTION_END: - m_in_gc_sweep = false; - if (m_profiler && m_sweep_begin_time != 0) { - _gjs_profiler_add_mark(m_profiler, m_sweep_begin_time, - now - m_sweep_begin_time, "GJS", "Sweep", - nullptr); - } - m_sweep_begin_time = 0; - break; - default: - g_assert_not_reached(); - } -} - void GjsContextPrivate::exit(uint8_t exit_code) { g_assert(!m_should_exit); m_should_exit = true; @@ -1096,6 +1019,14 @@ bool GjsContextPrivate::run_jobs_fallible() { JS::HandleValueArray args(JS::HandleValueArray::empty()); JS::RootedValue rval(m_cx); + if (m_job_queue.length() == 0) { + // Check FinalizationRegistry cleanup tasks at least once if there are + // no microtasks queued. This may enqueue more microtasks, which will be + // appended to m_job_queue. + if (!run_finalization_registry_cleanup()) + retval = false; + } + /* Execute jobs in a loop until we've reached the end of the queue. * Since executing a job can trigger enqueueing of additional jobs, * it's crucial to recheck the queue length during each iteration. */ @@ -1139,6 +1070,11 @@ bool GjsContextPrivate::run_jobs_fallible() { } } gjs_debug(GJS_DEBUG_MAINLOOP, "Completed job %zu", ix); + + // Run FinalizationRegistry cleanup tasks after each job. Cleanup tasks + // may enqueue more microtasks, which will be appended to m_job_queue. + if (!run_finalization_registry_cleanup()) + retval = false; } m_draining_job_queue = false; @@ -1148,6 +1084,44 @@ bool GjsContextPrivate::run_jobs_fallible() { return retval; } +bool GjsContextPrivate::run_finalization_registry_cleanup() { + bool retval = true; + + JS::Rooted tasks{m_cx}; + std::swap(tasks.get(), m_cleanup_tasks); + g_assert(m_cleanup_tasks.empty()); + + JS::RootedFunction task{m_cx}; + JS::RootedValue unused_rval{m_cx}; + for (JSFunction* func : tasks) { + gjs_debug(GJS_DEBUG_MAINLOOP, + "Running FinalizationRegistry cleanup callback"); + + task.set(func); + JS::ExposeObjectToActiveJS(JS_GetFunctionObject(func)); + + JSAutoRealm ar{m_cx, JS_GetFunctionObject(func)}; + if (!JS_CallFunction(m_cx, nullptr, task, JS::HandleValueArray::empty(), + &unused_rval)) { + // Same logic as above + if (!JS_IsExceptionPending(m_cx)) { + if (!should_exit(nullptr)) + g_critical( + "FinalizationRegistry callback terminated with " + "uncatchable exception"); + retval = false; + continue; + } + gjs_log_exception_uncaught(m_cx); + } + + gjs_debug(GJS_DEBUG_MAINLOOP, + "Completed FinalizationRegistry cleanup callback"); + } + + return retval; +} + class GjsContextPrivate::SavedQueue : public JS::JobQueue::SavedJobQueue { private: GjsContextPrivate* m_gjs; @@ -1187,7 +1161,7 @@ js::UniquePtr GjsContextPrivate::saveJobQueue( } void GjsContextPrivate::register_unhandled_promise_rejection( - uint64_t id, GjsAutoChar&& stack) { + uint64_t id, JS::UniqueChars&& stack) { m_unhandled_rejection_stacks[id] = std::move(stack); } @@ -1202,6 +1176,11 @@ void GjsContextPrivate::unregister_unhandled_promise_rejection(uint64_t id) { } } +bool GjsContextPrivate::queue_finalization_registry_cleanup( + JSFunction* cleanup_task) { + return m_cleanup_tasks.append(cleanup_task); +} + void GjsContextPrivate::async_closure_enqueue_for_gc(Gjs::Closure* trampoline) { // Because we can't free the mmap'd data for a callback // while it's in use, this list keeps track of ones that diff --git a/cjs/deprecation.cpp b/cjs/deprecation.cpp index 283c80e2a..9c4e44d98 100644 --- a/cjs/deprecation.cpp +++ b/cjs/deprecation.cpp @@ -49,8 +49,14 @@ const char* messages[] = { "to be exported from a module must be defined with 'var'. The property " "access will work as previously for the time being, but please fix your " "code anyway.", + + // PlatformSpecificTypelib: + ("{} has been moved to a separate platform-specific library. Please update " + "your code to use {} instead."), }; +static_assert(G_N_ELEMENTS(messages) == GjsDeprecationMessageId::LastValue); + struct DeprecationEntry { GjsDeprecationMessageId id; std::string loc; @@ -111,9 +117,9 @@ void _gjs_warn_deprecated_once_per_callsite(JSContext* cx, warn_deprecated_unsafe_internal(cx, id, messages[id]); } -void _gjs_warn_deprecated_once_per_callsite(JSContext* cx, - GjsDeprecationMessageId id, - std::vector args) { +void _gjs_warn_deprecated_once_per_callsite( + JSContext* cx, GjsDeprecationMessageId id, + const std::vector& args) { // In C++20, use std::format() for this std::string_view format_string{messages[id]}; std::stringstream message; @@ -126,7 +132,7 @@ void _gjs_warn_deprecated_once_per_callsite(JSContext* cx, while ((pos = format_string.find("{}", pos)) != std::string::npos) { if (args_ptr >= nargs_given) { g_critical("Only %zu format args passed for message ID %u", - nargs_given, id); + nargs_given, unsigned{id}); return; } @@ -136,11 +142,12 @@ void _gjs_warn_deprecated_once_per_callsite(JSContext* cx, } if (args_ptr != nargs_given) { g_critical("Excess %zu format args passed for message ID %u", - nargs_given, id); + nargs_given, unsigned{id}); return; } message << format_string.substr(copied, std::string::npos); - warn_deprecated_unsafe_internal(cx, id, message.str().c_str()); + std::string message_formatted = message.str(); + warn_deprecated_unsafe_internal(cx, id, message_formatted.c_str()); } diff --git a/cjs/deprecation.h b/cjs/deprecation.h index 1f68b95fb..a59613d3f 100644 --- a/cjs/deprecation.h +++ b/cjs/deprecation.h @@ -5,22 +5,26 @@ #ifndef GJS_DEPRECATION_H_ #define GJS_DEPRECATION_H_ +#include + #include struct JSContext; -enum GjsDeprecationMessageId { +enum GjsDeprecationMessageId : unsigned { None, ByteArrayInstanceToString, DeprecatedGObjectProperty, ModuleExportedLetOrConst, + PlatformSpecificTypelib, + LastValue, // insert new elements before this one }; void _gjs_warn_deprecated_once_per_callsite(JSContext* cx, GjsDeprecationMessageId message); -void _gjs_warn_deprecated_once_per_callsite(JSContext* cx, - GjsDeprecationMessageId id, - std::vector args); +void _gjs_warn_deprecated_once_per_callsite( + JSContext* cx, GjsDeprecationMessageId id, + const std::vector& args); #endif // GJS_DEPRECATION_H_ diff --git a/cjs/engine.cpp b/cjs/engine.cpp index 9991b545f..10543e10a 100644 --- a/cjs/engine.cpp +++ b/cjs/engine.cpp @@ -19,24 +19,32 @@ #include #include // for JS_SetGCParameter, JS_AddFin... #include // for JS_Init, JS_ShutDown +#include #include #include #include // for JS_SetNativeStackQuota +#include // for JS_WriteUint32Pair #include +#include // for UniqueChars #include #include #include // for JS_SetGlobalJitCompilerOption +#include // for Atomic in JSPrincipals #include #include "cjs/context-private.h" #include "cjs/engine.h" #include "cjs/jsapi-util.h" +#include "cjs/profiler-private.h" #include "util/log.h" +struct JSStructuredCloneWriter; + static void gjs_finalize_callback(JS::GCContext*, JSFinalizeStatus status, void* data) { auto* gjs = static_cast(data); - gjs->set_finalize_status(status); + if (gjs->profiler()) + _gjs_profiler_set_finalize_status(gjs->profiler(), status); } static void on_promise_unhandled_rejection( @@ -52,10 +60,19 @@ static void on_promise_unhandled_rejection( } JS::RootedObject allocation_site(cx, JS::GetPromiseAllocationSite(promise)); - GjsAutoChar stack = gjs_format_stack_trace(cx, allocation_site); + JS::UniqueChars stack = format_saved_frame(cx, allocation_site); gjs->register_unhandled_promise_rejection(id, std::move(stack)); } +static void on_cleanup_finalization_registry(JSFunction* cleanup_task, + JSObject* incumbent_global + [[maybe_unused]], + void* data) { + auto* gjs = static_cast(data); + if (!gjs->queue_finalization_registry_cleanup(cleanup_task)) + g_critical("Out of memory queueing FinalizationRegistry cleanup task"); +} + bool gjs_load_internal_source(JSContext* cx, const char* filename, char** src, size_t* length) { GjsAutoError error; @@ -82,31 +99,26 @@ class GjsSourceHook : public js::SourceHook { HMODULE gjs_dll; static bool gjs_is_inited = false; -BOOL WINAPI -DllMain (HINSTANCE hinstDLL, -DWORD fdwReason, -LPVOID lpvReserved) -{ - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: { - gjs_dll = hinstDLL; - const char* reason = JS_InitWithFailureDiagnostic(); - if (reason) - g_error("Could not initialize JavaScript: %s", reason); - gjs_is_inited = true; - } break; - - case DLL_THREAD_DETACH: - JS_ShutDown (); - break; - - default: - /* do nothing */ - ; +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { + switch (fdwReason) { + case DLL_PROCESS_ATTACH: { + gjs_dll = hinstDLL; + const char* reason = JS_InitWithFailureDiagnostic(); + if (reason) + g_error("Could not initialize JavaScript: %s", reason); + gjs_is_inited = true; + } break; + + case DLL_THREAD_DETACH: + JS_ShutDown(); + break; + + default: + /* do nothing */ + ; } - return TRUE; + return TRUE; } #else @@ -128,6 +140,49 @@ class GjsInit { static GjsInit gjs_is_inited; #endif +// JSPrincipals (basically a weird name for security callbacks) which are in +// effect in the module loader's realm (GjsInternalGlobal). This prevents module +// loader stack frames from showing up in public stack traces. +class ModuleLoaderPrincipals final : public JSPrincipals { + static constexpr uint32_t STRUCTURED_CLONE_TAG = JS_SCTAG_USER_MIN; + + bool write(JSContext* cx [[maybe_unused]], + JSStructuredCloneWriter* writer) override { + g_assert_not_reached(); + return JS_WriteUint32Pair(writer, STRUCTURED_CLONE_TAG, 1); + } + + bool isSystemOrAddonPrincipal() override { return true; } + + public: + static bool subsumes(JSPrincipals* first, JSPrincipals* second) { + if (first != &the_principals && second == &the_principals) + return false; + return true; + } + + static void destroy(JSPrincipals* principals [[maybe_unused]]) { + g_assert(principals == &the_principals && + "Should not create other instances of ModuleLoaderPrinciples"); + g_assert(principals->refcount == 0 && + "Mismatched JS_HoldPrincipals/JS_DropPrincipals"); + } + + // Singleton + static ModuleLoaderPrincipals the_principals; +}; + +ModuleLoaderPrincipals ModuleLoaderPrincipals::the_principals{}; + +JSPrincipals* get_internal_principals() { + return &ModuleLoaderPrincipals::the_principals; +} + +static const JSSecurityCallbacks security_callbacks = { + /* contentSecurityPolicyAllows = */ nullptr, + &ModuleLoaderPrincipals::subsumes, +}; + JSContext* gjs_create_js_context(GjsContextPrivate* uninitialized_gjs) { g_assert(gjs_is_inited); JSContext *cx = JS_NewContext(32 * 1024 * 1024 /* max bytes */); @@ -149,11 +204,15 @@ JSContext* gjs_create_js_context(GjsContextPrivate* uninitialized_gjs) { /* set ourselves as the private data */ JS_SetContextPrivate(cx, uninitialized_gjs); + JS_SetSecurityCallbacks(cx, &security_callbacks); + JS_InitDestroyPrincipalsCallback(cx, &ModuleLoaderPrincipals::destroy); JS_AddFinalizeCallback(cx, gjs_finalize_callback, uninitialized_gjs); JS::SetWarningReporter(cx, gjs_warning_reporter); JS::SetJobQueue(cx, dynamic_cast(uninitialized_gjs)); JS::SetPromiseRejectionTrackerCallback(cx, on_promise_unhandled_rejection, uninitialized_gjs); + JS::SetHostCleanupFinalizationRegistryCallback( + cx, on_cleanup_finalization_registry, uninitialized_gjs); // We use this to handle "lazy sources" that SpiderMonkey doesn't need to // keep in memory. Most sources should be kept in memory, but we can skip diff --git a/cjs/engine.h b/cjs/engine.h index e0140d6ff..9d8af4b57 100644 --- a/cjs/engine.h +++ b/cjs/engine.h @@ -5,14 +5,19 @@ #ifndef GJS_ENGINE_H_ #define GJS_ENGINE_H_ +#include + #include // for size_t class GjsContextPrivate; struct JSContext; +struct JSPrincipals; JSContext* gjs_create_js_context(GjsContextPrivate* uninitialized_gjs); bool gjs_load_internal_source(JSContext* cx, const char* filename, char** src, size_t* length); +JSPrincipals* get_internal_principals(); + #endif // GJS_ENGINE_H_ diff --git a/cjs/error-types.cpp b/cjs/error-types.cpp index 71d93ed20..0753e56c0 100644 --- a/cjs/error-types.cpp +++ b/cjs/error-types.cpp @@ -2,6 +2,8 @@ // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later // SPDX-FileCopyrightText: 2008 litl, LLC +#include + #include #include "cjs/error-types.h" diff --git a/cjs/global.cpp b/cjs/global.cpp index 877108e27..9e5ccf037 100644 --- a/cjs/global.cpp +++ b/cjs/global.cpp @@ -46,21 +46,16 @@ union Utf8Unit; } class GjsBaseGlobal { + GJS_JSAPI_RETURN_CONVENTION static JSObject* base(JSContext* cx, const JSClass* clasp, - JS::RealmCreationOptions options) { - // Enable WeakRef without the cleanupSome specification - // Re-evaluate if cleanupSome is standardized - // See: https://github.com/tc39/proposal-cleanup-some - options.setWeakRefsEnabled( - JS::WeakRefSpecifier::EnabledWithoutCleanupSome); - + JS::RealmCreationOptions options, + JSPrincipals* principals = nullptr) { JS::RealmBehaviors behaviors; JS::RealmOptions compartment_options(options, behaviors); - JS::RootedObject global( - cx, JS_NewGlobalObject(cx, clasp, nullptr, JS::FireOnNewGlobalHook, - compartment_options)); - + JS::RootedObject global{cx, JS_NewGlobalObject(cx, clasp, principals, + JS::FireOnNewGlobalHook, + compartment_options)}; if (!global) return nullptr; @@ -74,25 +69,29 @@ class GjsBaseGlobal { } protected: - [[nodiscard]] static JSObject* create( + GJS_JSAPI_RETURN_CONVENTION + static JSObject* create( JSContext* cx, const JSClass* clasp, - JS::RealmCreationOptions options = JS::RealmCreationOptions()) { + JS::RealmCreationOptions options = JS::RealmCreationOptions(), + JSPrincipals* principals = nullptr) { options.setNewCompartmentAndZone(); - return base(cx, clasp, options); + return base(cx, clasp, options, principals); } - [[nodiscard]] static JSObject* create_with_compartment( + GJS_JSAPI_RETURN_CONVENTION + static JSObject* create_with_compartment( JSContext* cx, JS::HandleObject existing, const JSClass* clasp, - JS::RealmCreationOptions options = JS::RealmCreationOptions()) { + JS::RealmCreationOptions options = JS::RealmCreationOptions(), + JSPrincipals* principals = nullptr) { options.setExistingCompartment(existing); - return base(cx, clasp, options); + return base(cx, clasp, options, principals); } GJS_JSAPI_RETURN_CONVENTION static bool run_bootstrap(JSContext* cx, const char* bootstrap_script, JS::HandleObject global) { GjsAutoChar uri = g_strdup_printf( - "resource:///org/gnome/gjs/modules/script/_bootstrap/%s.js", + "resource:///org/cinnamon/cjs/modules/script/_bootstrap/%s.js", bootstrap_script); JSAutoRealm ar(cx, global); @@ -132,8 +131,8 @@ class GjsBaseGlobal { JS::RootedObject native_obj(m_cx); - if (!Gjs::NativeModuleRegistry::get().load(m_cx, id.get(), - &native_obj)) { + if (!Gjs::NativeModuleDefineFuncs::get().define(m_cx, id.get(), + &native_obj)) { gjs_throw(m_cx, "Failed to load native module: %s", id.get()); return false; } @@ -165,12 +164,14 @@ class GjsGlobal : GjsBaseGlobal { JS_FS_END}; public: - [[nodiscard]] static JSObject* create(JSContext* cx) { + GJS_JSAPI_RETURN_CONVENTION + static JSObject* create(JSContext* cx) { return GjsBaseGlobal::create(cx, &klass); } - [[nodiscard]] static JSObject* create_with_compartment( - JSContext* cx, JS::HandleObject cmp_global) { + GJS_JSAPI_RETURN_CONVENTION + static JSObject* create_with_compartment(JSContext* cx, + JS::HandleObject cmp_global) { return GjsBaseGlobal::create_with_compartment(cx, cmp_global, &klass); } @@ -238,17 +239,20 @@ class GjsDebuggerGlobal : GjsBaseGlobal { JS_FN("loadNative", &load_native_module, 1, 0), JS_FS_END}; public: - [[nodiscard]] static JSObject* create(JSContext* cx) { + GJS_JSAPI_RETURN_CONVENTION + static JSObject* create(JSContext* cx) { JS::RealmCreationOptions options; options.setToSourceEnabled(true); // debugger uses uneval() return GjsBaseGlobal::create(cx, &klass, options); } - [[nodiscard]] static JSObject* create_with_compartment( - JSContext* cx, JS::HandleObject cmp_global) { + GJS_JSAPI_RETURN_CONVENTION + static JSObject* create_with_compartment(JSContext* cx, + JS::HandleObject cmp_global) { return GjsBaseGlobal::create_with_compartment(cx, cmp_global, &klass); } + GJS_JSAPI_RETURN_CONVENTION static bool define_properties(JSContext* cx, JS::HandleObject global, const char* realm_name, const char* bootstrap_script) { @@ -298,15 +302,19 @@ class GjsInternalGlobal : GjsBaseGlobal { }; public: - [[nodiscard]] static JSObject* create(JSContext* cx) { - return GjsBaseGlobal::create(cx, &klass); + GJS_JSAPI_RETURN_CONVENTION + static JSObject* create(JSContext* cx) { + return GjsBaseGlobal::create(cx, &klass, {}, get_internal_principals()); } - [[nodiscard]] static JSObject* create_with_compartment( - JSContext* cx, JS::HandleObject cmp_global) { - return GjsBaseGlobal::create_with_compartment(cx, cmp_global, &klass); + GJS_JSAPI_RETURN_CONVENTION + static JSObject* create_with_compartment(JSContext* cx, + JS::HandleObject cmp_global) { + return GjsBaseGlobal::create_with_compartment( + cx, cmp_global, &klass, {}, get_internal_principals()); } + GJS_JSAPI_RETURN_CONVENTION static bool define_properties(JSContext* cx, JS::HandleObject global, const char* realm_name, const char* bootstrap_script @@ -486,7 +494,7 @@ bool gjs_global_registry_get(JSContext* cx, JS::HandleObject registry, * @global: a JS global object that has not yet been passed to this function * @realm_name: (nullable): name of the realm, for debug output * @bootstrap_script: (nullable): name of a bootstrap script (found at - * resource://org/gnome/gjs/modules/script/_bootstrap/@bootstrap_script) or + * resource://org/cinnamon/cjs/modules/script/_bootstrap/@bootstrap_script) or * %NULL for none * * Defines properties on the global object such as 'window' and 'imports', and diff --git a/cjs/global.h b/cjs/global.h index 01fa79841..a1d02e955 100644 --- a/cjs/global.h +++ b/cjs/global.h @@ -8,12 +8,12 @@ #include +#include + #include // for Handle #include #include -#include - #include "cjs/macros.h" namespace JS { diff --git a/cjs/importer.cpp b/cjs/importer.cpp index d186d8775..379a35e04 100644 --- a/cjs/importer.cpp +++ b/cjs/importer.cpp @@ -24,9 +24,10 @@ #include #include // for JS_ReportOutOfMemory, JSEXN_ERR #include +#include // for StackGCVector #include // for CurrentGlobalOrNull -#include // for PropertyKey -#include // for GetClass +#include // for PropertyKey +#include // for GetClass #include #include #include @@ -265,26 +266,21 @@ cancel_import(JSContext *context, * gjs_import_native_module: * @cx: the #JSContext * @importer: the root importer - * @parse_name: Name under which the module was registered with - * add(), should be in the format as returned by - * g_file_get_parse_name() + * @id_str: Name under which the module was registered with add() * * Imports a builtin native-code module so that it is available to JS code as - * `imports[parse_name]`. + * `imports[id_str]`. * * Returns: true on success, false if an exception was thrown. */ -bool -gjs_import_native_module(JSContext *cx, - JS::HandleObject importer, - const char *parse_name) -{ - gjs_debug(GJS_DEBUG_IMPORTER, "Importing '%s'", parse_name); +bool gjs_import_native_module(JSContext* cx, JS::HandleObject importer, + const char* id_str) { + gjs_debug(GJS_DEBUG_IMPORTER, "Importing '%s'", id_str); JS::RootedObject native_registry( cx, gjs_get_native_registry(JS::CurrentGlobalOrNull(cx))); - JS::RootedId id(cx, gjs_intern_string_to_id(cx, parse_name)); + JS::RootedId id(cx, gjs_intern_string_to_id(cx, id_str)); if (id.isVoid()) return false; @@ -293,12 +289,12 @@ gjs_import_native_module(JSContext *cx, return false; if (!module && - (!Gjs::NativeModuleRegistry::get().load(cx, parse_name, &module) || + (!Gjs::NativeModuleDefineFuncs::get().define(cx, id_str, &module) || !gjs_global_registry_set(cx, native_registry, id, module))) return false; - return define_meta_properties(cx, module, nullptr, parse_name, importer) && - JS_DefineProperty(cx, importer, parse_name, module, + return define_meta_properties(cx, module, nullptr, id_str, importer) && + JS_DefineProperty(cx, importer, id_str, module, GJS_MODULE_PROP_FLAGS); } @@ -496,7 +492,7 @@ static bool do_import(JSContext* context, JS::HandleObject obj, /* First try importing an internal module like gi */ if (parent.isNull() && - Gjs::NativeModuleRegistry::get().is_registered(name.get())) { + Gjs::NativeModuleDefineFuncs::get().is_registered(name.get())) { if (!gjs_import_native_module(context, obj, name.get())) return false; @@ -676,7 +672,8 @@ static bool importer_new_enumerate(JSContext* context, JS::HandleObject object, while (true) { GFileInfo *info; GFile *file; - if (!g_file_enumerator_iterate(direnum, &info, &file, NULL, NULL)) + if (!direnum || + !g_file_enumerator_iterate(direnum, &info, &file, NULL, NULL)) break; if (info == NULL || file == NULL) break; @@ -797,14 +794,14 @@ JSFunctionSpec gjs_importer_proto_funcs[] = { g_free(dirs); } - gjs_search_path.push_back("resource:///org/gnome/gjs/modules/script/"); - gjs_search_path.push_back("resource:///org/gnome/gjs/modules/core/"); + gjs_search_path.push_back("resource:///org/cinnamon/cjs/modules/script/"); + gjs_search_path.push_back("resource:///org/cinnamon/cjs/modules/core/"); /* $XDG_DATA_DIRS /gjs-1.0 */ system_data_dirs = g_get_system_data_dirs(); for (i = 0; system_data_dirs[i] != NULL; ++i) { GjsAutoChar s = - g_build_filename(system_data_dirs[i], "gjs-1.0", nullptr); + g_build_filename(system_data_dirs[i], "cjs-1.0", nullptr); gjs_search_path.push_back(s.get()); } @@ -813,7 +810,7 @@ JSFunctionSpec gjs_importer_proto_funcs[] = { extern HMODULE gjs_dll; char *basedir = g_win32_get_package_installation_directory_of_module (gjs_dll); GjsAutoChar gjs_data_dir = - g_build_filename(basedir, "share", "gjs-1.0", nullptr); + g_build_filename(basedir, "share", "cjs-1.0", nullptr); gjs_search_path.push_back(gjs_data_dir.get()); g_free (basedir); #else @@ -896,7 +893,7 @@ static JSObject* gjs_create_importer( /* API users can replace this property from JS, is the idea */ if (!gjs_define_string_array( context, importer, "searchPath", search_paths, - /* settable (no READONLY) but not deleteable (PERMANENT) */ + // settable (no READONLY) but not deletable (PERMANENT) JSPROP_PERMANENT | JSPROP_RESOLVING)) return nullptr; diff --git a/cjs/internal.cpp b/cjs/internal.cpp index f529fbd2d..67ddc6dc0 100644 --- a/cjs/internal.cpp +++ b/cjs/internal.cpp @@ -1,8 +1,6 @@ // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later // SPDX-FileCopyrightText: 2020 Evan Welsh -#include "cjs/internal.h" - #include #include // for size_t @@ -21,7 +19,6 @@ #include #include // for JSEXN_ERR #include -#include // for JS_AddExtraGCRootsTracer #include #include #include @@ -30,7 +27,6 @@ #include #include #include -#include #include #include // for UniqueChars #include @@ -41,6 +37,7 @@ #include "cjs/context-private.h" #include "cjs/engine.h" #include "cjs/global.h" +#include "cjs/internal.h" #include "cjs/jsapi-util-args.h" #include "cjs/jsapi-util.h" #include "cjs/macros.h" @@ -59,7 +56,7 @@ union Utf8Unit; * gjs_load_internal_module: * * @brief Loads a module source from an internal resource, - * resource:///org/gnome/gjs/modules/internal/{#identifier}.js, registers it in + * resource:///org/cinnamon/cjs/modules/internal/{#identifier}.js, registers it in * the internal global's module registry, and proceeds to compile, initialize, * and evaluate the module. * @@ -70,7 +67,7 @@ union Utf8Unit; */ bool gjs_load_internal_module(JSContext* cx, const char* identifier) { GjsAutoChar full_path(g_strdup_printf( - "resource:///org/gnome/gjs/modules/internal/%s.js", identifier)); + "resource:///org/cinnamon/cjs/modules/internal/%s.js", identifier)); gjs_debug(GJS_DEBUG_IMPORTER, "Loading internal module '%s' (%s)", identifier, full_path.get()); @@ -346,7 +343,15 @@ bool gjs_internal_parse_uri(JSContext* cx, unsigned argc, JS::Value* vp) { if (!path) return false; - if (!JS_DefineProperty(cx, return_obj, "uri", string_arg, + GjsAutoChar no_query_str = + g_uri_to_string_partial(parsed, G_URI_HIDE_QUERY); + JS::RootedString uri_no_query{cx, JS_NewStringCopyZ(cx, no_query_str)}; + if (!uri_no_query) + return false; + + if (!JS_DefineProperty(cx, return_obj, "uri", uri_no_query, + JSPROP_ENUMERATE) || + !JS_DefineProperty(cx, return_obj, "uriWithQuery", string_arg, JSPROP_ENUMERATE) || !JS_DefineProperty(cx, return_obj, "scheme", scheme, JSPROP_ENUMERATE) || @@ -370,12 +375,10 @@ bool gjs_internal_resolve_relative_resource_or_file(JSContext* cx, return handle_wrong_args(cx); GjsAutoUnref module_file = g_file_new_for_uri(uri.get()); - GjsAutoUnref module_parent_file = g_file_get_parent(module_file); - if (module_parent_file) { - GjsAutoUnref output = g_file_resolve_relative_path( - module_parent_file, relative_path.get()); - GjsAutoChar output_uri = g_file_get_uri(output); + if (module_file) { + GjsAutoChar output_uri = g_uri_resolve_relative( + uri.get(), relative_path.get(), G_URI_FLAGS_NONE, nullptr); JS::ConstUTF8CharsZ uri_chars(output_uri, strlen(output_uri)); JS::RootedString retval(cx, JS_NewStringCopyUTF8Z(cx, uri_chars)); @@ -440,32 +443,16 @@ class PromiseData { JSContext* cx; private: - JS::Heap m_resolve; - JS::Heap m_reject; - - JS::HandleFunction resolver() { - return JS::HandleFunction::fromMarkedLocation(m_resolve.address()); - } - JS::HandleFunction rejecter() { - return JS::HandleFunction::fromMarkedLocation(m_reject.address()); - } + JS::PersistentRooted m_resolve; + JS::PersistentRooted m_reject; - static void trace(JSTracer* trc, void* data) { - auto* self = PromiseData::from_ptr(data); - JS::TraceEdge(trc, &self->m_resolve, "loadResourceOrFileAsync resolve"); - JS::TraceEdge(trc, &self->m_reject, "loadResourceOrFileAsync reject"); - } + JS::HandleFunction resolver() { return m_resolve; } + JS::HandleFunction rejecter() { return m_reject; } public: explicit PromiseData(JSContext* a_cx, JSFunction* resolve, JSFunction* reject) - : cx(a_cx), m_resolve(resolve), m_reject(reject) { - JS_AddExtraGCRootsTracer(cx, &PromiseData::trace, this); - } - - ~PromiseData() { - JS_RemoveExtraGCRootsTracer(cx, &PromiseData::trace, this); - } + : cx(a_cx), m_resolve(cx, resolve), m_reject(cx, reject) {} static PromiseData* from_ptr(void* ptr) { return static_cast(ptr); @@ -511,7 +498,7 @@ static void load_async_callback(GObject* file, GAsyncResult* res, void* data) { /* etag_out = */ nullptr, &error)) { GjsAutoChar uri = g_file_get_uri(G_FILE(file)); gjs_throw_custom(promise->cx, JSEXN_ERR, "ImportError", - "Unable to load file from: %s (%s)", uri.get(), + "Unable to load file async from: %s (%s)", uri.get(), error->message); promise->reject_with_pending_exception(); return; diff --git a/cjs/jsapi-class.h b/cjs/jsapi-class.h index 1e846c4e8..bad97a4d2 100644 --- a/cjs/jsapi-class.h +++ b/cjs/jsapi-class.h @@ -10,9 +10,10 @@ #include #include +#include // for JSNative #include +#include -#include "gi/wrapperutils.h" #include "cjs/global.h" #include "cjs/jsapi-util.h" #include "cjs/macros.h" @@ -35,14 +36,23 @@ JSObject *gjs_construct_object_dynamic(JSContext *cx, const JS::HandleValueArray& args); GJS_JSAPI_RETURN_CONVENTION -bool gjs_define_property_dynamic(JSContext *cx, - JS::HandleObject proto, - const char *prop_name, - const char *func_namespace, - JSNative getter, - JSNative setter, - JS::HandleValue private_slot, - unsigned flags); +bool gjs_define_property_dynamic(JSContext*, JS::HandleObject proto, + const char* prop_name, JS::HandleId, + const char* func_namespace, JSNative getter, + JS::HandleValue getter_slot, JSNative setter, + JS::HandleValue setter_slot, unsigned flags); + +GJS_JSAPI_RETURN_CONVENTION +inline bool gjs_define_property_dynamic(JSContext* cx, JS::HandleObject proto, + const char* prop_name, JS::HandleId id, + const char* func_namespace, + JSNative getter, JSNative setter, + JS::HandleValue private_slot, + unsigned flags) { + return gjs_define_property_dynamic(cx, proto, prop_name, id, func_namespace, + getter, private_slot, setter, + private_slot, flags); +} [[nodiscard]] JS::Value gjs_dynamic_property_private_slot( JSObject* accessor_obj); diff --git a/cjs/jsapi-dynamic-class.cpp b/cjs/jsapi-dynamic-class.cpp index fa51f35b6..6e4bed31a 100644 --- a/cjs/jsapi-dynamic-class.cpp +++ b/cjs/jsapi-dynamic-class.cpp @@ -194,31 +194,32 @@ define_native_accessor_wrapper(JSContext *cx, * * Returns: %true on success, %false if an exception is pending on @cx. */ -bool -gjs_define_property_dynamic(JSContext *cx, - JS::HandleObject proto, - const char *prop_name, - const char *func_namespace, - JSNative getter, - JSNative setter, - JS::HandleValue private_slot, - unsigned flags) -{ +bool gjs_define_property_dynamic(JSContext* cx, JS::HandleObject proto, + const char* prop_name, JS::HandleId id, + const char* func_namespace, JSNative getter, + JS::HandleValue getter_slot, JSNative setter, + JS::HandleValue setter_slot, unsigned flags) { GjsAutoChar getter_name = g_strconcat(func_namespace, "_get::", prop_name, nullptr); GjsAutoChar setter_name = g_strconcat(func_namespace, "_set::", prop_name, nullptr); - JS::RootedObject getter_obj(cx, - define_native_accessor_wrapper(cx, getter, 0, getter_name, private_slot)); + JS::RootedObject getter_obj( + cx, define_native_accessor_wrapper(cx, getter, 0, getter_name, + getter_slot)); if (!getter_obj) return false; - JS::RootedObject setter_obj(cx, - define_native_accessor_wrapper(cx, setter, 1, setter_name, private_slot)); + JS::RootedObject setter_obj( + cx, define_native_accessor_wrapper(cx, setter, 1, setter_name, + setter_slot)); if (!setter_obj) return false; - return JS_DefineProperty(cx, proto, prop_name, getter_obj, setter_obj, - flags); + if (id.isVoid()) { + return JS_DefineProperty(cx, proto, prop_name, getter_obj, setter_obj, + flags); + } + + return JS_DefinePropertyById(cx, proto, id, getter_obj, setter_obj, flags); } /** diff --git a/cjs/jsapi-util-args.h b/cjs/jsapi-util-args.h index 723b5d0a5..5ec05d51f 100644 --- a/cjs/jsapi-util-args.h +++ b/cjs/jsapi-util-args.h @@ -22,6 +22,7 @@ #include #include #include // for UniqueChars +#include #include // for GenericErrorResult #include // IWYU pragma: keep diff --git a/cjs/jsapi-util-error.cpp b/cjs/jsapi-util-error.cpp index a55e0739d..2533f6d12 100644 --- a/cjs/jsapi-util-error.cpp +++ b/cjs/jsapi-util-error.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include // for GCHashSet @@ -113,8 +114,10 @@ static bool append_new_cause(JSContext* cx, JS::HandleValue thrown, &source_string); uint32_t line_num; JS::GetSavedFrameLine(cx, nullptr, saved_frame, &line_num); - uint32_t column_num; - JS::GetSavedFrameColumn(cx, nullptr, saved_frame, &column_num); + JS::TaggedColumnNumberOneOrigin tagged_column; + JS::GetSavedFrameColumn(cx, nullptr, saved_frame, &tagged_column); + JS::ColumnNumberOneOrigin column_num{tagged_column.toLimitedColumnNumber()}; + // asserts that this isn't a WASM frame JS::RootedValue v_exc{cx}; if (!JS::CreateError(cx, error_kind, saved_frame, source_string, line_num, @@ -216,33 +219,30 @@ bool gjs_throw_gerror_message(JSContext* cx, GjsAutoError const& error) { } /** - * gjs_format_stack_trace: + * format_saved_frame: * @cx: the #JSContext * @saved_frame: a SavedFrame #JSObject + * @indent: (optional): spaces of indentation * - * Formats a stack trace as a string in filename encoding, suitable for - * printing to stderr. Ignores any errors. + * Formats a stack trace as a UTF-8 string. If there are errors, ignores them + * and returns null. + * If you print this to stderr, you will need to re-encode it in filename + * encoding with g_filename_from_utf8(). * - * Returns: unique string in filename encoding, or nullptr if no stack trace + * Returns (nullable) (transfer full): unique string */ -GjsAutoChar -gjs_format_stack_trace(JSContext *cx, - JS::HandleObject saved_frame) -{ +JS::UniqueChars format_saved_frame(JSContext* cx, JS::HandleObject saved_frame, + size_t indent /* = 0 */) { JS::AutoSaveExceptionState saved_exc(cx); JS::RootedString stack_trace(cx); JS::UniqueChars stack_utf8; - if (JS::BuildStackString(cx, nullptr, saved_frame, &stack_trace, 2)) + if (JS::BuildStackString(cx, nullptr, saved_frame, &stack_trace, indent)) stack_utf8 = JS_EncodeStringToUTF8(cx, stack_trace); saved_exc.restore(); - if (!stack_utf8) - return nullptr; - - return g_filename_from_utf8(stack_utf8.get(), -1, nullptr, nullptr, - nullptr); + return stack_utf8; } void gjs_warning_reporter(JSContext*, JSErrorReport* report) { @@ -254,8 +254,7 @@ void gjs_warning_reporter(JSContext*, JSErrorReport* report) { if (gjs_environment_variable_is_set("GJS_ABORT_ON_OOM") && !report->isWarning() && report->errorNumber == 137) { /* 137, JSMSG_OUT_OF_MEMORY */ - g_error("GJS ran out of memory at %s: %i.", - report->filename, + g_error("GJS ran out of memory at %s: %i.", report->filename.c_str(), report->lineno); } @@ -277,6 +276,6 @@ void gjs_warning_reporter(JSContext*, JSErrorReport* report) { level = G_LOG_LEVEL_WARNING; } - g_log(G_LOG_DOMAIN, level, "JS %s: [%s %d]: %s", warning, report->filename, - report->lineno, report->message().c_str()); + g_log(G_LOG_DOMAIN, level, "JS %s: [%s %d]: %s", warning, + report->filename.c_str(), report->lineno, report->message().c_str()); } diff --git a/cjs/jsapi-util-root.h b/cjs/jsapi-util-root.h index 11ce0ca2c..e2fdda12e 100644 --- a/cjs/jsapi-util-root.h +++ b/cjs/jsapi-util-root.h @@ -11,84 +11,57 @@ #include // for nullptr_t #include #include -#include // for enable_if_t, is_pointer #include +#include #include +#include // for ExposeObjectToActiveJS, GetGCThingZone +#include // for SafelyInitialized #include #include #include "util/log.h" +namespace JS { template struct GCPolicy; } + /* jsapi-util-root.h - Utilities for dealing with the lifetime and ownership of * JS Objects and other things that can be collected by the garbage collector * (collectively called "GC things.") * - * GjsMaybeOwned is a multi-purpose wrapper for a GC thing of type T. You can + * GjsMaybeOwned is a multi-purpose wrapper for a JSObject. You can * wrap a thing in one of three ways: * - * - trace the thing (tie it to the lifetime of another GC thing), - * - root the thing (keep it alive as long as the wrapper is in existence), - * - maintain a weak pointer to the thing (not keep it alive at all and have it + * - trace the object (tie it to the lifetime of another GC thing), + * - root the object (keep it alive as long as the wrapper is in existence), + * - maintain a weak pointer to the object (not keep it alive at all and have it * possibly be finalized out from under you). * - * To trace or maintain a weak pointer, simply assign a thing of type T to the + * To trace or maintain a weak pointer, simply assign an object to the * GjsMaybeOwned wrapper. For tracing, you must call the trace() method when * your other GC thing is traced. * * Rooting requires a JSContext so can't just assign a thing of type T. Instead * you need to call the root() method to set up rooting. * - * If the thing is rooted, it will be unrooted either when the GjsMaybeOwned is - * destroyed, or when the JSContext is destroyed. In the latter case, you can - * get an optional notification by registering a callback in the PrivateContext. + * If the thing is rooted, it will be unrooted when the GjsMaybeOwned is + * destroyed. * * To switch between one of the three modes, you must first call reset(). This - * drops all references to any GC thing and leaves the GjsMaybeOwned in the + * drops all references to any object and leaves the GjsMaybeOwned in the * same state as if it had just been constructed. */ -/* This struct contains operations that must be implemented differently - * depending on the type of the GC thing. Add more types as necessary. If an - * implementation is never used, it's OK to leave it out. The compiler will - * complain if it's used somewhere but not instantiated here. - */ -template -struct GjsHeapOperation { - [[nodiscard]] static bool update_after_gc(JS::Heap* location); - static void expose_to_js(JS::Heap& thing); -}; - -template<> -struct GjsHeapOperation { - [[nodiscard]] static bool update_after_gc(JSTracer* trc, - JS::Heap* location) { - JS_UpdateWeakPointerAfterGC(trc, location); - return (location->unbarrieredGet() == nullptr); - } - - static void expose_to_js(JS::Heap& thing) { - JSObject *obj = thing.unbarrieredGet(); - /* If the object has been swept already, then the zone is nullptr */ - if (!obj || !JS::GetGCThingZone(JS::GCCellPtr(obj))) - return; - if (!JS::RuntimeHeapIsCollecting()) - JS::ExposeObjectToActiveJS(obj); - } -}; - /* GjsMaybeOwned is intended for use as a member of classes that are allocated * on the heap. Do not allocate GjsMaybeOwned on the stack, and do not allocate * any instances of classes that have it as a member on the stack either. */ -template class GjsMaybeOwned { private: /* m_root value controls which of these members we can access. When switching * from one to the other, be careful to call the constructor and destructor * of JS::Heap, since they use post barriers. */ - JS::Heap m_heap; - std::unique_ptr> m_root; + JS::Heap m_heap; + std::unique_ptr m_root; /* No-op unless GJS_VERBOSE_ENABLE_LIFECYCLE is defined to 1. */ inline void debug(const char* what GJS_USED_VERBOSE_LIFECYCLE) { @@ -104,7 +77,7 @@ class GjsMaybeOwned { m_root.reset(); - new (&m_heap) JS::Heap(); + new (&m_heap) JS::Heap(); } public: @@ -116,68 +89,61 @@ class GjsMaybeOwned { debug("destroyed"); } - /* To access the GC thing, call get(). In many cases you can just use the - * GjsMaybeOwned wrapper in place of the GC thing itself due to the implicit - * cast operator. But if you want to call methods on the GC thing, for - * example if it's a JS::Value, you have to use get(). */ - [[nodiscard]] constexpr const T get() const { + // COMPAT: constexpr in C++23 + [[nodiscard]] JSObject* get() const { return m_root ? m_root->get() : m_heap.get(); } - constexpr operator const T() const { return get(); } - /* Use debug_addr() only for debug logging, because it is unbarriered. */ - template - [[nodiscard]] constexpr const void* debug_addr( - std::enable_if_t>* = nullptr) const { + // Use debug_addr() only for debug logging, because it is unbarriered. + // COMPAT: constexpr in C++23 + [[nodiscard]] const void* debug_addr() const { return m_root ? m_root->get() : m_heap.unbarrieredGet(); } - constexpr bool operator==(const T& other) const { + // COMPAT: constexpr in C++23 + bool operator==(JSObject* other) const { if (m_root) return m_root->get() == other; return m_heap == other; } - constexpr bool operator!=(const T& other) const { - return !(*this == other); - } + bool operator!=(JSObject* other) const { return !(*this == other); } - /* We can access the pointer without a read barrier if the only thing we - * are doing with it is comparing it to nullptr. */ - constexpr bool operator==(std::nullptr_t) const { + // We can access the pointer without a read barrier if the only thing we are + // are doing with it is comparing it to nullptr. + // COMPAT: constexpr in C++23 + bool operator==(std::nullptr_t) const { if (m_root) return m_root->get() == nullptr; return m_heap.unbarrieredGet() == nullptr; } - constexpr bool operator!=(std::nullptr_t) const { - return !(*this == nullptr); - } + bool operator!=(std::nullptr_t) const { return !(*this == nullptr); } - /* Likewise the truth value does not require a read barrier */ - constexpr explicit operator bool() const { return *this != nullptr; } + // Likewise the truth value does not require a read barrier + // COMPAT: constexpr in C++23 + explicit operator bool() const { return *this != nullptr; } - /* You can get a Handle if the thing is rooted, so that you can use this - * wrapper with stack rooting. However, you must not do this if the - * JSContext can be destroyed while the Handle is live. */ - [[nodiscard]] constexpr JS::Handle handle() { + // You can get a Handle if the thing is rooted, so that you can use this + // wrapper with stack rooting. However, you must not do this if the + // JSContext can be destroyed while the Handle is live. */ + // COMPAT: constexpr in C++23 + [[nodiscard]] JS::HandleObject handle() { g_assert(m_root); return *m_root; } /* Roots the GC thing. You must not use this if you're already using the * wrapper to store a non-rooted GC thing. */ - void root(JSContext* cx, const T& thing) { + void root(JSContext* cx, JSObject* thing) { debug("root()"); g_assert(!m_root); - g_assert(m_heap.get() == JS::SafelyInitialized::create()); + g_assert(!m_heap); m_heap.~Heap(); - m_root = std::make_unique>(cx, thing); + m_root = std::make_unique(cx, thing); } /* You can only assign directly to the GjsMaybeOwned wrapper in the * non-rooted case. */ - void - operator=(const T& thing) - { + void operator=(JSObject* thing) { g_assert(!m_root); m_heap = thing; } @@ -188,13 +154,18 @@ class GjsMaybeOwned { void prevent_collection() { debug("prevent_collection()"); g_assert(!m_root); - GjsHeapOperation::expose_to_js(m_heap); + JSObject* obj = m_heap.unbarrieredGet(); + // If the object has been swept already, then the zone is nullptr + if (!obj || !JS::GetGCThingZone(JS::GCCellPtr(obj))) + return; + if (!JS::RuntimeHeapIsCollecting()) + JS::ExposeObjectToActiveJS(obj); } void reset() { debug("reset()"); if (!m_root) { - m_heap = JS::SafelyInitialized::create(); + m_heap = nullptr; return; } @@ -207,7 +178,7 @@ class GjsMaybeOwned { /* Prevent the thing from being garbage collected while it is in neither * m_heap nor m_root */ - JS::Rooted thing(cx, m_heap); + JS::RootedObject thing{cx, m_heap}; reset(); root(cx, thing); @@ -220,7 +191,7 @@ class GjsMaybeOwned { /* Prevent the thing from being garbage collected while it is in neither * m_heap nor m_root */ - JS::Rooted thing(cx, *m_root); + JS::RootedObject thing{cx, *m_root}; reset(); m_heap = thing; @@ -235,7 +206,7 @@ class GjsMaybeOwned { { debug("trace()"); g_assert(!m_root); - JS::TraceEdge(tracer, &m_heap, name); + JS::TraceEdge(tracer, &m_heap, name); } /* If not tracing, then you must call this method during GC in order to @@ -244,10 +215,44 @@ class GjsMaybeOwned { bool update_after_gc(JSTracer* trc) { debug("update_after_gc()"); g_assert(!m_root); - return GjsHeapOperation::update_after_gc(trc, &m_heap); + JS_UpdateWeakPointerAfterGC(trc, &m_heap); + return !m_heap; } - [[nodiscard]] constexpr bool rooted() const { return m_root != nullptr; } + // COMPAT: constexpr in C++23 + [[nodiscard]] bool rooted() const { return m_root != nullptr; } }; +namespace Gjs { + +template +class WeakPtr : public JS::Heap { + public: + using JS::Heap::Heap; + using JS::Heap::operator=; +}; + +} // namespace Gjs + +namespace JS { + +template +struct GCPolicy> { + static void trace(JSTracer* trc, Gjs::WeakPtr* thingp, + const char* name) { + return JS::TraceEdge(trc, thingp, name); + } + + static bool traceWeak(JSTracer* trc, Gjs::WeakPtr* thingp) { + return js::gc::TraceWeakEdge(trc, thingp); + } + + static bool needsSweep(JSTracer* trc, const Gjs::WeakPtr* thingp) { + Gjs::WeakPtr thing{*thingp}; + return !js::gc::TraceWeakEdge(trc, &thing); + } +}; + +} // namespace JS + #endif // GJS_JSAPI_UTIL_ROOT_H_ diff --git a/cjs/jsapi-util-string.cpp b/cjs/jsapi-util-string.cpp index 9f1a0d1da..c0d5b7138 100644 --- a/cjs/jsapi-util-string.cpp +++ b/cjs/jsapi-util-string.cpp @@ -116,7 +116,7 @@ bool gjs_string_to_utf8_n(JSContext* cx, JS::HandleString str, JS::UniqueChars* return false; size_t length = JS::GetDeflatedUTF8StringLength(linear); - char* bytes = js_pod_arena_malloc(js::StringBufferArena, length + 1); + char* bytes = js_pod_malloc(length + 1); if (!bytes) return false; @@ -590,7 +590,7 @@ gjs_debug_object(JSObject * const obj) if (js::IsFunctionObject(obj)) { JSFunction* fun = JS_GetObjectFunction(obj); - JSString* display_name = JS_GetFunctionDisplayId(fun); + JSString* display_name = JS_GetMaybePartialFunctionDisplayId(fun); if (display_name && JS_GetStringLength(display_name)) out << " // for GetClass #include #include -#include // for BuildStackString #include #include #include @@ -40,6 +39,7 @@ #include // for JS_InstanceOf #include // for ProtoKeyToClass #include // for JSProto_InternalError, JSProto_SyntaxError +#include #include "cjs/atoms.h" #include "cjs/context-private.h" @@ -262,6 +262,44 @@ static JSString* exception_to_string(JSContext* cx, JS::HandleValue exc) { return JS::ToString(cx, exc); } +// Helper function: format the error's stack property. +static std::string format_exception_stack(JSContext* cx, JS::HandleObject exc) { + JS::AutoSaveExceptionState saved_exc(cx); + auto restore = + mozilla::MakeScopeExit([&saved_exc]() { saved_exc.restore(); }); + + const GjsAtoms& atoms = GjsContextPrivate::atoms(cx); + std::ostringstream out; + + // Check both the internal SavedFrame object and the stack property. + // GErrors will not have the former, and internal errors will not + // have the latter. + JS::RootedObject saved_frame{cx, JS::ExceptionStackOrNull(exc)}; + if (saved_frame) { + JS::UniqueChars utf8_stack{format_saved_frame(cx, saved_frame)}; + if (!utf8_stack) + return {}; + out << '\n' << utf8_stack.get(); + return out.str(); + } + + JS::RootedValue stack{cx}; + if (!JS_GetPropertyById(cx, exc, atoms.stack(), &stack) || !stack.isString()) + return {}; + + JS::RootedString str{cx, stack.toString()}; + bool is_empty; + if (!JS_StringEqualsLiteral(cx, str, "", &is_empty) || is_empty) + return {}; + + JS::UniqueChars utf8_stack{JS_EncodeStringToUTF8(cx, str)}; + if (!utf8_stack) + return {}; + + out << '\n' << utf8_stack.get(); + return out.str(); +} + // Helper function: format the file name, line number, and column number where a // SyntaxError occurred. static std::string format_syntax_error_location(JSContext* cx, @@ -311,25 +349,7 @@ static std::string format_exception_with_cause( std::ostringstream out; const GjsAtoms& atoms = GjsContextPrivate::atoms(cx); - JS::UniqueChars utf8_stack; - // Check both the internal SavedFrame object and the stack property. - // GErrors will not have the former, and internal errors will not - // have the latter. - JS::RootedObject saved_frame(cx, JS::ExceptionStackOrNull(exc_obj)); - JS::RootedString str(cx); - if (saved_frame) { - JS::BuildStackString(cx, nullptr, saved_frame, &str, 0); - } else { - JS::RootedValue stack(cx); - if (JS_GetPropertyById(cx, exc_obj, atoms.stack(), &stack) && - stack.isString()) - str = stack.toString(); - } - if (str) - utf8_stack = JS_EncodeStringToUTF8(cx, str); - if (utf8_stack) - out << '\n' << utf8_stack.get(); - JS_ClearPendingException(cx); + out << format_exception_stack(cx, exc_obj); JS::RootedValue v_cause(cx); if (!JS_GetPropertyById(cx, exc_obj, atoms.cause(), &v_cause)) @@ -347,7 +367,7 @@ static std::string format_exception_with_cause( return out.str(); // out of memory, just stop here } - out << "Caused by: "; + out << "\nCaused by: "; JS::RootedString exc_str(cx, exception_to_string(cx, v_cause)); if (exc_str) { JS::UniqueChars utf8_exception = JS_EncodeStringToUTF8(cx, exc_str); @@ -393,7 +413,8 @@ static std::string format_exception_log_message(JSContext* cx, // file name, line number, and column number from the exception. // We assume that syntax errors have no cause property, and are not the // cause of other exceptions, so no recursion. - out << format_syntax_error_location(cx, exc_obj); + out << format_syntax_error_location(cx, exc_obj) + << format_exception_stack(cx, exc_obj); return out.str(); } diff --git a/cjs/jsapi-util.h b/cjs/jsapi-util.h index 6e1a15ad3..eb51b01c5 100644 --- a/cjs/jsapi-util.h +++ b/cjs/jsapi-util.h @@ -549,8 +549,8 @@ void gjs_maybe_gc (JSContext *context); void gjs_gc_if_needed(JSContext *cx); GJS_JSAPI_RETURN_CONVENTION -GjsAutoChar gjs_format_stack_trace(JSContext *cx, - JS::HandleObject saved_frame); +JS::UniqueChars format_saved_frame(JSContext* cx, JS::HandleObject saved_frame, + size_t indent = 0); /* Overloaded functions, must be outside G_DECLS. More types are intended to be * added as the opportunity arises. */ @@ -600,6 +600,7 @@ bool gjs_object_require_converted_property(JSContext *context, [[nodiscard]] std::string gjs_debug_string(JSString* str); [[nodiscard]] std::string gjs_debug_symbol(JS::Symbol* const sym); [[nodiscard]] std::string gjs_debug_object(JSObject* obj); +[[nodiscard]] std::string gjs_debug_callable(JSObject* callable); [[nodiscard]] std::string gjs_debug_value(JS::Value v); [[nodiscard]] std::string gjs_debug_id(jsid id); diff --git a/cjs/mem-private.h b/cjs/mem-private.h index adb07ad67..42340db01 100644 --- a/cjs/mem-private.h +++ b/cjs/mem-private.h @@ -6,6 +6,8 @@ #ifndef GJS_MEM_PRIVATE_H_ #define GJS_MEM_PRIVATE_H_ +#include + #include // for size_t #include diff --git a/cjs/mem.cpp b/cjs/mem.cpp index 0a5c2c424..4464557a2 100644 --- a/cjs/mem.cpp +++ b/cjs/mem.cpp @@ -2,6 +2,8 @@ // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later // SPDX-FileCopyrightText: 2008 litl, LLC +#include + #include #include diff --git a/cjs/module.cpp b/cjs/module.cpp index 82972bff2..7fecd743a 100644 --- a/cjs/module.cpp +++ b/cjs/module.cpp @@ -7,7 +7,10 @@ #include // for size_t #include +#include // for vector + #include +#include #include #include @@ -438,7 +441,8 @@ static bool import_native_module_sync(JSContext* cx, unsigned argc, } JS::RootedObject native_obj(cx); - if (!Gjs::NativeModuleRegistry::get().load(cx, id.get(), &native_obj)) { + if (!Gjs::NativeModuleDefineFuncs::get().define(cx, id.get(), + &native_obj)) { gjs_throw(cx, "Failed to load native module: %s", id.get()); return false; } @@ -471,9 +475,9 @@ bool gjs_populate_module_meta(JSContext* cx, JS::HandleValue private_ref, &private_ref.toObject()); const GjsAtoms& atoms = GjsContextPrivate::atoms(cx); - JS::RootedValue v_uri(cx); - if (!JS_GetPropertyById(cx, module, atoms.uri(), &v_uri) || - !JS_DefinePropertyById(cx, meta, atoms.url(), v_uri, + JS::RootedValue specifier{cx}; + if (!JS_GetProperty(cx, module, "id", &specifier) || + !JS_DefinePropertyById(cx, meta, atoms.url(), specifier, GJS_MODULE_PROP_FLAGS)) return false; @@ -492,6 +496,47 @@ bool gjs_populate_module_meta(JSContext* cx, JS::HandleValue private_ref, return true; } +// Canonicalize specifier so that differently-spelled specifiers referring to +// the same module don't result in duplicate entries in the registry +static bool canonicalize_specifier(JSContext* cx, + JS::MutableHandleString specifier) { + JS::UniqueChars specifier_utf8 = JS_EncodeStringToUTF8(cx, specifier); + if (!specifier_utf8) + return false; + + GjsAutoChar scheme, host, path, query; + if (!g_uri_split(specifier_utf8.get(), G_URI_FLAGS_NONE, scheme.out(), + nullptr, host.out(), nullptr, path.out(), query.out(), + nullptr, nullptr)) + return false; + + if (g_strcmp0(scheme, "gi")) { + // canonicalize without the query portion to avoid it being encoded + GjsAutoChar for_file_uri = + g_uri_join(G_URI_FLAGS_NONE, scheme.get(), nullptr, host.get(), -1, + path.get(), nullptr, nullptr); + GjsAutoUnref file = g_file_new_for_uri(for_file_uri.get()); + for_file_uri = g_file_get_uri(file); + host.reset(); + path.reset(); + if (!g_uri_split(for_file_uri.get(), G_URI_FLAGS_NONE, nullptr, nullptr, + host.out(), nullptr, path.out(), nullptr, nullptr, + nullptr)) + return false; + } + + GjsAutoChar canonical_specifier = + g_uri_join(G_URI_FLAGS_NONE, scheme.get(), nullptr, host.get(), -1, + path.get(), query.get(), nullptr); + JS::ConstUTF8CharsZ chars{canonical_specifier, strlen(canonical_specifier)}; + JS::RootedString new_specifier{cx, JS_NewStringCopyUTF8Z(cx, chars)}; + if (!new_specifier) + return false; + + specifier.set(new_specifier); + return true; +} + /** * gjs_module_resolve: * @@ -518,6 +563,9 @@ JSObject* gjs_module_resolve(JSContext* cx, JS::HandleValue importingModulePriv, g_assert(v_loader.isObject()); JS::RootedObject loader(cx, &v_loader.toObject()); + if (!canonicalize_specifier(cx, &specifier)) + return nullptr; + JS::RootedValueArray<2> args(cx); args[0].set(importingModulePriv); args[1].setString(specifier); @@ -535,23 +583,6 @@ JSObject* gjs_module_resolve(JSContext* cx, JS::HandleValue importingModulePriv, return &result.toObject(); } -// Note: exception is never pending after this function finishes, even if it -// returns null. The return value is intended to be passed to -// JS::FinishDynamicModuleImport(). -static JSObject* reject_new_promise_with_pending_exception(JSContext* cx) { - JS::ExceptionStack stack{cx}; - if (!JS::StealPendingExceptionStack(cx, &stack)) { - gjs_log_exception(cx); - return nullptr; - } - JS::RootedObject rejected{cx, JS::NewPromiseObject(cx, nullptr)}; - if (!rejected || !JS::RejectPromise(cx, rejected, stack.exception())) { - gjs_log_exception(cx); - return nullptr; - } - return rejected; -} - // Call JS::FinishDynamicModuleImport() with the values stashed in the function. // Can fail in JS::FinishDynamicModuleImport(), but will assert if anything // fails in fetching the stashed values, since that would be a serious GJS bug. @@ -593,12 +624,9 @@ static bool finish_import(JSContext* cx, JS::HandleObject evaluation_promise, // case we must not call JS::FinishDynamicModuleImport(). GJS_JSAPI_RETURN_CONVENTION static bool fail_import(JSContext* cx, const JS::CallArgs& args) { - if (!JS_IsExceptionPending(cx)) - return false; - - JS::RootedObject rejected_promise{ - cx, reject_new_promise_with_pending_exception(cx)}; - return finish_import(cx, rejected_promise, args); + if (JS_IsExceptionPending(cx)) + return finish_import(cx, nullptr, args); + return false; } GJS_JSAPI_RETURN_CONVENTION @@ -607,16 +635,12 @@ static bool import_rejected(JSContext* cx, unsigned argc, JS::Value* vp) { gjs_debug(GJS_DEBUG_IMPORTER, "Async import promise rejected"); - // Reject a new promise with the rejection value of the async import - // promise, so that FinishDynamicModuleImport will reject the - // internal_promise with it. - JS::RootedObject rejected{cx, JS::NewPromiseObject(cx, nullptr)}; - if (!rejected || !JS::RejectPromise(cx, rejected, args.get(0))) { - gjs_log_exception(cx); - return finish_import(cx, nullptr, args); - } + // Throw the value that the promise is rejected with, so that + // FinishDynamicModuleImport will reject the internal_promise with it. + JS_SetPendingException(cx, args.get(0), + JS::ExceptionStackBehavior::DoNotCapture); - return finish_import(cx, rejected, args); + return finish_import(cx, nullptr, args); } GJS_JSAPI_RETURN_CONVENTION @@ -660,6 +684,9 @@ bool gjs_dynamic_module_resolve(JSContext* cx, JS::RootedString specifier( cx, JS::GetModuleRequestSpecifier(cx, module_request)); + if (!canonicalize_specifier(cx, &specifier)) + return false; + JS::RootedObject callback_data(cx, JS_NewPlainObject(cx)); if (!callback_data || !JS_DefineProperty(cx, callback_data, "module_request", module_request, @@ -688,16 +715,9 @@ bool gjs_dynamic_module_resolve(JSContext* cx, args[1].setString(specifier); JS::RootedValue result(cx); - if (!JS::Call(cx, loader, "moduleResolveAsyncHook", args, &result)) { - if (!JS_IsExceptionPending(cx)) - return false; - - JS::RootedObject rejected_promise{ - cx, reject_new_promise_with_pending_exception(cx)}; - return JS::FinishDynamicModuleImport(cx, rejected_promise, - importing_module_priv, + if (!JS::Call(cx, loader, "moduleResolveAsyncHook", args, &result)) + return JS::FinishDynamicModuleImport(cx, nullptr, importing_module_priv, module_request, internal_promise); - } // Release in finish_import GjsContextPrivate* priv = GjsContextPrivate::from_cx(cx); diff --git a/cjs/native.cpp b/cjs/native.cpp index f10d5f443..b474ef7cd 100644 --- a/cjs/native.cpp +++ b/cjs/native.cpp @@ -18,8 +18,8 @@ #include "cjs/native.h" #include "util/log.h" -void Gjs::NativeModuleRegistry::add(const char* module_id, - GjsDefineModuleFunc func) { +void Gjs::NativeModuleDefineFuncs::add(const char* module_id, + GjsDefineModuleFunc func) { bool inserted; std::tie(std::ignore, inserted) = m_modules.insert({module_id, func}); if (!inserted) { @@ -41,32 +41,30 @@ void Gjs::NativeModuleRegistry::add(const char* module_id, * been registered. This is used to check to see if a name is a * builtin module without starting to try and load it. */ -bool Gjs::NativeModuleRegistry::is_registered(const char* name) const { +bool Gjs::NativeModuleDefineFuncs::is_registered(const char* name) const { return m_modules.count(name) > 0; } /** - * gjs_load: + * define: * @context: the #JSContext - * @parse_name: Name under which the module was registered with - * add(), should be in the format as returned by - * g_file_get_parse_name() + * @id: Name under which the module was registered with add() * @module_out: Return location for a #JSObject * - * Loads a builtin native-code module called @name into @module_out. + * Loads a builtin native-code module called @name into @module_out by calling + * the function to define it. * * Returns: true on success, false if an exception was thrown. */ -bool Gjs::NativeModuleRegistry::load(JSContext* context, const char* parse_name, - JS::MutableHandleObject module_out) { - gjs_debug(GJS_DEBUG_NATIVE, "Defining native module '%s'", parse_name); +bool Gjs::NativeModuleDefineFuncs::define( + JSContext* context, const char* id, + JS::MutableHandleObject module_out) const { + gjs_debug(GJS_DEBUG_NATIVE, "Defining native module '%s'", id); - const auto& iter = m_modules.find(parse_name); + const auto& iter = m_modules.find(id); if (iter == m_modules.end()) { - gjs_throw(context, - "No native module '%s' has registered itself", - parse_name); + gjs_throw(context, "No native module '%s' has registered itself", id); return false; } diff --git a/cjs/native.h b/cjs/native.h index e69b0d194..f5acdd1f0 100644 --- a/cjs/native.h +++ b/cjs/native.h @@ -9,35 +9,34 @@ #include #include -#include #include #include "cjs/macros.h" namespace Gjs { -class NativeModuleRegistry { - NativeModuleRegistry() {} +class NativeModuleDefineFuncs { + NativeModuleDefineFuncs() {} typedef bool (*GjsDefineModuleFunc)(JSContext* context, JS::MutableHandleObject module_out); std::unordered_map m_modules; public: - static NativeModuleRegistry& get() { - static NativeModuleRegistry the_singleton; + static NativeModuleDefineFuncs& get() { + static NativeModuleDefineFuncs the_singleton; return the_singleton; } /* called on context init */ void add(const char* module_id, GjsDefineModuleFunc func); - /* called by importer.c to to check for already loaded modules */ + // called by importer.cpp to to check for already loaded modules [[nodiscard]] bool is_registered(const char* name) const; - /* called by importer.cpp to load a statically linked native module */ + // called by importer.cpp to load a built-in native module GJS_JSAPI_RETURN_CONVENTION - bool load(JSContext* cx, const char* name, - JS::MutableHandleObject module_out); + bool define(JSContext* cx, const char* name, + JS::MutableHandleObject module_out) const; }; }; // namespace Gjs diff --git a/cjs/objectbox.cpp b/cjs/objectbox.cpp index 0d4295aeb..a5f6e80d7 100644 --- a/cjs/objectbox.cpp +++ b/cjs/objectbox.cpp @@ -22,7 +22,7 @@ #include "cjs/objectbox.h" #include "util/log.h" -/* gjs/objectbox.cpp - GObject boxed type used to "box" a JS object so that it +/* cjs/objectbox.cpp - GObject boxed type used to "box" a JS object so that it * can be passed to or returned from a GObject signal, or used as the type of a * GObject property. */ diff --git a/cjs/profiler-private.h b/cjs/profiler-private.h index 764cb4775..60f328739 100644 --- a/cjs/profiler-private.h +++ b/cjs/profiler-private.h @@ -5,8 +5,11 @@ #ifndef GJS_PROFILER_PRIVATE_H_ #define GJS_PROFILER_PRIVATE_H_ +#include + #include +#include // for JSFinalizeStatus, JSGCStatus, GCReason #include #include #include @@ -55,4 +58,7 @@ void _gjs_profiler_add_mark(GjsProfiler* self, int64_t time, int64_t duration, void _gjs_profiler_setup_signals(GjsProfiler *self, GjsContext *context); +void _gjs_profiler_set_finalize_status(GjsProfiler*, JSFinalizeStatus); +void _gjs_profiler_set_gc_status(GjsProfiler*, JSGCStatus, JS::GCReason); + #endif // GJS_PROFILER_PRIVATE_H_ diff --git a/cjs/profiler.cpp b/cjs/profiler.cpp index 7a75cbcdf..9247af060 100644 --- a/cjs/profiler.cpp +++ b/cjs/profiler.cpp @@ -7,33 +7,40 @@ # include // for siginfo_t, sigevent, sigaction, SIGPROF, ... #endif -#include -#include - #ifdef ENABLE_PROFILER -# include +// IWYU has a weird loop where if this is present, it asks for it to be removed, +// and if absent, asks for it to be added +# include // IWYU pragma: keep # include # include -# include // for sscanf -# include // for memcpy, strlen +# include // for sscanf +# include // for memcpy, strlen # include // for __NR_gettid +# include // for timer_t # include // for size_t, CLOCK_MONOTONIC, itimerspec, ... # ifdef HAVE_UNISTD_H # include // for getpid, syscall # endif # include +#endif + +#include +#include + +#ifdef ENABLE_PROFILER # ifdef G_OS_UNIX # include # endif # include #endif +#include // for JSFinalizeStatus, JSGCStatus, GCReason #include // for EnableContextProfilingStack, ... #include #include // for ProfilingStack operators #include "cjs/context.h" -#include "cjs/jsapi-util.h" +#include "cjs/jsapi-util.h" // for gjs_explain_gc_reason #include "cjs/mem-private.h" #include "cjs/profiler-private.h" #include "cjs/profiler.h" @@ -49,7 +56,7 @@ * However, we do use a Linux'ism that allows us to deliver the signal * to only a single thread. Doing this in a generic fashion would * require thread-registration so that we can mask SIGPROF from all - * threads execpt the JS thread. The gecko engine uses tgkill() to do + * threads except the JS thread. The gecko engine uses tgkill() to do * this with a secondary thread instead of using POSIX timers. We could * do this too, but it would still be Linux-only. * @@ -89,6 +96,10 @@ struct _GjsProfiler { GSource* periodic_flush; SysprofCaptureWriter* target_capture; + + // Cache previous values of counters so that we don't overrun the output + // with counters that don't change very often + uint64_t last_counter_values[GJS_N_COUNTERS]; #endif /* ENABLE_PROFILER */ /* The filename to write to */ @@ -104,6 +115,12 @@ struct _GjsProfiler { /* Cached copy of our pid */ GPid pid; + /* Timing information */ + int64_t gc_begin_time; + int64_t sweep_begin_time; + int64_t group_sweep_begin_time; + const char* gc_reason; // statically allocated + /* GLib signal handler ID for SIGUSR2 */ unsigned sigusr2_id; unsigned counter_base; // index of first GObject memory counter @@ -435,15 +452,24 @@ static void gjs_profiler_sigprof(int signum [[maybe_unused]], siginfo_t* info, unsigned ids[GJS_N_COUNTERS]; SysprofCaptureCounterValue values[GJS_N_COUNTERS]; - -# define FETCH_COUNTERS(name, ix) \ - ids[ix] = self->counter_base + ix; \ - values[ix].v64 = GJS_GET_COUNTER(name); + size_t new_counts = 0; + +# define FETCH_COUNTERS(name, ix) \ + { \ + uint64_t count = GJS_GET_COUNTER(name); \ + if (count != self->last_counter_values[ix]) { \ + ids[new_counts] = self->counter_base + ix; \ + values[new_counts].v64 = count; \ + new_counts++; \ + } \ + self->last_counter_values[ix] = count; \ + } GJS_FOR_EACH_COUNTER(FETCH_COUNTERS); # undef FETCH_COUNTERS - if (!sysprof_capture_writer_set_counters(self->capture, now, -1, self->pid, - ids, values, GJS_N_COUNTERS)) + if (new_counts > 0 && + !sysprof_capture_writer_set_counters(self->capture, now, -1, self->pid, + ids, values, new_counts)) gjs_profiler_stop(self); } @@ -848,3 +874,87 @@ void gjs_profiler_set_fd(GjsProfiler* self, int fd) { (void)fd; // Unused in the no-profiler case #endif } + +void _gjs_profiler_set_finalize_status(GjsProfiler* self, + JSFinalizeStatus status) { +#ifdef ENABLE_PROFILER + // Implementation note for mozjs-128: + // + // Sweeping happens in three phases: + // 1st phase (JSFINALIZE_GROUP_PREPARE): the collector prepares to sweep a + // group of zones. 2nd phase (JSFINALIZE_GROUP_START): weak references to + // unmarked things have been removed, but no GC thing has been swept. 3rd + // Phase (JSFINALIZE_GROUP_END): all dead GC things for a group of zones + // have been swept. The above repeats for each sweep group. + // JSFINALIZE_COLLECTION_END occurs at the end of all GC. (see jsgc.cpp, + // BeginSweepPhase/BeginSweepingZoneGroup and SweepPhase, all called from + // IncrementalCollectSlice). + // + // Incremental GC muddies the waters, because BeginSweepPhase is always run + // to entirety, but SweepPhase can be run incrementally and mixed with JS + // code runs or even native code, when MaybeGC/IncrementalGC return. + // After GROUP_START, the collector may yield to the mutator meaning JS code + // can run between the callback for GROUP_START and GROUP_END. + + int64_t now = g_get_monotonic_time() * 1000L; + + switch (status) { + case JSFINALIZE_GROUP_PREPARE: + self->sweep_begin_time = now; + break; + case JSFINALIZE_GROUP_START: + self->group_sweep_begin_time = now; + break; + case JSFINALIZE_GROUP_END: + if (self->group_sweep_begin_time != 0) { + _gjs_profiler_add_mark(self, self->group_sweep_begin_time, + now - self->group_sweep_begin_time, + "GJS", "Group sweep", nullptr); + } + self->group_sweep_begin_time = 0; + break; + case JSFINALIZE_COLLECTION_END: + if (self->sweep_begin_time != 0) { + _gjs_profiler_add_mark(self, self->sweep_begin_time, + now - self->sweep_begin_time, "GJS", + "Sweep", nullptr); + } + self->sweep_begin_time = 0; + break; + default: + g_assert_not_reached(); + } +#else + (void)self; + (void)status; +#endif +} + +void _gjs_profiler_set_gc_status(GjsProfiler* self, JSGCStatus status, + JS::GCReason reason) { +#ifdef ENABLE_PROFILER + int64_t now = g_get_monotonic_time() * 1000L; + + switch (status) { + case JSGC_BEGIN: + self->gc_begin_time = now; + self->gc_reason = gjs_explain_gc_reason(reason); + break; + case JSGC_END: + if (self->gc_begin_time != 0) { + _gjs_profiler_add_mark(self, self->gc_begin_time, + now - self->gc_begin_time, "GJS", + "Garbage collection", self->gc_reason); + } + self->gc_begin_time = 0; + self->gc_reason = nullptr; + break; + default: + g_assert_not_reached(); + } +#else + (void)self; + (void)status; + (void)reason; +#endif +} diff --git a/cjs/promise.cpp b/cjs/promise.cpp index 62a79f740..095d20bb6 100644 --- a/cjs/promise.cpp +++ b/cjs/promise.cpp @@ -16,6 +16,7 @@ #include #include #include // for JS_NewPlainObject +#include // for RunJobs #include "cjs/context-private.h" #include "cjs/jsapi-util-args.h" @@ -81,7 +82,7 @@ class PromiseJobDispatcher::Source : public GSource { g_source_set_ready_time(this, -1); // Drain the job queue. - m_gjs->runJobs(m_gjs->context()); + js::RunJobs(m_gjs->context()); return G_SOURCE_CONTINUE; } @@ -193,8 +194,7 @@ GJS_JSAPI_RETURN_CONVENTION bool drain_microtask_queue(JSContext* cx, unsigned argc, JS::Value* vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - auto* gjs = GjsContextPrivate::from_cx(cx); - gjs->runJobs(cx); + js::RunJobs(cx); args.rval().setUndefined(); return true; diff --git a/cjs/stack.cpp b/cjs/stack.cpp index 30ca4a4cb..ba584d819 100644 --- a/cjs/stack.cpp +++ b/cjs/stack.cpp @@ -4,7 +4,7 @@ #include -#include // for stderr, open_memstream +#include // for stderr #include #include @@ -12,7 +12,9 @@ #include #include +#include #include +#include // for UniqueChars #include #include "cjs/context-private.h" @@ -40,48 +42,31 @@ gjs_dumpstack(void) } } -#ifdef HAVE_OPEN_MEMSTREAM -static std::string -stack_trace_string(GjsContext *context) { - JSContext *cx = static_cast(gjs_context_get_native_context(context)); - std::ostringstream out; - FILE *stream; - GjsAutoChar buf; - size_t len; - - stream = open_memstream(buf.out(), &len); - if (!stream) { - out << "No stack trace for context " << context << ": " - "open_memstream() failed\n\n"; - return out.str(); - } - js::DumpBacktrace(cx, stream); - fclose(stream); - out << "== Stack trace for context " << context << " ==\n" - << buf.get() << "\n"; - return out.str(); -} -#endif - std::string gjs_dumpstack_string() { std::string out; std::ostringstream all_traces; -#ifdef HAVE_OPEN_MEMSTREAM GjsSmartPointer contexts = gjs_context_get_all(); + js::Sprinter printer; GList *iter; for (iter = contexts; iter; iter = iter->next) { GjsAutoUnref context(GJS_CONTEXT(iter->data)); - all_traces << stack_trace_string(context); + if (!printer.init()) { + all_traces << "No stack trace for context " << context.get() + << ": out of memory\n\n"; + break; + } + auto* cx = + static_cast(gjs_context_get_native_context(context)); + js::DumpBacktrace(cx, printer); + JS::UniqueChars trace = printer.release(); + all_traces << "== Stack trace for context " << context.get() << " ==\n" + << trace.get() << "\n"; } out = all_traces.str(); out.resize(MAX(out.size() - 2, 0)); -#else - out = "No stack trace: no open_memstream() support. " - "See https://bugzilla.mozilla.org/show_bug.cgi?id=1826290"; -#endif return out; } diff --git a/cjs/text-encoding.cpp b/cjs/text-encoding.cpp index 13b5a915f..656185965 100644 --- a/cjs/text-encoding.cpp +++ b/cjs/text-encoding.cpp @@ -16,6 +16,7 @@ #include // for unique_ptr #include // for u16string #include // for tuple +#include // for move #include #include @@ -40,7 +41,7 @@ #include // for JSProto_InternalError #include #include -#include +#include #include "cjs/jsapi-util-args.h" #include "cjs/jsapi-util.h" @@ -93,7 +94,7 @@ static JSString* gjs_lossy_decode_from_uint8array_slow( // this is typical for ASCII and non-supplementary characters. // Because we are converting from an unknown encoding // technically a single byte could be supplementary in - // Unicode (4 bytes) or even represen multiple Unicode characters. + // Unicode (4 bytes) or even represent multiple Unicode characters. // // std::u16string does not care about these implementation // details, its only concern is that is consists of byte pairs. @@ -165,7 +166,7 @@ static JSString* gjs_lossy_decode_from_uint8array_slow( // Append the unicode fallback character to the output output_str.append(u"\ufffd", 1); } - } else if (g_error_matches(error, G_IO_ERROR, + } else if (g_error_matches(local_error, G_IO_ERROR, G_IO_ERROR_NO_SPACE)) { // If the buffer was full increase the buffer // size and re-try the conversion. @@ -180,15 +181,12 @@ static JSString* gjs_lossy_decode_from_uint8array_slow( } else { buffer_size += bytes_len; } + } else { + // Stop decoding if an unknown error occurs. + return gjs_throw_type_error_from_gerror(cx, local_error); } } - - // Stop decoding if an unknown error occurs. - } while (input_len > 0 && !error); - - // An unexpected error occurred. - if (error) - return gjs_throw_type_error_from_gerror(cx, error); + } while (input_len > 0); // Copy the accumulator's data into a JSString of Unicode (UTF-16) chars. return JS_NewUCStringCopyN(cx, output_str.c_str(), output_str.size()); @@ -401,13 +399,8 @@ JSObject* gjs_encode_to_uint8array(JSContext* cx, JS::HandleString str, utf8_len = strlen(utf8.get()); } - array_buffer = JS::NewArrayBufferWithContents(cx, utf8_len, utf8.get()); - - // array_buffer only assumes ownership if the call succeeded, - // if array_buffer assumes ownership we must release our ownership - // without freeing the data. - if (array_buffer) - mozilla::Unused << utf8.release(); + array_buffer = + JS::NewArrayBufferWithContents(cx, utf8_len, std::move(utf8)); } else { GjsAutoError error; GjsAutoChar encoded = nullptr; @@ -456,9 +449,10 @@ JSObject* gjs_encode_to_uint8array(JSContext* cx, JS::HandleString str, if (bytes_written == 0) return JS_NewUint8Array(cx, 0); + mozilla::UniquePtr contents{ + encoded.release(), gfree_arraybuffer_contents}; array_buffer = - JS::NewExternalArrayBuffer(cx, bytes_written, encoded.release(), - gfree_arraybuffer_contents, nullptr); + JS::NewExternalArrayBuffer(cx, bytes_written, std::move(contents)); } if (!array_buffer) diff --git a/debian/changelog b/debian/changelog index 93e12ef8d..61741e291 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +cjs (6.5.0) xia; urgency=medium + + * Rebase on gjs-1.82.1 (from debian 13/trixie) + + -- Michael Webster Mon, 27 Jan 2025 12:00:00 -0500 + cjs (6.4.0) xia; urgency=medium [ Leigh Scott ] diff --git a/debian/control b/debian/control index d3139f811..104900e69 100644 --- a/debian/control +++ b/debian/control @@ -2,48 +2,59 @@ Source: cjs Section: interpreters Priority: optional Maintainer: Linux Mint -Build-Depends: - at-spi2-core , - dbus-daemon , - dbus-x11 , - debhelper-compat (= 13), - dh-sequence-gir, - dh-sequence-gnome, - gir1.2-gtk-3.0, - gobject-introspection (>= 1.71), - libcairo2-dev, - libffi-dev (>= 3.3), - libgirepository1.0-dev (>= 1.71), - libglib2.0-dev (>= 2.58.0), - libmozjs-115-dev, - libreadline-dev, - libxml2-utils, - meson (>= 0.54.0), - pkg-config (>= 0.28), - xauth , - xvfb , +Build-Depends: at-spi2-core , + dbus-daemon , + debhelper-compat (= 13), + dh-sequence-gir, + gir1.2-cairo-1.0-dev, + gir1.2-gio-2.0-dev, + gir1.2-girepository-2.0-dev, + gir1.2-gobject-2.0-dev, + gir1.2-gtk-3.0, + gobject-introspection (>= 1.71), + libcairo2-dev, + libffi-dev, + libgirepository-1.0-dev (>= 1.71), + libglib2.0-dev, + libmozjs-128-dev, + libreadline-dev, + meson, + libsysprof-capture-4-dev (>= 3.38.0) [amd64 arm64 armel armhf i386 mips64el ppc64el riscv64 s390x hppa loong64 powerpc ppc64 sh4], + xauth , + xvfb Rules-Requires-Root: no -Standards-Version: 4.6.1 +Standards-Version: 4.7.0 Vcs-Git: https://github.com/linuxmint/cjs.git Package: cjs Architecture: any -Depends: - gir1.2-gtk-3.0, - ${misc:Depends}, - ${shlibs:Depends}, +Depends: gir1.2-gtk-3.0, + ${misc:Depends}, + ${shlibs:Depends} Description: Mozilla-based javascript bindings for the Cinnamon platform (cli tool) Makes it possible for applications to use all of Cinnamon's platform libraries using the JavaScript language. It's mainly based on the Mozilla JavaScript engine and the GObject introspection framework. . - This package is the frozen version of gjs that the cinnamon desktop currently - uses. - . This package contains the interactive console application. + +Package: libcjs0 +Architecture: any +Multi-Arch: same +Section: libs +Depends: gir1.2-gio-2.0, + gir1.2-girepository-2.0, + gir1.2-glib-2.0, + gir1.2-gobject-2.0, + ${gir:Depends}, + ${misc:Depends}, + ${shlibs:Depends} +Description: Mozilla-based javascript bindings for the Cinnamon platform + Makes it possible for applications to use all of Cinnamon's platform + libraries using the JavaScript language. It's mainly based on the + Mozilla JavaScript engine and the GObject introspection framework. . - This package contains test programs, designed to be run as part of a - regression testsuite. + This is the shared library applications link to. Package: libcjs-dbg Section: debug @@ -67,51 +78,15 @@ Package: libcjs-dev Architecture: any Multi-Arch: same Section: libdevel -Depends: - libcairo2-dev, - libcjs0 (= ${binary:Version}), - libgirepository1.0-dev (>= 1.64), - libmozjs-115-dev, - ${misc:Depends}, -Description: Mozilla-based javascript bindings for Cinnamon platform - Makes it possible for applications to use all of Cinnamon platform +Depends: libcairo2-dev, + libgirepository-1.0-dev, + libcjs0 (= ${binary:Version}), + libmozjs-128-dev, + ${misc:Depends} +Description: Mozilla-based javascript bindings for Cinnamon - development files + Makes it possible for applications to use all of Cinnamon's platform libraries using the JavaScript language. It's mainly based on the Mozilla JavaScript engine and the GObject introspection framework. . - This package is the frozen version of gjs that the cinnamon desktop currently - uses. - . This package contains the development files applications need to build against. - -Package: libcjs0 -Architecture: any -Multi-Arch: same -Section: libs -Depends: - ${gir:Depends}, - ${misc:Depends}, - ${shlibs:Depends}, - gir1.2-gio-2.0, - gir1.2-girepository-2.0, - gir1.2-glib-2.0, - gir1.2-gobject-2.0, -Conflicts: - libcjs0a, - libcjs0c, - libcjs0e, - libcjs0f, -Replaces: - libcjs0a, - libcjs0c, - libcjs0e, - libcjs0f, -Description: Mozilla-based javascript bindings for the Cinnamon platform - Makes it possible for applications to use all of Cinnamon platform - libraries using the JavaScript language. It's mainly based on the - Mozilla JavaScript engine and the GObject introspection framework. - . - This package is the frozen version of gjs that the cinnamon desktop currently - uses. - . - This package contains the shared library, used by cjs itself, and cinnamon. diff --git a/debian/copyright b/debian/copyright index 9118df18c..724cd553a 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,7 +1,14 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: cjs -Upstream-Contact: Clement Lefebvre -Source: https://github.com/linuxmint/cjs +Source: https://download.gnome.org/sources/gjs/ +Comment: + This work was packaged for Debian by: + . + Gustavo Noronha Silva on Mon, 12 Oct 2009 18:38:36 -0300 + . + Upstream Author: + . + litl, LLC +Upstream-Name: gjs Files: * Copyright: @@ -25,12 +32,18 @@ Copyright: 2020 Ole Jørgen Brønner 2017 Patrick Griffis 2013 Pavel Vasin - 2016-2021 Philip Chimento + 2016-2024 Philip Chimento 2008-2018 Red Hat, Inc. 2008 Robert Carr 2019-2021 Sonny Piers 2008-2010 litl, LLC -License: Expat or LGPL-2.0+ +License: Expat or LGPL-2+ + +Files: + .gitmodules +Copyright: + 2024 Philip Chimento +License: CC0-1.0 Files: *README* @@ -41,7 +54,6 @@ Files: examples/test.jpg installed-tests/js/modules/data.txt tools/heapgraph.md - tools/yarn.lock Copyright: No rights reserved License: CC0-1.0 @@ -63,15 +75,107 @@ Copyright: Node.js contributors License: Expat +Files: + subprojects/gobject-introspection-tests/* +Copyright: + 2012 Alban Browaeys + 2011 Alex Eftimie + 2007-2010 Andreas Rottmann + 2012 Bastian Winkler + 2015 Ben Iofel + 2011-2012 Canonical Ltd. + 2021 Carlos Garnacho + 2020 Centricular + 2015-2018 Christoph Reiter + 2014 Chun-wei Fan + 2012 Coeus Group + 2008-2015 Colin Walters + 2010-2015 Collabora, Ltd. + 2008-2012 Dan Winship + 2015 Debarshi Ray + 2012 Dieter Verfaillie + 2013-2022 Emmanuele Bassi + 2016-2017 Endless Mobile, Inc. + 2012 Epitech + 2023 Evan Welsh + 2013 Florian Müllner + 2011-2014 Giovanni Campagna + 2012 Gonzalo Odiard + 2009 Havoc Pennington + 2011 Ignacio Casal Quinteiro + 2016 Intel + 2011-2012 Jasper St. Pierre + 2008 Johan Bilien + 2008-2011 Johan Dahlin + 2012 Jon Nordby + 2010 Jonathan Matthew + 2008 Jürg Billeter + 2012 Krzesimir Nowak + 2011 Laszlo Pandy + 2014 Lionel Landwerlin + 2009-2011 litl, LLC + 2022 Lubomir Rintel + 2008 Lucas Rocha + 2008 Lucas Almeida Rocha + 2008 Marc-Andre Lureau + 2020-2023 Marco Trevisan + 2009 Mark Lee + 2011-2013 Martin Pitt + 2009 Maxim Ermilov + 2008-2011 Owen Taylor + 2008-2010 Owen W. Taylor + 2012-2013 Paolo Borelli + 2010-2011 Pavel Holejsovsky + 2016-2024 Philip Chimento + 2008 Philip Van Hoof + 2010-2024 Red Hat, Inc. + 2017 Rico Tzschichholz + 2014-2015 RIFT.io, Inc. + 2009 Robert Carr + 2012 Sebastian Pölsterl + 2013 Simon Feltman + 2020-2024 Simon McVittie + 2009 Simon van der Linden + 2013 Stef Walter + 2019 Stéphane Seng + 2009-2010 Sugar Labs + 2014 SuSE + 2018-2019 Tomasz Miąsko + 2008 Tommi Komulainen + 2011-2012 Torsten Schönfeld + 2008 Tristan Van Berkom + 2011 Xavier Claessens + 2010 Zach Goldberg +License: GPL-2+ and LGPL-2+ and Expat +Comment: + These files do not specify which license, but according to COPYING it is + one of them, so the conservative assumption is that we must comply with + all of the referenced licenses simultaneously. + +Files: + subprojects/gobject-introspection-tests/gobject-introspection-tests.doap +Copyright: + 2024 Philip Chimento +License: Expat + +Files: + subprojects/gobject-introspection-tests/tools/iwyu.imp + subprojects/gobject-introspection-tests/tools/run_clang_format.sh + subprojects/gobject-introspection-tests/tools/run_iwyu.sh +Copyright: + 2024 Philip Chimento +License: Expat or LGPL-2+ + Files: debian/* Copyright: - 2009 Collabora Ltd. + 2009 Collabora Ltd. + 2024 Simon McVittie License: Expat Files: modules/console.cpp modules/script/jsUnit.js -License: MPL-1.1 or GPL-2.0+ or LGPL-2.1+ +License: MPL-1.1 or GPL-2+ or LGPL-2.1+ The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -192,7 +296,12 @@ License: Expat FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -License: LGPL-2.0+ +License: GPL-2+ + SPDX license expression GPL-2.0-or-later refers to the GNU General + Public License, version 2.0 or any later version. On a Debian system, see + /usr/share/common-licenses/GPL-2 for a copy of this license. + +License: LGPL-2+ SPDX license expression LGPL-2.0-or-later refers to the GNU Library General Public License, version 2.0 or any later version. On a Debian system, see /usr/share/common-licenses/LGPL-2 for a copy of this license. diff --git a/debian/gbp.conf b/debian/gbp.conf new file mode 100644 index 000000000..b37f0bdca --- /dev/null +++ b/debian/gbp.conf @@ -0,0 +1,17 @@ +[DEFAULT] +pristine-tar = True +debian-branch = debian/latest +upstream-branch = upstream/latest +upstream-vcs-tag = %(version)s + +[buildpackage] +sign-tags = True + +[dch] +multimaint-merge = True + +[import-orig] +postimport = dch -v%(version)s New upstream release; git add debian/changelog; debcommit + +[pq] +patch-numbers = False diff --git a/debian/libcjs0.acc.in b/debian/libcjs0.acc.in deleted file mode 100644 index 46d9d95dc..000000000 --- a/debian/libcjs0.acc.in +++ /dev/null @@ -1,20 +0,0 @@ - - - - - 3.8.0 - - - - /usr/include/cjs-1.0/cjs/gjs.h - - - - /usr/lib/@@DEB_HOST_MULTIARCH@@/libcjs.so - - - - -I/usr/include/js - - - diff --git a/debian/libcjs0.symbols b/debian/libcjs0.symbols index 1ac0f55c4..76c03f230 100644 --- a/debian/libcjs0.symbols +++ b/debian/libcjs0.symbols @@ -1,72 +1,92 @@ libcjs.so.0 libcjs0 #MINVER# * Build-Depends-Package: libcjs-dev - gjs_bindtextdomain@Base 2.4.1 - gjs_cairo_pdf_surface_proto_props@Base 5.4.0 - gjs_clear_terminal@Base 5.4.0 - gjs_console_clear@Base 5.4.0 - gjs_console_is_tty@Base 5.4.0 - gjs_context_define_string_array@Base 2.0.0 - gjs_context_eval@Base 2.0.0 - gjs_context_eval_file@Base 2.0.0 - gjs_context_eval_module@Base 5.4.0 - gjs_context_eval_module_file@Base 5.4.0 - gjs_context_gc@Base 2.0.0 - gjs_context_get_all@Base 2.0.0 - gjs_context_get_current@Base 2.4.1 - gjs_context_get_native_context@Base 2.0.0 - gjs_context_get_profiler@Base 4.0.0 - gjs_context_get_type@Base 2.0.0 - gjs_context_make_current@Base 2.4.1 - gjs_context_maybe_gc@Base 2.0.0 - gjs_context_new@Base 2.0.0 - gjs_context_new_with_search_path@Base 2.0.0 - gjs_context_print_stack_stderr@Base 2.0.0 - gjs_context_register_module@Base 5.4.0 - gjs_context_run_in_realm@Base 6.0.0 - gjs_context_set_argv@Base 5.4.0 - gjs_context_setup_debugger_console@Base 4.6.0 - gjs_coverage_enable@Base 4.6.0 - gjs_coverage_get_type@Base 5.4.0 - gjs_coverage_new@Base 2.4.1 - gjs_coverage_write_statistics@Base 2.4.1 - gjs_dbus_implementation_emit_property_changed@Base 2.0.0 - gjs_dbus_implementation_emit_signal@Base 2.0.0 - gjs_dbus_implementation_get_type@Base 2.0.0 - gjs_dbus_implementation_unexport@Base 5.7.0 - gjs_dbus_implementation_unexport_from_connection@Base 5.7.0 - gjs_dumpstack@Base 2.0.0 - gjs_error_quark@Base 2.0.0 - gjs_format_int_alternative_output@Base 2.4.1 - gjs_g_binding_group_bind_full@Base 5.7.0 - gjs_g_object_bind_property_full@Base 5.4.0 - gjs_get_js_version@Base 4.0.0 - gjs_gobject_class_info@Base 5.4.0 - gjs_gobject_interface_info@Base 5.4.0 - gjs_gtk_container_child_set_property@Base 2.4.1 - gjs_gtk_custom_sorter_new@Base 5.7.0 - gjs_gtk_custom_sorter_set_sort_func@Base 5.7.0 - gjs_importer_class@Base 5.4.0 - gjs_importer_proto_funcs@Base 5.4.0 - gjs_js_error_get_type@Base 4.0.0 - gjs_js_error_quark@Base 4.0.0 - gjs_list_store_insert_sorted@Base 5.4.0 - gjs_list_store_sort@Base 5.4.0 - gjs_locale_category_get_type@Base 3.4.4 - gjs_log_set_writer_default@Base 5.4.0 - gjs_log_set_writer_func@Base 5.4.0 - gjs_memory_report@Base 2.0.0 - gjs_native_promise_module_funcs@Base 5.7.0 - gjs_param_class@Base 5.4.0 - gjs_param_spec_get_flags@Base 3.4.4 - gjs_param_spec_get_owner_type@Base 3.4.4 - gjs_param_spec_get_value_type@Base 3.4.4 - gjs_profiler_chain_signal@Base 4.0.0 - gjs_profiler_get_type@Base 4.0.0 - gjs_profiler_set_capture_writer@Base 5.4.0 - gjs_profiler_set_fd@Base 4.6.0 - gjs_profiler_set_filename@Base 4.0.0 - gjs_profiler_start@Base 4.0.0 - gjs_profiler_stop@Base 4.0.0 - gjs_repo_class@Base 5.4.0 - gjs_setlocale@Base 3.4.4 - gjs_textdomain@Base 2.4.1 + gjs_bindtextdomain@Base 1.63.90 + gjs_cairo_pdf_surface_proto_props@Base 1.70.0 + gjs_clear_terminal@Base 1.70.0 + gjs_console_clear@Base 1.70.0 + gjs_console_is_tty@Base 1.70.0 + gjs_context_define_string_array@Base 1.63.90 + gjs_context_eval@Base 1.63.90 + gjs_context_eval_file@Base 1.63.90 + gjs_context_eval_module@Base 1.67.2 + gjs_context_eval_module_file@Base 1.67.2 + gjs_context_gc@Base 1.63.90 + gjs_context_get_all@Base 1.63.90 + gjs_context_get_current@Base 1.63.90 + gjs_context_get_native_context@Base 1.63.90 + gjs_context_get_profiler@Base 1.63.90 + gjs_context_get_type@Base 1.63.90 + gjs_context_make_current@Base 1.63.90 + gjs_context_maybe_gc@Base 1.63.90 + gjs_context_new@Base 1.63.90 + gjs_context_new_with_search_path@Base 1.63.90 + gjs_context_print_stack_stderr@Base 1.63.90 + gjs_context_register_module@Base 1.67.2 + gjs_context_run_in_realm@Base 1.77.90 + gjs_context_set_argv@Base 1.67.2 + gjs_context_setup_debugger_console@Base 1.63.90 + gjs_coverage_enable@Base 1.65.90 + gjs_coverage_get_type@Base 1.70.0 + gjs_coverage_new@Base 1.63.90 + gjs_coverage_write_statistics@Base 1.63.90 + gjs_dbus_implementation_emit_property_changed@Base 1.63.90 + gjs_dbus_implementation_emit_signal@Base 1.63.90 + gjs_dbus_implementation_get_type@Base 1.63.90 + gjs_dbus_implementation_unexport@Base 1.71.1 + gjs_dbus_implementation_unexport_from_connection@Base 1.71.1 + gjs_dumpstack@Base 1.63.90 + gjs_error_quark@Base 1.63.90 + gjs_format_int_alternative_output@Base 1.63.90 + gjs_g_binding_group_bind_full@Base 1.73.2 + gjs_g_object_bind_property_full@Base 1.70.0 + gjs_get_js_version@Base 1.63.90 + gjs_gobject_class_info@Base 1.70.0 + gjs_gobject_interface_info@Base 1.70.0 + gjs_gtk_container_child_set_property@Base 1.63.90 + gjs_gtk_custom_sorter_new@Base 1.71.1 + gjs_gtk_custom_sorter_set_sort_func@Base 1.71.1 + gjs_importer_class@Base 1.70.0 + gjs_importer_proto_funcs@Base 1.70.0 + gjs_js_error_get_type@Base 1.63.90 + gjs_js_error_quark@Base 1.63.90 + gjs_list_store_insert_sorted@Base 1.70.0 + gjs_list_store_sort@Base 1.70.0 + gjs_locale_category_get_type@Base 1.63.90 + gjs_log_set_writer_default@Base 1.70.0 + gjs_log_set_writer_func@Base 1.70.0 + gjs_match_info_expand_references@Base 1.81.2 + gjs_match_info_fetch@Base 1.81.2 + gjs_match_info_fetch_all@Base 1.81.2 + gjs_match_info_fetch_named@Base 1.81.2 + gjs_match_info_fetch_named_pos@Base 1.81.2 + gjs_match_info_fetch_pos@Base 1.81.2 + gjs_match_info_free@Base 1.81.2 + gjs_match_info_get_match_count@Base 1.81.2 + gjs_match_info_get_regex@Base 1.81.2 + gjs_match_info_get_string@Base 1.81.2 + gjs_match_info_get_type@Base 1.81.2 + gjs_match_info_is_partial_match@Base 1.81.2 + gjs_match_info_matches@Base 1.81.2 + gjs_match_info_next@Base 1.81.2 + gjs_match_info_ref@Base 1.81.2 + gjs_match_info_unref@Base 1.81.2 + gjs_memory_report@Base 1.63.90 + gjs_native_promise_module_funcs@Base 1.71.1 + gjs_param_class@Base 1.70.0 + gjs_param_spec_get_flags@Base 1.63.90 + gjs_param_spec_get_owner_type@Base 1.63.90 + gjs_param_spec_get_value_type@Base 1.63.90 + gjs_profiler_chain_signal@Base 1.63.90 + gjs_profiler_get_type@Base 1.63.90 + gjs_profiler_set_capture_writer@Base 1.67.2 + gjs_profiler_set_fd@Base 1.63.90 + gjs_profiler_set_filename@Base 1.63.90 + gjs_profiler_start@Base 1.63.90 + gjs_profiler_stop@Base 1.63.90 + gjs_regex_match@Base 1.81.2 + gjs_regex_match_all@Base 1.81.2 + gjs_regex_match_all_full@Base 1.81.2 + gjs_regex_match_full@Base 1.81.2 + gjs_repo_class@Base 1.70.0 + gjs_setlocale@Base 1.63.90 + gjs_textdomain@Base 1.63.90 diff --git a/debian/not-installed b/debian/not-installed new file mode 100644 index 000000000..ed6a5349c --- /dev/null +++ b/debian/not-installed @@ -0,0 +1,9 @@ +usr/libexec/installed-tests/cjs/GIMarshallingTests-1.0.typelib +usr/libexec/installed-tests/cjs/Regress-1.0.typelib +usr/libexec/installed-tests/cjs/RegressUnix-1.0.typelib +usr/libexec/installed-tests/cjs/Utility-1.0.typelib +usr/libexec/installed-tests/cjs/WarnLib-1.0.typelib +usr/libexec/installed-tests/cjs/libgimarshallingtests.so +usr/libexec/installed-tests/cjs/libregress.so +usr/libexec/installed-tests/cjs/libutility.so +usr/libexec/installed-tests/cjs/libwarnlib.so diff --git a/debian/rules b/debian/rules index 19ae3f16b..b074acb4e 100755 --- a/debian/rules +++ b/debian/rules @@ -4,20 +4,24 @@ built_binaries := $(shell dh_listpackages) export DEB_BUILD_MAINT_OPTIONS = hardening=+all export DEB_LDFLAGS_MAINT_APPEND = -Wl,-z,defs -export DPKG_GENSYMBOLS_CHECK_LEVEL = 2 include /usr/share/dpkg/default.mk export DH_VERBOSE=1 +ifeq ($(filter amd64 arm64 armel armhf i386 mips64el ppc64el riscv64 s390x hppa loong64 powerpc ppc64 sh4,$(DEB_HOST_ARCH)),) +SYSPROF = -Dprofiler=disabled +endif + %: dh $@ override_dh_auto_configure: dh_auto_configure -- \ - -Dauto_features=enabled \ - -Dprofiler=disabled \ + --unity=on \ -Dinstalled_tests=false \ + -Dauto_features=enabled \ + $(SYSPROF) \ $(NULL) override_dh_girepository: @@ -28,16 +32,12 @@ override_dh_auto_test: obj-$(DEB_HOST_GNU_TYPE)/cjs-console -c 'print("Smoke-test OK")' env \ TZ=UTC \ + dbus-run-session -- \ xvfb-run -a \ dh_auto_test -- -v -C $(CURDIR)/obj-$(DEB_HOST_GNU_TYPE) --timeout-multiplier 4 -override_dh_makeshlibs: - dh_makeshlibs -Xusr/lib/$(DEB_HOST_MULTIARCH)/cjs-1.0 -- -c4 - override_dh_strip: dh_strip --dbg-package=libcjs-dbg -override_dh_gnome_clean: - dh_gnome_clean --no-control - - +override_dh_makeshlibs: + dh_makeshlibs -Xusr/lib/$(DEB_HOST_MULTIARCH)/cjs-1.0 -- -c4 diff --git a/debian/shlibs.local b/debian/shlibs.local index 4972e4394..8423e79bf 100644 --- a/debian/shlibs.local +++ b/debian/shlibs.local @@ -1 +1 @@ -libcjs 0 libcjs0 (= ${binary:Version}) +libgjs 0 libgjs0g (= ${binary:Version}) diff --git a/debian/tests/acc b/debian/tests/acc deleted file mode 100755 index 4251c76b9..000000000 --- a/debian/tests/acc +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -DEB_HOST_MULTIARCH=$(dpkg-architecture -qDEB_HOST_MULTIARCH) - -for in_file in debian/*.acc.in; do - out_file=${in_file%.in} - sed 's/@@DEB_HOST_MULTIARCH@@/'"${DEB_HOST_MULTIARCH}"'/' \ - "${in_file}" > "${out_file}" -done - -DH_VERBOSE=1 - -dh_acc -ret=$? -if [ 0 -ne $ret ] && [ -n "$ADT_ARTIFACTS" ]; then - cp -r logs "$ADT_ARTIFACTS"/acc.logs -fi -exit $ret diff --git a/debian/tests/build b/debian/tests/build old mode 100755 new mode 100644 index 599fbc682..c3c439ed5 --- a/debian/tests/build +++ b/debian/tests/build @@ -16,7 +16,7 @@ else CROSS_COMPILE= fi -cat < cjstest.c +cat < gjstest.c #include int main() @@ -29,8 +29,8 @@ EOF # Deliberately word-splitting, that's how pkg-config works: # shellcheck disable=SC2046 -"${CROSS_COMPILE}gcc" -o cjstest cjstest.c $("${CROSS_COMPILE}pkg-config" --cflags --libs cjs-1.0) +"${CROSS_COMPILE}gcc" -o gjstest gjstest.c $("${CROSS_COMPILE}pkg-config" --cflags --libs gjs-1.0) echo "build: OK" -[ -x cjstest ] -./cjstest +[ -x gjstest ] +./gjstest echo "run: OK" diff --git a/debian/tests/control b/debian/tests/control index 2d64be92c..6316b0b12 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -1,5 +1,11 @@ Tests: build -Depends: build-essential, libcjs-dev +Restrictions: superficial +Depends: build-essential, + libgjs-dev -#Tests: installed-tests -#Depends: dbus-daemon, dbus-x11, cjs-tests, gnome-desktop-testing, xauth, xvfb +Tests: installed-tests +Depends: dbus-daemon, + gjs-tests, + gnome-desktop-testing, + xauth, + xvfb diff --git a/debian/tests/installed-tests b/debian/tests/installed-tests old mode 100755 new mode 100644 diff --git a/debian/tests/testsuite b/debian/tests/testsuite deleted file mode 100755 index f0bdf42b2..000000000 --- a/debian/tests/testsuite +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -# dh_auto_test -make check diff --git a/debian/watch b/debian/watch new file mode 100644 index 000000000..1b6d01304 --- /dev/null +++ b/debian/watch @@ -0,0 +1,4 @@ +version=4 +opts="searchmode=plain, uversionmangle=s/\.(alpha|beta|rc)/~$1/, downloadurlmangle=s|cache.json||" \ +https://download.gnome.org/sources/@PACKAGE@/cache.json \ + [\d.]+[02468]/@PACKAGE@-([\d.]+)@ARCHIVE_EXT@ diff --git a/debian/watch.devel b/debian/watch.devel new file mode 100644 index 000000000..64675b41f --- /dev/null +++ b/debian/watch.devel @@ -0,0 +1,4 @@ +version=4 +opts="searchmode=plain, uversionmangle=s/\.(alpha|beta|rc)/~$1/, downloadurlmangle=s|cache.json||" \ +https://download.gnome.org/sources/@PACKAGE@/cache.json \ + [\d.]+/@PACKAGE@-([\d.]+)@ARCHIVE_EXT@ diff --git a/doc/CPP_Style_Guide.md b/doc/CPP_Style_Guide.md index d911c08f5..312838f6f 100644 --- a/doc/CPP_Style_Guide.md +++ b/doc/CPP_Style_Guide.md @@ -1,6 +1,6 @@ -# C++ Coding Standards # +# C++ Coding Standards -## Introduction ## +## Introduction This guide attempts to describe a few coding standards that are being used in GJS. @@ -36,7 +36,7 @@ at . [llvm]: https://llvm.org/docs/CodingStandards.html [llvm-source]: https://raw.githubusercontent.com/llvm-mirror/llvm/HEAD/docs/CodingStandards.rst -## Languages, Libraries, and Standards ## +## Languages, Libraries, and Standards Most source code in GJS using these coding standards is C++ code. There are some places where C code is used due to environment @@ -44,7 +44,7 @@ restrictions or historical reasons. Generally, our preference is for standards conforming, modern, and portable C++ code as the implementation language of choice. -### C++ Standard Versions ### +### C++ Standard Versions GJS is currently written using C++17 conforming code, although we restrict ourselves to features which are available in the major @@ -55,7 +55,7 @@ reasonable) be standard, portable, and modern C++17 code. We avoid unnecessary vendor-specific extensions, etc., including `g_autoptr()` and friends. -### C++ Standard Library ### +### C++ Standard Library Use the C++ standard library facilities whenever they are available for a particular task. @@ -65,14 +65,14 @@ and friends, for their type safety and memory management. There are some exceptions such as the standard I/O streams library which is avoided, and use in space-constrained situations. -### Supported C++17 Language and Library Features ### +### Supported C++17 Language and Library Features While GJS and SpiderMonkey use C++17, not all features are available in all of the toolchains which we support. A good rule of thumb is to check whether SpiderMonkey uses the feature. If so, it's okay to use in GJS. -### Other Languages ### +### Other Languages Any code written in JavaScript is not subject to the formatting rules below. @@ -81,7 +81,7 @@ Instead, we adopt the formatting rules enforced by the [eslint]: https://eslint.org/ -## Mechanical Source Issues ## +## Mechanical Source Issues All source code formatting should follow the [Google C++ Style Guide][google] with a few exceptions: @@ -100,9 +100,9 @@ the tools reject. [google]: https://google.github.io/styleguide/cppguide.html -### Source Code Formatting ### +### Source Code Formatting -#### Commenting #### +#### Commenting Comments are one critical part of readability and maintainability. Everyone knows they should comment their code, and so should you. @@ -112,7 +112,7 @@ Aim to describe what the code is trying to do and why, not *how* it does it at a micro level. Here are a few critical things to document: -##### File Headers ###### +##### File Headers Every source file should have a header on it that describes the basic purpose of the file. @@ -153,14 +153,14 @@ code to watch out for. [reuse]: https://reuse.software/ -##### Class overviews ###### +##### Class overviews Classes are one fundamental part of a good object oriented design. As such, a class definition should have a comment block that explains what the class is used for and how it works. Every non-trivial class is expected to have such a comment block. -##### Method information ###### +##### Method information Methods defined in a class (as well as any global functions) should also be documented properly. @@ -170,7 +170,7 @@ tricky or insidious is going on). The hope is that people can figure out how to use your interfaces without reading the code itself. -#### Comment Formatting #### +#### Comment Formatting Either C++ style comments (`//`) or C style (`/* */`) comments are acceptable. @@ -191,9 +191,9 @@ comments. [gtk-doc style]: https://developer.gnome.org/gtk-doc-manual/unstable/documenting.html.en -### Language and Compiler Issues ### +### Language and Compiler Issues -#### Treat Compiler Warnings Like Errors #### +#### Treat Compiler Warnings Like Errors If your code has compiler warnings in it, something is wrong — you aren't casting values correctly, you have questionable constructs in @@ -212,7 +212,7 @@ the arbiter. [ax-compiler-flags]: https://www.gnu.org/software/autoconf-archive/ax_compiler_flags.html#ax_compiler_flags -#### Write Portable Code #### +#### Write Portable Code In almost all cases, it is possible and within reason to write completely portable code. @@ -222,7 +222,7 @@ isolate it behind a well defined (and well documented) interface. In practice, this means that you shouldn't assume much about the host compiler (and Visual Studio tends to be the lowest common denominator). -#### Use of `class` and `struct` Keywords #### +#### Use of `class` and `struct` Keywords In C++, the `class` and `struct` keywords can be used almost interchangeably. @@ -269,7 +269,7 @@ This can lead to problems at link time. }; ``` -#### Use `auto` Type Deduction to Make Code More Readable #### +#### Use `auto` Type Deduction to Make Code More Readable Some are advocating a policy of "almost always `auto`" in C++11 and later, but GJS uses a more moderate stance. @@ -282,7 +282,7 @@ Another time when `auto` works well for these purposes is when the type would have been abstracted away anyway, often behind a container's typedef such as `std::vector::iterator`. -#### Beware unnecessary copies with ``auto`` #### +#### Beware unnecessary copies with ``auto`` The convenience of `auto` makes it easy to forget that its default behaviour is a copy. @@ -311,7 +311,7 @@ for (auto* ptr : container) ptr->change(); ``` -#### Beware of non-determinism due to ordering of pointers #### +#### Beware of non-determinism due to ordering of pointers In general, there is no relative ordering among pointers. As a result, when unordered containers like sets and maps are used with @@ -328,18 +328,18 @@ sort an unordered container before iteration. Or use ordered containers like `std::vector` if you want to iterate pointer keys. -#### Beware of non-deterministic sorting order of equal elements #### +#### Beware of non-deterministic sorting order of equal elements `std::sort` uses a non-stable sorting algorithm in which the order of equal elements is not guaranteed to be preserved. Thus using `std::sort` for a container having equal elements may result in non-determinstic behaviour. -## Style Issues ## +## Style Issues -### The High-Level Issues ### +### The High-Level Issues -#### Self-contained Headers #### +#### Self-contained Headers Header files should be self-contained (compile on their own) and end in `.h`. @@ -361,7 +361,7 @@ prerequisites. Name such files with the `.inc` extension. Use sparingly, and prefer self-contained headers when possible. -#### `#include` as Little as Possible #### +#### `#include` as Little as Possible `#include` hurts compile time performance. Don't do it unless you have to, especially in header files. @@ -400,7 +400,7 @@ else. [iwyu]: https://include-what-you-use.org/ -#### Header inclusion order #### +#### Header inclusion order Headers should be included in the following order: @@ -432,7 +432,7 @@ its functionality is no longer used in the file. Here is an example of all of the above rules together: ```c++ -#include // for ENABLE_CAIRO +#include // for ENABLE_PROFILER #include // for strlen @@ -450,12 +450,12 @@ Here is an example of all of the above rules together: #include // for JS_New, JSAutoRealm, JS_GetProperty #include -#include "cjs/atoms.h" -#include "cjs/context-private.h" -#include "cjs/jsapi-util.h" +#include "gjs/atoms.h" +#include "gjs/context-private.h" +#include "gjs/jsapi-util.h" ``` -#### Keep "Internal" Headers Private #### +#### Keep "Internal" Headers Private Many modules have a complex implementation that causes them to use more than one implementation (`.cpp`) file. It is often tempting to put @@ -471,7 +471,7 @@ by outsiders. It's okay to put extra implementation methods in a public class itself. Just make them private (or protected) and all is well. -#### Use Early Exits and `continue` to Simplify Code #### +#### Use Early Exits and `continue` to Simplify Code When reading code, keep in mind how much state and how many previous decisions have to be remembered by the reader to understand a block of @@ -574,7 +574,7 @@ are true, and it makes it obvious to the reader that there is no `else` coming up that they have to push context into their brain for. If a loop is large, this can be a big understandability win. -#### Don't use `else` after a `return` #### +#### Don't use `else` after a `return` For similar reasons above (reduction of indentation and easier reading), please do not use `else` or `else if` after something that interrupts @@ -642,7 +642,7 @@ case 'J': The idea is to reduce indentation and the amount of code you have to keep track of when reading the code. -#### Turn Predicate Loops into Predicate Functions ##### +#### Turn Predicate Loops into Predicate Functions It is very common to write small loops that just compute a boolean value. @@ -696,9 +696,9 @@ Instead of being faced with the in-line details of how we check to see if the `bar_list` contains a foo, we can trust the function name and continue reading with better locality. -### The Low-Level Issues ### +### The Low-Level Issues -#### Name Types, Functions, Variables, and Enumerators Properly #### +#### Name Types, Functions, Variables, and Enumerators Properly Poorly-chosen names can mislead the reader and cause bugs. We cannot stress enough how important it is to use *descriptive* names. @@ -768,7 +768,7 @@ Vehicle make_vehicle(VehicleType Type) { } ``` -#### Assert Liberally #### +#### Assert Liberally Use the `g_assert()` macro to its fullest. Check all of your preconditions and assumptions, you never know when a @@ -841,7 +841,7 @@ bool new_to_set = my_set.insert(value); g_assert(new_to_set && "The value shouldn't be in the set yet"); ``` -#### Do Not Use `using namespace std` #### +#### Do Not Use `using namespace std` In GJS, we prefer to explicitly prefix all identifiers from the standard namespace with an `std::` prefix, rather than rely on `using namespace @@ -876,7 +876,7 @@ The general form of this rule is that any `.cpp` file that implements code in any namespace may use that namespace (and its parents'), but should not use any others. -#### Provide a Virtual Method Anchor for Classes in Headers #### +#### Provide a Virtual Method Anchor for Classes in Headers If a class is defined in a header file and has a vtable (either it has virtual methods or it derives from classes with virtual methods), it @@ -885,7 +885,7 @@ Without this, the compiler will copy the vtable and RTTI into every `.o` file that `#include`s the header, bloating `.o` file sizes and increasing link times. -#### Don't use default labels in fully covered switches over enumerations #### +#### Don't use default labels in fully covered switches over enumerations `-Wswitch` warns if a switch, without a default label, over an enumeration, does not cover every enumeration value. @@ -901,7 +901,7 @@ switch-over-enum because GCC assumes that the enum expression may take any representable value, not just those of individual enumerators. To suppress this warning, use `g_assert_not_reached()` after the switch. -#### Use range-based `for` loops wherever possible #### +#### Use range-based `for` loops wherever possible The introduction of range-based `for` loops in C++11 means that explicit manipulation of iterators is rarely necessary. We use range-based `for` @@ -912,7 +912,7 @@ for (GClosure* closure : m_closures) ... use closure ...; ``` -#### Don't evaluate `end()` every time through a loop #### +#### Don't evaluate `end()` every time through a loop In cases where range-based `for` loops can't be used and it is necessary to write an explicit iterator-based loop, pay close attention to whether @@ -968,7 +968,7 @@ what it does. While the second form of the loop is a few extra keystrokes, we do strongly prefer it. -#### Avoid `std::endl` #### +#### Avoid `std::endl` The `std::endl` modifier, when used with `iostreams`, outputs a newline to the output stream specified. @@ -983,7 +983,7 @@ std::cout << '\n' << std::flush; Most of the time, you probably have no reason to flush the output stream, so it's better to use a literal `'\n'`. -#### Don't use `inline` when defining a function in a class definition #### +#### Don't use `inline` when defining a function in a class definition A member function defined in a class definition is implicitly inline, so don't put the `inline` keyword in this case. diff --git a/doc/Hacking.md b/doc/Hacking.md index 592eab42b..e939cb149 100644 --- a/doc/Hacking.md +++ b/doc/Hacking.md @@ -1,6 +1,6 @@ -# Hacking on GJS # +# Hacking on GJS -## Quick start ## +## Quick start If you are looking to get started quickly, then you can clone GJS using GNOME Builder and choose the `org.gnome.GjsConsole` build configuration. @@ -11,7 +11,7 @@ If you need to issue any of the Meson commands manually, make sure to do so in a runtime terminal (Ctrl+Alt+T) rather than a build terminal or a regular terminal. -## Setting up ## +## Setting up First of all, download the GJS source code using Git. Go to [GJS on GitLab](https://gitlab.gnome.org/GNOME/gjs), and click @@ -37,7 +37,7 @@ You can also skip this step if you are not writing any C++ code.) ## Dependencies GJS requires five other libraries to be installed: GLib, libffi, -gobject-introspection, SpiderMonkey (also called "mozjs115" on some +gobject-introspection, SpiderMonkey (also called "mozjs128" on some systems.) and the build tool Meson. The readline library is not required, but strongly recommended. We recommend installing your system's development packages for GLib, @@ -66,19 +66,19 @@ will help catch mistakes in the API that could otherwise go unnoticed and cause crashes in gnome-shell later on. If you aren't writing any C++ code, and your system provides it (for -example, Fedora 36 or Ubuntu 22.04 and later versions), then you don't +example, Fedora 41 or Ubuntu 24.10 and later versions), then you don't need to build it yourself. Install SpiderMonkey using your system's package manager instead: - +
Fedora - sudo dnf install mozjs115-devel + sudo dnf install mozjs128-devel
If you _are_ writing C++ code, then please build SpiderMonkey yourself @@ -86,11 +86,11 @@ with the debugging features enabled. This can save you time later when you submit your merge request, because the code will be checked using the debugging features. -To build SpiderMonkey, follow the instructions on [this page](https://github.com/mozilla-spidermonkey/spidermonkey-embedding-examples/blob/esr115/docs/Building%20SpiderMonkey.md) to download the source code and build the library. +To build SpiderMonkey, follow the instructions on [this page](https://github.com/mozilla-spidermonkey/spidermonkey-embedding-examples/blob/esr128/docs/Building%20SpiderMonkey.md) to download the source code and build the library. If you are using `-Dprefix` to build GJS into a different path, then make sure to use the same build prefix for SpiderMonkey with `--prefix`. -## First build ## +## First build To build GJS, change to your `gjs` directory, and run: ```sh @@ -104,14 +104,15 @@ For a list of available options, run `meson configure`. That's it! You can now run your build of gjs for testing and hacking with ```sh -LD_LIBRARY_PATH=_build GI_TYPELIB_PATH=_build GJS_USE_UNINSTALLED_FILES=1 ./_build/cjs-console script.js +meson devenv -C _build cjs-console ../script.js ``` +(the path `../script.js` is relative to `_build`, not the root folder) To install GJS into the path you chose with `-Dprefix`, (or into `/usr/local` if you didn't choose a path), run `ninja -C _build install`, adding `sudo` if necessary. -## Making Sure Your Stuff Doesn't Break Anything Else ## +## Making Sure Your Stuff Doesn't Break Anything Else Make your changes in your `gjs` directory, then run `ninja -C _build` to build a modified copy of GJS. @@ -128,7 +129,7 @@ it with `jhbuild run gnome-shell --replace`. You need to be logged into an Xorg session, not Wayland, for this to work. -## Debugging ## +## Debugging Mozilla has some pretty-printers that make debugging JSAPI code easier. Unfortunately they're not included in most packaged distributions of @@ -143,16 +144,30 @@ source /path/to/spidermonkey/js/src/_build/js/src/shell/js-gdb.py (replace `/path/to/spidermonkey` with the path to your SpiderMonkey sources) -## Checking Things More Thoroughly Before A Release ## +## Getting a stack trace -### GC Zeal ### +Run your program with `gdb --args gjs myfile.js`. +This will drop you into the GDB debugger interface. + +Enter `r` to start the program. + +When it segfaults, enter `bt full` to get the C++ stack trace, and enter +`call gjs_dumpstack()` to get the JS stack trace. +(It may need to be `call (void) gjs_dumpstack()` if you don't have debugging +symbols installed.) + +Enter `q` to quit. + +## Checking Things More Thoroughly Before A Release + +### GC Zeal Run the test suite with "GC zeal" to make non-deterministic GC errors more likely to show up. To see which GC zeal options are available: ```sh -JS_GC_ZEAL=-1 js115 +JS_GC_ZEAL=-1 js128 ``` We include three test setups, `extra_gc`, `pre_verify`, and @@ -168,7 +183,7 @@ traced when it should have been. Failures in mode `post_verify` usually point to a weak pointer's location not being updated after GC moved it. -### Valgrind ### +### Valgrind Valgrind catches memory leak errors in the C++ code. It's a good idea to run the test suite under Valgrind before each @@ -186,7 +201,7 @@ Note that LeakSanitizer, part of ASan (see below) can catch many, but not all, errors that Valgrind can catch. LSan executes faster than Valgrind, however. -### Static Code Analysis ### +### Static Code Analysis To execute cppcheck, a static code analysis tool for the C and C++, run: ```sh @@ -196,7 +211,7 @@ It is a versatile tool that can check non-standard code, including: variable checking, bounds checking, leaks, etc. It can detect the types of bugs that the compilers normally fail to detect. -### Sanitizers ### +### Sanitizers To build GJS with support for the ASan and UBSan sanitizers, configure meson like this: @@ -205,7 +220,7 @@ meson setup _build -Db_sanitize=address,undefined ``` and then run the tests as normal. -### Test Coverage ### +### Test Coverage To generate a test coverage report, run this script: ```sh @@ -216,7 +231,7 @@ This will build GJS into a separate build directory with code coverage instrumentation enabled, run the test suite to collect the coverage data, and open the generated HTML report. -[embedder](https://github.com/spidermonkey-embedders/spidermonkey-embedding-examples/blob/esr115/docs/Building%20SpiderMonkey.md) +[embedder](https://github.com/spidermonkey-embedders/spidermonkey-embedding-examples/blob/esr128/docs/Building%20SpiderMonkey.md) ## Troubleshooting diff --git a/doc/Mainloop.md b/doc/Mainloop.md index 729f1d24b..9cdf611c5 100644 --- a/doc/Mainloop.md +++ b/doc/Mainloop.md @@ -187,7 +187,7 @@ Creates a new timeout source. The scheduling granularity/accuracy of this source will be in milliseconds. If not given, `priority` defaults to `GLib.PRIORITY_DEFAULT`. -[gtimeoutadd]: https://gjs-docs.gnome.org/glib20/glib.timeout_source_new +[gtimeoutsourcenew]: https://gjs-docs.gnome.org/glib20/glib.timeout_source_new ### Mainloop.timeout_seconds_source(timeout, handler, priority) diff --git a/doc/Overrides.md b/doc/Overrides.md index 445a6e06a..08b079150 100644 --- a/doc/Overrides.md +++ b/doc/Overrides.md @@ -192,8 +192,9 @@ Gio._promisify(Gio.InputStream.prototype, 'read_bytes_async', 'read_bytes_finish'); try { - const inputStream = new Gio.UnixInputStream({fd: 0}); - const bytes = await inputStream.read_bytes_async(4096, + const inputBytes = new GLib.Bytes('content'); + const inputStream = Gio.MemoryInputStream.new_from_bytes(inputBytes); + const result = await inputStream.read_bytes_async(inputBytes.get_size(), GLib.PRIORITY_DEFAULT, null); } catch (e) { logError(e, 'Failed to read bytes'); @@ -619,6 +620,35 @@ signal. [gobject-signals-tutorial]: https://gjs.guide/guides/gobject/basics.html#signals +### GObject.Object.connect_object(name, callback, gobject, flags) + +> See also: [GObject Signals Tutorial][gobject-signals-tutorial] + +Parameters: +* name (`String`) — A detailed signal name +* callback (`Function`) — A callback function +* gobject (`GObject.Object`) — A [`GObject.Object`][gobject] instance +* flags (`GObject.ConnectFlags`) — Flags + +Returns: +* (`Number`) — A signal handler ID + +Connects a callback function to a signal for a particular object. + +The `gobject` parameter is used to limit the lifetime of the connection. When the +object is destroyed, the callback will be disconnected automatically. The +`gobject` parameter is not otherwise used. + +The first argument of the callback will be the object emitting the signal, while +the remaining arguments are the signal parameters. + +If `GObject.ConnectFlags.AFTER` is specified in `flags`, the handler will be +called after the default handler of the signal. Otherwise, it will be called +before. `GObject.ConnectFlags.SWAPPED` is not supported and its use will +throw an exception. + +[gobject-signals-tutorial]: https://gjs.guide/guides/gobject/basics.html#signals + ### GObject.Object.disconnect(id) > See also: [GObject Signals Tutorial][gobject-signals-tutorial] diff --git a/doc/Signals.md b/doc/Signals.md index 70f038b73..444cb9a8a 100644 --- a/doc/Signals.md +++ b/doc/Signals.md @@ -63,7 +63,7 @@ Returns: * (`Number`) — A handler ID Connects a callback to a signal for an object. Pass the returned ID to -`disconect()` to remove the handler. +`disconnect()` to remove the handler. If `callback` returns `true`, emission will stop and no other handlers will be invoked. diff --git a/doc/SpiderMonkey_Memory.md b/doc/SpiderMonkey_Memory.md index 99f893f7c..c56a354d1 100644 --- a/doc/SpiderMonkey_Memory.md +++ b/doc/SpiderMonkey_Memory.md @@ -1,16 +1,16 @@ -# Memory management in SpiderMonkey # +# Memory management in SpiderMonkey When writing JavaScript extensions in C++, we have to understand and be careful about memory management. This document only applies to C++ code using the jsapi.h API. If you simply write a GObject-style library and describe it via gobject-introspection typelib, there is no need to understand garbage collection details. -## Mark-and-sweep collector ## +## Mark-and-sweep collector As background, SpiderMonkey uses mark-and-sweep garbage collection. (see [this page][1] for one explanation, if not familiar with this.) This is a good approach for "embeddable" interpreters, because unlike say the Boehm GC, it doesn't rely on any weird hacks like scanning the entire memory or stack of the process. The collector only has to know about stuff that the language runtime created itself. Also, mark-and-sweep is simple to understand when working with the embedding API. -## Representation of objects ## +## Representation of objects An object has two forms. * `JS::Value` is a type-tagged version, think of `GValue` (though it is much more efficient) @@ -28,7 +28,7 @@ The methods `val.toObject()`, `val.toInt32()`, etc. are just accessing the appro The jsapi.h header is pretty readable, if you want to learn more. Types you see in there not mentioned above, such as `JSFunction*`, would show up as an object - `val.isObject()` would return true. From a `JS::Value` perspective, everything is one of object, string, symbol, double, int, boolean, null, or undefined. -## Value types vs. allocated types; "gcthing" ## +## Value types vs. allocated types; "gcthing" For integers, booleans, doubles, null, and undefined there is no pointer. The value is just part of the `JS::Value` union. So there is no way to "free" these, and no way for them to be finalized or become dangling. @@ -41,7 +41,7 @@ The API refers to these allocated types as "GC things." The macro `val.toGCThing()` returns the value part of the union as a pointer. `val.isGCThing()` returns true for string, object, symbol, null; and false for void, boolean, double, integer. -## Tracing ## +## Tracing The general rule is that SpiderMonkey has a set of GC roots. To do the garbage collection, it finds all objects accessible from those roots, and finalizes all objects that are not. @@ -53,7 +53,7 @@ If you reference JavaScript objects from your custom object, you have to use `JS Tracing doesn't add a GC thing to the GC root set! It just notifies the interpreter that a thing is reachable from another thing. -## Global roots ## +## Global roots The GC roots include anything you have declared with `JS::Rooted` and the global object set on each `JSContext*`. You can also manually add roots with [`JS::PersistentRooted()`][3]. Anything reachable from any of these root objects will not be collected. @@ -64,7 +64,7 @@ Note that the wrapped T in `JS::PersistentRooted` is the location of your val * the location can't go away (don't use a stack address that will vanish before the `JS::PersistentRooted` is destructed, for example) * the root is keeping "whatever is at the location" from being collected, not "whatever was originally at the location" -## Local roots ## +## Local roots Here is the trickier part. If you create an object, say: @@ -87,17 +87,17 @@ So instead of the above code, you would write JS::RootedObject obj(cx, JS_NewPlainObject(cx)); ``` -### JSFunctionSpec and extra local roots ### +### JSFunctionSpec and extra local roots When SpiderMonkey is calling a native function, it will pass in an argv of `JS::Value`. It already has to add all the argv values as GC roots. The "extra local roots" feature tells SpiderMonkey to stick some extra slots on the end of argv that are also GC roots. You can then assign to `argv[MAX(min_args, actual_argc)]` and whatever you put in there won't get garbage collected. This is kind of a confusing and unreadable hack IMO, though it is probably efficient and thus justified in certain cases. I don't know really. -## More tips ## +## More tips For another attempt to explain all this, see [Rooting Guide from Mozilla.org][4]. -[1] http://www.brpreiss.com/books/opus5/html/page424.html -[2] http://developer.mozilla.org/en/docs/JSTraceOp -[3] https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_reference/JS::PersistentRooted -[4] https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/GC_Rooting_Guide GC +[1]: http://www.brpreiss.com/books/opus5/html/page424.html +[2]: http://developer.mozilla.org/en/docs/JSTraceOp +[3]: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_reference/JS::PersistentRooted +[4]: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/GC_Rooting_Guide "GC" diff --git a/doc/Style_Guide.md b/doc/Style_Guide.md index e2a537646..ae1078de7 100644 --- a/doc/Style_Guide.md +++ b/doc/Style_Guide.md @@ -1,10 +1,10 @@ -# Coding style # +# Coding style Our goal is to have all JavaScript code in GNOME follow a consistent style. In a dynamic language like JavaScript, it is essential to be rigorous about style (and unit tests), or you rapidly end up with a spaghetti-code mess. -## Linter ## +## Linter GJS includes an eslint configuration file, `.eslintrc.yml`. There is an additional one that applies to test code in @@ -21,7 +21,7 @@ The style guide for JS code in GJS is, by definition, the eslint config file. This file only contains conventions that the linter can't catch. -## Imports ## +## Imports Use CamelCase when importing modules to distinguish them from ordinary variables, e.g. @@ -30,7 +30,7 @@ const Big = imports.big; const {GLib} = imports.gi; ``` -## Variable declaration ## +## Variable declaration Always use `const` or `let` when block scope is intended. In almost all cases `const` is correct if you don't reassign the @@ -64,7 +64,7 @@ for (let i = 0; i < 10; ++i) { If you used `var` instead of `let` it would print "10" a bunch of times. -## `this` in closures ## +## `this` in closures `this` will not be captured in a closure; `this` is relative to how the closure is invoked, not to the value of this where the closure is created, because `this` is a keyword with a value passed @@ -93,7 +93,7 @@ const MyPrototype = { }; ``` -## Object literal syntax ## +## Object literal syntax JavaScript allows equivalently: ```js @@ -110,7 +110,7 @@ If your usage of an object is like an object, then you're defining "member varia If your usage of an object is like a hash table (and thus conceptually the keys can have special chars in them), don't use quotes, but use brackets, `{bar: 42}`, `foo['bar']`. -## Variable naming ## +## Variable naming - We use javaStyle variable names, with CamelCase for type names and lowerCamelCase for variable and method names. However, when calling a C method with underscore-based names via introspection, we just keep them looking as they do in C for simplicity. - Private variables, whether object member variables or module-scoped variables, should begin with `_`. @@ -118,4 +118,4 @@ If your usage of an object is like a hash table (and thus conceptually the keys - When you assign a module to an alias to avoid typing `imports.foo.bar` all the time, the alias should be `const TitleCase` so `const Bar = imports.foo.bar;` - If you need to name a variable something weird to avoid a namespace collision, add a trailing `_` (not leading, leading `_` means private). -[1] http://developer.mozilla.org/en/docs/index.php?title=New_in_JavaScript_1.7&printable=yes#Block_scope_with_let +[1]: http://developer.mozilla.org/en/docs/index.php?title=New_in_JavaScript_1.7&printable=yes#Block_scope_with_let diff --git a/doc/Understanding-SpiderMonkey-code.md b/doc/Understanding-SpiderMonkey-code.md index 2742cba4a..6c150d95b 100644 --- a/doc/Understanding-SpiderMonkey-code.md +++ b/doc/Understanding-SpiderMonkey-code.md @@ -1,17 +1,15 @@ -Basics ------- +## Basics - SpiderMonkey is the Javascript engine from Mozilla Firefox. It's also known as "mozjs" in most Linux distributions, and sometimes as "JSAPI" in code. - Like most browsers' JS engines, SpiderMonkey works standalone, which is what allows GJS to work. In Mozilla terminology, this is known as "embedding", and GJS is an "embedder." - Functions that start with `JS_` or `JS::`, or types that start with `JS`, are part of the SpiderMonkey API. - Functions that start with `js_` or `js::` are part of the "JS Friend" API, which is a section of the SpiderMonkey API which is supposedly less stable. (Although SpiderMonkey isn't API stable in the first place.) - We use the SpiderMonkey from the ESR (Extended Support Release) of Firefox. These ESRs are released approximately once a year. -- Since ESR 24, the SpiderMonkey team has gotten sloppy about making official releases of standalone SpiderMonkey. (Arguably, that was because nobody, including us, was using them.) We had high hopes for an official release of ESR 52, but there were some problems that couldn't be fixed on the ESR branch. The SpiderMonkey team will likely make an official release of ESR 60, but they may need some reminders when the time comes. +- Since ESR 24, the official releases of standalone SpiderMonkey have fallen by the wayside. (Arguably, that was because nobody, including us, was using them.) The SpiderMonkey team may make official releases again sometime, but it's a low priority. - When reading GJS code, to quickly find out what a SpiderMonkey API function does, you can go to https://searchfox.org/ and search for it. This is literally faster than opening `jsapi.h` in your editor, and you can click through to other functions, and find everywhere a function is used. - Don't trust the wiki on MDN as documentation for SpiderMonkey, as it is mostly out of date and can be quite misleading. -Coding conventions ------------------- +## Coding conventions - Most API functions take a `JSContext *` as their first parameter. This context contains the state of the JS engine. - `cx` stands for "context." @@ -20,4 +18,4 @@ Coding conventions - There are two ways to violate that condition: - Returning `false` with no exception pending. This is interpreted as an "uncatchable" exception, and it's used for out-of-memory and killing scripts within Firefox, for example. In GJS we use it to implement `System.exit()`. - Returning `true` while an exception is pending. This can easily happen by forgetting to check the return value of a SpiderMonkey function, and is a programmer error but not too serious. It will probably cause some warnings. -- Likewise if an API function returns a pointer such as `JSObject*` (this is less common), the convention is that it should return `nullptr` on failure, in which case an exception should be pending. \ No newline at end of file +- Likewise if an API function returns a pointer such as `JSObject*` (this is less common), the convention is that it should return `nullptr` on failure, in which case an exception should be pending. diff --git a/doc/cairo.md b/doc/cairo.md index 14fddcef8..4ac7585d7 100644 --- a/doc/cairo.md +++ b/doc/cairo.md @@ -122,18 +122,42 @@ Prototype hierarchy * `Cairo.Surface` (abstract) * `Cairo.ImageSurface` * `Cairo.PDFSurface` + * `Cairo.PSSurface` * `Cairo.SVGSurface` - * `Cairo.PostScriptSurface` The native surfaces (win32, quartz, xlib) are not supported at this time. Methods manipulating a surface are present in the surface class. For example, -creating a `Cairo.ImageSurface` from a PNG is done by calling a static method: +creating a `Cairo.ImageSurface` from a PNG is done by calling a static method. + +### Examples + +Creating an empty image surface can be done by passing a [`Cairo.Format`]: + +```js +/* Creating a surface from a PDF (format, width, height) */ +const imageSurface = new Cairo.ImageSurface(Cairo.Format.ARGB32, 10, 10); +``` + +Creating a `Cairo.ImageSurface` from a file differs somewhat depending on the +file type: ```js -const surface = Cairo.ImageSurface.createFromPNG('filename.png'); +/* Creating a surface from a PNG */ +const pngSurface = Cairo.ImageSurface.createFromPNG('filename.png'); + +/* Creating a surface from a PDF (filename, width, height) */ +const pdfSurface = new Cairo.PDFSurface('filename.pdf', 32, 32); + +/* Creating a surface from a PostScript file (filename, width, height) */ +const psSurface = new Cairo.PSSurface('filename.ps', 32, 32); + +/* Creating a surface from a SVG (filename, width, height) */ +const svgSurface = new Cairo.SVGSurface('filename.svg', 32, 32); ``` +[`Cairo.Format`]: https://gjs-docs.gnome.org/cairo10/cairo.format + ## To-do List As previously mentioned, the Cairo bindings for GJS are not entirely complete diff --git a/examples/dbus-client.js b/examples/dbus-client.js index e9d1aeafc..07d090a81 100644 --- a/examples/dbus-client.js +++ b/examples/dbus-client.js @@ -9,7 +9,7 @@ import Gio from 'gi://Gio'; */ const ifaceXml = ` - + @@ -26,7 +26,7 @@ const ifaceXml = ` -// Pass the XML string to make a re-usable proxy class for an interface proxies. +// Pass the XML string to make a reusable proxy class for an interface proxies. const TestProxy = Gio.DBusProxy.makeProxyWrapper(ifaceXml); @@ -45,8 +45,8 @@ function onNameAppeared(connection, name, _owner) { try { proxy = new TestProxy( Gio.DBus.session, - 'org.gnome.gjs.Test', - '/org/gnome/gjs/Test' + 'org.cinnamon.cjs.Test', + '/org/cinnamon/cjs/Test' ); } catch (err) { logError(err); @@ -119,7 +119,7 @@ function onNameVanished(connection, name) { let busWatchId = Gio.bus_watch_name( Gio.BusType.SESSION, - 'org.gnome.gjs.Test', + 'org.cinnamon.cjs.Test', Gio.BusNameWatcherFlags.NONE, onNameAppeared, onNameVanished @@ -143,8 +143,8 @@ proxy = null; new TestProxy( Gio.DBus.session, - 'org.gnome.gjs.Test', - '/org/gnome/gjs/Test', + 'org.cinnamon.cjs.Test', + '/org/cinnamon/cjs/Test', (sourceObj, error) => { // If @error is not `null` it will be an Error object indicating the // failure. @proxy will be `null` in this case. diff --git a/examples/dbus-service.js b/examples/dbus-service.js index b4af5c1af..31ebf6a20 100644 --- a/examples/dbus-service.js +++ b/examples/dbus-service.js @@ -9,7 +9,7 @@ import Gio from 'gi://Gio'; */ const ifaceXml = ` - + @@ -85,7 +85,7 @@ let serviceSignalId = 0; function onBusAcquired(connection, _name) { // At this point you have acquired a connection to the bus, and you should // export your interfaces now. - serviceObj.dbus.export(connection, '/org/gnome/gjs/Test'); + serviceObj.dbus.export(connection, '/org/cinnamon/cjs/Test'); } function onNameAcquired(_connection, _name) { @@ -113,7 +113,7 @@ function onNameLost(_connection, _name) { let ownerId = Gio.bus_own_name( Gio.BusType.SESSION, - 'org.gnome.gjs.Test', + 'org.cinnamon.cjs.Test', Gio.BusNameOwnerFlags.NONE, onBusAcquired, onNameAcquired, diff --git a/examples/gtk-application.js b/examples/gtk-application.js index 4aa4f26d2..4f50503e3 100644 --- a/examples/gtk-application.js +++ b/examples/gtk-application.js @@ -26,7 +26,7 @@ let ExampleApplication = GObject.registerClass({ }, class ExampleApplication extends Gtk.Application { constructor() { super({ - application_id: 'org.gnome.gjs.ExampleApplication', + application_id: 'org.cinnamon.cjs.ExampleApplication', flags: Gio.ApplicationFlags.FLAGS_NONE, }); } diff --git a/examples/http-server.js b/examples/http-server.js index 8f9e9172b..74f36db26 100644 --- a/examples/http-server.js +++ b/examples/http-server.js @@ -43,13 +43,9 @@ function helloHandler(_server, msg, path, query) { `); } -function main() { - let server = new Soup.Server(); - server.add_handler('/', handler); - server.add_handler('/hello', helloHandler); - server.listen_local(1080, Soup.ServerListenOptions.IPV4_ONLY); -} - -main(); +let server = new Soup.Server(); +server.add_handler('/', handler); +server.add_handler('/hello', helloHandler); +server.listen_local(1080, Soup.ServerListenOptions.IPV4_ONLY); loop.run(); diff --git a/gi/arg-cache.cpp b/gi/arg-cache.cpp index 3de89bee1..f319b8bfd 100644 --- a/gi/arg-cache.cpp +++ b/gi/arg-cache.cpp @@ -63,9 +63,9 @@ static const char* expected_type_names[] = {"object", "function", "string"}; static_assert(G_N_ELEMENTS(expected_type_names) == ExpectedType::LAST, "Names must match the values in ExpectedType"); -static constexpr void gjs_g_argument_set_array_length(GITypeTag tag, - GIArgument* arg, - size_t value) { +static constexpr void gjs_gi_argument_set_array_length(GITypeTag tag, + GIArgument* arg, + size_t value) { switch (tag) { case GI_TYPE_TAG_INT8: gjs_arg_set(arg, value); @@ -145,18 +145,13 @@ struct BasicType { GITypeTag m_tag : 5; }; -struct String { - constexpr String() : m_filename(false) {} - bool m_filename : 1; -}; - -struct TypeInfo { +struct HasTypeInfo { constexpr GITypeInfo* type_info() const { // Should be const GITypeInfo*, but G-I APIs won't accept that return const_cast(&m_type_info); } - GITypeInfo m_type_info; + GITypeInfo m_type_info{}; }; struct Transferable { @@ -187,8 +182,21 @@ struct Positioned { constexpr bool set_out_parameter(GjsFunctionCallState* state, GIArgument* arg) { - gjs_arg_unset(&state->out_cvalue(m_arg_pos)); - gjs_arg_set(arg, &gjs_arg_member(&state->out_cvalue(m_arg_pos))); + // Clear all bits of the out C value. No one member is guaranteed to + // span the whole union on all architectures, so use memset() instead of + // gjs_arg_unset(). + memset(&state->out_cvalue(m_arg_pos), 0, sizeof(GIArgument)); + // The value passed to the function is actually the address of the out + // C value + gjs_arg_set(arg, &state->out_cvalue(m_arg_pos)); + return true; + } + + constexpr bool set_inout_parameter(GjsFunctionCallState* state, + GIArgument* arg) { + state->out_cvalue(m_arg_pos) = state->inout_original_cvalue(m_arg_pos) = + *arg; + gjs_arg_set(arg, &state->out_cvalue(m_arg_pos)); return true; } @@ -197,20 +205,24 @@ struct Positioned { struct Array : BasicType { uint8_t m_length_pos = 0; + GIDirection m_length_direction : 2; - void set_array_length(int pos, GITypeTag tag) { + Array() : BasicType(), m_length_direction(GI_DIRECTION_IN) {} + + void set_array_length(int pos, GITypeTag tag, GIDirection direction) { g_assert(pos >= 0 && pos <= Argument::MAX_ARGS && "No more than 253 arguments allowed"); m_length_pos = pos; + m_length_direction = direction; m_tag = tag; } }; -struct BaseInfo { - constexpr explicit BaseInfo(GIBaseInfo* info, - const GjsAutoTakeOwnership& add_ref) +struct HasIntrospectionInfo { + constexpr explicit HasIntrospectionInfo(GIBaseInfo* info, + const GjsAutoTakeOwnership& add_ref) : m_info(info, add_ref) {} - constexpr explicit BaseInfo(GIBaseInfo* info) : m_info(info) {} + constexpr explicit HasIntrospectionInfo(GIBaseInfo* info) : m_info(info) {} GjsAutoBaseInfo m_info; }; @@ -227,7 +239,7 @@ struct GTypedType { struct RegisteredType : GTypedType { RegisteredType(GType gtype, GIInfoType info_type) : GTypedType(gtype), m_info_type(info_type) {} - explicit RegisteredType(GIBaseInfo* info) + explicit RegisteredType(GIRegisteredTypeInfo* info) : GTypedType(g_registered_type_info_get_g_type(info)), m_info_type(g_base_info_get_type(info)) { g_assert(m_gtype != G_TYPE_NONE && @@ -237,15 +249,15 @@ struct RegisteredType : GTypedType { GIInfoType m_info_type : 5; }; -struct RegisteredInterface : BaseInfo, GTypedType { - explicit RegisteredInterface(GIBaseInfo* info) - : BaseInfo(info, GjsAutoTakeOwnership{}), +struct RegisteredInterface : HasIntrospectionInfo, GTypedType { + explicit RegisteredInterface(GIRegisteredTypeInfo* info) + : HasIntrospectionInfo(info, GjsAutoTakeOwnership{}), GTypedType(g_registered_type_info_get_g_type(m_info)) {} }; -struct Callback : Nullable, BaseInfo { - explicit Callback(GIInterfaceInfo* info) - : BaseInfo(info, GjsAutoTakeOwnership{}), +struct Callback : Nullable, HasIntrospectionInfo { + explicit Callback(GICallbackInfo* info) + : HasIntrospectionInfo(info, GjsAutoTakeOwnership{}), m_scope(GI_SCOPE_TYPE_INVALID) {} inline void set_callback_destroy_pos(int pos) { @@ -319,7 +331,7 @@ struct SkipAll : Argument { constexpr bool skip() { return true; } }; -struct Generic : SkipAll, Transferable, TypeInfo {}; +struct Generic : SkipAll, Transferable, HasTypeInfo {}; struct GenericIn : Generic { bool in(JSContext*, GjsFunctionCallState*, GIArgument*, @@ -347,7 +359,10 @@ struct GenericOut : GenericInOut { bool release(JSContext*, GjsFunctionCallState*, GIArgument*, GIArgument*) override; - const ReturnValue* as_return_value() const override { return this; } + GITypeTag return_tag() const override { + return g_type_info_get_tag(&const_cast(this)->m_type_info); + } + const GITypeInfo* return_type() const override { return &m_type_info; } }; struct GenericReturn : ReturnValue { @@ -358,6 +373,39 @@ struct GenericReturn : ReturnValue { } }; +template +struct NumericOut : SkipAll, Positioned { + static_assert(std::is_arithmetic_v, "Not arithmetic type"); + bool in(JSContext*, GjsFunctionCallState* state, GIArgument* arg, + JS::HandleValue) override { + return set_out_parameter(state, arg); + } + bool out(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, + JS::MutableHandleValue value) override { + return Gjs::c_value_to_js_checked(cx, gjs_arg_get(arg), + value); + } +}; + +using BooleanOut = NumericOut; + +template +struct NumericReturn : SkipAll { + static_assert(std::is_arithmetic_v, "Not arithmetic type"); + bool in(JSContext* cx, GjsFunctionCallState*, GIArgument*, + JS::HandleValue) override { + return invalid(cx, G_STRFUNC); + } + bool out(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, + JS::MutableHandleValue value) override { + return Gjs::c_value_to_js_checked(cx, gjs_arg_get(arg), + value); + } + GITypeTag return_tag() const override { return TAG; } +}; + +using BooleanReturn = NumericReturn; + struct SimpleOut : SkipAll, Positioned { bool in(JSContext*, GjsFunctionCallState* state, GIArgument* arg, JS::HandleValue) override { @@ -403,6 +451,13 @@ struct ExplicitArrayOut : ExplicitArrayInOut { struct ReturnArray : ExplicitArrayOut { bool in(JSContext* cx, GjsFunctionCallState* state, GIArgument* arg, JS::HandleValue value) override { + if (m_length_direction != GI_DIRECTION_OUT) { + gjs_throw(cx, + "Using different length argument direction for array %s" + "is not supported for out arrays", + m_arg_name); + return false; + } return GenericOut::in(cx, state, arg, value); }; }; @@ -506,14 +561,14 @@ struct ForeignStructIn : ForeignStructInstanceIn { GIArgument*) override; }; -struct FallbackInterfaceIn : RegisteredInterfaceIn, TypeInfo { +struct FallbackInterfaceIn : RegisteredInterfaceIn, HasTypeInfo { using RegisteredInterfaceIn::RegisteredInterfaceIn; bool in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, JS::HandleValue value) override { - return gjs_value_to_g_argument(cx, value, &m_type_info, m_arg_name, - GJS_ARGUMENT_ARGUMENT, m_transfer, - flags(), arg); + return gjs_value_to_gi_argument(cx, value, &m_type_info, m_arg_name, + GJS_ARGUMENT_ARGUMENT, m_transfer, + flags(), arg); } }; @@ -536,11 +591,11 @@ struct BoxedIn : BoxedInTransferNone { } }; -struct UnregisteredBoxedIn : BoxedIn, BaseInfo { - explicit UnregisteredBoxedIn(GIInterfaceInfo* info) +struct UnregisteredBoxedIn : BoxedIn, HasIntrospectionInfo { + explicit UnregisteredBoxedIn(GIStructInfo* info) : BoxedIn(g_registered_type_info_get_g_type(info), g_base_info_get_type(info)), - BaseInfo(info, GjsAutoTakeOwnership{}) {} + HasIntrospectionInfo(info, GjsAutoTakeOwnership{}) {} // This is a smart argument, no release needed GIBaseInfo* info() const override { return m_info; } }; @@ -625,12 +680,32 @@ struct BooleanIn : SkipAll { JS::HandleValue) override; }; -struct NumericIn : SkipAll, BasicType { - explicit NumericIn(GITypeTag tag) : BasicType(tag) {} +template +struct NumericIn : SkipAll { + static_assert(std::is_arithmetic_v, "Not arithmetic type"); bool in(JSContext*, GjsFunctionCallState*, GIArgument*, JS::HandleValue) override; }; +template +struct NumericInOut : NumericIn, Positioned { + static_assert(std::is_arithmetic_v, "Not arithmetic type"); + bool in(JSContext* cx, GjsFunctionCallState* state, GIArgument* arg, + JS::HandleValue value) override { + if (!NumericIn::in(cx, state, arg, value)) + return false; + + return set_inout_parameter(state, arg); + } + bool out(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, + JS::MutableHandleValue value) override { + return Gjs::c_value_to_js_checked(cx, gjs_arg_get(arg), + value); + } +}; + +using BooleanInOut = NumericInOut; + struct UnicharIn : SkipAll { bool in(JSContext*, GjsFunctionCallState*, GIArgument*, JS::HandleValue) override; @@ -641,26 +716,61 @@ struct GTypeIn : SkipAll { JS::HandleValue) override; }; -struct StringInTransferNone : NullableIn, String { +template +struct StringInTransferNone : NullableIn { bool in(JSContext*, GjsFunctionCallState*, GIArgument*, JS::HandleValue) override; bool release(JSContext*, GjsFunctionCallState*, GIArgument*, GIArgument*) override; }; -struct StringIn : StringInTransferNone { +struct StringIn : StringInTransferNone { bool release(JSContext*, GjsFunctionCallState*, GIArgument*, GIArgument*) override { return skip(); } }; -struct FilenameInTransferNone : StringInTransferNone { - FilenameInTransferNone() { m_filename = true; } +template +struct StringOutBase : SkipAll { + bool out(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, + JS::MutableHandleValue value) override { + return Gjs::c_value_to_js(cx, gjs_arg_get(arg), value); + } + bool release(JSContext* cx, GjsFunctionCallState*, GIArgument*, + GIArgument* out_arg [[maybe_unused]]) override { + if constexpr (TRANSFER == GI_TRANSFER_NOTHING) { + return skip(); + } else if constexpr (TRANSFER == GI_TRANSFER_EVERYTHING) { + g_clear_pointer(&gjs_arg_member(out_arg), g_free); + return true; + } else { + return invalid(cx, G_STRFUNC); + } + } +}; + +template +struct StringReturn : StringOutBase { + bool in(JSContext* cx, GjsFunctionCallState*, GIArgument*, + JS::HandleValue) override { + return Argument::invalid(cx, G_STRFUNC); + } + + GITypeTag return_tag() const override { return GI_TYPE_TAG_UTF8; } +}; + +template +struct StringOut : StringOutBase, Positioned { + bool in(JSContext*, GjsFunctionCallState* state, GIArgument* arg, + JS::HandleValue) override { + return set_out_parameter(state, arg); + } }; +using FilenameInTransferNone = StringInTransferNone; + struct FilenameIn : FilenameInTransferNone { - FilenameIn() { m_filename = true; } bool release(JSContext*, GjsFunctionCallState*, GIArgument*, GIArgument*) override { return skip(); @@ -722,6 +832,78 @@ struct BoxedCallerAllocatesOut : CallerAllocatesOut, GTypedType { GIArgument*) override; }; +struct ZeroTerminatedArrayInOut : GenericInOut { + bool release(JSContext* cx, GjsFunctionCallState* state, GIArgument*, + GIArgument* out_arg) override { + GITransfer transfer = + state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; + GIArgument* original_out_arg = &state->inout_original_cvalue(m_arg_pos); + if (!gjs_gi_argument_release_in_array(cx, transfer, &m_type_info, + original_out_arg)) + return false; + + transfer = + state->call_completed() ? m_transfer : GI_TRANSFER_EVERYTHING; + return gjs_gi_argument_release_out_array(cx, transfer, &m_type_info, + out_arg); + } +}; + +struct ZeroTerminatedArrayIn : GenericIn, Nullable { + bool out(JSContext*, GjsFunctionCallState*, GIArgument*, + JS::MutableHandleValue) override { + return skip(); + } + + bool release(JSContext* cx, GjsFunctionCallState* state, GIArgument* in_arg, + GIArgument*) override { + GITransfer transfer = + state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; + + return gjs_gi_argument_release_in_array(cx, transfer, &m_type_info, + in_arg); + } + + GjsArgumentFlags flags() const override { + return Argument::flags() | Nullable::flags(); + } +}; + +struct FixedSizeArrayIn : GenericIn { + bool out(JSContext*, GjsFunctionCallState*, GIArgument*, + JS::MutableHandleValue) override { + return skip(); + } + + bool release(JSContext* cx, GjsFunctionCallState* state, GIArgument* in_arg, + GIArgument*) override { + GITransfer transfer = + state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; + + int size = g_type_info_get_array_fixed_size(&m_type_info); + return gjs_gi_argument_release_in_array(cx, transfer, &m_type_info, + size, in_arg); + } +}; + +struct FixedSizeArrayInOut : GenericInOut { + bool release(JSContext* cx, GjsFunctionCallState* state, GIArgument*, + GIArgument* out_arg) override { + GITransfer transfer = + state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; + GIArgument* original_out_arg = &state->inout_original_cvalue(m_arg_pos); + int size = g_type_info_get_array_fixed_size(&m_type_info); + if (!gjs_gi_argument_release_in_array(cx, transfer, &m_type_info, size, + original_out_arg)) + return false; + + transfer = + state->call_completed() ? m_transfer : GI_TRANSFER_EVERYTHING; + return gjs_gi_argument_release_out_array(cx, transfer, &m_type_info, + size, out_arg); + } +}; + GJS_JSAPI_RETURN_CONVENTION bool NotIntrospectable::in(JSContext* cx, GjsFunctionCallState* state, GIArgument*, JS::HandleValue) { @@ -769,9 +951,9 @@ bool NotIntrospectable::in(JSContext* cx, GjsFunctionCallState* state, GJS_JSAPI_RETURN_CONVENTION bool GenericIn::in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, JS::HandleValue value) { - return gjs_value_to_g_argument(cx, value, &m_type_info, m_arg_name, - GJS_ARGUMENT_ARGUMENT, m_transfer, flags(), - arg); + return gjs_value_to_gi_argument(cx, value, &m_type_info, m_arg_name, + GJS_ARGUMENT_ARGUMENT, m_transfer, flags(), + arg); } GJS_JSAPI_RETURN_CONVENTION @@ -780,25 +962,29 @@ bool GenericInOut::in(JSContext* cx, GjsFunctionCallState* state, if (!GenericIn::in(cx, state, arg, value)) return false; - state->out_cvalue(m_arg_pos) = state->inout_original_cvalue(m_arg_pos) = - *arg; - gjs_arg_set(arg, &state->out_cvalue(m_arg_pos)); - return true; + return set_inout_parameter(state, arg); } GJS_JSAPI_RETURN_CONVENTION bool ExplicitArrayIn::in(JSContext* cx, GjsFunctionCallState* state, - GArgument* arg, JS::HandleValue value) { + GIArgument* arg, JS::HandleValue value) { void* data; size_t length; + if (m_length_direction != GI_DIRECTION_INOUT && + m_length_direction != GI_DIRECTION_IN) { + gjs_throw(cx, "Using different length argument direction for array %s" + "is not supported for in arrays", m_arg_name); + return false; + } + if (!gjs_array_to_explicit_array(cx, value, &m_type_info, m_arg_name, GJS_ARGUMENT_ARGUMENT, m_transfer, flags(), &data, &length)) return false; - gjs_g_argument_set_array_length(m_tag, &state->in_cvalue(m_length_pos), - length); + gjs_gi_argument_set_array_length(m_tag, &state->in_cvalue(m_length_pos), + length); gjs_arg_set(arg, data); return true; } @@ -822,11 +1008,13 @@ bool ExplicitArrayInOut::in(JSContext* cx, GjsFunctionCallState* state, gjs_arg_unset(&state->out_cvalue(ix)); gjs_arg_unset(&state->inout_original_cvalue(ix)); } else { - state->out_cvalue(length_pos) = - state->inout_original_cvalue(length_pos) = - state->in_cvalue(length_pos); - gjs_arg_set(&state->in_cvalue(length_pos), - &state->out_cvalue(length_pos)); + if G_LIKELY (m_length_direction == GI_DIRECTION_INOUT) { + state->out_cvalue(length_pos) = + state->inout_original_cvalue(length_pos) = + state->in_cvalue(length_pos); + gjs_arg_set(&state->in_cvalue(length_pos), + &state->out_cvalue(length_pos)); + } state->out_cvalue(ix) = state->inout_original_cvalue(ix) = *arg; gjs_arg_set(arg, &state->out_cvalue(ix)); @@ -938,60 +1126,31 @@ bool BooleanIn::in(JSContext*, GjsFunctionCallState*, GIArgument* arg, } template -GJS_JSAPI_RETURN_CONVENTION inline static bool gjs_arg_set_from_js_value( - JSContext* cx, const JS::HandleValue& value, GArgument* arg, - Argument* gjs_arg) { +GJS_JSAPI_RETURN_CONVENTION bool NumericIn::in(JSContext* cx, + GjsFunctionCallState*, + GIArgument* arg, + JS::HandleValue value) { bool out_of_range = false; if (!gjs_arg_set_from_js_value(cx, value, arg, &out_of_range)) { if (out_of_range) { gjs_throw(cx, "Argument %s: value is out of range for %s", - gjs_arg->arg_name(), Gjs::static_type_name()); + arg_name(), Gjs::static_type_name()); } return false; } - gjs_debug_marshal( - GJS_DEBUG_GFUNCTION, "%s set to value %s (type %s)", - GjsAutoChar(gjs_argument_display_name(gjs_arg->arg_name(), - GJS_ARGUMENT_ARGUMENT)) - .get(), - std::to_string(gjs_arg_get(arg)).c_str(), - Gjs::static_type_name()); + gjs_debug_marshal(GJS_DEBUG_GFUNCTION, "%s set to value %s (type %s)", + GjsAutoChar{gjs_argument_display_name( + arg_name(), GJS_ARGUMENT_ARGUMENT)} + .get(), + std::to_string(gjs_arg_get(arg)).c_str(), + Gjs::static_type_name()); return true; } -GJS_JSAPI_RETURN_CONVENTION -bool NumericIn::in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, - JS::HandleValue value) { - switch (m_tag) { - case GI_TYPE_TAG_INT8: - return gjs_arg_set_from_js_value(cx, value, arg, this); - case GI_TYPE_TAG_UINT8: - return gjs_arg_set_from_js_value(cx, value, arg, this); - case GI_TYPE_TAG_INT16: - return gjs_arg_set_from_js_value(cx, value, arg, this); - case GI_TYPE_TAG_UINT16: - return gjs_arg_set_from_js_value(cx, value, arg, this); - case GI_TYPE_TAG_INT32: - return gjs_arg_set_from_js_value(cx, value, arg, this); - case GI_TYPE_TAG_DOUBLE: - return gjs_arg_set_from_js_value(cx, value, arg, this); - case GI_TYPE_TAG_FLOAT: - return gjs_arg_set_from_js_value(cx, value, arg, this); - case GI_TYPE_TAG_INT64: - return gjs_arg_set_from_js_value(cx, value, arg, this); - case GI_TYPE_TAG_UINT64: - return gjs_arg_set_from_js_value(cx, value, arg, this); - case GI_TYPE_TAG_UINT32: - return gjs_arg_set_from_js_value(cx, value, arg, this); - default: - g_assert_not_reached(); - } -} - GJS_JSAPI_RETURN_CONVENTION bool UnicharIn::in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, JS::HandleValue value) { @@ -1025,9 +1184,10 @@ bool Nullable::handle_nullable(JSContext* cx, GIArgument* arg, return true; } -GJS_JSAPI_RETURN_CONVENTION -bool StringInTransferNone::in(JSContext* cx, GjsFunctionCallState* state, - GIArgument* arg, JS::HandleValue value) { +template +GJS_JSAPI_RETURN_CONVENTION bool StringInTransferNone::in( + JSContext* cx, GjsFunctionCallState* state, GIArgument* arg, + JS::HandleValue value) { if (value.isNull()) return NullableIn::in(cx, state, arg, value); @@ -1035,19 +1195,21 @@ bool StringInTransferNone::in(JSContext* cx, GjsFunctionCallState* state, return report_typeof_mismatch(cx, m_arg_name, value, ExpectedType::STRING); - if (m_filename) { + if constexpr (TAG == GI_TYPE_TAG_FILENAME) { GjsAutoChar str; if (!gjs_string_to_filename(cx, value, &str)) return false; gjs_arg_set(arg, str.release()); return true; + } else if constexpr (TAG == GI_TYPE_TAG_UTF8) { + JS::UniqueChars str = gjs_string_to_utf8(cx, value); + if (!str) + return false; + gjs_arg_set(arg, g_strdup(str.get())); + return true; + } else { + return invalid(cx, G_STRFUNC); } - - JS::UniqueChars str = gjs_string_to_utf8(cx, value); - if (!str) - return false; - gjs_arg_set(arg, g_strdup(str.get())); - return true; } GJS_JSAPI_RETURN_CONVENTION @@ -1091,8 +1253,7 @@ bool FlagsIn::in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, if ((uint64_t(number) & m_mask) != uint64_t(number)) { gjs_throw(cx, - "0x%" G_GINT64_MODIFIER - "x is not a valid value for flags argument %s", + "0x%" PRId64 " is not a valid value for flags argument %s", number, m_arg_name); return false; } @@ -1107,7 +1268,7 @@ bool FlagsIn::in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, GJS_JSAPI_RETURN_CONVENTION bool ForeignStructInstanceIn::in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, JS::HandleValue value) { - return gjs_struct_foreign_convert_to_g_argument( + return gjs_struct_foreign_convert_to_gi_argument( cx, value, m_info, m_arg_name, GJS_ARGUMENT_ARGUMENT, m_transfer, flags(), arg); } @@ -1340,14 +1501,20 @@ bool ParamInstanceIn::in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, GJS_JSAPI_RETURN_CONVENTION bool GenericInOut::out(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, JS::MutableHandleValue value) { - return gjs_value_from_g_argument(cx, value, &m_type_info, arg, true); + return gjs_value_from_gi_argument(cx, value, &m_type_info, arg, true); } GJS_JSAPI_RETURN_CONVENTION bool ExplicitArrayInOut::out(JSContext* cx, GjsFunctionCallState* state, GIArgument* arg, JS::MutableHandleValue value) { - GIArgument* length_arg = &(state->out_cvalue(m_length_pos)); - size_t length = gjs_g_argument_get_array_length(m_tag, length_arg); + GIArgument* length_arg; + + if (m_length_direction != GI_DIRECTION_IN) + length_arg = &(state->out_cvalue(m_length_pos)); + else + length_arg = &(state->in_cvalue(m_length_pos)); + + size_t length = gjs_gi_argument_get_array_length(m_tag, length_arg); return gjs_value_from_explicit_array(cx, value, &m_type_info, m_transfer, arg, length); @@ -1358,14 +1525,14 @@ bool GenericIn::release(JSContext* cx, GjsFunctionCallState* state, GIArgument* in_arg, GIArgument*) { GITransfer transfer = state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; - return gjs_g_argument_release_in_arg(cx, transfer, &m_type_info, in_arg); + return gjs_gi_argument_release_in_arg(cx, transfer, &m_type_info, in_arg); } GJS_JSAPI_RETURN_CONVENTION bool GenericOut::release(JSContext* cx, GjsFunctionCallState*, GIArgument* in_arg [[maybe_unused]], GIArgument* out_arg) { - return gjs_g_argument_release(cx, m_transfer, &m_type_info, out_arg); + return gjs_gi_argument_release(cx, m_transfer, &m_type_info, out_arg); } GJS_JSAPI_RETURN_CONVENTION @@ -1376,11 +1543,11 @@ bool GenericInOut::release(JSContext* cx, GjsFunctionCallState* state, // freeing it. GIArgument* original_out_arg = &state->inout_original_cvalue(m_arg_pos); - if (!gjs_g_argument_release_in_arg(cx, GI_TRANSFER_NOTHING, &m_type_info, - original_out_arg)) + if (!gjs_gi_argument_release_in_arg(cx, GI_TRANSFER_NOTHING, &m_type_info, + original_out_arg)) return false; - return gjs_g_argument_release(cx, m_transfer, &m_type_info, out_arg); + return gjs_gi_argument_release(cx, m_transfer, &m_type_info, out_arg); } GJS_JSAPI_RETURN_CONVENTION @@ -1388,10 +1555,10 @@ bool ExplicitArrayOut::release(JSContext* cx, GjsFunctionCallState* state, GIArgument* in_arg [[maybe_unused]], GIArgument* out_arg) { GIArgument* length_arg = &state->out_cvalue(m_length_pos); - size_t length = gjs_g_argument_get_array_length(m_tag, length_arg); + size_t length = gjs_gi_argument_get_array_length(m_tag, length_arg); - return gjs_g_argument_release_out_array(cx, m_transfer, &m_type_info, - length, out_arg); + return gjs_gi_argument_release_out_array(cx, m_transfer, &m_type_info, + length, out_arg); } GJS_JSAPI_RETURN_CONVENTION @@ -1399,34 +1566,42 @@ bool ExplicitArrayIn::release(JSContext* cx, GjsFunctionCallState* state, GIArgument* in_arg, GIArgument* out_arg [[maybe_unused]]) { GIArgument* length_arg = &state->in_cvalue(m_length_pos); - size_t length = gjs_g_argument_get_array_length(m_tag, length_arg); + size_t length = gjs_gi_argument_get_array_length(m_tag, length_arg); GITransfer transfer = state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; - return gjs_g_argument_release_in_array(cx, transfer, &m_type_info, length, - in_arg); + return gjs_gi_argument_release_in_array(cx, transfer, &m_type_info, length, + in_arg); } GJS_JSAPI_RETURN_CONVENTION bool ExplicitArrayInOut::release(JSContext* cx, GjsFunctionCallState* state, GIArgument* in_arg [[maybe_unused]], GIArgument* out_arg) { - GIArgument* length_arg = &state->in_cvalue(m_length_pos); - size_t length = gjs_g_argument_get_array_length(m_tag, length_arg); + GIArgument* length_arg = &state->out_cvalue(m_length_pos); + size_t length = gjs_gi_argument_get_array_length(m_tag, length_arg); // For inout, transfer refers to what we get back from the function; for // the temporary C value we allocated, clearly we're responsible for // freeing it. GIArgument* original_out_arg = &state->inout_original_cvalue(m_arg_pos); - if (gjs_arg_get(original_out_arg) != gjs_arg_get(out_arg) && - !gjs_g_argument_release_in_array(cx, GI_TRANSFER_NOTHING, &m_type_info, - length, original_out_arg)) - return false; + // Due to https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/192 + // Here we've to guess what to do, but in general is "better" to leak than + // crash, so let's assume that in/out transfer is matching. + if (gjs_arg_get(original_out_arg) != gjs_arg_get(out_arg)) { + GITransfer transfer = + state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; + if (!gjs_gi_argument_release_in_array(cx, transfer, &m_type_info, + length, original_out_arg)) + return false; + } - return gjs_g_argument_release_out_array(cx, m_transfer, &m_type_info, - length, out_arg); + GITransfer transfer = + state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; + return gjs_gi_argument_release_out_array(cx, transfer, &m_type_info, length, + out_arg); } GJS_JSAPI_RETURN_CONVENTION @@ -1459,10 +1634,10 @@ bool CallbackIn::release(JSContext*, GjsFunctionCallState*, GIArgument* in_arg, return true; } -GJS_JSAPI_RETURN_CONVENTION -bool StringInTransferNone::release(JSContext*, GjsFunctionCallState*, - GIArgument* in_arg, - GIArgument* out_arg [[maybe_unused]]) { +template +GJS_JSAPI_RETURN_CONVENTION bool StringInTransferNone::release( + JSContext*, GjsFunctionCallState*, GIArgument* in_arg, + GIArgument* out_arg [[maybe_unused]]) { g_free(gjs_arg_get(in_arg)); return true; } @@ -1475,8 +1650,8 @@ bool ForeignStructIn::release(JSContext* cx, GjsFunctionCallState* state, state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; if (transfer == GI_TRANSFER_NOTHING) - return gjs_struct_foreign_release_g_argument(cx, m_transfer, m_info, - in_arg); + return gjs_struct_foreign_release_gi_argument(cx, m_transfer, m_info, + in_arg); return true; } @@ -1534,7 +1709,7 @@ bool Argument::release(JSContext*, GjsFunctionCallState*, GIArgument*, #ifdef GJS_DO_ARGUMENTS_SIZE_CHECK template constexpr size_t argument_maximum_size() { - if constexpr (std::is_same_v) + if constexpr (std::is_same_v>) return 24; if constexpr (std::is_same_v || std::is_same_v) @@ -1582,7 +1757,7 @@ GjsAutoCppPointer Argument::make(uint8_t index, const char* name, if constexpr (std::is_base_of_v) arg->m_transfer = transfer; - if constexpr (std::is_base_of_v && + if constexpr (std::is_base_of_v && ArgKind != Arg::Kind::INSTANCE) { arg->m_type_info = std::move(*type_info); } @@ -1680,12 +1855,20 @@ GType ArgsCache::instance_type() const { return instance()->as_instance()->gtype(); } +GITypeTag ArgsCache::return_tag() const { + Argument* rval = return_value(); + if (!rval) + return GI_TYPE_TAG_VOID; + + return rval->return_tag(); +} + GITypeInfo* ArgsCache::return_type() const { Argument* rval = return_value(); if (!rval) return nullptr; - return const_cast(rval->as_return_value()->type_info()); + return const_cast(rval->return_type()); } constexpr void ArgsCache::set_skip_all(uint8_t index, const char* name) { @@ -1734,7 +1917,8 @@ void ArgsCache::set_array_argument(GICallableInfo* callable, uint8_t gi_index, static_cast(flags | GjsArgumentFlags::SKIP_ALL)); } - array->set_array_length(length_pos, g_type_info_get_tag(&length_type)); + array->set_array_length(length_pos, g_type_info_get_tag(&length_type), + g_arg_info_get_direction(&length_arg)); } void ArgsCache::build_return(GICallableInfo* callable, bool* inc_counter_out) { @@ -1753,14 +1937,89 @@ void ArgsCache::build_return(GICallableInfo* callable, bool* inc_counter_out) { *inc_counter_out = true; GjsArgumentFlags flags = GjsArgumentFlags::SKIP_IN; - if (tag == GI_TYPE_TAG_ARRAY) { - int length_pos = g_type_info_get_array_length(&type_info); - if (length_pos >= 0) { - set_array_argument( - callable, 0, &type_info, GI_DIRECTION_OUT, nullptr, flags, - length_pos); + if (g_callable_info_may_return_null(callable)) + flags |= GjsArgumentFlags::MAY_BE_NULL; + + switch (tag) { + case GI_TYPE_TAG_BOOLEAN: + set_return(&type_info, transfer, flags); + return; + + case GI_TYPE_TAG_INT8: + set_return>( + &type_info, transfer, flags); + return; + + case GI_TYPE_TAG_INT16: + set_return>( + &type_info, transfer, flags); + return; + + case GI_TYPE_TAG_INT32: + set_return>( + &type_info, transfer, flags); + return; + + case GI_TYPE_TAG_UINT8: + set_return>( + &type_info, transfer, flags); + return; + + case GI_TYPE_TAG_UINT16: + set_return>( + &type_info, transfer, flags); + return; + + case GI_TYPE_TAG_UINT32: + set_return>( + &type_info, transfer, flags); + return; + + case GI_TYPE_TAG_INT64: + set_return>( + &type_info, transfer, flags); + return; + + case GI_TYPE_TAG_UINT64: + set_return>( + &type_info, transfer, flags); + return; + + case GI_TYPE_TAG_FLOAT: + set_return>( + &type_info, transfer, flags); + return; + + case GI_TYPE_TAG_DOUBLE: + set_return>( + &type_info, transfer, flags); return; + + case GI_TYPE_TAG_UTF8: + if (transfer == GI_TRANSFER_NOTHING) { + set_return>( + &type_info, transfer, flags); + return; + } else { + set_return>( + &type_info, transfer, flags); + return; + } + + case GI_TYPE_TAG_ARRAY: { + int length_pos = g_type_info_get_array_length(&type_info); + if (length_pos >= 0) { + set_array_argument( + callable, 0, &type_info, GI_DIRECTION_OUT, nullptr, flags, + length_pos); + return; + } + + [[fallthrough]]; } + + default: + break; } // in() is ignored for the return value, but skip_in is not (it is used @@ -2020,17 +2279,44 @@ void ArgsCache::build_normal_in_arg(uint8_t gi_index, GITypeInfo* type_info, break; case GI_TYPE_TAG_INT8: + set_argument_auto>(common_args); + return; + case GI_TYPE_TAG_INT16: + set_argument_auto>(common_args); + return; + case GI_TYPE_TAG_INT32: + set_argument_auto>(common_args); + return; + case GI_TYPE_TAG_UINT8: + set_argument_auto>(common_args); + return; + case GI_TYPE_TAG_UINT16: + set_argument_auto>(common_args); + return; + case GI_TYPE_TAG_UINT32: + set_argument_auto>(common_args); + return; + case GI_TYPE_TAG_INT64: + set_argument_auto>(common_args); + return; + case GI_TYPE_TAG_UINT64: + set_argument_auto>(common_args); + return; + case GI_TYPE_TAG_FLOAT: + set_argument_auto>(common_args); + return; + case GI_TYPE_TAG_DOUBLE: - set_argument_auto(common_args, tag); - break; + set_argument_auto>(common_args); + return; case GI_TYPE_TAG_UNICHAR: set_argument_auto(common_args); @@ -2049,7 +2335,8 @@ void ArgsCache::build_normal_in_arg(uint8_t gi_index, GITypeInfo* type_info, case GI_TYPE_TAG_UTF8: if (transfer == GI_TRANSFER_NOTHING) - set_argument_auto(common_args); + set_argument_auto>( + common_args); else set_argument_auto(common_args); break; @@ -2073,6 +2360,132 @@ void ArgsCache::build_normal_in_arg(uint8_t gi_index, GITypeInfo* type_info, } } +void ArgsCache::build_normal_out_arg(uint8_t gi_index, GITypeInfo* type_info, + GIArgInfo* arg, GjsArgumentFlags flags) { + const char* name = g_base_info_get_name(arg); + GITransfer transfer = g_arg_info_get_ownership_transfer(arg); + auto common_args = + std::make_tuple(gi_index, name, type_info, transfer, flags); + GITypeTag tag = g_type_info_get_tag(type_info); + + switch (tag) { + case GI_TYPE_TAG_BOOLEAN: + set_argument_auto(common_args); + break; + + case GI_TYPE_TAG_INT8: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_INT16: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_INT32: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_UINT8: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_UINT16: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_UINT32: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_INT64: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_UINT64: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_FLOAT: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_DOUBLE: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_UTF8: + if (transfer == GI_TRANSFER_NOTHING) { + set_argument_auto>( + common_args); + } else { + set_argument_auto>( + common_args); + } + return; + + default: + set_argument_auto(common_args); + } +} + +void ArgsCache::build_normal_inout_arg(uint8_t gi_index, GITypeInfo* type_info, + GIArgInfo* arg, GjsArgumentFlags flags) { + const char* name = g_base_info_get_name(arg); + GITransfer transfer = g_arg_info_get_ownership_transfer(arg); + auto common_args = + std::make_tuple(gi_index, name, type_info, transfer, flags); + GITypeTag tag = g_type_info_get_tag(type_info); + + switch (tag) { + case GI_TYPE_TAG_BOOLEAN: + set_argument_auto(common_args); + break; + + case GI_TYPE_TAG_INT8: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_INT16: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_INT32: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_UINT8: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_UINT16: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_UINT32: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_INT64: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_UINT64: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_FLOAT: + set_argument_auto>(common_args); + return; + + case GI_TYPE_TAG_DOUBLE: + set_argument_auto>(common_args); + return; + + default: + set_argument_auto(common_args); + } +} + void ArgsCache::build_instance(GICallableInfo* callable) { if (!m_is_method) return; @@ -2107,6 +2520,11 @@ void ArgsCache::build_instance(GICallableInfo* callable) { GjsArgumentFlags::NONE); } +static constexpr bool type_tag_is_scalar(GITypeTag tag) { + return GI_TYPE_TAG_IS_NUMERIC(tag) || tag == GI_TYPE_TAG_BOOLEAN || + tag == GI_TYPE_TAG_GTYPE; +} + void ArgsCache::build_arg(uint8_t gi_index, GIDirection direction, GIArgInfo* arg, GICallableInfo* callable, bool* inc_counter_out) { @@ -2159,7 +2577,11 @@ void ArgsCache::build_arg(uint8_t gi_index, GIDirection direction, default: break; } - } else { + } else if (!type_tag_is_scalar(type_tag) && + !g_type_info_is_pointer(&type_info)) { + // Scalar out parameters should not be annotated with + // caller-allocates, which is for structured types that need to be + // allocated in order for the function to fill them in. size = gjs_type_get_element_size(type_tag, &type_info); } @@ -2254,15 +2676,31 @@ void ArgsCache::build_arg(uint8_t gi_index, GIDirection direction, } return; + } else if (g_type_info_is_zero_terminated(&type_info)) { + if (direction == GI_DIRECTION_IN) { + set_argument_auto(common_args); + return; + } else if (direction == GI_DIRECTION_INOUT) { + set_argument_auto(common_args); + return; + } + } else if (g_type_info_get_array_fixed_size(&type_info) >= 0) { + if (direction == GI_DIRECTION_IN) { + set_argument_auto(common_args); + return; + } else if (direction == GI_DIRECTION_INOUT) { + set_argument_auto(common_args); + return; + } } } if (direction == GI_DIRECTION_IN) build_normal_in_arg(gi_index, &type_info, arg, flags); else if (direction == GI_DIRECTION_INOUT) - set_argument_auto(common_args); + build_normal_inout_arg(gi_index, &type_info, arg, flags); else - set_argument_auto(common_args); + build_normal_out_arg(gi_index, &type_info, arg, flags); return; } diff --git a/gi/arg-cache.h b/gi/arg-cache.h index 14c8946f4..e16b3c1f0 100644 --- a/gi/arg-cache.h +++ b/gi/arg-cache.h @@ -94,7 +94,8 @@ struct Argument { protected: constexpr Argument() : m_skip_in(false), m_skip_out(false) {} - virtual const Arg::ReturnValue* as_return_value() const { return nullptr; } + virtual GITypeTag return_tag() const { return GI_TYPE_TAG_VOID; } + virtual const GITypeInfo* return_type() const { return nullptr; } virtual const Arg::Instance* as_instance() const { return nullptr; } constexpr void set_instance_parameter() { @@ -156,11 +157,16 @@ struct ArgsCache { void build_instance(GICallableInfo* callable); GType instance_type() const; + GITypeTag return_tag() const; GITypeInfo* return_type() const; private: void build_normal_in_arg(uint8_t gi_index, GITypeInfo*, GIArgInfo*, GjsArgumentFlags); + void build_normal_out_arg(uint8_t gi_index, GITypeInfo*, GIArgInfo*, + GjsArgumentFlags); + void build_normal_inout_arg(uint8_t gi_index, GITypeInfo*, GIArgInfo*, + GjsArgumentFlags); template void build_interface_in_arg(uint8_t gi_index, GITypeInfo*, GIBaseInfo*, diff --git a/gi/arg-inl.h b/gi/arg-inl.h index 36db51b7d..f6e6f375a 100644 --- a/gi/arg-inl.h +++ b/gi/arg-inl.h @@ -4,6 +4,8 @@ #pragma once +#include + #include #include // for nullptr_t @@ -114,6 +116,20 @@ template } } +typedef enum { + GJS_TYPE_TAG_LONG = 0, +} ExtraTag; + +template +[[nodiscard]] constexpr inline decltype(auto) gjs_arg_member(GIArgument* arg) { + if constexpr (TAG == GJS_TYPE_TAG_LONG && + std::is_same_v) // NOLINT(runtime/int) + return gjs_arg_member<&GIArgument::v_long>(arg); + else if constexpr (TAG == GJS_TYPE_TAG_LONG && + std::is_same_v) // NOLINT(runtime/int) + return gjs_arg_member<&GIArgument::v_ulong>(arg); +} + template constexpr inline void gjs_arg_set(GIArgument* arg, T v) { if constexpr (std::is_pointer_v) { @@ -129,6 +145,11 @@ constexpr inline void gjs_arg_set(GIArgument* arg, T v) { } } +template +constexpr inline void gjs_arg_set(GIArgument* arg, T v) { + gjs_arg_member(arg) = v; +} + // Store function pointers as void*. It is a requirement of GLib that your // compiler can do this template @@ -151,6 +172,11 @@ template return gjs_arg_member(arg); } +template +[[nodiscard]] constexpr inline T gjs_arg_get(GIArgument* arg) { + return gjs_arg_member(arg); +} + template [[nodiscard]] constexpr inline void* gjs_arg_get_as_pointer(GIArgument* arg) { return gjs_int_to_pointer(gjs_arg_get(arg)); @@ -192,29 +218,29 @@ gjs_arg_get_maybe_rounded(GIArgument* arg) { return static_cast(val); } -template +template GJS_JSAPI_RETURN_CONVENTION inline bool gjs_arg_set_from_js_value( - JSContext* cx, const JS::HandleValue& value, GArgument* arg, + JSContext* cx, const JS::HandleValue& value, GIArgument* arg, bool* out_of_range) { if constexpr (Gjs::type_has_js_getter()) - return Gjs::js_value_to_c(cx, value, &gjs_arg_member(arg)); + return Gjs::js_value_to_c(cx, value, &gjs_arg_member(arg)); Gjs::JsValueHolder::Relaxed val{}; - if (!Gjs::js_value_to_c_checked(cx, value, &val, out_of_range)) + if (!Gjs::js_value_to_c_checked(cx, value, &val, out_of_range)) return false; if (*out_of_range) return false; - gjs_arg_set(arg, val); + gjs_arg_set(arg, val); return true; } // A helper function to retrieve array lengths from a GIArgument (letting the // compiler generate good instructions in case of big endian machines) -[[nodiscard]] constexpr size_t gjs_g_argument_get_array_length( +[[nodiscard]] constexpr size_t gjs_gi_argument_get_array_length( GITypeTag tag, GIArgument* arg) { switch (tag) { case GI_TYPE_TAG_INT8: diff --git a/gi/arg-types-inl.h b/gi/arg-types-inl.h index ca70ba171..c3975c41c 100644 --- a/gi/arg-types-inl.h +++ b/gi/arg-types-inl.h @@ -102,4 +102,14 @@ inline const char* static_type_name() { return "string"; } +template <> +inline const char* static_type_name() { + return "constant string"; +} + +template <> +inline const char* static_type_name() { + return "void"; +} + } // namespace Gjs diff --git a/gi/arg.cpp b/gi/arg.cpp index 3fe5c015e..82a74302a 100644 --- a/gi/arg.cpp +++ b/gi/arg.cpp @@ -5,11 +5,11 @@ #include +#include #include #include // for strcmp, strlen, memcpy #include -#include #include #include @@ -32,6 +32,7 @@ #include #include #include // for InformalValueTypeName, IdVector +#include #include "gi/arg-inl.h" #include "gi/arg-types-inl.h" @@ -65,7 +66,7 @@ static void throw_invalid_argument(JSContext* cx, JS::HandleValue value, GITypeInfo* arginfo, const char* arg_name, GjsArgumentType arg_type); -bool _gjs_flags_value_is_valid(JSContext* context, GType gtype, int64_t value) { +bool _gjs_flags_value_is_valid(JSContext* cx, GType gtype, int64_t value) { /* Do proper value check for flags with GType's */ if (gtype != G_TYPE_NONE) { GjsAutoTypeClass gflags_class(gtype); @@ -73,9 +74,8 @@ bool _gjs_flags_value_is_valid(JSContext* context, GType gtype, int64_t value) { /* check all bits are valid bits for the flag and is a 32 bit flag*/ if ((tmpval &= gflags_class->mask) != value) { /* Not a guint32 with invalid mask values*/ - gjs_throw(context, - "0x%" G_GINT64_MODIFIER "x is not a valid value for flags %s", - value, g_type_name(gtype)); + gjs_throw(cx, "0x%" PRIx64 " is not a valid value for flags %s", + value, g_type_name(gtype)); return false; } } @@ -84,7 +84,7 @@ bool _gjs_flags_value_is_valid(JSContext* context, GType gtype, int64_t value) { } GJS_JSAPI_RETURN_CONVENTION -static bool _gjs_enum_value_is_valid(JSContext* context, GIEnumInfo* enum_info, +static bool _gjs_enum_value_is_valid(JSContext* cx, GIEnumInfo* enum_info, int64_t value) { bool found; int n_values; @@ -104,9 +104,8 @@ static bool _gjs_enum_value_is_valid(JSContext* context, GIEnumInfo* enum_info, } if (!found) { - gjs_throw(context, - "%" G_GINT64_MODIFIER "d is not a valid value for enumeration %s", - value, g_base_info_get_name((GIBaseInfo *)enum_info)); + gjs_throw(cx, "%" PRId64 " is not a valid value for enumeration %s", + value, g_base_info_get_name(enum_info)); } return found; @@ -163,7 +162,7 @@ static bool _gjs_enum_value_is_valid(JSContext* context, GIEnumInfo* enum_info, g_type_info_get_interface(type_info); g_assert(interface_info != nullptr); - switch (g_base_info_get_type(interface_info)) { + switch (interface_info.type()) { case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: @@ -175,9 +174,6 @@ static bool _gjs_enum_value_is_valid(JSContext* context, GIEnumInfo* enum_info, // cast is safe gtype = g_registered_type_info_get_g_type(interface_info); break; - case GI_INFO_TYPE_VALUE: - // Special case for GValues - return true; default: gtype = G_TYPE_NONE; } @@ -218,7 +214,7 @@ static bool _gjs_enum_value_is_valid(JSContext* context, GIEnumInfo* enum_info, GjsAutoBaseInfo interface_info = g_type_info_get_interface(type_info); - switch (g_base_info_get_type(interface_info)) { + switch (interface_info.type()) { case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: return false; @@ -271,7 +267,7 @@ GJS_JSAPI_RETURN_CONVENTION static bool gjs_array_to_g_list( if (transfer == GI_TRANSFER_CONTAINER) { if (type_needs_release (param_info, g_type_info_get_tag(param_info))) { /* FIXME: to make this work, we'd have to keep a list of temporary - * GArguments for the function call so we could free them after + * GIArguments for the function call so we could free them after * the surrounding container had been freed by the callee. */ gjs_throw(cx, "Container transfer for in parameters not supported"); @@ -286,8 +282,6 @@ GJS_JSAPI_RETURN_CONVENTION static bool gjs_array_to_g_list( T* list = nullptr; for (size_t i = 0; i < length; ++i) { - GArgument elem_arg = { 0 }; - elem = JS::UndefinedValue(); if (!JS_GetElement(cx, array, i, &elem)) { gjs_throw(cx, "Missing array element %zu", i); @@ -298,9 +292,10 @@ GJS_JSAPI_RETURN_CONVENTION static bool gjs_array_to_g_list( * gobject-introspection needs to tell us this. * Always say they can't for now. */ - if (!gjs_value_to_g_argument(cx, elem, param_info, - GJS_ARGUMENT_LIST_ELEMENT, transfer, - &elem_arg)) { + GIArgument elem_arg; + if (!gjs_value_to_gi_argument(cx, elem, param_info, + GJS_ARGUMENT_LIST_ELEMENT, transfer, + &elem_arg)) { return false; } @@ -327,7 +322,7 @@ GJS_JSAPI_RETURN_CONVENTION static bool gjs_array_to_g_list( GITypeTag key_type) { /* Don't use key/value destructor functions here, because we can't * construct correct ones in general if the value type is complex. - * Rely on the type-aware g_argument_release functions. */ + * Rely on the type-aware gi_argument_release functions. */ if (is_string_type(key_type)) return g_hash_table_new(g_str_hash, g_str_equal); return g_hash_table_new(NULL, NULL); @@ -492,14 +487,14 @@ static bool gjs_object_to_g_hash(JSContext* context, JS::HandleObject props, g_assert(props && "Property bag cannot be null"); - GjsAutoBaseInfo key_param_info = g_type_info_get_param_type(type_info, 0); - GjsAutoBaseInfo val_param_info = g_type_info_get_param_type(type_info, 1); + GjsAutoTypeInfo key_param_info = g_type_info_get_param_type(type_info, 0); + GjsAutoTypeInfo val_param_info = g_type_info_get_param_type(type_info, 1); if (transfer == GI_TRANSFER_CONTAINER) { if (type_needs_release (key_param_info, g_type_info_get_tag(key_param_info)) || type_needs_release (val_param_info, g_type_info_get_tag(val_param_info))) { /* FIXME: to make this work, we'd have to keep a list of temporary - * GArguments for the function call so we could free them after + * GIArguments for the function call so we could free them after * the surrounding container had been freed by the callee. */ gjs_throw(context, @@ -530,9 +525,9 @@ static bool gjs_object_to_g_hash(JSContext* context, JS::HandleObject props, !value_to_ghashtable_key(context, key_js, key_tag, &key_ptr) || !JS_GetPropertyById(context, props, cur_id, &val_js) || // Type check and convert value to a C type - !gjs_value_to_g_argument(context, val_js, val_param_info, nullptr, - GJS_ARGUMENT_HASH_ELEMENT, transfer, - GjsArgumentFlags::MAY_BE_NULL, &val_arg)) + !gjs_value_to_gi_argument(context, val_js, val_param_info, nullptr, + GJS_ARGUMENT_HASH_ELEMENT, transfer, + GjsArgumentFlags::MAY_BE_NULL, &val_arg)) return false; GITypeTag val_type = g_type_info_get_tag(val_param_info); @@ -644,7 +639,7 @@ gjs_array_from_strv(JSContext *context, return false; } - JS::RootedObject obj(context, JS::NewArrayObject(context, elems)); + JSObject* obj = JS::NewArrayObject(context, elems); if (!obj) return false; @@ -731,10 +726,9 @@ gjs_array_to_ptrarray(JSContext *context, return false; } - if (!gjs_value_to_g_argument( - context, elem, param_info, - GJS_ARGUMENT_ARRAY_ELEMENT, transfer, - &arg)) { + if (!gjs_value_to_gi_argument(context, elem, param_info, + GJS_ARGUMENT_ARRAY_ELEMENT, transfer, + &arg)) { gjs_throw(context, "Invalid element in array"); return false; @@ -767,9 +761,9 @@ static bool gjs_array_to_flat_array(JSContext* cx, JS::HandleValue array_value, } GIArgument arg; - if (!gjs_value_to_g_argument(cx, elem, param_info, - GJS_ARGUMENT_ARRAY_ELEMENT, - GI_TRANSFER_NOTHING, &arg)) + if (!gjs_value_to_gi_argument(cx, elem, param_info, + GJS_ARGUMENT_ARRAY_ELEMENT, + GI_TRANSFER_NOTHING, &arg)) return false; memcpy(&flat_array[param_size * i], gjs_arg_get(&arg), @@ -780,11 +774,8 @@ static bool gjs_array_to_flat_array(JSContext* cx, JS::HandleValue array_value, return true; } -[[nodiscard]] static bool is_gvalue(GIBaseInfo* info, GIInfoType info_type) { - switch (info_type) { - case GI_INFO_TYPE_VALUE: - return true; - +[[nodiscard]] static bool is_gvalue(GIBaseInfo* info) { + switch (g_base_info_get_type(info)) { case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_OBJECT: case GI_INFO_TYPE_INTERFACE: @@ -852,9 +843,7 @@ static bool gjs_array_to_array(JSContext* context, JS::HandleValue array_value, if (!g_type_info_is_pointer(param_info)) { GjsAutoBaseInfo interface_info = g_type_info_get_interface(param_info); - GIInfoType info_type = g_base_info_get_type(interface_info); - - if (is_gvalue(interface_info, info_type)) { + if (is_gvalue(interface_info)) { // Special case for GValue "flat arrays", this could also // using the generic case, but if we do so we're leaking atm. return gjs_array_to_auto_array(context, array_value, @@ -935,7 +924,7 @@ size_t gjs_type_get_element_size(GITypeTag element_type, case GI_TYPE_TAG_INTERFACE: { GjsAutoBaseInfo interface_info = g_type_info_get_interface(type_info); - switch (g_base_info_get_type(interface_info)) { + switch (interface_info.type()) { case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: return sizeof(unsigned int); @@ -944,8 +933,6 @@ size_t gjs_type_get_element_size(GITypeTag element_type, return g_struct_info_get_size(interface_info); case GI_INFO_TYPE_UNION: return g_union_info_get_size(interface_info); - case GI_INFO_TYPE_VALUE: - return sizeof(GValue); default: return 0; } @@ -960,14 +947,10 @@ size_t gjs_type_get_element_size(GITypeTag element_type, if (length < 0) return sizeof(void*); - GjsAutoBaseInfo param_info = + GjsAutoTypeInfo param_info = g_type_info_get_param_type(type_info, 0); GITypeTag param_tag = g_type_info_get_tag(param_info); - size_t param_size = - gjs_type_get_element_size(param_tag, param_info); - - if (param_size) - return param_size * length; + return gjs_type_get_element_size(param_tag, param_info); } return sizeof(void*); @@ -979,22 +962,27 @@ size_t gjs_type_get_element_size(GITypeTag element_type, g_return_val_if_reached(0); } -template -static inline bool gjs_g_argument_release_array_internal( +enum class ArrayReleaseType { + EXPLICIT_LENGTH, + ZERO_TERMINATED, +}; + +template +static inline bool gjs_gi_argument_release_array_internal( JSContext* cx, GITransfer element_transfer, GjsArgumentFlags flags, GITypeInfo* param_type, unsigned length, GIArgument* arg) { GjsAutoPointer arg_array = gjs_arg_steal(arg); + if (!arg_array) + return true; + if (element_transfer != GI_TRANSFER_EVERYTHING) return true; - if constexpr (!zero_terminated) { + if constexpr (release_type == ArrayReleaseType::EXPLICIT_LENGTH) { if (length == 0) return true; - } else { - if (!arg_array) - return true; } GITypeTag type_tag = g_type_info_get_tag(param_type); @@ -1015,16 +1003,21 @@ static inline bool gjs_g_argument_release_array_internal( for (size_t i = 0;; i++) { GIArgument elem; auto* element_start = &arg_array[i * element_size]; + auto* pointer = + is_pointer ? *reinterpret_cast(element_start) : nullptr; - if constexpr (zero_terminated) { - if (*element_start == 0 && - memcmp(element_start, element_start + 1, element_size - 1) == 0) + if constexpr (release_type == ArrayReleaseType::ZERO_TERMINATED) { + if (is_pointer) { + if (!pointer) + break; + } else if (*element_start == 0 && + memcmp(element_start, element_start + 1, + element_size - 1) == 0) { break; + } } - gjs_arg_set(&elem, is_pointer - ? *reinterpret_cast(element_start) - : element_start); + gjs_arg_set(&elem, is_pointer ? pointer : element_start); JS::AutoSaveExceptionState saved_exc(cx); if (!gjs_g_arg_release_internal(cx, element_transfer, param_type, type_tag, GJS_ARGUMENT_ARRAY_ELEMENT, @@ -1032,7 +1025,7 @@ static inline bool gjs_g_argument_release_array_internal( return false; } - if constexpr (!zero_terminated) { + if constexpr (release_type == ArrayReleaseType::EXPLICIT_LENGTH) { if (i == length - 1) break; } @@ -1076,7 +1069,7 @@ char* gjs_argument_display_name(const char* arg_name, if (tag == GI_TYPE_TAG_INTERFACE) { GjsAutoBaseInfo interface = g_type_info_get_interface(type_info); - return g_info_type_to_string(g_base_info_get_type(interface)); + return g_info_type_to_string(interface.type()); } else { return g_type_tag_to_string(tag); } @@ -1173,10 +1166,7 @@ namespace arg { } } // namespace arg -static void -intern_gdk_atom(const char *name, - GArgument *ret) -{ +static void intern_gdk_atom(const char* name, GIArgument* ret) { GjsAutoFunctionInfo atom_intern_fun = g_irepository_find_by_name(nullptr, "Gdk", "atom_intern"); @@ -1187,11 +1177,8 @@ intern_gdk_atom(const char *name, gjs_arg_set(&atom_intern_args[0], name); gjs_arg_set(&atom_intern_args[1], false); - g_function_info_invoke(atom_intern_fun, - atom_intern_args, 2, - nullptr, 0, - ret, - nullptr); + mozilla::Unused << g_function_info_invoke(atom_intern_fun, atom_intern_args, + 2, nullptr, 0, ret, nullptr); } static bool value_to_interface_gi_argument( @@ -1215,11 +1202,6 @@ static bool value_to_interface_gi_argument( gtype = g_registered_type_info_get_g_type(interface_info); break; - case GI_INFO_TYPE_VALUE: - // Special case for GValues - gtype = G_TYPE_VALUE; - break; - default: gtype = G_TYPE_NONE; } @@ -1358,11 +1340,18 @@ static bool value_to_interface_gi_argument( } else if (g_type_is_a(gtype, G_TYPE_BOXED)) { if (g_type_is_a(gtype, G_TYPE_CLOSURE)) { + if (BoxedBase::typecheck(cx, obj, interface_info, gtype, + GjsTypecheckNoThrow())) { + return BoxedBase::transfer_to_gi_argument( + cx, obj, arg, GI_DIRECTION_IN, transfer, gtype, + interface_info); + } + GClosure* closure = Gjs::Closure::create_marshaled(cx, obj, "boxed"); // GI doesn't know about floating GClosure references. We // guess that if this is a return value going from JS::Value - // to GArgument, it's intended to be passed to a C API that + // to GIArgument, it's intended to be passed to a C API that // will consume the floating reference. if (arg_type != GJS_ARGUMENT_RETURN_VALUE) { g_closure_ref(closure); @@ -1458,7 +1447,7 @@ static bool value_to_interface_gi_argument( template GJS_JSAPI_RETURN_CONVENTION inline static bool gjs_arg_set_from_js_value( - JSContext* cx, const JS::HandleValue& value, GArgument* arg, + JSContext* cx, const JS::HandleValue& value, GIArgument* arg, const char* arg_name, GjsArgumentType arg_type) { bool out_of_range = false; @@ -1498,10 +1487,10 @@ static bool check_nullable_argument(JSContext* cx, const char* arg_name, return true; } -bool gjs_value_to_g_argument(JSContext* context, JS::HandleValue value, - GITypeInfo* type_info, const char* arg_name, - GjsArgumentType arg_type, GITransfer transfer, - GjsArgumentFlags flags, GIArgument* arg) { +bool gjs_value_to_gi_argument(JSContext* context, JS::HandleValue value, + GITypeInfo* type_info, const char* arg_name, + GjsArgumentType arg_type, GITransfer transfer, + GjsArgumentFlags flags, GIArgument* arg) { GITypeTag type_tag = g_type_info_get_tag(type_info); gjs_debug_marshal( @@ -1648,7 +1637,7 @@ bool gjs_value_to_g_argument(JSContext* context, JS::HandleValue value, GjsAutoBaseInfo interface_info = g_type_info_get_interface(type_info); g_assert(interface_info); - GIInfoType interface_type = g_base_info_get_type(interface_info); + GIInfoType interface_type = interface_info.type(); if (interface_type == GI_INFO_TYPE_ENUM || interface_type == GI_INFO_TYPE_FLAGS || arg::is_gdk_atom(interface_info)) @@ -1656,7 +1645,7 @@ bool gjs_value_to_g_argument(JSContext* context, JS::HandleValue value, if (interface_type == GI_INFO_TYPE_STRUCT && g_struct_info_is_foreign(interface_info)) { - return gjs_struct_foreign_convert_to_g_argument( + return gjs_struct_foreign_convert_to_gi_argument( context, value, interface_info, arg_name, arg_type, transfer, flags, arg); } @@ -1765,7 +1754,7 @@ bool gjs_value_to_g_argument(JSContext* context, JS::HandleValue value, break; } default: - g_warning("Unhandled type %s for JavaScript to GArgument conversion", + g_warning("Unhandled type %s for JavaScript to GIArgument conversion", g_type_tag_to_string(type_tag)); throw_invalid_argument(context, value, type_info, arg_name, arg_type); return false; @@ -1779,13 +1768,11 @@ bool gjs_value_to_g_argument(JSContext* context, JS::HandleValue value, * is. It basically boils down to memset(arg, 0, sizeof(*arg)), but * gives as a bit more future flexibility and also will work if * libffi passes us a buffer that only has room for the appropriate - * branch of GArgument. (Currently it appears that the return buffer + * branch of GIArgument. (Currently it appears that the return buffer * has a fixed size large enough for the union of all types.) */ void gjs_gi_argument_init_default(GITypeInfo* type_info, GIArgument* arg) { - GITypeTag type_tag; - - type_tag = g_type_info_get_tag( (GITypeInfo*) type_info); + GITypeTag type_tag = g_type_info_get_tag(type_info); switch (type_tag) { case GI_TYPE_TAG_VOID: @@ -1839,13 +1826,11 @@ void gjs_gi_argument_init_default(GITypeInfo* type_info, GIArgument* arg) { gjs_arg_unset(arg); break; case GI_TYPE_TAG_INTERFACE: { - GIInfoType interface_type; - GjsAutoBaseInfo interface_info = g_type_info_get_interface(type_info); g_assert(interface_info != nullptr); - interface_type = g_base_info_get_type(interface_info); + GIInfoType interface_type = interface_info.type(); if (interface_type == GI_INFO_TYPE_ENUM || interface_type == GI_INFO_TYPE_FLAGS) @@ -1861,7 +1846,7 @@ void gjs_gi_argument_init_default(GITypeInfo* type_info, GIArgument* arg) { gjs_arg_unset(arg); break; default: - g_warning("Unhandled type %s for default GArgument initialization", + g_warning("Unhandled type %s for default GIArgument initialization", g_type_tag_to_string(type_tag)); break; } @@ -1897,7 +1882,7 @@ bool gjs_value_to_callback_out_arg(JSContext* context, JS::HandleValue value, if (g_arg_info_is_caller_allocates(arg_info)) flags |= GjsArgumentFlags::CALLER_ALLOCATES; - return gjs_value_to_g_argument( + return gjs_value_to_gi_argument( context, value, &type_info, g_base_info_get_name(arg_info), (g_arg_info_is_return_value(arg_info) ? GJS_ARGUMENT_RETURN_VALUE : GJS_ARGUMENT_ARGUMENT), @@ -1909,12 +1894,12 @@ GJS_JSAPI_RETURN_CONVENTION static bool gjs_array_from_g_list( JSContext* cx, JS::MutableHandleValue value_p, GITypeInfo* type_info, GITransfer transfer, T* list) { static_assert(std::is_same_v || std::is_same_v); - GArgument arg; JS::RootedValueVector elems(cx); GjsAutoTypeInfo param_info = g_type_info_get_param_type(type_info, 0); g_assert(param_info); + GIArgument arg; for (size_t i = 0; list; list = list->next, ++i) { g_type_info_argument_from_hash_pointer(param_info, list->data, &arg); @@ -1923,13 +1908,13 @@ GJS_JSAPI_RETURN_CONVENTION static bool gjs_array_from_g_list( return false; } - if (!gjs_value_from_g_argument(cx, elems[i], param_info, - GJS_ARGUMENT_LIST_ELEMENT, transfer, - &arg)) + if (!gjs_value_from_gi_argument(cx, elems[i], param_info, + GJS_ARGUMENT_LIST_ELEMENT, transfer, + &arg)) return false; } - JS::RootedObject obj(cx, JS::NewArrayObject(cx, elems)); + JSObject* obj = JS::NewArrayObject(cx, elems); if (!obj) return false; @@ -1974,9 +1959,9 @@ GJS_JSAPI_RETURN_CONVENTION static bool fill_vector_from_carray( for (size_t i = 0; i < length; i++) { gjs_arg_set(arg, *(static_cast(array) + i)); - if (!gjs_value_from_g_argument(cx, elems[i], param_info, - GJS_ARGUMENT_ARRAY_ELEMENT, - transfer, arg)) + if (!gjs_value_from_gi_argument(cx, elems[i], param_info, + GJS_ARGUMENT_ARRAY_ELEMENT, transfer, + arg)) return false; } @@ -1987,7 +1972,6 @@ GJS_JSAPI_RETURN_CONVENTION static bool gjs_array_from_carray_internal( JSContext* context, JS::MutableHandleValue value_p, GIArrayType array_type, GITypeInfo* param_info, GITransfer transfer, guint length, void* array) { - GArgument arg; GITypeTag element_type; guint i; @@ -1995,7 +1979,7 @@ static bool gjs_array_from_carray_internal( /* Special case array(guint8) */ if (element_type == GI_TYPE_TAG_UINT8) { - JSObject* obj = gjs_byte_array_from_data(context, length, array); + JSObject* obj = gjs_byte_array_from_data_copy(context, length, array); if (!obj) return false; value_p.setObject(*obj); @@ -2021,6 +2005,7 @@ static bool gjs_array_from_carray_internal( return false; } + GIArgument arg; switch (element_type) { /* Special cases handled above */ case GI_TYPE_TAG_UINT8: @@ -2079,12 +2064,11 @@ static bool gjs_array_from_carray_internal( case GI_TYPE_TAG_INTERFACE: { GjsAutoBaseInfo interface_info = g_type_info_get_interface(param_info); - GIInfoType info_type = g_base_info_get_type (interface_info); + GIInfoType info_type = interface_info.type(); if (array_type != GI_ARRAY_TYPE_PTR_ARRAY && (info_type == GI_INFO_TYPE_STRUCT || - info_type == GI_INFO_TYPE_UNION || - info_type == GI_INFO_TYPE_VALUE) && + info_type == GI_INFO_TYPE_UNION) && !g_type_info_is_pointer(param_info)) { size_t struct_size; @@ -2097,7 +2081,7 @@ static bool gjs_array_from_carray_internal( gjs_arg_set(&arg, static_cast(array) + (struct_size * i)); - if (!gjs_value_from_g_argument( + if (!gjs_value_from_gi_argument( context, elems[i], param_info, GJS_ARGUMENT_ARRAY_ELEMENT, transfer, &arg)) return false; @@ -2125,7 +2109,7 @@ static bool gjs_array_from_carray_internal( return false; } - JS::RootedObject obj(context, JS::NewArrayObject(context, elems)); + JSObject* obj = JS::NewArrayObject(context, elems); if (!obj) return false; @@ -2168,7 +2152,7 @@ static bool gjs_array_from_boxed_array(JSContext* context, JS::MutableHandleValue value_p, GIArrayType array_type, GITypeInfo* param_info, - GITransfer transfer, GArgument* arg) { + GITransfer transfer, GIArgument* arg) { GArray *array; GPtrArray *ptr_array; gpointer data = NULL; @@ -2192,7 +2176,7 @@ static bool gjs_array_from_boxed_array(JSContext* context, data = ptr_array->pdata; length = ptr_array->len; break; - case GI_ARRAY_TYPE_C: /* already checked in gjs_value_from_g_argument() */ + case GI_ARRAY_TYPE_C: // already checked in gjs_value_from_gi_argument() default: g_assert_not_reached(); } @@ -2227,6 +2211,8 @@ bool gjs_array_from_g_value_array(JSContext* cx, JS::MutableHandleValue value_p, length = ptr_array->len; } else { g_assert_not_reached(); + gjs_throw(cx, "%s is not an array type", g_type_name(value_gtype)); + return false; } return gjs_array_from_carray_internal(cx, value_p, array_type, param_info, @@ -2261,9 +2247,9 @@ GJS_JSAPI_RETURN_CONVENTION static bool fill_vector_from_zero_terminated_carray( return false; } - if (!gjs_value_from_g_argument(cx, elems[i], param_info, - GJS_ARGUMENT_ARRAY_ELEMENT, transfer, - arg)) + if (!gjs_value_from_gi_argument(cx, elems[i], param_info, + GJS_ARGUMENT_ARRAY_ELEMENT, transfer, + arg)) return false; } @@ -2274,7 +2260,6 @@ GJS_JSAPI_RETURN_CONVENTION static bool gjs_array_from_zero_terminated_c_array( JSContext* context, JS::MutableHandleValue value_p, GITypeInfo* param_info, GITransfer transfer, void* c_array) { - GArgument arg; GITypeTag element_type; element_type = g_type_info_get_tag(param_info); @@ -2282,7 +2267,7 @@ static bool gjs_array_from_zero_terminated_c_array( /* Special case array(guint8) */ if (element_type == GI_TYPE_TAG_UINT8) { size_t len = strlen(static_cast(c_array)); - JSObject* obj = gjs_byte_array_from_data(context, len, c_array); + JSObject* obj = gjs_byte_array_from_data_copy(context, len, c_array); if (!obj) return false; value_p.setObject(*obj); @@ -2295,6 +2280,7 @@ static bool gjs_array_from_zero_terminated_c_array( JS::RootedValueVector elems(context); + GIArgument arg; switch (element_type) { /* Special cases handled above. */ case GI_TYPE_TAG_UINT8: @@ -2350,14 +2336,21 @@ static bool gjs_array_from_zero_terminated_c_array( g_type_info_get_interface(param_info); if (!g_type_info_is_pointer(param_info) && - is_gvalue(interface_info, - g_base_info_get_type(interface_info))) { + is_gvalue(interface_info)) { if (!fill_vector_from_zero_terminated_carray( context, elems, param_info, &arg, c_array)) return false; break; } + if (!g_type_info_is_pointer(param_info)) { + gjs_throw(context, + "Flat C array of %s.%s not supported (see " + "https://gitlab.gnome.org/GNOME/cjs/-/issues/603)", + interface_info.ns(), interface_info.name()); + return false; + } + [[fallthrough]]; } case GI_TYPE_TAG_GTYPE: @@ -2383,7 +2376,7 @@ static bool gjs_array_from_zero_terminated_c_array( return false; } - JS::RootedObject obj(context, JS::NewArrayObject(context, elems)); + JSObject* obj = JS::NewArrayObject(context, elems); if (!obj) return false; @@ -2397,7 +2390,6 @@ bool gjs_object_from_g_hash(JSContext* context, JS::MutableHandleValue value_p, GITypeInfo* val_param_info, GITransfer transfer, GHashTable* hash) { GHashTableIter iter; - GArgument keyarg, valarg; // a NULL hash table becomes a null JS value if (hash==NULL) { @@ -2417,13 +2409,14 @@ bool gjs_object_from_g_hash(JSContext* context, JS::MutableHandleValue value_p, g_hash_table_iter_init(&iter, hash); void* key_pointer; void* val_pointer; + GIArgument keyarg, valarg; while (g_hash_table_iter_next(&iter, &key_pointer, &val_pointer)) { g_type_info_argument_from_hash_pointer(key_param_info, key_pointer, &keyarg); - if (!gjs_value_from_g_argument(context, &keyjs, key_param_info, - GJS_ARGUMENT_HASH_ELEMENT, - transfer, &keyarg)) - return false; + if (!gjs_value_from_gi_argument(context, &keyjs, key_param_info, + GJS_ARGUMENT_HASH_ELEMENT, transfer, + &keyarg)) + return false; keystr = JS::ToString(context, keyjs); if (!keystr) @@ -2435,9 +2428,9 @@ bool gjs_object_from_g_hash(JSContext* context, JS::MutableHandleValue value_p, g_type_info_argument_from_hash_pointer(val_param_info, val_pointer, &valarg); - if (!gjs_value_from_g_argument(context, &valjs, val_param_info, - GJS_ARGUMENT_HASH_ELEMENT, - transfer, &valarg)) + if (!gjs_value_from_gi_argument(context, &valjs, val_param_info, + GJS_ARGUMENT_HASH_ELEMENT, transfer, + &valarg)) return false; if (!JS_DefineProperty(context, obj, keyutf8.get(), valjs, @@ -2448,21 +2441,17 @@ bool gjs_object_from_g_hash(JSContext* context, JS::MutableHandleValue value_p, return true; } -bool gjs_value_from_g_argument(JSContext* context, - JS::MutableHandleValue value_p, - GITypeInfo* type_info, - GjsArgumentType argument_type, - GITransfer transfer, GArgument* arg) { - GITypeTag type_tag; - - type_tag = g_type_info_get_tag( (GITypeInfo*) type_info); +bool gjs_value_from_gi_argument(JSContext* context, + JS::MutableHandleValue value_p, + GITypeInfo* type_info, + GjsArgumentType argument_type, + GITransfer transfer, GIArgument* arg) { + GITypeTag type_tag = g_type_info_get_tag(type_info); gjs_debug_marshal(GJS_DEBUG_GFUNCTION, - "Converting GArgument %s to JS::Value", + "Converting GIArgument %s to JS::Value", g_type_tag_to_string(type_tag)); - value_p.setNull(); - switch (type_tag) { case GI_TYPE_TAG_VOID: // If the argument is a pointer, convert to null to match our @@ -2510,20 +2499,22 @@ bool gjs_value_from_g_argument(JSContext* context, break; case GI_TYPE_TAG_FLOAT: - value_p.setNumber(gjs_arg_get(arg)); + value_p.setNumber(JS::CanonicalizeNaN(gjs_arg_get(arg))); break; case GI_TYPE_TAG_DOUBLE: - value_p.setNumber(gjs_arg_get(arg)); + value_p.setNumber(JS::CanonicalizeNaN(gjs_arg_get(arg))); break; case GI_TYPE_TAG_GTYPE: { GType gtype = gjs_arg_get(arg); - if (gtype == 0) - return true; /* value_p is set to JS null */ + if (gtype == 0) { + value_p.setNull(); + return true; + } - JS::RootedObject obj(context, gjs_gtype_create_gtype_wrapper(context, gtype)); + JSObject* obj = gjs_gtype_create_gtype_wrapper(context, gtype); if (!obj) return false; @@ -2553,10 +2544,10 @@ bool gjs_value_from_g_argument(JSContext* context, case GI_TYPE_TAG_FILENAME: case GI_TYPE_TAG_UTF8: { const char* str = gjs_arg_get(arg); - // For nullptr we'll return JS::NullValue(), which is already set - // in *value_p - if (!str) + if (!str) { + value_p.setNull(); return true; + } if (type_tag == GI_TYPE_TAG_FILENAME) return gjs_string_from_filename(context, str, -1, value_p); @@ -2566,8 +2557,10 @@ bool gjs_value_from_g_argument(JSContext* context, case GI_TYPE_TAG_ERROR: { GError* ptr = gjs_arg_get(arg); - if (!ptr) + if (!ptr) { + value_p.setNull(); return true; + } JSObject* obj = ErrorInstance::object_for_c_ptr(context, ptr); if (!obj) @@ -2579,14 +2572,11 @@ bool gjs_value_from_g_argument(JSContext* context, case GI_TYPE_TAG_INTERFACE: { - GIInfoType interface_type; - GType gtype; - GjsAutoBaseInfo interface_info = g_type_info_get_interface(type_info); g_assert(interface_info); - interface_type = g_base_info_get_type(interface_info); + GIInfoType interface_type = interface_info.type(); if (interface_type == GI_INFO_TYPE_UNRESOLVED) { gjs_throw(context, @@ -2614,14 +2604,17 @@ bool gjs_value_from_g_argument(JSContext* context, interface_info, gjs_arg_get(arg)); - gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*)interface_info); + GType gtype = g_registered_type_info_get_g_type( + interface_info.as()); if (gtype != G_TYPE_NONE) { /* check make sure 32 bit flag */ - if (static_cast(value_int64) != value_int64) { /* Not a guint32 */ + if (static_cast(value_int64) != value_int64) { + // Not a 32-bit integer gjs_throw(context, - "0x%" G_GINT64_MODIFIER "x is not a valid value for flags %s", - value_int64, g_type_name(gtype)); + "0x%" PRIx64 + " is not a valid value for flags %s", + value_int64, g_type_name(gtype)); return false; } @@ -2635,8 +2628,8 @@ bool gjs_value_from_g_argument(JSContext* context, } if (interface_type == GI_INFO_TYPE_STRUCT && - g_struct_info_is_foreign((GIStructInfo*)interface_info)) { - return gjs_struct_foreign_convert_from_g_argument( + g_struct_info_is_foreign(interface_info.as())) { + return gjs_struct_foreign_convert_from_gi_argument( context, value_p, interface_info, arg); } @@ -2647,12 +2640,13 @@ bool gjs_value_from_g_argument(JSContext* context, } if (interface_type == GI_INFO_TYPE_STRUCT && - g_struct_info_is_gtype_struct((GIStructInfo*)interface_info)) { + g_struct_info_is_gtype_struct( + interface_info.as())) { /* XXX: here we make the implicit assumption that GTypeClass is the same as GTypeInterface. This is true for the GType field, which is what we use, but not for the rest of the structure! */ - gtype = G_TYPE_FROM_CLASS(gjs_arg_get(arg)); + GType gtype = G_TYPE_FROM_CLASS(gjs_arg_get(arg)); if (g_type_is_a(gtype, G_TYPE_INTERFACE)) { return gjs_lookup_interface_constructor(context, gtype, @@ -2661,7 +2655,8 @@ bool gjs_value_from_g_argument(JSContext* context, return gjs_lookup_object_constructor(context, gtype, value_p); } - gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*)interface_info); + GType gtype = g_registered_type_info_get_g_type( + interface_info.as()); if (G_TYPE_IS_INSTANTIATABLE(gtype) || G_TYPE_IS_INTERFACE(gtype)) gtype = G_TYPE_FROM_INSTANCE(gjs_arg_get(arg)); @@ -2691,11 +2686,14 @@ bool gjs_value_from_g_argument(JSContext* context, g_struct_info_find_method(interface_info, "name"); GIArgument atom_name_ret; - g_function_info_invoke(atom_name_fun, - arg, 1, - nullptr, 0, - &atom_name_ret, - nullptr); + GjsAutoError error = nullptr; + if (!g_function_info_invoke(atom_name_fun, arg, 1, nullptr, + 0, &atom_name_ret, + error.out())) { + gjs_throw(context, "Failed to call gdk_atom_name(): %s", + error->message); + return false; + } GjsAutoChar name = gjs_arg_get(&atom_name_ret); if (g_strcmp0("NONE", name) == 0) { @@ -2738,7 +2736,7 @@ bool gjs_value_from_g_argument(JSContext* context, if (interface_type == GI_INFO_TYPE_UNION) { JSObject* obj = UnionInstance::new_for_c_union( - context, static_cast(interface_info), + context, interface_info.as(), gjs_arg_get(arg)); if (!obj) return false; @@ -2775,7 +2773,9 @@ bool gjs_value_from_g_argument(JSContext* context, } if (gtype == G_TYPE_NONE) { - gjs_throw(context, "Unexpected unregistered type packing GArgument into JS::Value"); + gjs_throw(context, + "Unexpected unregistered type packing GIArgument " + "into JS::Value"); return false; } @@ -2789,17 +2789,20 @@ bool gjs_value_from_g_argument(JSContext* context, } gjs_throw(context, - "Unhandled GType %s packing GArgument into JS::Value", + "Unhandled GType %s packing GIArgument into JS::Value", g_type_name(gtype)); return false; } case GI_TYPE_TAG_ARRAY: if (!gjs_arg_get(arg)) { - /* OK, but no conversion to do */ - } else if (g_type_info_get_array_type(type_info) == GI_ARRAY_TYPE_C) { + value_p.setNull(); + return true; + } + + if (g_type_info_get_array_type(type_info) == GI_ARRAY_TYPE_C) { if (g_type_info_is_zero_terminated(type_info)) { - GjsAutoBaseInfo param_info = + GjsAutoTypeInfo param_info = g_type_info_get_param_type(type_info, 0); g_assert(param_info != nullptr); @@ -2861,7 +2864,7 @@ bool gjs_value_from_g_argument(JSContext* context, break; default: - g_warning("Unhandled type %s converting GArgument to JavaScript", + g_warning("Unhandled type %s converting GIArgument to JavaScript", g_type_tag_to_string(type_tag)); return false; } @@ -2880,14 +2883,14 @@ struct GHR_closure { static gboolean gjs_ghr_helper(gpointer key, gpointer val, gpointer user_data) { GHR_closure *c = (GHR_closure *) user_data; - GArgument key_arg, val_arg; + GIArgument key_arg, val_arg; gjs_arg_set(&key_arg, key); gjs_arg_set(&val_arg, val); if (!gjs_g_arg_release_internal(c->context, c->transfer, c->key_param_info, g_type_info_get_tag(c->key_param_info), GJS_ARGUMENT_HASH_ELEMENT, c->flags, &key_arg)) - c->failed = true; + c->failed = true; GITypeTag val_type = g_type_info_get_tag(c->val_param_info); @@ -2955,19 +2958,16 @@ static bool gjs_g_arg_release_internal( case GI_TYPE_TAG_INTERFACE: { - GIInfoType interface_type; - GType gtype; - GjsAutoBaseInfo interface_info = g_type_info_get_interface(type_info); g_assert(interface_info); - interface_type = g_base_info_get_type(interface_info); + GIInfoType interface_type = interface_info.type(); if (interface_type == GI_INFO_TYPE_STRUCT && - g_struct_info_is_foreign((GIStructInfo*)interface_info)) - return gjs_struct_foreign_release_g_argument(context, - transfer, interface_info, arg); + g_struct_info_is_foreign(interface_info.as())) + return gjs_struct_foreign_release_gi_argument( + context, transfer, interface_info, arg); if (interface_type == GI_INFO_TYPE_ENUM || interface_type == GI_INFO_TYPE_FLAGS) return true; @@ -2976,7 +2976,8 @@ static bool gjs_g_arg_release_internal( if (!gjs_arg_get(arg)) return true; - gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*)interface_info); + GType gtype = g_registered_type_info_get_g_type( + interface_info.as()); if (G_TYPE_IS_INSTANTIATABLE(gtype) || G_TYPE_IS_INTERFACE(gtype)) gtype = G_TYPE_FROM_INSTANCE(gjs_arg_get(arg)); @@ -2984,11 +2985,10 @@ static bool gjs_g_arg_release_internal( gjs_debug_marshal(GJS_DEBUG_GFUNCTION, "gtype of INTERFACE is %s", g_type_name(gtype)); - /* In gjs_value_from_g_argument we handle Struct/Union types without a - * registered GType, but here we are specifically handling a GArgument that - * *owns* its value, and that is non-sensical for such types, so we - * don't have to worry about it. - */ + // In gjs_value_from_gi_argument we handle Struct/Union types + // without a registered GType, but here we are specifically handling + // a GIArgument that *owns* its value, and that is nonsensical for + // such types, so we don't have to worry about it. if (g_type_is_a(gtype, G_TYPE_OBJECT)) { if (!is_transfer_in_nothing(transfer, flags)) @@ -3016,7 +3016,9 @@ static bool gjs_g_arg_release_internal( g_variant_unref); } else if (gtype == G_TYPE_NONE) { if (!is_transfer_in_nothing(transfer, flags)) { - gjs_throw(context, "Don't know how to release GArgument: not an object or boxed type"); + gjs_throw(context, + "Don't know how to release GIArgument: not an " + "object or boxed type"); return false; } } else if (G_TYPE_IS_INSTANTIATABLE(gtype)) { @@ -3026,7 +3028,7 @@ static bool gjs_g_arg_release_internal( priv->call_unref_function(gjs_arg_steal(arg)); } } else { - gjs_throw(context, "Unhandled GType %s releasing GArgument", + gjs_throw(context, "Unhandled GType %s releasing GIArgument", g_type_name(gtype)); return false; } @@ -3077,7 +3079,7 @@ static bool gjs_g_arg_release_internal( if (!g_type_info_is_pointer(param_info)) { GjsAutoBaseInfo interface_info = g_type_info_get_interface(param_info); - GIInfoType info_type = g_base_info_get_type(interface_info); + GIInfoType info_type = interface_info.type(); if (info_type == GI_INFO_TYPE_STRUCT || info_type == GI_INFO_TYPE_UNION) { g_clear_pointer(&gjs_arg_member(arg), g_free); @@ -3097,11 +3099,13 @@ static bool gjs_g_arg_release_internal( element_transfer = GI_TRANSFER_NOTHING; if (g_type_info_is_zero_terminated(type_info)) { - return gjs_g_argument_release_array_internal( + return gjs_gi_argument_release_array_internal< + ArrayReleaseType::ZERO_TERMINATED>( context, element_transfer, flags | GjsArgumentFlags::ARG_OUT, param_info, 0, arg); } else { - return gjs_g_argument_release_array_internal( + return gjs_gi_argument_release_array_internal< + ArrayReleaseType::EXPLICIT_LENGTH>( context, element_transfer, flags | GjsArgumentFlags::ARG_OUT, param_info, g_type_info_get_array_fixed_size(type_info), arg); @@ -3155,7 +3159,7 @@ static bool gjs_g_arg_release_internal( guint i; for (i = 0; i < array->len; i++) { - GArgument arg_iter; + GIArgument arg_iter; gjs_arg_set(&arg_iter, g_array_index(array, gpointer, i)); @@ -3190,11 +3194,11 @@ static bool gjs_g_arg_release_internal( guint i; for (i = 0; i < array->len; i++) { - GArgument arg_iter; + GIArgument arg_iter; gjs_arg_set(&arg_iter, g_ptr_array_index(array, i)); - if (!gjs_g_argument_release(context, transfer, param_info, - flags, &arg_iter)) + if (!gjs_gi_argument_release(context, transfer, param_info, + flags, &arg_iter)) return false; } } @@ -3236,7 +3240,7 @@ static bool gjs_g_arg_release_internal( break; default: - g_warning("Unhandled type %s releasing GArgument", + g_warning("Unhandled type %s releasing GIArgument", g_type_tag_to_string(type_tag)); return false; } @@ -3244,30 +3248,26 @@ static bool gjs_g_arg_release_internal( return true; } -bool gjs_g_argument_release(JSContext* cx, GITransfer transfer, - GITypeInfo* type_info, GjsArgumentFlags flags, - GIArgument* arg) { - GITypeTag type_tag; - +bool gjs_gi_argument_release(JSContext* cx, GITransfer transfer, + GITypeInfo* type_info, GjsArgumentFlags flags, + GIArgument* arg) { if (transfer == GI_TRANSFER_NOTHING && !is_transfer_in_nothing(transfer, flags)) return true; - type_tag = g_type_info_get_tag( (GITypeInfo*) type_info); + GITypeTag type_tag = g_type_info_get_tag(type_info); gjs_debug_marshal(GJS_DEBUG_GFUNCTION, - "Releasing GArgument %s out param or return value", + "Releasing GIArgument %s out param or return value", g_type_tag_to_string(type_tag)); return gjs_g_arg_release_internal(cx, transfer, type_info, type_tag, GJS_ARGUMENT_ARGUMENT, flags, arg); } -bool gjs_g_argument_release_in_arg(JSContext* cx, GITransfer transfer, - GITypeInfo* type_info, - GjsArgumentFlags flags, GIArgument* arg) { - GITypeTag type_tag; - +bool gjs_gi_argument_release_in_arg(JSContext* cx, GITransfer transfer, + GITypeInfo* type_info, + GjsArgumentFlags flags, GIArgument* arg) { /* GI_TRANSFER_EVERYTHING: we don't own the argument anymore. * GI_TRANSFER_CONTAINER: * - non-containers: treated as GI_TRANSFER_EVERYTHING @@ -3277,10 +3277,9 @@ bool gjs_g_argument_release_in_arg(JSContext* cx, GITransfer transfer, if (transfer != GI_TRANSFER_NOTHING) return true; - type_tag = g_type_info_get_tag( (GITypeInfo*) type_info); + GITypeTag type_tag = g_type_info_get_tag(type_info); - gjs_debug_marshal(GJS_DEBUG_GFUNCTION, - "Releasing GArgument %s in param", + gjs_debug_marshal(GJS_DEBUG_GFUNCTION, "Releasing GIArgument %s in param", g_type_tag_to_string(type_tag)); if (type_needs_release (type_info, type_tag)) @@ -3290,36 +3289,72 @@ bool gjs_g_argument_release_in_arg(JSContext* cx, GITransfer transfer, return true; } -bool gjs_g_argument_release_in_array(JSContext* context, GITransfer transfer, - GITypeInfo* type_info, unsigned length, - GIArgument* arg) { +bool gjs_gi_argument_release_in_array(JSContext* context, GITransfer transfer, + GITypeInfo* type_info, unsigned length, + GIArgument* arg) { if (transfer != GI_TRANSFER_NOTHING) return true; gjs_debug_marshal(GJS_DEBUG_GFUNCTION, - "Releasing GArgument array in param"); + "Releasing GIArgument array in param"); GjsAutoTypeInfo param_type = g_type_info_get_param_type(type_info, 0); - return gjs_g_argument_release_array_internal( - context, GI_TRANSFER_EVERYTHING, GjsArgumentFlags::ARG_IN, param_type, - length, arg); + return gjs_gi_argument_release_array_internal< + ArrayReleaseType::EXPLICIT_LENGTH>(context, GI_TRANSFER_EVERYTHING, + GjsArgumentFlags::ARG_IN, param_type, + length, arg); } -bool gjs_g_argument_release_out_array(JSContext* context, GITransfer transfer, - GITypeInfo* type_info, unsigned length, - GIArgument* arg) { +bool gjs_gi_argument_release_in_array(JSContext* context, GITransfer transfer, + GITypeInfo* type_info, GIArgument* arg) { + if (transfer != GI_TRANSFER_NOTHING) + return true; + + gjs_debug_marshal(GJS_DEBUG_GFUNCTION, + "Releasing GIArgument array in param"); + + GjsAutoTypeInfo param_type = g_type_info_get_param_type(type_info, 0); + return gjs_gi_argument_release_array_internal< + ArrayReleaseType::ZERO_TERMINATED>(context, GI_TRANSFER_EVERYTHING, + GjsArgumentFlags::ARG_IN, param_type, + 0, arg); +} + +bool gjs_gi_argument_release_out_array(JSContext* context, GITransfer transfer, + GITypeInfo* type_info, unsigned length, + GIArgument* arg) { + if (transfer == GI_TRANSFER_NOTHING) + return true; + + gjs_debug_marshal(GJS_DEBUG_GFUNCTION, + "Releasing GIArgument array out param"); + + GITransfer element_transfer = transfer == GI_TRANSFER_CONTAINER + ? GI_TRANSFER_NOTHING + : GI_TRANSFER_EVERYTHING; + + GjsAutoTypeInfo param_type = g_type_info_get_param_type(type_info, 0); + return gjs_gi_argument_release_array_internal< + ArrayReleaseType::EXPLICIT_LENGTH>(context, element_transfer, + GjsArgumentFlags::ARG_OUT, + param_type, length, arg); +} + +bool gjs_gi_argument_release_out_array(JSContext* context, GITransfer transfer, + GITypeInfo* type_info, GIArgument* arg) { if (transfer == GI_TRANSFER_NOTHING) return true; gjs_debug_marshal(GJS_DEBUG_GFUNCTION, - "Releasing GArgument array out param"); + "Releasing GIArgument array out param"); GITransfer element_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : GI_TRANSFER_EVERYTHING; GjsAutoTypeInfo param_type = g_type_info_get_param_type(type_info, 0); - return gjs_g_argument_release_array_internal(context, element_transfer, - GjsArgumentFlags::ARG_OUT, - param_type, length, arg); + return gjs_gi_argument_release_array_internal< + ArrayReleaseType::ZERO_TERMINATED>(context, element_transfer, + GjsArgumentFlags::ARG_OUT, + param_type, 0, arg); } diff --git a/gi/arg.h b/gi/arg.h index c834d3b3d..fac73eb4d 100644 --- a/gi/arg.h +++ b/gi/arg.h @@ -65,34 +65,30 @@ size_t gjs_type_get_element_size(GITypeTag element_type, GITypeInfo* type_info); void gjs_gi_argument_init_default(GITypeInfo* type_info, GIArgument* arg); GJS_JSAPI_RETURN_CONVENTION -bool gjs_value_to_g_argument(JSContext* cx, JS::HandleValue value, - GITypeInfo* type_info, const char* arg_name, - GjsArgumentType argument_type, GITransfer transfer, - GjsArgumentFlags flags, GIArgument* arg); - -GJS_JSAPI_RETURN_CONVENTION -bool inline gjs_value_to_g_argument(JSContext* cx, JS::HandleValue value, - GITypeInfo* type_info, - GjsArgumentType argument_type, - GITransfer transfer, GIArgument* arg) { - return gjs_value_to_g_argument(cx, value, type_info, nullptr /* arg_name */, - argument_type, transfer, - GjsArgumentFlags::NONE, arg); +bool gjs_value_to_gi_argument(JSContext*, JS::HandleValue, GITypeInfo*, + const char* arg_name, GjsArgumentType, GITransfer, + GjsArgumentFlags, GIArgument*); + +GJS_JSAPI_RETURN_CONVENTION +bool inline gjs_value_to_gi_argument(JSContext* cx, JS::HandleValue value, + GITypeInfo* type_info, + GjsArgumentType argument_type, + GITransfer transfer, GIArgument* arg) { + return gjs_value_to_gi_argument(cx, value, type_info, + nullptr /* arg_name */, argument_type, + transfer, GjsArgumentFlags::NONE, arg); } GJS_JSAPI_RETURN_CONVENTION -bool gjs_value_from_g_argument(JSContext* context, - JS::MutableHandleValue value_p, - GITypeInfo* type_info, - GjsArgumentType argument_type, - GITransfer transfer, GIArgument* arg); +bool gjs_value_from_gi_argument(JSContext*, JS::MutableHandleValue, GITypeInfo*, + GjsArgumentType, GITransfer, GIArgument*); GJS_JSAPI_RETURN_CONVENTION -inline bool gjs_value_from_g_argument(JSContext* cx, - JS::MutableHandleValue value_p, - GITypeInfo* type_info, GIArgument* arg, - bool copy_structs) { - return gjs_value_from_g_argument( +inline bool gjs_value_from_gi_argument(JSContext* cx, + JS::MutableHandleValue value_p, + GITypeInfo* type_info, GIArgument* arg, + bool copy_structs) { + return gjs_value_from_gi_argument( cx, value_p, type_info, GJS_ARGUMENT_ARGUMENT, copy_structs ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING, arg); } @@ -113,31 +109,35 @@ inline bool gjs_value_from_explicit_array(JSContext* context, } GJS_JSAPI_RETURN_CONVENTION -bool gjs_g_argument_release(JSContext*, GITransfer, GITypeInfo*, - GjsArgumentFlags, GIArgument*); +bool gjs_gi_argument_release(JSContext*, GITransfer, GITypeInfo*, + GjsArgumentFlags, GIArgument*); GJS_JSAPI_RETURN_CONVENTION -inline bool gjs_g_argument_release(JSContext* cx, GITransfer transfer, - GITypeInfo* type_info, GIArgument* arg) { - return gjs_g_argument_release(cx, transfer, type_info, - GjsArgumentFlags::NONE, arg); +inline bool gjs_gi_argument_release(JSContext* cx, GITransfer transfer, + GITypeInfo* type_info, GIArgument* arg) { + return gjs_gi_argument_release(cx, transfer, type_info, + GjsArgumentFlags::NONE, arg); } GJS_JSAPI_RETURN_CONVENTION -bool gjs_g_argument_release_out_array(JSContext* cx, GITransfer transfer, - GITypeInfo* type_info, unsigned length, - GIArgument* arg); +bool gjs_gi_argument_release_out_array(JSContext*, GITransfer, GITypeInfo*, + unsigned length, GIArgument*); GJS_JSAPI_RETURN_CONVENTION -bool gjs_g_argument_release_in_array(JSContext* cx, GITransfer transfer, - GITypeInfo* type_info, unsigned length, - GIArgument* arg); +bool gjs_gi_argument_release_out_array(JSContext*, GITransfer, GITypeInfo*, + GIArgument*); GJS_JSAPI_RETURN_CONVENTION -bool gjs_g_argument_release_in_arg(JSContext*, GITransfer, GITypeInfo*, - GjsArgumentFlags, GIArgument*); +bool gjs_gi_argument_release_in_array(JSContext*, GITransfer, GITypeInfo*, + unsigned length, GIArgument*); GJS_JSAPI_RETURN_CONVENTION -inline bool gjs_g_argument_release_in_arg(JSContext* cx, GITransfer transfer, - GITypeInfo* type_info, - GIArgument* arg) { - return gjs_g_argument_release_in_arg(cx, transfer, type_info, - GjsArgumentFlags::ARG_IN, arg); +bool gjs_gi_argument_release_in_array(JSContext*, GITransfer, GITypeInfo*, + GIArgument*); +GJS_JSAPI_RETURN_CONVENTION +bool gjs_gi_argument_release_in_arg(JSContext*, GITransfer, GITypeInfo*, + GjsArgumentFlags, GIArgument*); +GJS_JSAPI_RETURN_CONVENTION +inline bool gjs_gi_argument_release_in_arg(JSContext* cx, GITransfer transfer, + GITypeInfo* type_info, + GIArgument* arg) { + return gjs_gi_argument_release_in_arg(cx, transfer, type_info, + GjsArgumentFlags::ARG_IN, arg); } GJS_JSAPI_RETURN_CONVENTION diff --git a/gi/boxed.cpp b/gi/boxed.cpp index d9149b013..67b59ff5f 100644 --- a/gi/boxed.cpp +++ b/gi/boxed.cpp @@ -214,7 +214,7 @@ GIFieldInfo* BoxedPrototype::lookup_field(JSContext* cx, JSString* prop_name) { } /* Initialize a newly created Boxed from an object that is a "hash" of - * properties to set as fieds of the object. We don't require that every field + * properties to set as fields of the object. We don't require that every field * of the object be set. */ bool BoxedInstance::init_from_props(JSContext* context, JS::Value props_value) { @@ -480,10 +480,10 @@ GIFieldInfo* BoxedBase::get_field_info(JSContext* cx, uint32_t id) const { */ bool BoxedInstance::get_nested_interface_object( JSContext* context, JSObject* parent_obj, GIFieldInfo* field_info, - GIBaseInfo* interface_info, JS::MutableHandleValue value) const { + GIStructInfo* struct_info, JS::MutableHandleValue value) const { int offset; - if (!struct_is_simple(reinterpret_cast(interface_info))) { + if (!struct_is_simple(struct_info)) { gjs_throw(context, "Reading field %s.%s is not supported", name(), g_base_info_get_name(field_info)); @@ -492,8 +492,8 @@ bool BoxedInstance::get_nested_interface_object( offset = g_field_info_get_offset (field_info); - JS::RootedObject obj(context, gjs_new_object_with_generic_prototype( - context, interface_info)); + JS::RootedObject obj{ + context, gjs_new_object_with_generic_prototype(context, struct_info)}; if (!obj) return false; @@ -567,26 +567,26 @@ bool BoxedInstance::field_getter_impl(JSContext* cx, JSObject* obj, get_field_info(cx, length_field_ix); if (!length_field_info) { gjs_throw(cx, "Reading field %s.%s is not supported", name(), - g_base_info_get_name(length_field_info)); + g_base_info_get_name(field_info)); return false; } GIArgument length_arg; if (!g_field_info_get_field(length_field_info, m_ptr, &length_arg)) { gjs_throw(cx, "Reading field %s.%s is not supported", name(), - g_base_info_get_name(length_field_info)); + length_field_info.name()); return false; } GjsAutoTypeInfo length_type_info = g_field_info_get_type(length_field_info); - size_t length = gjs_g_argument_get_array_length( + size_t length = gjs_gi_argument_get_array_length( g_type_info_get_tag(length_type_info), &length_arg); return gjs_value_from_explicit_array(cx, rval, type_info, &arg, length); } - return gjs_value_from_g_argument(cx, rval, type_info, GJS_ARGUMENT_FIELD, - GI_TRANSFER_EVERYTHING, &arg); + return gjs_value_from_gi_argument(cx, rval, type_info, GJS_ARGUMENT_FIELD, + GI_TRANSFER_EVERYTHING, &arg); } /* @@ -603,19 +603,19 @@ bool BoxedInstance::field_getter_impl(JSContext* cx, JSObject* obj, */ bool BoxedInstance::set_nested_interface_object(JSContext* context, GIFieldInfo* field_info, - GIBaseInfo* interface_info, + GIStructInfo* struct_info, JS::HandleValue value) { int offset; - if (!struct_is_simple(reinterpret_cast(interface_info))) { + if (!struct_is_simple(struct_info)) { gjs_throw(context, "Writing field %s.%s is not supported", name(), g_base_info_get_name(field_info)); return false; } - JS::RootedObject proto( - context, gjs_lookup_generic_prototype(context, interface_info)); + JS::RootedObject proto{context, + gjs_lookup_generic_prototype(context, struct_info)}; if (!proto) return false; @@ -647,7 +647,6 @@ bool BoxedInstance::set_nested_interface_object(JSContext* context, bool BoxedInstance::field_setter_impl(JSContext* context, GIFieldInfo* field_info, JS::HandleValue value) { - GArgument arg; GjsAutoTypeInfo type_info = g_field_info_get_type(field_info); if (!g_type_info_is_pointer (type_info) && @@ -661,10 +660,11 @@ bool BoxedInstance::field_setter_impl(JSContext* context, } } - if (!gjs_value_to_g_argument(context, value, type_info, - g_base_info_get_name(field_info), - GJS_ARGUMENT_FIELD, GI_TRANSFER_NOTHING, - GjsArgumentFlags::MAY_BE_NULL, &arg)) + GIArgument arg; + if (!gjs_value_to_gi_argument(context, value, type_info, + g_base_info_get_name(field_info), + GJS_ARGUMENT_FIELD, GI_TRANSFER_NOTHING, + GjsArgumentFlags::MAY_BE_NULL, &arg)) return false; bool success = true; @@ -675,7 +675,7 @@ bool BoxedInstance::field_setter_impl(JSContext* context, } JS::AutoSaveExceptionState saved_exc(context); - if (!gjs_g_argument_release(context, GI_TRANSFER_NOTHING, type_info, &arg)) + if (!gjs_gi_argument_release(context, GI_TRANSFER_NOTHING, type_info, &arg)) gjs_log_exception(context); saved_exc.restore(); @@ -718,28 +718,41 @@ bool BoxedPrototype::define_boxed_class_fields(JSContext* cx, int n_fields = g_struct_info_get_n_fields(info()); int i; - /* We define all fields as read/write so that the user gets an - * error message. If we omitted fields or defined them read-only - * we'd: - * - * - Store a new property for a non-accessible field - * - Silently do nothing when writing a read-only field - * - * Which is pretty confusing if the only reason a field isn't - * writable is language binding or memory-management restrictions. - * - * We just go ahead and define the fields immediately for the - * class; doing it lazily in boxed_resolve() would be possible - * as well if doing it ahead of time caused to much start-up - * memory overhead. - */ + // We define all fields as read/write so that the user gets an error + // message. If we omitted fields or defined them read-only we'd: + // + // - Store a new property for a non-accessible field + // - Silently do nothing when writing a read-only field + // + // Which is pretty confusing if the only reason a field isn't writable is + // language binding or memory-management restrictions. + // + // We just go ahead and define the fields immediately for the class; doing + // it lazily in boxed_resolve() would be possible as well if doing it ahead + // of time caused too much start-up memory overhead. + // + // At this point methods have already been defined on the prototype, so we + // may get name conflicts which we need to check for. for (i = 0; i < n_fields; i++) { GjsAutoFieldInfo field = g_struct_info_get_field(info(), i); JS::RootedValue private_id(cx, JS::PrivateUint32Value(i)); - if (!gjs_define_property_dynamic(cx, proto, field.name(), "boxed_field", - &BoxedBase::field_getter, - &BoxedBase::field_setter, private_id, - GJS_MODULE_PROP_FLAGS)) + JS::RootedId id{cx, gjs_intern_string_to_id(cx, field.name())}; + + bool already_defined; + if (!JS_HasOwnPropertyById(cx, proto, id, &already_defined)) + return false; + if (already_defined) { + gjs_debug(GJS_DEBUG_GBOXED, + "Field %s.%s.%s overlaps with method of the same name; " + "skipping", + ns(), name(), field.name()); + continue; + } + + if (!gjs_define_property_dynamic( + cx, proto, field.name(), id, "boxed_field", + &BoxedBase::field_getter, &BoxedBase::field_setter, private_id, + GJS_MODULE_PROP_FLAGS)) return false; } @@ -768,7 +781,7 @@ const struct JSClassOps BoxedBase::class_ops = { &BoxedBase::trace }; -/* We allocate 1 reserved slot; this is typically unused, but if the +/* We allocate 1 extra reserved slot; this is typically unused, but if the * boxed is for a nested structure inside a parent structure, the * reserved slot is used to hold onto the parent Javascript object and * make sure it doesn't get freed. @@ -787,7 +800,7 @@ const struct JSClass BoxedBase::klass = { if (g_type_info_is_pointer(type_info)) { if (g_type_info_get_tag(type_info) == GI_TYPE_TAG_ARRAY && g_type_info_get_array_type(type_info) == GI_ARRAY_TYPE_C) { - GjsAutoBaseInfo param_info = + GjsAutoTypeInfo param_info = g_type_info_get_param_type(type_info, 0); return type_can_be_allocated_directly(param_info); } @@ -798,7 +811,7 @@ const struct JSClass BoxedBase::klass = { case GI_TYPE_TAG_INTERFACE: { GjsAutoBaseInfo interface = g_type_info_get_interface(type_info); - switch (g_base_info_get_type(interface)) { + switch (interface.type()) { case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: return struct_is_simple(interface.as()); @@ -867,7 +880,7 @@ const struct JSClass BoxedBase::klass = { if (g_type_info_is_pointer(type_info)) { if (g_type_info_get_tag(type_info) == GI_TYPE_TAG_ARRAY && g_type_info_get_array_type(type_info) == GI_ARRAY_TYPE_C) { - GjsAutoBaseInfo param_info = + GjsAutoTypeInfo param_info = g_type_info_get_param_type(type_info, 0); return direct_allocation_has_pointers(param_info); } @@ -900,8 +913,8 @@ const struct JSClass BoxedBase::klass = { return false; for (i = 0; i < n_fields && is_simple; i++) { - GjsAutoBaseInfo field_info = g_struct_info_get_field(info, i); - GjsAutoBaseInfo type_info = g_field_info_get_type(field_info); + GjsAutoFieldInfo field_info = g_struct_info_get_field(info, i); + GjsAutoTypeInfo type_info = g_field_info_get_type(field_info); is_simple = type_can_be_allocated_directly(type_info); } @@ -917,8 +930,8 @@ const struct JSClass BoxedBase::klass = { g_assert(n_fields > 0); for (int i = 0; i < n_fields; i++) { - GjsAutoBaseInfo field_info = g_struct_info_get_field(info, i); - GjsAutoBaseInfo type_info = g_field_info_get_type(field_info); + GjsAutoFieldInfo field_info = g_struct_info_get_field(info, i); + GjsAutoTypeInfo type_info = g_field_info_get_type(field_info); if (direct_allocation_has_pointers(type_info)) return true; } diff --git a/gi/boxed.h b/gi/boxed.h index 1f1612551..087cf7fd8 100644 --- a/gi/boxed.h +++ b/gi/boxed.h @@ -198,11 +198,11 @@ class BoxedInstance GJS_JSAPI_RETURN_CONVENTION bool get_nested_interface_object(JSContext* cx, JSObject* parent_obj, GIFieldInfo* field_info, - GIBaseInfo* interface_info, + GIStructInfo* interface_info, JS::MutableHandleValue value) const; GJS_JSAPI_RETURN_CONVENTION bool set_nested_interface_object(JSContext* cx, GIFieldInfo* field_info, - GIBaseInfo* interface_info, + GIStructInfo* interface_info, JS::HandleValue value); GJS_JSAPI_RETURN_CONVENTION diff --git a/gi/gjs_gi_probes.d b/gi/cjs_gi_probes.d similarity index 100% rename from gi/gjs_gi_probes.d rename to gi/cjs_gi_probes.d diff --git a/gi/gjs_gi_trace.h b/gi/cjs_gi_trace.h similarity index 95% rename from gi/gjs_gi_trace.h rename to gi/cjs_gi_trace.h index db2339983..7dfbbc080 100644 --- a/gi/gjs_gi_trace.h +++ b/gi/cjs_gi_trace.h @@ -11,7 +11,7 @@ #ifdef HAVE_DTRACE /* include the generated probes header and put markers in code */ -#include "gjs_gi_probes.h" +#include "cjs_gi_probes.h" #define TRACE(probe) probe #else diff --git a/gi/closure.cpp b/gi/closure.cpp index cf2bc3fbd..982c49c31 100644 --- a/gi/closure.cpp +++ b/gi/closure.cpp @@ -171,7 +171,7 @@ bool Closure::invoke(JS::HandleObject this_obj, return false; } - JSAutoRealm ar(m_cx, m_callable); + JSAutoRealm ar{m_cx, m_callable.get()}; if (gjs_log_exception(m_cx)) { gjs_debug_closure( @@ -180,7 +180,7 @@ bool Closure::invoke(JS::HandleObject this_obj, this); } - JS::RootedValue v_callable(m_cx, JS::ObjectValue(*m_callable)); + JS::RootedValue v_callable{m_cx, JS::ObjectValue(*m_callable.get())}; bool ok = JS::Call(m_cx, this_obj, v_callable, args, retval); GjsContextPrivate* gjs = GjsContextPrivate::from_cx(m_cx); diff --git a/gi/closure.h b/gi/closure.h index 72b837052..2bbc04bd0 100644 --- a/gi/closure.h +++ b/gi/closure.h @@ -9,9 +9,10 @@ #include -#include #include +#include + #include #include "gi/utils-inl.h" @@ -68,8 +69,9 @@ class Closure : public GClosure { [[nodiscard]] static Closure* create_marshaled(JSContext* cx, JSObject* callable, - const char* description) { - auto* self = new Closure(cx, callable, true /* root */, description); + const char* description, + bool root = true) { + auto* self = new Closure(cx, callable, root, description); self->add_finalize_notifier(); g_closure_set_marshal(self, marshal_cb); return self; @@ -86,7 +88,8 @@ class Closure : public GClosure { return self; } - constexpr JSObject* callable() const { return m_callable; } + // COMPAT: constexpr in C++23 + JSObject* callable() const { return m_callable.get(); } [[nodiscard]] constexpr JSContext* context() const { return m_cx; } [[nodiscard]] constexpr bool is_valid() const { return !!m_cx; } GJS_JSAPI_RETURN_CONVENTION bool invoke(JS::HandleObject, @@ -127,7 +130,7 @@ class Closure : public GClosure { // The context could be attached to the default context of the runtime // using if we wanted the closure to survive the context that created it. JSContext* m_cx; - GjsMaybeOwned m_callable; + GjsMaybeOwned m_callable; }; } // namespace Gjs diff --git a/gi/cwrapper.h b/gi/cwrapper.h index a176c10f8..2fad86909 100644 --- a/gi/cwrapper.h +++ b/gi/cwrapper.h @@ -16,6 +16,7 @@ #include #include #include // for JSEXN_TYPEERR +#include // for MutableHandleIdVector #include // for CurrentGlobalOrNull #include #include // for GetClass diff --git a/gi/enumeration.cpp b/gi/enumeration.cpp index 6632bd35a..fb8ba356e 100644 --- a/gi/enumeration.cpp +++ b/gi/enumeration.cpp @@ -4,6 +4,8 @@ #include +#include + #include #include #include @@ -46,7 +48,7 @@ gjs_define_enum_value(JSContext *context, } gjs_debug(GJS_DEBUG_GENUM, - "Defining enum value %s (fixed from %s) %" G_GINT64_MODIFIER "d", + "Defining enum value %s (fixed from %s) %" PRId64, fixed_name.get(), value_name, value_val); if (!JS_DefineProperty(context, in_object, diff --git a/gi/foreign.cpp b/gi/foreign.cpp index a37f9f135..67a0a6c64 100644 --- a/gi/foreign.cpp +++ b/gi/foreign.cpp @@ -4,112 +4,92 @@ #include -#include // for strcmp +#include // for size_t + #include +#include +#include // for pair #include #include +#include #include #include "gi/foreign.h" #include "cjs/context-private.h" #include "cjs/jsapi-util.h" +#include "cjs/macros.h" -static struct { - const char* gi_namespace; - bool loaded; -} foreign_modules[] = { - // clang-format off - {"cairo", false}, - {nullptr} - // clang-format on -}; - -static GHashTable* foreign_structs_table = NULL; +enum LoadedStatus { NotLoaded, Loaded }; +static std::unordered_map foreign_modules{ + {"cairo", NotLoaded}}; -[[nodiscard]] static GHashTable* get_foreign_structs() { - // FIXME: look into hasing on GITypeInfo instead. - if (!foreign_structs_table) { - foreign_structs_table = g_hash_table_new_full(g_str_hash, g_str_equal, - (GDestroyNotify)g_free, - NULL); +using StructID = std::pair; +struct StructIDHash { + [[nodiscard]] size_t operator()(StructID val) const { + std::hash hasher; + return hasher(val.first) ^ hasher(val.second); } - - return foreign_structs_table; -} +}; +static std::unordered_map + foreign_structs_table; [[nodiscard]] static bool gjs_foreign_load_foreign_module( - JSContext* context, const char* gi_namespace) { - int i; - - for (i = 0; foreign_modules[i].gi_namespace; ++i) { - if (strcmp(gi_namespace, foreign_modules[i].gi_namespace) != 0) - continue; - - if (foreign_modules[i].loaded) - return true; - - // FIXME: Find a way to check if a module is imported - // and only execute this statement if isn't - std::string script = "imports." + std::string(gi_namespace) + ';'; - JS::RootedValue retval(context); - GjsContextPrivate* gjs = GjsContextPrivate::from_cx(context); - if (!gjs->eval_with_scope(nullptr, script.c_str(), script.length(), - "", &retval)) { - g_critical("ERROR importing foreign module %s\n", gi_namespace); - return false; - } - foreign_modules[i].loaded = true; + JSContext* cx, const char* gi_namespace) { + auto entry = foreign_modules.find(gi_namespace); + if (entry == foreign_modules.end()) + return false; + + if (entry->second == Loaded) return true; - } - return false; + // FIXME: Find a way to check if a module is imported and only execute this + // statement if it isn't + std::string script = "imports." + entry->first + ';'; + JS::RootedValue retval{cx}; + GjsContextPrivate* gjs = GjsContextPrivate::from_cx(cx); + if (!gjs->eval_with_scope(nullptr, script.c_str(), script.length(), + "", &retval)) { + g_critical("ERROR importing foreign module %s\n", gi_namespace); + return false; + } + entry->second = Loaded; + return true; } void gjs_struct_foreign_register(const char* gi_namespace, const char* type_name, GjsForeignInfo* info) { - char *canonical_name; - - g_return_if_fail(info); - g_return_if_fail(info->to_func); - g_return_if_fail(info->from_func); - - canonical_name = g_strdup_printf("%s.%s", gi_namespace, type_name); - g_hash_table_insert(get_foreign_structs(), canonical_name, info); + foreign_structs_table.insert({{gi_namespace, type_name}, info}); } -[[nodiscard]] static GjsForeignInfo* gjs_struct_foreign_lookup( - JSContext* context, GIBaseInfo* interface_info) { - GHashTable* hash_table; - - auto key = std::string(g_base_info_get_namespace(interface_info)) + '.' + - g_base_info_get_name(interface_info); - hash_table = get_foreign_structs(); - auto* retval = static_cast( - g_hash_table_lookup(hash_table, key.c_str())); - if (!retval) { - if (gjs_foreign_load_foreign_module(context, g_base_info_get_namespace(interface_info))) { - retval = static_cast( - g_hash_table_lookup(hash_table, key.c_str())); - } +GJS_JSAPI_RETURN_CONVENTION +static GjsForeignInfo* gjs_struct_foreign_lookup(JSContext* cx, + GIStructInfo* info) { + const char* ns = g_base_info_get_namespace(info); + StructID key{ns, g_base_info_get_name(info)}; + auto entry = foreign_structs_table.find(key); + if (entry == foreign_structs_table.end()) { + if (gjs_foreign_load_foreign_module(cx, ns)) + entry = foreign_structs_table.find(key); } - if (!retval) { - gjs_throw(context, "Unable to find module implementing foreign type %s", - key.c_str()); + if (entry == foreign_structs_table.end()) { + gjs_throw(cx, "Unable to find module implementing foreign type %s.%s", + key.first.c_str(), key.second.c_str()); + return nullptr; } - return retval; + return entry->second; } -bool gjs_struct_foreign_convert_to_g_argument( - JSContext* context, JS::Value value, GIBaseInfo* interface_info, +bool gjs_struct_foreign_convert_to_gi_argument( + JSContext* context, JS::Value value, GIStructInfo* info, const char* arg_name, GjsArgumentType argument_type, GITransfer transfer, - GjsArgumentFlags flags, GArgument* arg) { + GjsArgumentFlags flags, GIArgument* arg) { GjsForeignInfo *foreign; - foreign = gjs_struct_foreign_lookup(context, interface_info); + foreign = gjs_struct_foreign_lookup(context, info); if (!foreign) return false; @@ -120,15 +100,11 @@ bool gjs_struct_foreign_convert_to_g_argument( return true; } -bool -gjs_struct_foreign_convert_from_g_argument(JSContext *context, - JS::MutableHandleValue value_p, - GIBaseInfo *interface_info, - GIArgument *arg) -{ - GjsForeignInfo *foreign; - - foreign = gjs_struct_foreign_lookup(context, interface_info); +bool gjs_struct_foreign_convert_from_gi_argument(JSContext* context, + JS::MutableHandleValue value_p, + GIStructInfo* info, + GIArgument* arg) { + GjsForeignInfo* foreign = gjs_struct_foreign_lookup(context, info); if (!foreign) return false; @@ -138,15 +114,11 @@ gjs_struct_foreign_convert_from_g_argument(JSContext *context, return true; } -bool -gjs_struct_foreign_release_g_argument(JSContext *context, - GITransfer transfer, - GIBaseInfo *interface_info, - GArgument *arg) -{ - GjsForeignInfo *foreign; - - foreign = gjs_struct_foreign_lookup(context, interface_info); +bool gjs_struct_foreign_release_gi_argument(JSContext* context, + GITransfer transfer, + GIStructInfo* info, + GIArgument* arg) { + GjsForeignInfo* foreign = gjs_struct_foreign_lookup(context, info); if (!foreign) return false; @@ -158,4 +130,3 @@ gjs_struct_foreign_release_g_argument(JSContext *context, return true; } - diff --git a/gi/foreign.h b/gi/foreign.h index 2219d19a1..4f16756a0 100644 --- a/gi/foreign.h +++ b/gi/foreign.h @@ -9,50 +9,46 @@ #include -#include #include #include #include "gi/arg.h" #include "cjs/macros.h" -typedef bool (*GjsArgOverrideToGArgumentFunc)( - JSContext* context, JS::Value value, const char* arg_name, - GjsArgumentType argument_type, GITransfer transfer, GjsArgumentFlags flags, - GArgument* arg); +typedef bool (*GjsArgOverrideToGIArgumentFunc)(JSContext*, JS::Value, + const char* arg_name, + GjsArgumentType, GITransfer, + GjsArgumentFlags, GIArgument*); -typedef bool (*GjsArgOverrideFromGArgumentFunc) (JSContext *context, - JS::MutableHandleValue value_p, - GIArgument *arg); +typedef bool (*GjsArgOverrideFromGIArgumentFunc)(JSContext*, + JS::MutableHandleValue, + GIArgument*); -typedef bool (*GjsArgOverrideReleaseGArgumentFunc) (JSContext *context, - GITransfer transfer, - GArgument *arg); +typedef bool (*GjsArgOverrideReleaseGIArgumentFunc)(JSContext*, GITransfer, + GIArgument*); typedef struct { - GjsArgOverrideToGArgumentFunc to_func; - GjsArgOverrideFromGArgumentFunc from_func; - GjsArgOverrideReleaseGArgumentFunc release_func; + GjsArgOverrideToGIArgumentFunc to_func; + GjsArgOverrideFromGIArgumentFunc from_func; + GjsArgOverrideReleaseGIArgumentFunc release_func; } GjsForeignInfo; void gjs_struct_foreign_register(const char* gi_namespace, const char* type_name, GjsForeignInfo* info); GJS_JSAPI_RETURN_CONVENTION -bool gjs_struct_foreign_convert_to_g_argument( - JSContext* context, JS::Value value, GIBaseInfo* interface_info, - const char* arg_name, GjsArgumentType argument_type, GITransfer transfer, - GjsArgumentFlags flags, GArgument* arg); +bool gjs_struct_foreign_convert_to_gi_argument(JSContext*, JS::Value, + GIStructInfo*, + const char* arg_name, + GjsArgumentType, GITransfer, + GjsArgumentFlags, GIArgument*); GJS_JSAPI_RETURN_CONVENTION -bool gjs_struct_foreign_convert_from_g_argument(JSContext *context, - JS::MutableHandleValue value_p, - GIBaseInfo *interface_info, - GIArgument *arg); +bool gjs_struct_foreign_convert_from_gi_argument(JSContext*, + JS::MutableHandleValue, + GIStructInfo*, GIArgument*); GJS_JSAPI_RETURN_CONVENTION -bool gjs_struct_foreign_release_g_argument (JSContext *context, - GITransfer transfer, - GIBaseInfo *interface_info, - GArgument *arg); +bool gjs_struct_foreign_release_gi_argument(JSContext*, GITransfer, + GIStructInfo*, GIArgument*); #endif // GI_FOREIGN_H_ diff --git a/gi/function.cpp b/gi/function.cpp index 5666157d2..11a47797d 100644 --- a/gi/function.cpp +++ b/gi/function.cpp @@ -25,19 +25,18 @@ #include #include // for JS_ReportOutOfMemory #include +#include // for RuntimeHeapIsCollecting #include #include // for JSPROP_PERMANENT #include #include // for GetRealmFunctionPrototype #include -#include #include #include #include #include -#include // for HandleValueArray -#include // for JS_GetObjectFunction -#include // for JSProtoKey +#include // for HandleValueArray +#include // for JSProtoKey #include "gi/arg-cache.h" #include "gi/arg-inl.h" @@ -132,8 +131,7 @@ class Function : public CWrapper { static JSObject* inherit_builtin_function(JSContext* cx, JSProtoKey) { JS::RootedObject builtin_function_proto( cx, JS::GetRealmFunctionPrototype(cx)); - return JS_NewObjectWithGivenProto(cx, &Function::klass, - builtin_function_proto); + return JS_NewObjectWithGivenProto(cx, nullptr, builtin_function_proto); } static const JSClassOps class_ops; @@ -192,12 +190,10 @@ static inline void set_ffi_arg(void* result, GIArgument* value) { } } -static void -set_return_ffi_arg_from_giargument (GITypeInfo *ret_type, - void *result, - GIArgument *return_value) -{ - // Be consistent with gjs_value_to_g_argument() +static void set_return_ffi_arg_from_gi_argument(GITypeInfo* ret_type, + void* result, + GIArgument* return_value) { + // Be consistent with gjs_value_to_gi_argument() switch (g_type_info_get_tag(ret_type)) { case GI_TYPE_TAG_VOID: g_assert_not_reached(); @@ -230,10 +226,8 @@ set_return_ffi_arg_from_giargument (GITypeInfo *ret_type, break; case GI_TYPE_TAG_INTERFACE: { - GIInfoType interface_type; - GjsAutoBaseInfo interface_info(g_type_info_get_interface(ret_type)); - interface_type = g_base_info_get_type(interface_info); + GIInfoType interface_type = interface_info.type(); if (interface_type == GI_INFO_TYPE_ENUM || interface_type == GI_INFO_TYPE_FLAGS) @@ -303,7 +297,7 @@ void GjsCallbackTrampoline::callback_closure(GIArgument** args, void* result) { if (g_type_info_get_tag(&ret_type) != GI_TYPE_TAG_VOID) { GIArgument argument = {}; gjs_gi_argument_init_default(&ret_type, &argument); - set_return_ffi_arg_from_giargument(&ret_type, result, &argument); + set_return_ffi_arg_from_gi_argument(&ret_type, result, &argument); } if (G_UNLIKELY(!is_valid())) { @@ -317,7 +311,7 @@ void GjsCallbackTrampoline::callback_closure(GIArgument** args, void* result) { JSContext* context = this->context(); GjsContextPrivate* gjs = GjsContextPrivate::from_cx(context); - if (G_UNLIKELY(gjs->sweeping())) { + if (JS::RuntimeHeapIsCollecting()) { warn_about_illegal_js_callback( "during garbage collection", "destroying a Clutter actor or GTK widget with ::destroy signal " @@ -396,12 +390,9 @@ void GjsCallbackTrampoline::callback_closure(GIArgument** args, void* result) { gjs->exit_immediately(code); // Some other uncatchable exception, e.g. out of memory - JSFunction* fn = JS_GetObjectFunction(callable()); - std::string descr = - fn ? "function " + gjs_debug_string(JS_GetFunctionDisplayId(fn)) - : "callable object " + gjs_debug_object(callable()); g_error("Call to %s (%s.%s) terminated with uncatchable exception", - descr.c_str(), m_info.ns(), m_info.name()); + gjs_debug_callable(callable()).c_str(), m_info.ns(), + m_info.name()); } // If the callback has a GError** argument, then make a GError from the @@ -480,7 +471,7 @@ bool GjsCallbackTrampoline::callback_closure_inner( g_callable_info_load_arg(m_info, array_length_pos, &array_length_arg); g_arg_info_load_type(&array_length_arg, &arg_type_info); - size_t length = gjs_g_argument_get_array_length( + size_t length = gjs_gi_argument_get_array_length( g_type_info_get_tag(&arg_type_info), args[array_length_pos + c_args_offset]); @@ -503,8 +494,8 @@ bool GjsCallbackTrampoline::callback_closure_inner( !g_arg_info_is_caller_allocates(&arg_info)) arg = *reinterpret_cast(arg); - if (!gjs_value_from_g_argument(context, jsargs[n_jsargs++], - &type_info, arg, false)) + if (!gjs_value_from_gi_argument(context, jsargs[n_jsargs++], + &type_info, arg, false)) return false; break; } @@ -530,12 +521,12 @@ bool GjsCallbackTrampoline::callback_closure_inner( transfer = g_callable_info_get_caller_owns(m_info); /* non-void return value, no out args. Should * be a single return value. */ - if (!gjs_value_to_g_argument(context, rval, ret_type, "callback", - GJS_ARGUMENT_RETURN_VALUE, transfer, - GjsArgumentFlags::MAY_BE_NULL, &argument)) + if (!gjs_value_to_gi_argument(context, rval, ret_type, "callback", + GJS_ARGUMENT_RETURN_VALUE, transfer, + GjsArgumentFlags::MAY_BE_NULL, &argument)) return false; - set_return_ffi_arg_from_giargument(ret_type, result, &argument); + set_return_ffi_arg_from_gi_argument(ret_type, result, &argument); } else if (n_outargs == 1 && ret_type_is_void) { /* void return value, one out args. Should * be a single return value. */ @@ -559,14 +550,11 @@ bool GjsCallbackTrampoline::callback_closure_inner( return false; if (!is_array) { - JSFunction* fn = JS_GetObjectFunction(callable()); - std::string descr = - fn ? "function " + gjs_debug_string(JS_GetFunctionDisplayId(fn)) - : "callable object " + gjs_debug_object(callable()); gjs_throw(context, "Call to %s (%s.%s) returned unexpected value, expecting " "an Array", - descr.c_str(), m_info.ns(), m_info.name()); + gjs_debug_callable(callable()).c_str(), m_info.ns(), + m_info.name()); return false; } @@ -583,10 +571,10 @@ bool GjsCallbackTrampoline::callback_closure_inner( if (!JS_GetElement(context, out_array, elem_idx, &elem)) return false; - if (!gjs_value_to_g_argument(context, elem, ret_type, "callback", - GJS_ARGUMENT_RETURN_VALUE, transfer, - GjsArgumentFlags::MAY_BE_NULL, - &argument)) + if (!gjs_value_to_gi_argument(context, elem, ret_type, "callback", + GJS_ARGUMENT_RETURN_VALUE, transfer, + GjsArgumentFlags::MAY_BE_NULL, + &argument)) return false; if ((ret_tag == GI_TYPE_TAG_FILENAME || @@ -604,7 +592,7 @@ bool GjsCallbackTrampoline::callback_closure_inner( } } - set_return_ffi_arg_from_giargument(ret_type, result, &argument); + set_return_ffi_arg_from_gi_argument(ret_type, result, &argument); elem_idx++; } @@ -647,7 +635,7 @@ bool GjsCallbackTrampoline::callback_closure_inner( GITypeInfo type_info; g_arg_info_load_type(&arg_info, &type_info); - if (!gjs_g_argument_release(context, transfer, &type_info, arg)) + if (!gjs_gi_argument_release(context, transfer, &type_info, arg)) return false; continue; @@ -669,8 +657,8 @@ bool GjsCallbackTrampoline::callback_closure_inner( GITypeInfo type_info; g_arg_info_load_type(&data->arg_info, &type_info); - if (!gjs_g_argument_release(self->context(), transfer, - &type_info, &data->arg)) { + if (!gjs_gi_argument_release(self->context(), transfer, + &type_info, &data->arg)) { gjs_throw(self->context(), "Impossible to release closure argument '%s'", g_base_info_get_name(&data->arg_info)); @@ -782,11 +770,9 @@ bool GjsCallbackTrampoline::initialize() { } if (type_tag == GI_TYPE_TAG_INTERFACE) { - GIInfoType interface_type; - GjsAutoBaseInfo interface_info = g_type_info_get_interface(&type_info); - interface_type = g_base_info_get_type(interface_info); + GIInfoType interface_type = interface_info.type(); if (interface_type == GI_INFO_TYPE_CALLBACK) { gjs_throw(context(), "%s %s accepts another callback as a parameter. This " @@ -843,13 +829,13 @@ std::string Gjs::Function::format_name() { namespace Gjs { -static void* get_return_ffi_pointer_from_giargument( - GITypeInfo* return_type, GIFFIReturnValue* return_value) { - // This should be the inverse of gi_type_info_extract_ffi_return_value(). - if (!return_type) - return nullptr; - - switch (g_type_info_get_tag(return_type)) { +static void* get_return_ffi_pointer_from_gi_argument( + GITypeTag tag, GITypeInfo* return_type, GIFFIReturnValue* return_value) { + if (return_type && g_type_info_is_pointer(return_type)) + return &gjs_arg_member(return_value); + switch (tag) { + case GI_TYPE_TAG_VOID: + return nullptr; case GI_TYPE_TAG_INT8: return &gjs_arg_member(return_value); case GI_TYPE_TAG_INT16: @@ -875,9 +861,12 @@ static void* get_return_ffi_pointer_from_giargument( case GI_TYPE_TAG_DOUBLE: return &gjs_arg_member(return_value); case GI_TYPE_TAG_INTERFACE: { + if (!return_type) + return nullptr; + GjsAutoBaseInfo info = g_type_info_get_interface(return_type); - switch (g_base_info_get_type(info)) { + switch (info.type()) { case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: return &gjs_arg_member( @@ -894,7 +883,7 @@ static void* get_return_ffi_pointer_from_giargument( // This function can be called in two different ways. You can either use it to // create JavaScript objects by calling it without @r_value, or you can decide -// to keep the return values in #GArgument format by providing a @r_value +// to keep the return values in GIArgument format by providing a @r_value // argument. bool Function::invoke(JSContext* context, const JS::CallArgs& args, JS::HandleObject this_obj /* = nullptr */, @@ -1054,9 +1043,10 @@ bool Function::invoke(JSContext* context, const JS::CallArgs& args, g_assert_cmpuint(ffi_arg_pos, ==, ffi_argc); g_assert_cmpuint(gi_arg_pos, ==, state.gi_argc); + GITypeTag return_tag = m_arguments.return_tag(); GITypeInfo* return_type = m_arguments.return_type(); - return_value_p = - get_return_ffi_pointer_from_giargument(return_type, &return_value); + return_value_p = get_return_ffi_pointer_from_gi_argument( + return_tag, return_type, &return_value); ffi_call(&m_invoker.cif, FFI_FN(m_invoker.native_address), return_value_p, ffi_arg_pointers.get()); @@ -1069,6 +1059,11 @@ bool Function::invoke(JSContext* context, const JS::CallArgs& args, if (return_type) { gi_type_info_extract_ffi_return_value(return_type, &return_value, state.return_value()); + } else if (return_tag != GI_TYPE_TAG_VOID) { + g_assert(GI_TYPE_TAG_IS_BASIC(return_tag)); + gi_type_tag_extract_ffi_return_value(return_tag, GI_INFO_TYPE_INVALID, + &return_value, + state.return_value()); } // Process out arguments and return values. This loop is skipped if we fail @@ -1102,8 +1097,7 @@ bool Function::invoke(JSContext* context, const JS::CallArgs& args, "to pass to the out '%s' argument. It may be that the " "function is unsupported, or there may be a bug in " "its annotations.", - g_base_info_get_namespace(m_info), - g_base_info_get_name(m_info), + m_info.ns(), m_info.name(), g_base_info_get_name(&arg_info)); state.failed = true; break; @@ -1234,9 +1228,7 @@ bool Function::call(JSContext* context, unsigned js_argc, JS::Value* vp) { gjs_debug_marshal(GJS_DEBUG_GFUNCTION, "Call callee %p priv %p", callee.get(), priv); - if (priv == NULL) - return true; // we are the prototype - + g_assert(priv); return priv->invoke(context, js_argv); } @@ -1246,8 +1238,7 @@ Function::~Function() { } void Function::finalize_impl(JS::GCContext*, Function* priv) { - if (priv == NULL) - return; /* we are the prototype, not a real instance, so constructor never called */ + g_assert(priv); delete priv; } @@ -1262,15 +1253,6 @@ bool Function::get_length(JSContext* cx, unsigned argc, JS::Value* vp) { bool Function::to_string(JSContext* context, unsigned argc, JS::Value* vp) { GJS_CHECK_WRAPPER_PRIV(context, argc, vp, rec, this_obj, Function, priv); - - if (priv == NULL) { - JSString* retval = JS_NewStringCopyZ(context, "function () {\n}"); - if (!retval) - return false; - rec.rval().setString(retval); - return true; - } - return priv->to_string_impl(context, rec.rval()); } @@ -1293,7 +1275,7 @@ bool Function::to_string_impl(JSContext* cx, JS::MutableHandleValue rval) { } GjsAutoChar descr; - if (g_base_info_get_type(m_info) == GI_INFO_TYPE_FUNCTION) { + if (m_info.type() == GI_INFO_TYPE_FUNCTION) { descr = g_strdup_printf( "%s(%s) {\n\t/* wrapper for native symbol %s() */\n}", format_name().c_str(), arg_names.c_str(), diff --git a/gi/fundamental.cpp b/gi/fundamental.cpp index 1a946d23c..52d074ef3 100644 --- a/gi/fundamental.cpp +++ b/gi/fundamental.cpp @@ -8,11 +8,9 @@ #include #include -#include // for SystemAllocPolicy #include #include // for JS_ReportOutOfMemory #include // for WeakCache -#include // for DefaultHasher via WeakCache #include // for GetClass #include #include @@ -200,7 +198,7 @@ bool FundamentalInstance::invoke_constructor(JSContext* context, bool FundamentalInstance::constructor_impl(JSContext* cx, JS::HandleObject object, const JS::CallArgs& argv) { - GArgument ret_value; + GIArgument ret_value; GITypeInfo return_info; if (!invoke_constructor(cx, object, argv, &ret_value) || @@ -210,7 +208,7 @@ bool FundamentalInstance::constructor_impl(JSContext* cx, GICallableInfo* constructor_info = get_prototype()->constructor_info(); g_callable_info_load_return_type(constructor_info, &return_info); - return gjs_g_argument_release( + return gjs_gi_argument_release( cx, g_callable_info_get_caller_owns(constructor_info), &return_info, &ret_value); } diff --git a/gi/gerror.cpp b/gi/gerror.cpp index 4411741e0..8dbf886b5 100644 --- a/gi/gerror.cpp +++ b/gi/gerror.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include // for JSPROP_ENUMERATE @@ -263,7 +264,7 @@ bool ErrorPrototype::define_class(JSContext* context, /* last attempt: load GIRepository (for invoke errors, rarely needed) */ - g_irepository_require(nullptr, "GIRepository", "1.0", + g_irepository_require(nullptr, "GIRepository", "2.0", GIRepositoryLoadFlags(0), nullptr); info = g_irepository_find_by_error_domain(nullptr, domain); @@ -278,7 +279,8 @@ bool gjs_define_error_properties(JSContext* cx, JS::HandleObject obj) { JS::RootedObject frame(cx); JS::RootedString stack(cx); JS::RootedString source(cx); - uint32_t line, column; + uint32_t line; + JS::TaggedColumnNumberOneOrigin tagged_column; if (!JS::CaptureCurrentStack(cx, &frame) || !JS::BuildStackString(cx, nullptr, frame, &stack)) @@ -287,7 +289,7 @@ bool gjs_define_error_properties(JSContext* cx, JS::HandleObject obj) { auto ok = JS::SavedFrameResult::Ok; if (JS::GetSavedFrameSource(cx, nullptr, frame, &source) != ok || JS::GetSavedFrameLine(cx, nullptr, frame, &line) != ok || - JS::GetSavedFrameColumn(cx, nullptr, frame, &column) != ok) { + JS::GetSavedFrameColumn(cx, nullptr, frame, &tagged_column) != ok) { gjs_throw(cx, "Error getting saved frame information"); return false; } @@ -299,7 +301,8 @@ bool gjs_define_error_properties(JSContext* cx, JS::HandleObject obj) { JSPROP_ENUMERATE) && JS_DefinePropertyById(cx, obj, atoms.line_number(), line, JSPROP_ENUMERATE) && - JS_DefinePropertyById(cx, obj, atoms.column_number(), column, + JS_DefinePropertyById(cx, obj, atoms.column_number(), + tagged_column.oneOriginValue(), JSPROP_ENUMERATE); } diff --git a/gi/gobject.cpp b/gi/gobject.cpp index c84f03f83..940992bae 100644 --- a/gi/gobject.cpp +++ b/gi/gobject.cpp @@ -163,12 +163,10 @@ static GObject* gjs_object_constructor( */ Gjs::AutoMainRealm ar{gjs}; - JS::RootedObject constructor( - cx, gjs_lookup_object_constructor_from_info(cx, nullptr, type)); - if (!constructor) + JS::RootedValue constructor{cx}; + if (!gjs_lookup_object_constructor(cx, type, &constructor)) return nullptr; - JS::RootedValue v_constructor(cx, JS::ObjectValue(*constructor)); JS::RootedObject object(cx); if (n_construct_properties) { JS::RootedObject props_hash(cx, JS_NewPlainObject(cx)); @@ -182,9 +180,9 @@ static GObject* gjs_object_constructor( JS::RootedValueArray<1> args(cx); args[0].set(JS::ObjectValue(*props_hash)); - if (!JS::Construct(cx, v_constructor, args, &object)) + if (!JS::Construct(cx, constructor, args, &object)) return nullptr; - } else if (!JS::Construct(cx, v_constructor, JS::HandleValueArray::empty(), + } else if (!JS::Construct(cx, constructor, JS::HandleValueArray::empty(), &object)) { return nullptr; } diff --git a/gi/gobject.h b/gi/gobject.h index b156c3ccd..f336fd604 100644 --- a/gi/gobject.h +++ b/gi/gobject.h @@ -5,6 +5,8 @@ #ifndef GI_GOBJECT_H_ #define GI_GOBJECT_H_ +#include + #include #include diff --git a/gi/gtype.cpp b/gi/gtype.cpp index ec4c354c7..1cc024217 100644 --- a/gi/gtype.cpp +++ b/gi/gtype.cpp @@ -8,11 +8,9 @@ #include #include -#include // for SystemAllocPolicy #include #include #include // for WeakCache -#include // for DefaultHasher via WeakCache #include #include // for JSPROP_PERMANENT #include diff --git a/gi/interface.cpp b/gi/interface.cpp index f3b5ef197..82fc13907 100644 --- a/gi/interface.cpp +++ b/gi/interface.cpp @@ -9,6 +9,7 @@ #include #include // for JS_ReportOutOfMemory +#include // for MutableHandleIdVector #include // for PropertyKey, jsid #include #include // for UniqueChars @@ -34,18 +35,20 @@ InterfacePrototype::~InterfacePrototype(void) { GJS_DEC_COUNTER(interface); } -static bool append_inferface_properties(JSContext* cx, - JS::MutableHandleIdVector properties, - GIInterfaceInfo* iface_info) { - int n_methods = g_interface_info_get_n_methods(iface_info); +bool InterfacePrototype::new_enumerate_impl( + JSContext* cx, JS::HandleObject, JS::MutableHandleIdVector properties, + bool only_enumerable [[maybe_unused]]) { + if (!info()) + return true; + + int n_methods = g_interface_info_get_n_methods(info()); if (!properties.reserve(properties.length() + n_methods)) { JS_ReportOutOfMemory(cx); return false; } for (int i = 0; i < n_methods; i++) { - GjsAutoFunctionInfo meth_info = - g_interface_info_get_method(iface_info, i); + GjsAutoFunctionInfo meth_info = g_interface_info_get_method(info(), i); GIFunctionInfoFlags flags = g_function_info_get_flags(meth_info); if (flags & GI_FUNCTION_IS_METHOD) { @@ -60,31 +63,6 @@ static bool append_inferface_properties(JSContext* cx, return true; } -bool InterfacePrototype::new_enumerate_impl( - JSContext* cx, JS::HandleObject obj [[maybe_unused]], - JS::MutableHandleIdVector properties, - bool only_enumerable [[maybe_unused]]) { - unsigned n_interfaces; - GjsAutoPointer interfaces = - g_type_interfaces(gtype(), &n_interfaces); - - for (unsigned k = 0; k < n_interfaces; k++) { - GjsAutoInterfaceInfo iface_info = - g_irepository_find_by_gtype(nullptr, interfaces[k]); - - if (!iface_info) - continue; - - if (!append_inferface_properties(cx, properties, iface_info)) - return false; - } - - if (!info()) - return true; - - return append_inferface_properties(cx, properties, info()); -} - // See GIWrapperBase::resolve(). bool InterfacePrototype::resolve_impl(JSContext* context, JS::HandleObject obj, JS::HandleId id, bool* resolved) { @@ -194,25 +172,18 @@ gjs_lookup_interface_constructor(JSContext *context, JS::MutableHandleValue value_p) { JSObject *constructor; - GIBaseInfo *interface_info; - - interface_info = g_irepository_find_by_gtype(nullptr, gtype); + GjsAutoInterfaceInfo interface_info = gjs_lookup_gtype(nullptr, gtype); if (!interface_info) { gjs_throw(context, "Cannot expose non introspectable interface %s", g_type_name(gtype)); return false; } - g_assert(g_base_info_get_type(interface_info) == - GI_INFO_TYPE_INTERFACE); - constructor = gjs_lookup_generic_constructor(context, interface_info); if (G_UNLIKELY(!constructor)) return false; - g_base_info_unref(interface_info); - value_p.setObject(*constructor); return true; } diff --git a/gi/js-value-inl.h b/gi/js-value-inl.h index 3d785b598..11533be90 100644 --- a/gi/js-value-inl.h +++ b/gi/js-value-inl.h @@ -10,6 +10,7 @@ #include // for isnan #include +#include #include #include @@ -20,6 +21,7 @@ #include #include #include // for UniqueChars +#include // for CanonicalizeNaN #include "gi/gtype.h" #include "gi/value.h" @@ -229,7 +231,7 @@ template return std::numeric_limits::lowest(); } -template +template GJS_JSAPI_RETURN_CONVENTION inline bool js_value_to_c_checked( JSContext* cx, const JS::HandleValue& value, T* out, bool* out_of_range) { static_assert(std::numeric_limits::max() >= @@ -266,7 +268,7 @@ GJS_JSAPI_RETURN_CONVENTION inline bool js_value_to_c_checked( } if constexpr (std::is_same_v) - return js_value_to_c(cx, value, out); + return js_value_to_c(cx, value, out); // JS::ToIntNN() converts undefined, NaN, infinity to 0 if constexpr (std::is_integral_v) { @@ -278,7 +280,7 @@ GJS_JSAPI_RETURN_CONVENTION inline bool js_value_to_c_checked( } if constexpr (std::is_arithmetic_v) { - bool ret = js_value_to_c(cx, value, out); + bool ret = js_value_to_c(cx, value, out); if (out_of_range) { // Infinity and NaN preserved between floating point types if constexpr (std::is_floating_point_v && @@ -300,18 +302,20 @@ GJS_JSAPI_RETURN_CONVENTION inline bool js_value_to_c_checked( *out_of_range |= std::isnan(*out); } return ret; + // https://trac.cppcheck.net/ticket/10731 + // cppcheck-suppress missingReturn } } -template +template GJS_JSAPI_RETURN_CONVENTION inline bool js_value_to_c_checked( JSContext* cx, const JS::HandleValue& value, TypeWrapper* out, bool* out_of_range) { static_assert(std::is_integral_v); WantedType wanted_out; - if (!js_value_to_c_checked(cx, value, &wanted_out, - out_of_range)) + if (!js_value_to_c_checked(cx, value, &wanted_out, + out_of_range)) return false; *out = TypeWrapper{wanted_out}; @@ -319,4 +323,61 @@ GJS_JSAPI_RETURN_CONVENTION inline bool js_value_to_c_checked( return true; } +template +GJS_JSAPI_RETURN_CONVENTION inline bool c_value_to_js( + JSContext* cx [[maybe_unused]], T value, + JS::MutableHandleValue js_value_p) { + if constexpr (std::is_same_v) { + js_value_p.setBoolean(value); + return true; + } else if constexpr (std::is_same_v< // NOLINT(readability/braces) + T, gboolean> && + TAG == GI_TYPE_TAG_BOOLEAN) { + js_value_p.setBoolean(value); + return true; + } else if constexpr (std::is_arithmetic_v) { + if constexpr (std::is_same_v || + std::is_same_v) { + if (value < Gjs::min_safe_big_number() || + value > Gjs::max_safe_big_number()) { + js_value_p.setDouble(value); + return true; + } + } + if constexpr (std::is_floating_point_v) { + js_value_p.setDouble(JS::CanonicalizeNaN(double{value})); + return true; + } + js_value_p.setNumber(value); + return true; + } else if constexpr (std::is_same_v || + std::is_same_v) { + if (!value) { + js_value_p.setNull(); + return true; + } + return gjs_string_from_utf8(cx, value, js_value_p); + } else { + static_assert(std::is_arithmetic_v, "Unsupported type"); + } +} + +template +GJS_JSAPI_RETURN_CONVENTION inline bool c_value_to_js_checked( + JSContext* cx [[maybe_unused]], T value, + JS::MutableHandleValue js_value_p) { + if constexpr (std::is_same_v || std::is_same_v) { + if (value < Gjs::min_safe_big_number() || + value > Gjs::max_safe_big_number()) { + g_warning( + "Value %s cannot be safely stored in a JS Number " + "and may be rounded", + std::to_string(value).c_str()); + } + } + + return c_value_to_js(cx, value, js_value_p); +} + } // namespace Gjs diff --git a/gi/ns.cpp b/gi/ns.cpp index d39ff13d1..e3f09e10e 100644 --- a/gi/ns.cpp +++ b/gi/ns.cpp @@ -4,6 +4,10 @@ #include +#include + +#include + #include #include @@ -11,6 +15,7 @@ #include #include #include // for JS_ReportOutOfMemory +#include // for MutableHandleIdVector #include #include // for JSPROP_READONLY #include @@ -30,6 +35,10 @@ #include "cjs/mem-private.h" #include "util/log.h" +#if GLIB_CHECK_VERSION(2, 79, 2) +# include "cjs/deprecation.h" +#endif // GLib >= 2.79.2 + [[nodiscard]] static bool type_is_enumerable(GIInfoType info_type) { switch (info_type) { case GI_INFO_TYPE_BOXED: @@ -64,16 +73,51 @@ class Ns : private GjsAutoChar, public CWrapper { friend CWrapperPointerOps; friend CWrapper; +#if GLIB_CHECK_VERSION(2, 79, 2) + bool m_is_gio_or_glib : 1; +#endif // GLib >= 2.79.2 + static constexpr auto PROTOTYPE_SLOT = GjsGlobalSlot::PROTOTYPE_ns; static constexpr GjsDebugTopic DEBUG_TOPIC = GJS_DEBUG_GNAMESPACE; explicit Ns(const char* ns_name) : GjsAutoChar(const_cast(ns_name), GjsAutoTakeOwnership()) { GJS_INC_COUNTER(ns); +#if GLIB_CHECK_VERSION(2, 79, 2) + m_is_gio_or_glib = + strcmp(ns_name, "Gio") == 0 || strcmp(ns_name, "GLib") == 0; +#endif // GLib >= 2.79.2 } ~Ns() { GJS_DEC_COUNTER(ns); } +#if GLIB_CHECK_VERSION(2, 79, 2) + // helper function + void platform_specific_warning(JSContext* cx, const char* prefix, + const char* platform, + const char* resolved_name, + const char** exceptions = nullptr) { + if (!g_str_has_prefix(resolved_name, prefix)) + return; + + const char* base_name = resolved_name + strlen(prefix); + GjsAutoChar old_name = + g_strdup_printf("%s.%s", this->get(), resolved_name); + if (exceptions) { + for (const char** exception = exceptions; *exception; exception++) { + if (strcmp(old_name, *exception) == 0) + return; + } + } + + GjsAutoChar new_name = + g_strdup_printf("%s%s.%s", this->get(), platform, base_name); + _gjs_warn_deprecated_once_per_callsite( + cx, GjsDeprecationMessageId::PlatformSpecificTypelib, + {old_name.get(), new_name.get()}); + } +#endif // GLib >= 2.79.2 + // JSClass operations // The *resolved out parameter, on success, should be false to indicate that @@ -112,6 +156,24 @@ class Ns : private GjsAutoChar, public CWrapper { "Found info type %s for '%s' in namespace '%s'", gjs_info_type_name(info.type()), info.name(), info.ns()); +#if GLIB_CHECK_VERSION(2, 79, 2) + static const char* unix_types_exceptions[] = { + "Gio.UnixConnection", + "Gio.UnixCredentialsMessage", + "Gio.UnixFDList", + "Gio.UnixSocketAddress", + "Gio.UnixSocketAddressType", + nullptr}; + + if (m_is_gio_or_glib) { + platform_specific_warning(cx, "Unix", "Unix", name.get(), + unix_types_exceptions); + platform_specific_warning(cx, "unix_", "Unix", name.get()); + platform_specific_warning(cx, "Win32", "Win32", name.get()); + platform_specific_warning(cx, "win32_", "Win32", name.get()); + } +#endif // GLib >= 2.79.2 + bool defined; if (!gjs_define_info(cx, obj, info, &defined)) { gjs_debug(GJS_DEBUG_GNAMESPACE, "Failed to define info '%s'", diff --git a/gi/ns.h b/gi/ns.h index c7071a163..dd28641df 100644 --- a/gi/ns.h +++ b/gi/ns.h @@ -5,6 +5,8 @@ #ifndef GI_NS_H_ #define GI_NS_H_ +#include + #include "cjs/macros.h" class JSObject; diff --git a/gi/object.cpp b/gi/object.cpp index 7008b1442..0384b738e 100644 --- a/gi/object.cpp +++ b/gi/object.cpp @@ -49,7 +49,7 @@ #include "gi/closure.h" #include "gi/cwrapper.h" #include "gi/function.h" -#include "gi/gjs_gi_trace.h" +#include "gi/cjs_gi_trace.h" #include "gi/object.h" #include "gi/repo.h" #include "gi/toggle.h" @@ -92,8 +92,8 @@ decltype(ObjectInstance::s_wrapped_gobject_list) static const auto DISPOSED_OBJECT = std::numeric_limits::max(); GJS_JSAPI_RETURN_CONVENTION -static JSObject* gjs_lookup_object_prototype_from_info(JSContext*, - GIObjectInfo*, GType); +static JSObject* gjs_lookup_object_prototype_from_info(JSContext*, GIBaseInfo*, + GType); // clang-format off G_DEFINE_QUARK(gjs::custom-type, ObjectBase::custom_type) @@ -114,16 +114,6 @@ bool ObjectBase::is_custom_js_class() { return !!g_type_get_qdata(gtype(), ObjectBase::custom_type_quark()); } -// Plain g_type_query fails and leaves @query uninitialized for dynamic types. -// See https://gitlab.gnome.org/GNOME/glib/issues/623 -void ObjectBase::type_query_dynamic_safe(GTypeQuery* query) { - GType type = gtype(); - while (g_type_get_qdata(type, ObjectBase::custom_type_quark())) - type = g_type_parent(type); - - g_type_query(type, query); -} - void ObjectInstance::link() { g_assert(std::find(s_wrapped_gobject_list.begin(), s_wrapped_gobject_list.end(), @@ -242,32 +232,24 @@ ObjectInstance::unset_object_qdata(void) g_object_steal_qdata(m_ptr, priv_quark); } -GParamSpec* ObjectPrototype::find_param_spec_from_id(JSContext* cx, - JS::HandleString key) { +GParamSpec* ObjectPrototype::find_param_spec_from_id( + JSContext* cx, GjsAutoTypeClass const& object_class, + JS::HandleString key) { /* First check for the ID in the cache */ - auto entry = m_property_cache.lookupForAdd(key); - if (entry) - return entry->value(); JS::UniqueChars js_prop_name(JS_EncodeStringToUTF8(cx, key)); if (!js_prop_name) return nullptr; GjsAutoChar gname = gjs_hyphen_from_camel(js_prop_name.get()); - GjsAutoTypeClass gobj_class(m_gtype); - GParamSpec* pspec = g_object_class_find_property(gobj_class, gname); - GjsAutoParam param_spec(pspec, GjsAutoTakeOwnership()); + GParamSpec* pspec = g_object_class_find_property(object_class, gname); - if (!param_spec) { + if (!pspec) { gjs_wrapper_throw_nonexistent_field(cx, m_gtype, js_prop_name.get()); return nullptr; } - if (!m_property_cache.add(entry, key, std::move(param_spec))) { - JS_ReportOutOfMemory(cx); - return nullptr; - } - return pspec; /* owned by property cache */ + return pspec; } /* A hook on adding a property to an object. This is called during a set @@ -298,52 +280,41 @@ bool ObjectInstance::add_property_impl(JSContext* cx, JS::HandleObject obj, if (is_custom_js_class()) return true; - if (!ensure_uses_toggle_ref(cx)) { - gjs_throw(cx, "Impossible to set toggle references on %sobject %p", - m_gobj_disposed ? "disposed " : "", m_ptr.get()); - return false; - } - + ensure_uses_toggle_ref(cx); return true; } bool ObjectBase::prop_getter(JSContext* cx, unsigned argc, JS::Value* vp) { GJS_CHECK_WRAPPER_PRIV(cx, argc, vp, args, obj, ObjectBase, priv); - JS::RootedString name(cx, - gjs_dynamic_property_private_slot(&args.callee()).toString()); + auto* pspec = static_cast( + gjs_dynamic_property_private_slot(&args.callee()).toPrivate()); - std::string fullName{priv->format_name() + "[" + gjs_debug_string(name) + - "]"}; + std::string fullName{priv->format_name() + "[\"" + pspec->name + "\"]"}; AutoProfilerLabel label(cx, "property getter", fullName.c_str()); - priv->debug_jsprop("Property getter", name, obj); + priv->debug_jsprop("Property getter", pspec->name, obj); if (priv->is_prototype()) return true; /* Ignore silently; note that this is different from what we do for * boxed types, for historical reasons */ - return priv->to_instance()->prop_getter_impl(cx, name, args.rval()); + return priv->to_instance()->prop_getter_impl(cx, pspec, args.rval()); } -bool ObjectInstance::prop_getter_impl(JSContext* cx, JS::HandleString name, +bool ObjectInstance::prop_getter_impl(JSContext* cx, GParamSpec* param, JS::MutableHandleValue rval) { if (!check_gobject_finalized("get any property from")) { rval.setUndefined(); return true; } - ObjectPrototype* proto_priv = get_prototype(); - GParamSpec *param = proto_priv->find_param_spec_from_id(cx, name); - - /* This is guaranteed because we resolved the property before */ - g_assert(param); - - /* Do not fetch JS overridden properties from GObject, to avoid - * infinite recursion. */ - if (g_param_spec_get_qdata(param, ObjectBase::custom_property_quark())) - return true; + if (param->flags & G_PARAM_DEPRECATED) { + const std::string& class_name = format_name(); + _gjs_warn_deprecated_once_per_callsite( + cx, DeprecatedGObjectProperty, {class_name.c_str(), param->name}); + } if ((param->flags & G_PARAM_READABLE) == 0) { rval.setUndefined(); @@ -384,7 +355,8 @@ bool ObjectBase::field_getter(JSContext* cx, unsigned argc, JS::Value* vp) { JS::RootedString name(cx, gjs_dynamic_property_private_slot(&args.callee()).toString()); - std::string fullName = priv->format_name() + "." + gjs_debug_string(name); + std::string fullName{priv->format_name() + "[" + gjs_debug_string(name) + + "]"}; AutoProfilerLabel label(cx, "field getter", fullName.c_str()); priv->debug_jsprop("Field getter", name, obj); @@ -437,8 +409,8 @@ bool ObjectInstance::field_getter_impl(JSContext* cx, JS::HandleString name, return false; } - return gjs_value_from_g_argument(cx, rval, type, GJS_ARGUMENT_FIELD, - GI_TRANSFER_EVERYTHING, &arg); + return gjs_value_from_gi_argument(cx, rval, type, GJS_ARGUMENT_FIELD, + GI_TRANSFER_EVERYTHING, &arg); /* transfer is irrelevant because g_field_info_get_field() doesn't * handle boxed types */ } @@ -448,14 +420,13 @@ bool ObjectInstance::field_getter_impl(JSContext* cx, JS::HandleString name, bool ObjectBase::prop_setter(JSContext* cx, unsigned argc, JS::Value* vp) { GJS_CHECK_WRAPPER_PRIV(cx, argc, vp, args, obj, ObjectBase, priv); - JS::RootedString name(cx, - gjs_dynamic_property_private_slot(&args.callee()).toString()); + auto* pspec = static_cast( + gjs_dynamic_property_private_slot(&args.callee()).toPrivate()); - std::string fullName{priv->format_name() + "[" + gjs_debug_string(name) + - "]"}; + std::string fullName{priv->format_name() + "[\"" + pspec->name + "\"]"}; AutoProfilerLabel label(cx, "property setter", fullName.c_str()); - priv->debug_jsprop("Property setter", name, obj); + priv->debug_jsprop("Property setter", pspec->name, obj); if (priv->is_prototype()) return true; @@ -465,24 +436,14 @@ bool ObjectBase::prop_setter(JSContext* cx, unsigned argc, JS::Value* vp) { /* Clear the JS stored value, to avoid keeping additional references */ args.rval().setUndefined(); - return priv->to_instance()->prop_setter_impl(cx, name, args[0]); + return priv->to_instance()->prop_setter_impl(cx, pspec, args[0]); } -bool ObjectInstance::prop_setter_impl(JSContext* cx, JS::HandleString name, +bool ObjectInstance::prop_setter_impl(JSContext* cx, GParamSpec* param_spec, JS::HandleValue value) { if (!check_gobject_finalized("set any property on")) return true; - ObjectPrototype* proto_priv = get_prototype(); - GParamSpec *param_spec = proto_priv->find_param_spec_from_id(cx, name); - if (!param_spec) - return false; - - /* Do not set JS overridden properties through GObject, to avoid - * infinite recursion (unless constructing) */ - if (g_param_spec_get_qdata(param_spec, ObjectBase::custom_property_quark())) - return true; - if (!(param_spec->flags & G_PARAM_WRITABLE)) /* prevent setting the prop even in JS */ return gjs_wrapper_throw_readonly_field(cx, gtype(), param_spec->name); @@ -622,11 +583,9 @@ static void canonicalize_key(const GjsAutoChar& key) { return !!prop_info; } -bool ObjectPrototype::lazy_define_gobject_property(JSContext* cx, - JS::HandleObject obj, - JS::HandleId id, - bool* resolved, - const char* name) { +bool ObjectPrototype::lazy_define_gobject_property( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, GParamSpec* pspec, + bool* resolved, const char* name) { bool found = false; if (!JS_AlreadyHasOwnPropertyById(cx, obj, id, &found)) return false; @@ -639,10 +598,17 @@ bool ObjectPrototype::lazy_define_gobject_property(JSContext* cx, debug_jsprop("Defining lazy GObject property", id, obj); - JS::RootedValue private_id(cx, JS::StringValue(id.toString())); + // Do not fetch JS overridden properties from GObject, to avoid + // infinite recursion. + if (g_param_spec_get_qdata(pspec, ObjectBase::custom_property_quark())) { + *resolved = false; + return true; + } + + JS::RootedValue private_value{cx, JS::PrivateValue(pspec)}; if (!gjs_define_property_dynamic( - cx, obj, name, "gobject_prop", &ObjectBase::prop_getter, - &ObjectBase::prop_setter, private_id, + cx, obj, name, id, "gobject_prop", &ObjectBase::prop_getter, + &ObjectBase::prop_setter, private_value, // Make property configurable so that interface properties can be // overridden by GObject.ParamSpec.override in the class that // implements them @@ -701,8 +667,11 @@ static bool interface_getter(JSContext* cx, unsigned argc, JS::Value* vp) { g_assert(v_prototype.isObject() && "prototype must be an object"); JS::RootedObject prototype(cx, &v_prototype.toObject()); - JS::RootedId id(cx, JS::PropertyKey::NonIntAtom(JS_GetFunctionId( - JS_GetObjectFunction(&args.callee())))); + JS::RootedFunction fn_obj{cx, JS_GetObjectFunction(&args.callee())}; + JS::RootedString fn_name{cx}; + if (!JS_GetFunctionId(cx, fn_obj, &fn_name)) + return false; + JS::RootedId id{cx, JS::PropertyKey::NonIntAtom(fn_name)}; return JS_GetPropertyById(cx, prototype, id, args.rval()); } @@ -731,7 +700,7 @@ static bool interface_setter(JSContext* cx, unsigned argc, JS::Value* vp) { } static bool resolve_on_interface_prototype(JSContext* cx, - GIObjectInfo* iface_info, + GIInterfaceInfo* iface_info, JS::HandleId identifier, JS::HandleObject class_prototype, bool* found) { @@ -832,8 +801,10 @@ bool ObjectPrototype::resolve_no_info(JSContext* cx, JS::HandleObject obj, if (canonical_name && G_TYPE_IS_CLASSED(m_gtype) && !is_custom_js_class()) { GjsAutoTypeClass oclass(m_gtype); - if (g_object_class_find_property(oclass, canonical_name)) - return lazy_define_gobject_property(cx, obj, id, resolved, name); + if (GParamSpec* pspec = + g_object_class_find_property(oclass, canonical_name)) + return lazy_define_gobject_property(cx, obj, id, pspec, resolved, + name); for (i = 0; i < n_interfaces; i++) { GType iface_gtype = @@ -843,8 +814,10 @@ bool ObjectPrototype::resolve_no_info(JSContext* cx, JS::HandleObject obj, GjsAutoTypeClass iclass(iface_gtype); - if (g_object_class_find_property(iclass, canonical_name)) - return lazy_define_gobject_property(cx, obj, id, resolved, name); + if (GParamSpec* pspec = + g_object_class_find_property(iclass, canonical_name)) + return lazy_define_gobject_property(cx, obj, id, pspec, + resolved, name); } } @@ -880,8 +853,8 @@ bool ObjectPrototype::resolve_no_info(JSContext* cx, JS::HandleObject obj, GParamSpec* pspec = g_object_class_find_property( oclass, canonical_name); // unowned if (pspec && pspec->owner_type == m_gtype) { - return lazy_define_gobject_property(cx, obj, id, resolved, - name); + return lazy_define_gobject_property(cx, obj, id, pspec, + resolved, name); } } @@ -893,11 +866,11 @@ bool ObjectPrototype::resolve_no_info(JSContext* cx, JS::HandleObject obj, return true; } -[[nodiscard]] static bool is_gobject_property_name(GIObjectInfo* info, - const char* name) { +[[nodiscard]] static GjsAutoChar get_gobject_property_name(GIObjectInfo* info, + const char* name) { // Optimization: GObject property names must start with a letter if (!g_ascii_isalpha(name[0])) - return false; + return nullptr; int n_props = g_object_info_get_n_properties(info); int n_ifaces = g_object_info_get_n_interfaces(info); @@ -909,15 +882,15 @@ bool ObjectPrototype::resolve_no_info(JSContext* cx, JS::HandleObject obj, for (ix = 0; ix < n_props; ix++) { GjsAutoPropertyInfo prop_info = g_object_info_get_property(info, ix); if (strcmp(canonical_name, prop_info.name()) == 0) - return true; + return canonical_name; } for (ix = 0; ix < n_ifaces; ix++) { GjsAutoInterfaceInfo iface_info = g_object_info_get_interface(info, ix); if (is_ginterface_property_name(iface_info, canonical_name)) - return true; + return canonical_name; } - return false; + return nullptr; } // Override of GIWrapperBase::id_is_never_lazy() @@ -1005,8 +978,13 @@ bool ObjectPrototype::uncached_resolve(JSContext* context, JS::HandleObject obj, * method resolution. */ } - if (is_gobject_property_name(m_info, name)) - return lazy_define_gobject_property(context, obj, id, resolved, name); + if (auto const& canonical_name = get_gobject_property_name(m_info, name)) { + GjsAutoTypeClass gobj_class{m_gtype}; + if (GParamSpec* pspec = + g_object_class_find_property(gobj_class, canonical_name)) + return lazy_define_gobject_property(context, obj, id, pspec, + resolved, name); + } GjsAutoFieldInfo field_info = lookup_field_info(m_info, name); if (field_info) { @@ -1032,8 +1010,9 @@ bool ObjectPrototype::uncached_resolve(JSContext* context, JS::HandleObject obj, JS::RootedValue private_id(context, JS::StringValue(key)); if (!gjs_define_property_dynamic( - context, obj, name, "gobject_field", &ObjectBase::field_getter, - &ObjectBase::field_setter, private_id, flags)) + context, obj, name, id, "gobject_field", + &ObjectBase::field_getter, &ObjectBase::field_setter, + private_id, flags)) return false; *resolved = true; @@ -1190,10 +1169,10 @@ bool ObjectPrototype::new_enumerate_impl(JSContext* cx, JS::HandleObject, /* Set properties from args to constructor (args[0] is supposed to be * a hash) */ -bool ObjectPrototype::props_to_g_parameters(JSContext* context, - JS::HandleObject props, - std::vector* names, - AutoGValueVector* values) { +bool ObjectPrototype::props_to_g_parameters( + JSContext* context, GjsAutoTypeClass const& object_class, + JS::HandleObject props, std::vector* names, + AutoGValueVector* values) { size_t ix, length; JS::RootedId prop_id(context); JS::RootedValue value(context); @@ -1215,7 +1194,8 @@ bool ObjectPrototype::props_to_g_parameters(JSContext* context, context, m_gtype, gjs_debug_id(prop_id).c_str()); JS::RootedString js_prop_name(context, prop_id.toString()); - GParamSpec *param_spec = find_param_spec_from_id(context, js_prop_name); + GParamSpec* param_spec = + find_param_spec_from_id(context, object_class, js_prop_name); if (!param_spec) return false; @@ -1241,7 +1221,7 @@ bool ObjectPrototype::props_to_g_parameters(JSContext* context, if (!gjs_value_to_g_value(context, value, &gvalue)) return false; - names->push_back(param_spec->name); /* owned by GParamSpec in cache */ + names->push_back(param_spec->name); // owned by GParamSpec } return true; @@ -1501,6 +1481,8 @@ void ObjectInstance::wrapped_gobj_toggle_notify(void* instance, GObject*, void ObjectInstance::release_native_object(void) { + static GType gdksurface_type = 0; + discard_wrapper(); if (m_gobj_finalized) { @@ -1519,11 +1501,41 @@ ObjectInstance::release_native_object(void) if (m_gobj_disposed) ignore_gobject_finalization(); - if (m_uses_toggle_ref && !m_gobj_disposed) + if (m_uses_toggle_ref && !m_gobj_disposed) { g_object_remove_toggle_ref(m_ptr.release(), wrapped_gobj_toggle_notify, this); - else - m_ptr = nullptr; + return; + } + + // Unref the object. Handle any special cases for destruction here + if (m_ptr->ref_count == 1) { + // Quickest way to check for GdkSurface if Gdk has been loaded? + // surface_type may be 0 if Gdk not loaded. The type may be a private + // type and not have introspection info. + if (!gdksurface_type) + gdksurface_type = g_type_from_name("GdkSurface"); + if (gdksurface_type && g_type_is_a(gtype(), gdksurface_type)) { + GObject* ptr = m_ptr.release(); + + // Workaround for https://gitlab.gnome.org/GNOME/gtk/-/issues/6289 + GjsAutoObjectInfo surface_info = + g_irepository_find_by_gtype(nullptr, gdksurface_type); + g_assert(surface_info && "Could not find introspected GdkSurface info"); + GjsAutoFunctionInfo destroy_func = + g_object_info_find_method(surface_info, "destroy"); + GIArgument destroy_args; + gjs_arg_set(&destroy_args, ptr); + GIArgument unused_return; + + GjsAutoError err; + if (!g_function_info_invoke(destroy_func, &destroy_args, 1, nullptr, + 0, &unused_return, err.out())) + g_critical("Error destroying GdkSurface %p: %s", ptr, + err->message); + } + } + + m_ptr = nullptr; } /* At shutdown, we need to ensure we've cleared the context of any @@ -1565,7 +1577,7 @@ ObjectInstance::ObjectInstance(ObjectPrototype* prototype, m_gobj_finalized(false), m_uses_toggle_ref(false) { GTypeQuery query; - type_query_dynamic_safe(&query); + g_type_query(gtype(), &query); if (G_LIKELY(query.type)) JS::AddAssociatedMemory(object, query.instance_size, MemoryUse::GObjectInstanceStruct); @@ -1668,12 +1680,12 @@ ObjectInstance::associate_js_gobject(JSContext *context, g_object_weak_ref(gobj, wrapped_gobj_dispose_notify, this); } -bool ObjectInstance::ensure_uses_toggle_ref(JSContext* cx) { +void ObjectInstance::ensure_uses_toggle_ref(JSContext* cx) { if (m_uses_toggle_ref) - return true; + return; if (!check_gobject_disposed_or_finalized("add toggle reference on")) - return true; + return; debug_lifecycle("Switching object instance to toggle ref"); @@ -1698,8 +1710,6 @@ bool ObjectInstance::ensure_uses_toggle_ref(JSContext* cx) { * This may immediately remove the GC root we just added, since refcount * may drop to 1. */ g_object_unref(m_ptr); - - return true; } static void invalidate_closure_vector(std::vector* closures, @@ -1730,8 +1740,8 @@ ObjectInstance::disassociate_js_gobject(void) { bool had_toggle_down, had_toggle_up; - auto locked_queue = ToggleQueue::get_default(); - std::tie(had_toggle_down, had_toggle_up) = locked_queue->cancel(this); + std::tie(had_toggle_down, had_toggle_up) = + ToggleQueue::get_default()->cancel(this); if (had_toggle_up && !had_toggle_down) { g_error( "JS object wrapper for GObject %p (%s) is being released while " @@ -1766,20 +1776,30 @@ bool ObjectInstance::init_impl(JSContext* context, const JS::CallArgs& args, name(), args.length())) return false; + GjsAutoTypeClass object_class(gtype()); std::vector names; AutoGValueVector values; if (args.length() > 0 && !args[0].isUndefined()) { if (!args[0].isObject()) { gjs_throw(context, - "Argument to the constructor of %s should be an object " - "with properties to set", + "Argument to the constructor of %s should be a plain JS " + "object with properties to set", name()); return false; } JS::RootedObject props(context, &args[0].toObject()); - if (!m_proto->props_to_g_parameters(context, props, &names, &values)) + if (ObjectInstance::typecheck(context, props, nullptr, G_TYPE_NONE, + GjsTypecheckNoThrow{})) { + gjs_throw(context, + "Argument to the constructor of %s should be a plain JS " + "object with properties to set", + name()); + return false; + } + if (!m_proto->props_to_g_parameters(context, object_class, props, + &names, &values)) return false; } @@ -1822,17 +1842,11 @@ bool ObjectInstance::init_impl(JSContext* context, const JS::CallArgs& args, * */ bool toggle_ref_added = false; if (!m_uses_toggle_ref) { - if (!other_priv->ensure_uses_toggle_ref(context)) { - gjs_throw(context, - "Impossible to set toggle references on %sobject %p", - other_priv->m_gobj_disposed ? "disposed " : "", gobj); - return false; - } - + other_priv->ensure_uses_toggle_ref(context); toggle_ref_added = m_uses_toggle_ref; } - args.rval().setObject(*other_priv->m_wrapper); + args.rval().setObject(*other_priv->m_wrapper.get()); if (toggle_ref_added) g_clear_object(&gobj); /* We already own a reference */ @@ -1897,7 +1911,6 @@ void ObjectInstance::trace_impl(JSTracer* tracer) { } void ObjectPrototype::trace_impl(JSTracer* tracer) { - m_property_cache.trace(tracer); m_field_cache.trace(tracer); m_unresolvable_cache.trace(tracer); for (GClosure* closure : m_vfuncs) @@ -1906,7 +1919,7 @@ void ObjectPrototype::trace_impl(JSTracer* tracer) { void ObjectInstance::finalize_impl(JS::GCContext* gcx, JSObject* obj) { GTypeQuery query; - type_query_dynamic_safe(&query); + g_type_query(gtype(), &query); if (G_LIKELY(query.type)) JS::RemoveAssociatedMemory(obj, query.instance_size, MemoryUse::GObjectInstanceStruct); @@ -1978,15 +1991,18 @@ ObjectPrototype::~ObjectPrototype() { GJS_DEC_COUNTER(object_prototype); } -JSObject* gjs_lookup_object_constructor_from_info(JSContext* context, - GIObjectInfo* info, - GType gtype) { +static JSObject* gjs_lookup_object_constructor_from_info(JSContext* context, + GIBaseInfo* info, + GType gtype) { + g_return_val_if_fail( + !info || GI_IS_OBJECT_INFO(info) || GI_IS_INTERFACE_INFO(info), NULL); + JS::RootedObject in_object(context); const char *constructor_name; if (info) { - in_object = gjs_lookup_namespace_object(context, (GIBaseInfo*) info); - constructor_name = g_base_info_get_name((GIBaseInfo*) info); + in_object = gjs_lookup_namespace_object(context, info); + constructor_name = g_base_info_get_name(info); } else { in_object = gjs_lookup_private_namespace(context); constructor_name = g_type_name(gtype); @@ -2025,11 +2041,12 @@ JSObject* gjs_lookup_object_constructor_from_info(JSContext* context, } GJS_JSAPI_RETURN_CONVENTION -static JSObject * -gjs_lookup_object_prototype_from_info(JSContext *context, - GIObjectInfo *info, - GType gtype) -{ +static JSObject* gjs_lookup_object_prototype_from_info(JSContext* context, + GIBaseInfo* info, + GType gtype) { + g_return_val_if_fail( + !info || GI_IS_OBJECT_INFO(info) || GI_IS_INTERFACE_INFO(info), NULL); + JS::RootedObject constructor(context, gjs_lookup_object_constructor_from_info(context, info, gtype)); @@ -2050,7 +2067,7 @@ static JSObject * gjs_lookup_object_prototype(JSContext *context, GType gtype) { - GjsAutoObjectInfo info = g_irepository_find_by_gtype(nullptr, gtype); + GjsAutoObjectInfo info = gjs_lookup_gtype(nullptr, gtype); return gjs_lookup_object_prototype_from_info(context, info, gtype); } @@ -2100,13 +2117,8 @@ GIFieldInfo* ObjectPrototype::lookup_cached_field_info(JSContext* cx, } bool ObjectInstance::associate_closure(JSContext* cx, GClosure* closure) { - if (!is_prototype()) { - if (!to_instance()->ensure_uses_toggle_ref(cx)) { - gjs_throw(cx, "Impossible to set toggle references on %sobject %p", - m_gobj_disposed ? "disposed " : "", to_instance()->ptr()); - return false; - } - } + if (!is_prototype()) + to_instance()->ensure_uses_toggle_ref(cx); g_assert(std::find(m_closures.begin(), m_closures.end(), closure) == m_closures.end() && @@ -2148,14 +2160,22 @@ bool ObjectBase::connect_after(JSContext* cx, unsigned argc, JS::Value* vp) { return priv->to_instance()->connect_impl(cx, args, true); } -bool -ObjectInstance::connect_impl(JSContext *context, - const JS::CallArgs& args, - bool after) -{ +bool ObjectBase::connect_object(JSContext* cx, unsigned argc, JS::Value* vp) { + GJS_CHECK_WRAPPER_PRIV(cx, argc, vp, args, obj, ObjectBase, priv); + if (!priv->check_is_instance(cx, "connect to signals")) + return false; + + return priv->to_instance()->connect_impl(cx, args, false, true); +} + +bool ObjectInstance::connect_impl(JSContext* context, const JS::CallArgs& args, + bool after, bool object) { gulong id; guint signal_id; GQuark signal_detail; + const char* func_name = object ? "connect_object" + : after ? "connect_after" + : "connect"; gjs_debug_gsignal("connect obj %p priv %p", m_wrapper.get(), this); @@ -2166,14 +2186,29 @@ ObjectInstance::connect_impl(JSContext *context, JS::UniqueChars signal_name; JS::RootedObject callback(context); - if (!gjs_parse_call_args(context, after ? "connect_after" : "connect", args, "so", - "signal name", &signal_name, - "callback", &callback)) - return false; + JS::RootedObject associate_obj(context); + GConnectFlags flags; + if (object) { + if (!gjs_parse_call_args(context, func_name, args, "sooi", + "signal name", &signal_name, "callback", + &callback, "gobject", &associate_obj, + "connect_flags", &flags)) + return false; - std::string dynamicString = format_name() + '.' + - (after ? "connect_after" : "connect") + "('" + - signal_name.get() + "')"; + if (flags & G_CONNECT_SWAPPED) { + gjs_throw(context, "Unsupported connect flag G_CONNECT_SWAPPED"); + return false; + } + + after = flags & G_CONNECT_AFTER; + } else { + if (!gjs_parse_call_args(context, func_name, args, "so", "signal name", + &signal_name, "callback", &callback)) + return false; + } + + std::string dynamicString = + format_name() + '.' + func_name + "('" + signal_name.get() + "')"; AutoProfilerLabel label(context, "", dynamicString.c_str()); if (!JS::IsCallable(callback)) { @@ -2192,8 +2227,17 @@ ObjectInstance::connect_impl(JSContext *context, context, callback, "signal callback", signal_id); if (closure == NULL) return false; - if (!associate_closure(context, closure)) + + if (associate_obj.get() != nullptr) { + ObjectInstance* obj = ObjectInstance::for_js(context, associate_obj); + if (!obj) + return false; + + if (!obj->associate_closure(context, closure)) + return false; + } else if (!associate_closure(context, closure)) { return false; + } id = g_signal_connect_closure_by_id(m_ptr, signal_id, signal_detail, closure, after); @@ -2255,6 +2299,7 @@ ObjectInstance::emit_impl(JSContext *context, AutoGValueVector instance_and_args; instance_and_args.reserve(signal_query.n_params + 1); + std::vector args_to_steal; Gjs::AutoGValue& instance = instance_and_args.emplace_back(gtype()); g_value_set_instance(&instance, m_ptr); @@ -2268,12 +2313,31 @@ ObjectInstance::emit_impl(JSContext *context, if (!gjs_value_to_g_value(context, argv[i + 1], &value)) return false; } + + if (!ObjectBase::info()) + continue; + + GjsAutoSignalInfo signal_info = g_object_info_find_signal( + ObjectBase::info(), signal_query.signal_name); + if (!signal_info) + continue; + + GjsAutoArgInfo arg_info = g_callable_info_get_arg(signal_info, i); + if (g_arg_info_get_ownership_transfer(arg_info) != + GI_TRANSFER_NOTHING) { + // FIXME(3v1n0): As it happens in many places in gjs, we can't track + // (yet) containers content, so in case of transfer container we + // can only leak. + args_to_steal.push_back(&value); + } } if (signal_query.return_type == G_TYPE_NONE) { g_signal_emitv(instance_and_args.data(), signal_id, signal_detail, nullptr); argv.rval().setUndefined(); + std::for_each(args_to_steal.begin(), args_to_steal.end(), + [](Gjs::AutoGValue* value) { value->steal(); }); return true; } @@ -2281,6 +2345,9 @@ ObjectInstance::emit_impl(JSContext *context, Gjs::AutoGValue rvalue(gtype); g_signal_emitv(instance_and_args.data(), signal_id, signal_detail, &rvalue); + std::for_each(args_to_steal.begin(), args_to_steal.end(), + [](Gjs::AutoGValue* value) { value->steal(); }); + return gjs_value_from_g_value(context, argv.rval(), &rvalue); } @@ -2555,6 +2622,7 @@ JSFunctionSpec ObjectBase::proto_methods[] = { JS_FN("_init", &ObjectBase::init_gobject, 0, 0), JS_FN("connect", &ObjectBase::connect, 0, 0), JS_FN("connect_after", &ObjectBase::connect_after, 0, 0), + JS_FN("connect_object", &ObjectBase::connect_object, 0, 0), JS_FN("emit", &ObjectBase::emit, 0, 0), JS_FS_END }; @@ -2682,7 +2750,8 @@ bool ObjectInstance::init_custom_class_from_gobject(JSContext* cx, // Custom JS objects will most likely have visible state, so just do this // from the start. - if (!ensure_uses_toggle_ref(cx) || !m_uses_toggle_ref) { + ensure_uses_toggle_ref(cx); + if (!m_uses_toggle_ref) { gjs_throw(cx, "Impossible to set toggle references on %sobject %p", m_gobj_disposed ? "disposed " : "", gobj); return false; @@ -2971,7 +3040,7 @@ bool ObjectPrototype::hook_up_vfunc_impl(JSContext* cx, // case, print a more helpful error than... // "Could not find definition of virtual function" // - // See https://gitlab.gnome.org/GNOME/gjs/-/issues/89 + // See https://gitlab.gnome.org/GNOME/cjs/-/issues/89 if (!vfunc) { unsigned n_interfaces; GjsAutoPointer interface_list = @@ -3058,7 +3127,7 @@ gjs_lookup_object_constructor(JSContext *context, { JSObject *constructor; - GjsAutoObjectInfo object_info = g_irepository_find_by_gtype(nullptr, gtype); + GjsAutoObjectInfo object_info = gjs_lookup_gtype(nullptr, gtype); constructor = gjs_lookup_object_constructor_from_info(context, object_info, gtype); diff --git a/gi/object.h b/gi/object.h index 3276d3364..fdbb6f66c 100644 --- a/gi/object.h +++ b/gi/object.h @@ -104,8 +104,6 @@ class ObjectBase [[nodiscard]] bool is_custom_js_class(); public: - void type_query_dynamic_safe(GTypeQuery* query); - GJS_JSAPI_RETURN_CONVENTION static bool typecheck(JSContext* cx, JS::HandleObject obj, GIObjectInfo* expected_info, GType expected_gtype); @@ -141,6 +139,8 @@ class ObjectBase GJS_JSAPI_RETURN_CONVENTION static bool connect_after(JSContext* cx, unsigned argc, JS::Value* vp); GJS_JSAPI_RETURN_CONVENTION + static bool connect_object(JSContext* cx, unsigned argc, JS::Value* vp); + GJS_JSAPI_RETURN_CONVENTION static bool emit(JSContext* cx, unsigned argc, JS::Value* vp); GJS_JSAPI_RETURN_CONVENTION static bool signal_find(JSContext* cx, unsigned argc, JS::Value* vp); @@ -185,16 +185,12 @@ class ObjectPrototype ObjectInstance>; friend class GIWrapperBase; - using PropertyCache = - JS::GCHashMap, GjsAutoParam, - js::DefaultHasher, js::SystemAllocPolicy>; using FieldCache = - JS::GCHashMap, GjsAutoInfo, + JS::GCHashMap, GjsAutoFieldInfo, js::DefaultHasher, js::SystemAllocPolicy>; using NegativeLookupCache = JS::GCHashSet, IdHasher, js::SystemAllocPolicy>; - PropertyCache m_property_cache; FieldCache m_field_cache; NegativeLookupCache m_unresolvable_cache; // a list of vfunc GClosures installed on this prototype, used when tracing @@ -224,8 +220,8 @@ class ObjectPrototype GJS_JSAPI_RETURN_CONVENTION bool lazy_define_gobject_property(JSContext* cx, JS::HandleObject obj, - JS::HandleId id, bool* resolved, - const char* name); + JS::HandleId id, GParamSpec*, + bool* resolved, const char* name); enum ResolveWhat { ConsiderOnlyMethods, ConsiderMethodsAndProperties }; GJS_JSAPI_RETURN_CONVENTION @@ -240,11 +236,15 @@ class ObjectPrototype void set_interfaces(GType* interface_gtypes, uint32_t n_interface_gtypes); void set_type_qdata(void); GJS_JSAPI_RETURN_CONVENTION - GParamSpec* find_param_spec_from_id(JSContext* cx, JS::HandleString key); + GParamSpec* find_param_spec_from_id(JSContext*, + GjsAutoTypeClass const&, + JS::HandleString key); GJS_JSAPI_RETURN_CONVENTION GIFieldInfo* lookup_cached_field_info(JSContext* cx, JS::HandleString key); GJS_JSAPI_RETURN_CONVENTION - bool props_to_g_parameters(JSContext* cx, JS::HandleObject props, + bool props_to_g_parameters(JSContext*, + GjsAutoTypeClass const&, + JS::HandleObject props, std::vector* names, AutoGValueVector* values); @@ -293,7 +293,7 @@ class ObjectInstance : public GIWrapperInstance m_wrapper; + GjsMaybeOwned m_wrapper; // a list of all GClosures installed on this object (from signal connections // and scope-notify callbacks passed to methods), used when tracing std::vector m_closures; @@ -329,7 +329,7 @@ class ObjectInstance : public GIWrapperInstance #include #include // for JSEXN_TYPEERR -#include // for GetClass +#include // for GetClass #include +#include // for JSPROP_READONLY +#include // for JSPropertySpec, JS_PS_END, JS_STR... #include #include #include // for UniqueChars @@ -148,10 +150,24 @@ static const struct JSClassOps gjs_param_class_ops = { nullptr, // mayResolve param_finalize}; +static JSPropertySpec proto_props[] = { + JS_STRING_SYM_PS(toStringTag, "GObject_ParamSpec", JSPROP_READONLY), + JS_PS_END}; + +static constexpr js::ClassSpec class_spec = { + nullptr, // createConstructor + nullptr, // createPrototype + nullptr, // constructorFunctions + nullptr, // constructorProperties + nullptr, // prototypeFunctions + proto_props, // prototypeProperties + nullptr // finishInit +}; + struct JSClass gjs_param_class = { "GObject_ParamSpec", JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE, - &gjs_param_class_ops}; + &gjs_param_class_ops, &class_spec}; GJS_JSAPI_RETURN_CONVENTION static JSObject* @@ -187,10 +203,10 @@ gjs_define_param_class(JSContext *context, if (!gjs_init_class_dynamic( context, in_object, nullptr, "GObject", "ParamSpec", &gjs_param_class, gjs_param_constructor, 0, - nullptr, // props of prototype - nullptr, // funcs of prototype - nullptr, // props of constructor, MyConstructor.myprop - nullptr, // funcs of constructor + proto_props, // props of prototype + nullptr, // funcs of prototype + nullptr, // props of constructor, MyConstructor.myprop + nullptr, // funcs of constructor &prototype, &constructor)) return false; diff --git a/gi/private.cpp b/gi/private.cpp index 3ad0f76f1..bc896722c 100644 --- a/gi/private.cpp +++ b/gi/private.cpp @@ -10,7 +10,8 @@ #include #include -#include // for JS::GetArrayLength, +#include // for JS::GetArrayLength +#include // for IsCallable #include #include #include @@ -21,6 +22,7 @@ #include #include // for JS_NewPlainObject +#include "gi/closure.h" #include "gi/gobject.h" #include "gi/gtype.h" #include "gi/interface.h" @@ -28,6 +30,7 @@ #include "gi/param.h" #include "gi/private.h" #include "gi/repo.h" +#include "gi/value.h" #include "cjs/atoms.h" #include "cjs/context-private.h" #include "cjs/jsapi-util-args.h" @@ -344,10 +347,11 @@ static bool gjs_register_type_impl(JSContext* cx, const char* name, g_assert(parent_priv); GTypeQuery query; - parent_priv->type_query_dynamic_safe(&query); - if (G_UNLIKELY(query.type == 0)) { - gjs_throw(cx, - "Cannot inherit from a non-gjs dynamic type [bug 687184]"); + g_type_query(parent_priv->gtype(), &query); + + if (G_UNLIKELY( + g_type_test_flags(parent_priv->gtype(), G_TYPE_FLAG_FINAL))) { + gjs_throw(cx, "Cannot inherit from a final type"); return false; } @@ -554,6 +558,37 @@ GJS_JSAPI_RETURN_CONVENTION static bool symbol_getter(JSContext* cx, return true; } +GJS_JSAPI_RETURN_CONVENTION +static bool gjs_associate_closure(JSContext* context, unsigned argc, + JS::Value* vp) { + JS::CallArgs argv = JS::CallArgsFromVp(argc, vp); + JS::RootedObject func_obj(context); + JS::RootedObject target_obj(context); + Gjs::Closure::Ptr closure; + Gjs::AutoGValue value(G_TYPE_CLOSURE); + ObjectInstance* obj; + + if (!gjs_parse_call_args(context, "associateClosure", argv, "oo", "object", + &target_obj, "func", &func_obj)) + return false; + + g_assert(JS::IsCallable(func_obj) && + "associateClosure's function must be callable"); + + obj = ObjectInstance::for_js(context, target_obj); + if (!obj) + return false; + + closure = + Gjs::Closure::create_marshaled(context, func_obj, "wrapped", false); + + if (!obj->associate_closure(context, closure)) + return false; + + g_value_set_boxed(&value, closure); + return gjs_value_from_g_value(context, argv.rval(), &value); +} + static JSFunctionSpec private_module_funcs[] = { JS_FN("override_property", gjs_override_property, 2, GJS_MODULE_PROP_FLAGS), JS_FN("register_interface", gjs_register_interface, 3, @@ -565,6 +600,7 @@ static JSFunctionSpec private_module_funcs[] = { GJS_MODULE_PROP_FLAGS), JS_FN("signal_new", gjs_signal_new, 6, GJS_MODULE_PROP_FLAGS), JS_FN("lookupConstructor", gjs_lookup_constructor, 1, 0), + JS_FN("associateClosure", gjs_associate_closure, 2, GJS_MODULE_PROP_FLAGS), JS_FS_END, }; diff --git a/gi/repo.cpp b/gi/repo.cpp index e346a2969..42403cff1 100644 --- a/gi/repo.cpp +++ b/gi/repo.cpp @@ -106,6 +106,27 @@ static bool resolve_namespace_object(JSContext* context, return false; GjsAutoError error; + // If resolving Gio, load the platform-specific typelib first, so that + // GioUnix/GioWin32 GTypes get looked up in there with higher priority, + // instead of in Gio. +#if GLIB_CHECK_VERSION(2, 79, 2) && (defined(G_OS_UNIX) || defined(G_OS_WIN32)) + if (strcmp(ns_name.get(), "Gio") == 0) { +# ifdef G_OS_UNIX + const char* platform = "Unix"; +# else // G_OS_WIN32 + const char* platform = "Win32"; +# endif // G_OS_UNIX/G_OS_WIN32 + GjsAutoChar platform_specific = + g_strconcat(ns_name.get(), platform, nullptr); + if (!g_irepository_require(nullptr, platform_specific, version.get(), + GIRepositoryLoadFlags(0), &error)) { + gjs_throw(context, "Failed to require %s %s: %s", + platform_specific.get(), version.get(), error->message); + return false; + } + } +#endif // GLib >= 2.79.2 + g_irepository_require(nullptr, ns_name.get(), version.get(), GIRepositoryLoadFlags(0), &error); if (error) { @@ -122,12 +143,10 @@ static bool resolve_namespace_object(JSContext* context, gjs_create_ns(context, ns_name.get())); JS::RootedValue override(context); - if (!lookup_override_function(context, ns_id, &override)) - return false; - - /* Define the property early, to avoid reentrancy issues if - the override module looks for namespaces that import this */ - if (!JS_DefinePropertyById(context, repo_obj, ns_id, gi_namespace, + if (!lookup_override_function(context, ns_id, &override) || + // Define the property early, to avoid reentrancy issues if the override + // module looks for namespaces that import this + !JS_DefinePropertyById(context, repo_obj, ns_id, gi_namespace, GJS_MODULE_PROP_FLAGS)) return false; @@ -216,14 +235,28 @@ repo_new(JSContext *context) */ JS::RootedString two_point_oh(context, JS_NewStringCopyZ(context, "2.0")); if (!JS_DefinePropertyById(context, versions, atoms.glib(), two_point_oh, + JSPROP_PERMANENT) || + !JS_DefinePropertyById(context, versions, atoms.gobject(), two_point_oh, + JSPROP_PERMANENT) || + !JS_DefinePropertyById(context, versions, atoms.gio(), two_point_oh, JSPROP_PERMANENT)) return nullptr; - if (!JS_DefinePropertyById(context, versions, atoms.gobject(), two_point_oh, - JSPROP_PERMANENT)) + +#if GLIB_CHECK_VERSION(2, 79, 2) +# if defined(G_OS_UNIX) + if (!JS_DefineProperty(context, versions, "GLibUnix", two_point_oh, + JSPROP_PERMANENT) || + !JS_DefineProperty(context, versions, "GioUnix", two_point_oh, + JSPROP_PERMANENT)) return nullptr; - if (!JS_DefinePropertyById(context, versions, atoms.gio(), two_point_oh, - JSPROP_PERMANENT)) +# elif defined(G_OS_WIN32) + if (!JS_DefineProperty(context, versions, "GLibWin32", two_point_oh, + JSPROP_PERMANENT) || + !JS_DefineProperty(context, versions, "GioWin32", two_point_oh, + JSPROP_PERMANENT)) return nullptr; +# endif // G_OS_UNIX/G_OS_WIN32 +#endif // GLib >= 2.79.2 JS::RootedObject private_ns(context, JS_NewPlainObject(context)); if (!JS_DefinePropertyById(context, repo, atoms.private_ns_marker(), @@ -249,7 +282,7 @@ static bool gjs_value_from_constant_info(JSContext* cx, GIConstantInfo* info, GjsAutoTypeInfo type_info = g_constant_info_get_type(info); - bool ok = gjs_value_from_g_argument(cx, value, type_info, &garg, true); + bool ok = gjs_value_from_gi_argument(cx, value, type_info, &garg, true); g_constant_info_free_value(info, &garg); return ok; @@ -662,11 +695,9 @@ JSObject * gjs_lookup_generic_constructor(JSContext *context, GIBaseInfo *info) { - const char *constructor_name; - - JS::RootedObject in_object(context, - gjs_lookup_namespace_object(context, (GIBaseInfo*) info)); - constructor_name = g_base_info_get_name((GIBaseInfo*) info); + JS::RootedObject in_object{context, + gjs_lookup_namespace_object(context, info)}; + const char* constructor_name = g_base_info_get_name(info); if (G_UNLIKELY (!in_object)) return NULL; @@ -717,3 +748,39 @@ JSObject* gjs_new_object_with_generic_prototype(JSContext* cx, return JS_NewObjectWithGivenProto(cx, JS::GetClass(proto), proto); } + +// Handle the case where g_irepository_find_by_gtype() returns a type in Gio +// that should be in GioUnix or GioWin32. This may be an interface, class, or +// boxed. This function only needs to be called if you are going to do something +// with the GIBaseInfo that involves handing a JS object to the user. Otherwise, +// use g_irepository_find_by_gtype() directly. +GIBaseInfo* gjs_lookup_gtype(GIRepository* repo, GType gtype) { + GjsAutoBaseInfo retval = g_irepository_find_by_gtype(repo, gtype); + if (!retval) + return nullptr; + +#if GLIB_CHECK_VERSION(2, 79, 2) && (defined(G_OS_UNIX) || defined(G_OS_WIN32)) +# ifdef G_OS_UNIX + static const char* c_prefix = "GUnix"; + static const char* new_ns = "GioUnix"; +# else // G_OS_WIN32 + static const char* c_prefix = "GWin32"; + static const char* new_ns = "GioWin32"; +# endif + + const char* ns = g_base_info_get_namespace(retval); + if (strcmp(ns, "Gio") != 0) + return retval.release(); + + const char* gtype_name = g_type_name(gtype); + if (!g_str_has_prefix(gtype_name, c_prefix)) + return retval.release(); + + const char* new_name = gtype_name + strlen(c_prefix); + GIBaseInfo* new_info = g_irepository_find_by_name(repo, new_ns, new_name); + if (new_info) + return new_info; +#endif // GLib >= 2.79.2 + + return retval.release(); +} diff --git a/gi/repo.h b/gi/repo.h index 7be04ce2e..eccfec144 100644 --- a/gi/repo.h +++ b/gi/repo.h @@ -8,6 +8,7 @@ #include #include +#include #include @@ -47,6 +48,8 @@ bool gjs_define_info(JSContext *context, [[nodiscard]] char* gjs_hyphen_from_camel(const char* camel_name); +[[nodiscard]] GIBaseInfo* gjs_lookup_gtype(GIRepository*, GType); + #if GJS_VERBOSE_ENABLE_GI_USAGE void _gjs_log_info_usage(GIBaseInfo *info); #endif diff --git a/gi/toggle.cpp b/gi/toggle.cpp index 02ce2b484..ae791f1d1 100644 --- a/gi/toggle.cpp +++ b/gi/toggle.cpp @@ -6,6 +6,8 @@ // SPDX-FileContributor: Philip Chimento // SPDX-FileContributor: Marco Trevisan +#include + #include // for find_if #include #include @@ -146,6 +148,8 @@ ToggleQueue::shutdown(void) } void ToggleQueue::enqueue(ObjectInstance* obj, ToggleQueue::Direction direction, + // https://trac.cppcheck.net/ticket/10733 + // cppcheck-suppress passedByValue ToggleQueue::Handler handler) { g_assert(owns_lock() && "Unsafe access to queue"); diff --git a/gi/toggle.h b/gi/toggle.h index 141df5521..163fdcc2a 100644 --- a/gi/toggle.h +++ b/gi/toggle.h @@ -9,13 +9,15 @@ #ifndef GI_TOGGLE_H_ #define GI_TOGGLE_H_ -#include // for gboolean +#include #include #include #include #include // for pair +#include // for gboolean + class ObjectInstance; namespace Gjs { namespace Test { diff --git a/gi/utils-inl.h b/gi/utils-inl.h index e7b6c734b..e38b3e6aa 100644 --- a/gi/utils-inl.h +++ b/gi/utils-inl.h @@ -8,6 +8,7 @@ #include +#include // IWYU pragma: keep (for find) #include // IWYU pragma: keep (for swap) #include diff --git a/gi/value.cpp b/gi/value.cpp index 8b6ccfbd3..73dcc4145 100644 --- a/gi/value.cpp +++ b/gi/value.cpp @@ -20,6 +20,7 @@ #include #include #include // for RootedVector +#include // for RuntimeHeapIsCollecting #include #include #include @@ -28,7 +29,6 @@ #include #include #include // for InformalValueTypeName, JS_Get... -#include // for JS_GetObjectFunction #include "gi/arg-inl.h" #include "gi/arg.h" @@ -41,6 +41,7 @@ #include "gi/js-value-inl.h" #include "gi/object.h" #include "gi/param.h" +#include "gi/repo.h" #include "gi/union.h" #include "gi/value.h" #include "gi/wrapperutils.h" @@ -54,10 +55,117 @@ GJS_JSAPI_RETURN_CONVENTION static bool gjs_value_from_g_value_internal(JSContext*, JS::MutableHandleValue, const GValue*, bool no_copy = false, - GjsAutoSignalInfo const& = nullptr, - GjsAutoArgInfo const& = nullptr, + bool is_introspected_signal = false, + GIArgInfo* = nullptr, GITypeInfo* = nullptr); +GJS_JSAPI_RETURN_CONVENTION +static bool gjs_arg_set_from_gvalue(JSContext* cx, GIArgument* arg, + const GValue* value) { + switch (G_VALUE_TYPE(value)) { + case G_TYPE_CHAR: + gjs_arg_set(arg, g_value_get_schar(value)); + return true; + case G_TYPE_UCHAR: + gjs_arg_set(arg, g_value_get_uchar(value)); + return true; + case G_TYPE_BOOLEAN: + gjs_arg_set(arg, g_value_get_boolean(value)); + return true; + case G_TYPE_INT: + gjs_arg_set(arg, g_value_get_int(value)); + return true; + case G_TYPE_UINT: + gjs_arg_set(arg, g_value_get_uint(value)); + return true; + case G_TYPE_LONG: + gjs_arg_set( // NOLINT(runtime/int) + arg, g_value_get_long(value)); + return true; + case G_TYPE_ULONG: + gjs_arg_set(arg, g_value_get_ulong(value)); + return true; + case G_TYPE_INT64: + gjs_arg_set(arg, int64_t{g_value_get_int64(value)}); + return true; + case G_TYPE_UINT64: + gjs_arg_set(arg, uint64_t{g_value_get_uint64(value)}); + return true; + case G_TYPE_FLOAT: + gjs_arg_set(arg, g_value_get_float(value)); + return true; + case G_TYPE_DOUBLE: + gjs_arg_set(arg, g_value_get_double(value)); + return true; + case G_TYPE_STRING: + gjs_arg_set(arg, g_value_get_string(value)); + return true; + case G_TYPE_POINTER: + gjs_arg_set(arg, g_value_get_pointer(value)); + return true; + case G_TYPE_VARIANT: + gjs_arg_set(arg, g_value_get_variant(value)); + return true; + default: { + if (g_value_fits_pointer(value)) { + gjs_arg_set(arg, g_value_peek_pointer(value)); + return true; + } + + GType gtype = G_VALUE_TYPE(value); + + if (g_type_is_a(gtype, G_TYPE_FLAGS)) { + gjs_arg_set(arg, g_value_get_flags(value)); + return true; + } + + if (g_type_is_a(gtype, G_TYPE_ENUM)) { + gjs_arg_set(arg, g_value_get_enum(value)); + return true; + } + + if (g_type_is_a(gtype, G_TYPE_GTYPE)) { + gjs_arg_set(arg, + g_value_get_gtype(value)); + return true; + } + + if (g_type_is_a(gtype, G_TYPE_PARAM)) { + gjs_arg_set(arg, g_value_get_param(value)); + return true; + } + } + } + + gjs_throw(cx, "No know GArgument conversion for %s", + G_VALUE_TYPE_NAME(value)); + return false; +} + +GJS_JSAPI_RETURN_CONVENTION +static bool maybe_release_signal_value(JSContext* cx, + GjsAutoArgInfo const& arg_info, + GITypeInfo* type_info, + const GValue* gvalue, + GITransfer transfer) { + if (transfer == GI_TRANSFER_NOTHING) + return true; + + GIArgument arg; + if (!gjs_arg_set_from_gvalue(cx, &arg, gvalue)) + return false; + + if (!gjs_gi_argument_release(cx, transfer, type_info, + GjsArgumentFlags::ARG_OUT, &arg)) { + gjs_throw(cx, "Cannot release argument %s value, we're gonna leak!", + arg_info.name()); + return false; + } + + return true; +} + /* * Gets signal introspection info about closure, or NULL if not found. Currently * only works for signals on introspected GObjects, not signals on GJS-defined @@ -65,8 +173,6 @@ static bool gjs_value_from_g_value_internal(JSContext*, JS::MutableHandleValue, */ [[nodiscard]] static GjsAutoSignalInfo get_signal_info_if_available( GSignalQuery* signal_query) { - GIInfoType info_type; - if (!signal_query->itype) return nullptr; @@ -75,7 +181,7 @@ static bool gjs_value_from_g_value_internal(JSContext*, JS::MutableHandleValue, if (!obj) return nullptr; - info_type = g_base_info_get_type (obj); + GIInfoType info_type = obj.type(); if (info_type == GI_INFO_TYPE_OBJECT) return g_object_info_find_signal(obj, signal_query->signal_name); else if (info_type == GI_INFO_TYPE_INTERFACE) @@ -90,22 +196,22 @@ static bool gjs_value_from_g_value_internal(JSContext*, JS::MutableHandleValue, */ GJS_JSAPI_RETURN_CONVENTION static bool gjs_value_from_array_and_length_values( - JSContext* context, GjsAutoSignalInfo const& signal_info, - JS::MutableHandleValue value_p, GITypeInfo* array_type_info, - const GValue* array_value, GjsAutoArgInfo const& array_length_arg_info, - GITypeInfo* array_length_type_info, const GValue* array_length_value, - bool no_copy) { + JSContext* context, JS::MutableHandleValue value_p, + GITypeInfo* array_type_info, const GValue* array_value, + GIArgInfo* array_length_arg_info, GITypeInfo* array_length_type_info, + const GValue* array_length_value, bool no_copy, + bool is_introspected_signal) { JS::RootedValue array_length(context); - GArgument array_arg; g_assert(G_VALUE_HOLDS_POINTER(array_value)); g_assert(G_VALUE_HOLDS_INT(array_length_value)); if (!gjs_value_from_g_value_internal( - context, &array_length, array_length_value, no_copy, signal_info, + context, &array_length, array_length_value, no_copy, is_introspected_signal, array_length_arg_info, array_length_type_info)) return false; + GIArgument array_arg; gjs_arg_set(&array_arg, g_value_get_pointer(array_value)); return gjs_value_from_explicit_array( @@ -131,7 +237,7 @@ void Gjs::Closure::marshal(GValue* return_value, unsigned n_param_values, context = m_cx; GjsContextPrivate* gjs = GjsContextPrivate::from_cx(context); - if (G_UNLIKELY(gjs->sweeping())) { + if (JS::RuntimeHeapIsCollecting()) { GSignalInvocationHint *hint = (GSignalInvocationHint*) invocation_hint; std::ostringstream message; @@ -189,6 +295,7 @@ void Gjs::Closure::marshal(GValue* return_value, unsigned n_param_values, GjsAutoArgInfo arg_info; }; std::vector args_details(n_param_values); + bool needs_cleanup = false; GjsAutoSignalInfo signal_info = get_signal_info_if_available(&signal_query); if (signal_info) { @@ -206,6 +313,11 @@ void Gjs::Closure::marshal(GValue* return_value, unsigned n_param_values, args_details[array_len_pos + 1].skip = true; arg_details.array_len_index_for = array_len_pos + 1; } + + if (!needs_cleanup && + g_arg_info_get_ownership_transfer(arg_details.arg_info) != + GI_TRANSFER_NOTHING) + needs_cleanup = true; } } @@ -214,6 +326,7 @@ void Gjs::Closure::marshal(GValue* return_value, unsigned n_param_values, if (!argv.reserve(n_param_values)) g_error("Unable to reserve space"); JS::RootedValue argv_to_append(context); + bool is_introspected_signal = !!signal_info; for (i = 0; i < n_param_values; ++i) { const GValue* gval = ¶m_values[i]; ArgumentDetails& arg_details = args_details[i]; @@ -235,12 +348,12 @@ void Gjs::Closure::marshal(GValue* return_value, unsigned n_param_values, ArgumentDetails& array_len_details = args_details[arg_details.array_len_index_for]; res = gjs_value_from_array_and_length_values( - context, signal_info, &argv_to_append, &arg_details.type_info, - gval, array_len_details.arg_info, &array_len_details.type_info, - array_len_gval, no_copy); + context, &argv_to_append, &arg_details.type_info, gval, + array_len_details.arg_info, &array_len_details.type_info, + array_len_gval, no_copy, is_introspected_signal); } else { res = gjs_value_from_g_value_internal( - context, &argv_to_append, gval, no_copy, signal_info, + context, &argv_to_append, gval, no_copy, is_introspected_signal, arg_details.arg_info, &arg_details.type_info); } @@ -268,12 +381,29 @@ void Gjs::Closure::marshal(GValue* return_value, unsigned n_param_values, gjs->exit_immediately(code); // Some other uncatchable exception, e.g. out of memory - JSFunction* fn = JS_GetObjectFunction(callable()); - std::string descr = - fn ? "function " + gjs_debug_string(JS_GetFunctionDisplayId(fn)) - : "callable object " + gjs_debug_object(callable()); g_error("Call to %s terminated with uncatchable exception", - descr.c_str()); + gjs_debug_callable(callable()).c_str()); + } + } + + if (needs_cleanup) { + for (i = 0; i < n_param_values; ++i) { + ArgumentDetails& arg_details = args_details[i]; + if (!arg_details.arg_info) + continue; + + GITransfer transfer = + g_arg_info_get_ownership_transfer(arg_details.arg_info); + + if (transfer == GI_TRANSFER_NOTHING) + continue; + + if (!maybe_release_signal_value(context, arg_details.arg_info, + &arg_details.type_info, + ¶m_values[i], transfer)) { + gjs_log_exception(context); + return; + } } } @@ -635,13 +765,14 @@ gjs_value_to_g_value_internal(JSContext *context, /* We don't necessarily have the typelib loaded when we first see the structure... */ if (registered) { - GIInfoType info_type = g_base_info_get_type (registered); + GIInfoType info_type = registered.type(); if (info_type == GI_INFO_TYPE_STRUCT && - g_struct_info_is_foreign ((GIStructInfo*)registered)) { - GArgument arg; + g_struct_info_is_foreign( + registered.as())) { + GIArgument arg; - if (!gjs_struct_foreign_convert_to_g_argument( + if (!gjs_struct_foreign_convert_to_gi_argument( context, value, registered, nullptr, GJS_ARGUMENT_ARGUMENT, GI_TRANSFER_NOTHING, GjsArgumentFlags::MAY_BE_NULL, &arg)) @@ -847,10 +978,12 @@ gjs_value_to_g_value_no_copy(JSContext *context, } GJS_JSAPI_RETURN_CONVENTION -static bool gjs_value_from_g_value_internal( - JSContext* context, JS::MutableHandleValue value_p, const GValue* gvalue, - bool no_copy, GjsAutoSignalInfo const& signal_info, - GjsAutoArgInfo const& arg_info, GITypeInfo* type_info) { +static bool gjs_value_from_g_value_internal(JSContext* context, + JS::MutableHandleValue value_p, + const GValue* gvalue, bool no_copy, + bool is_introspected_signal, + GIArgInfo* arg_info, + GITypeInfo* type_info) { GType gtype; gtype = G_VALUE_TYPE(gvalue); @@ -893,11 +1026,11 @@ static bool gjs_value_from_g_value_internal( } else if (gtype == G_TYPE_DOUBLE) { double d; d = g_value_get_double(gvalue); - value_p.setNumber(d); + value_p.setNumber(JS::CanonicalizeNaN(d)); } else if (gtype == G_TYPE_FLOAT) { double d; d = g_value_get_float(gvalue); - value_p.setNumber(d); + value_p.setNumber(JS::CanonicalizeNaN(d)); } else if (gtype == G_TYPE_BOOLEAN) { bool v; v = g_value_get_boolean(gvalue); @@ -928,15 +1061,15 @@ static bool gjs_value_from_g_value_internal( return true; } - if (!signal_info || !arg_info) { + if (!is_introspected_signal || !arg_info) { gjs_throw(context, "Unknown signal"); return false; } + GITransfer transfer = g_arg_info_get_ownership_transfer(arg_info); GjsAutoTypeInfo element_info = g_type_info_get_param_type(type_info, 0); - if (!gjs_array_from_g_value_array( - context, value_p, element_info, - g_arg_info_get_ownership_transfer(arg_info), gvalue)) { + if (!gjs_array_from_g_value_array(context, value_p, element_info, + transfer, gvalue)) { gjs_throw(context, "Failed to convert array"); return false; } @@ -992,7 +1125,7 @@ static bool gjs_value_from_g_value_internal( /* The only way to differentiate unions and structs is from * their g-i info as both GBoxed */ - GjsAutoBaseInfo info = g_irepository_find_by_gtype(nullptr, gtype); + GjsAutoBaseInfo info = gjs_lookup_gtype(nullptr, gtype); if (!info) { gjs_throw(context, "No introspection information found for %s", @@ -1004,8 +1137,8 @@ static bool gjs_value_from_g_value_internal( g_struct_info_is_foreign(info)) { GIArgument arg; gjs_arg_set(&arg, gboxed); - return gjs_struct_foreign_convert_from_g_argument(context, value_p, - info, &arg); + return gjs_struct_foreign_convert_from_gi_argument(context, value_p, + info, &arg); } GIInfoType type = info.type(); @@ -1034,9 +1167,7 @@ static bool gjs_value_from_g_value_internal( obj = gjs_param_from_g_param(context, gparam); value_p.setObjectOrNull(obj); - } else if (signal_info && g_type_is_a(gtype, G_TYPE_POINTER)) { - GArgument arg; - + } else if (is_introspected_signal && g_type_is_a(gtype, G_TYPE_POINTER)) { if (!arg_info) { gjs_throw(context, "Unknown signal."); return false; @@ -1046,10 +1177,11 @@ static bool gjs_value_from_g_value_internal( " calling gjs_value_from_g_value_internal()", g_type_info_get_array_length(type_info) == -1)); + GIArgument arg; gjs_arg_set(&arg, g_value_get_pointer(gvalue)); - return gjs_value_from_g_argument(context, value_p, type_info, &arg, - true); + return gjs_value_from_gi_argument(context, value_p, type_info, &arg, + true); } else if (gtype == G_TYPE_GTYPE) { GType gvalue_gtype = g_value_get_gtype(gvalue); diff --git a/gi/value.h b/gi/value.h index 352edef7a..047430718 100644 --- a/gi/value.h +++ b/gi/value.h @@ -51,11 +51,12 @@ struct AutoGValue : GValue { break; default: // We can't safely move in complex cases, so let's just copy - *static_cast(this) = G_VALUE_INIT; + this->steal(); *this = src; g_value_unset(&src); } } + void steal() { *static_cast(this) = G_VALUE_INIT; } ~AutoGValue() { g_value_unset(this); } }; } // namespace Gjs diff --git a/gi/wrapperutils.h b/gi/wrapperutils.h index e0450dc97..d2fa7eade 100644 --- a/gi/wrapperutils.h +++ b/gi/wrapperutils.h @@ -20,6 +20,7 @@ #include #include #include // for JSEXN_TYPEERR +#include // for MutableHandleIdVector #include #include #include @@ -33,7 +34,7 @@ #include "gi/cwrapper.h" #include "cjs/atoms.h" #include "cjs/context-private.h" -#include "cjs/jsapi-class.h" // IWYU pragma: keep +#include "cjs/jsapi-class.h" #include "cjs/jsapi-util.h" #include "cjs/macros.h" #include "cjs/profiler-private.h" diff --git a/gjs.doap b/gjs.doap index 6770e9709..c624c3d8a 100644 --- a/gjs.doap +++ b/gjs.doap @@ -32,20 +32,4 @@ pchimento - - - - Cosimo Cecchi - - cosimoc - - - - - - Giovanni Campagna - - - - diff --git a/installed-tests/debugger-test.sh b/installed-tests/debugger-test.sh old mode 100755 new mode 100644 diff --git a/installed-tests/debugger/backtrace.debugger.output b/installed-tests/debugger/backtrace.debugger.output index 2f2bb4c90..1602e7958 100644 --- a/installed-tests/debugger/backtrace.debugger.output +++ b/installed-tests/debugger/backtrace.debugger.output @@ -2,40 +2,40 @@ GJS debugger. Type "help" for help db> # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later db> # SPDX-FileCopyrightText: 2018 Philip Chimento db> backtrace -#0 toplevel at backtrace.debugger.js:3:0 +#0 toplevel at backtrace.debugger.js:3:1 db> c -Debugger statement, toplevel at backtrace.debugger.js:3:0 +Debugger statement, toplevel at backtrace.debugger.js:3:1 db> bt -#0 toplevel at backtrace.debugger.js:3:0 +#0 toplevel at backtrace.debugger.js:3:1 db> c -Debugger statement, ([object Array], 0, [object Array]) at backtrace.debugger.js:5:4 +Debugger statement, ([object Array], 0, [object Array]) at backtrace.debugger.js:5:5 db> backtrace full -#0 ([object Array], 0, [object Array]) at backtrace.debugger.js:5:4 +#0 ([object Array], 0, [object Array]) at backtrace.debugger.js:5:5 arguments = [object Arguments] array = [object Array] -#1 toplevel at backtrace.debugger.js:4:36 +#1 toplevel at backtrace.debugger.js:4:37 db> bt full -#0 ([object Array], 0, [object Array]) at backtrace.debugger.js:5:4 +#0 ([object Array], 0, [object Array]) at backtrace.debugger.js:5:5 arguments = [object Arguments] array = [object Array] -#1 toplevel at backtrace.debugger.js:4:36 +#1 toplevel at backtrace.debugger.js:4:37 db> where -#0 ([object Array], 0, [object Array]) at backtrace.debugger.js:5:4 -#1 toplevel at backtrace.debugger.js:4:36 +#0 ([object Array], 0, [object Array]) at backtrace.debugger.js:5:5 +#1 toplevel at backtrace.debugger.js:4:37 db> c -Debugger statement, (1, 0, [object Array]) at backtrace.debugger.js:7:8 +Debugger statement, (1, 0, [object Array]) at backtrace.debugger.js:7:9 db> # test printing locals when exception is thrown before initialization of a value db> c 1 Unwinding due to exception. (Type 'c' to continue unwinding.) -#0 mistake([object Array]) at backtrace.debugger.js:14:33 +#0 mistake([object Array]) at backtrace.debugger.js:14:34 14 let {uninitialized_} = array.shift(); Exception value is: $1 = [object TypeError] TypeError: array.shift() is undefined db> bt full -#0 mistake([object Array]) at backtrace.debugger.js:14:33 +#0 mistake([object Array]) at backtrace.debugger.js:14:34 uninitialized_ = -#1 toplevel at backtrace.debugger.js:16:7 +#1 toplevel at backtrace.debugger.js:16:8 db> q Program exited with code 0 diff --git a/installed-tests/debugger/breakpoint.debugger.output b/installed-tests/debugger/breakpoint.debugger.output index 6ba35fb57..9802391e6 100644 --- a/installed-tests/debugger/breakpoint.debugger.output +++ b/installed-tests/debugger/breakpoint.debugger.output @@ -2,20 +2,20 @@ GJS debugger. Type "help" for help db> # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later db> # SPDX-FileCopyrightText: 2018 Philip Chimento db> breakpoint 4 -Breakpoint 1 at breakpoint.debugger.js:4:0 +Breakpoint 1 at breakpoint.debugger.js:4:1 db> break 6 -Breakpoint 2 at breakpoint.debugger.js:6:4 +Breakpoint 2 at breakpoint.debugger.js:6:5 db> b 8 -Breakpoint 3 at breakpoint.debugger.js:8:0 +Breakpoint 3 at breakpoint.debugger.js:8:1 db> c 1 -Breakpoint 1, toplevel at breakpoint.debugger.js:4:0 +Breakpoint 1, toplevel at breakpoint.debugger.js:4:1 db> c 2 -Breakpoint 3, toplevel at breakpoint.debugger.js:8:0 +Breakpoint 3, toplevel at breakpoint.debugger.js:8:1 db> c 3 -Breakpoint 2, foo() at breakpoint.debugger.js:6:4 +Breakpoint 2, foo() at breakpoint.debugger.js:6:5 db> c Function foo Program exited with code 0 diff --git a/installed-tests/debugger/continue.debugger.output b/installed-tests/debugger/continue.debugger.output index 93d0bc0fb..8326b8122 100644 --- a/installed-tests/debugger/continue.debugger.output +++ b/installed-tests/debugger/continue.debugger.output @@ -2,8 +2,8 @@ GJS debugger. Type "help" for help db> # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later db> # SPDX-FileCopyrightText: 2018 Philip Chimento db> continue -Debugger statement, toplevel at continue.debugger.js:3:0 +Debugger statement, toplevel at continue.debugger.js:3:1 db> cont -Debugger statement, toplevel at continue.debugger.js:4:0 +Debugger statement, toplevel at continue.debugger.js:4:1 db> c Program exited with code 0 diff --git a/installed-tests/debugger/delete.debugger.output b/installed-tests/debugger/delete.debugger.output index 7b9f98f88..a6e7b4f53 100644 --- a/installed-tests/debugger/delete.debugger.output +++ b/installed-tests/debugger/delete.debugger.output @@ -2,26 +2,26 @@ GJS debugger. Type "help" for help db> # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later db> # SPDX-FileCopyrightText: 2018 Philip Chimento db> b 4 -Breakpoint 1 at delete.debugger.js:4:0 +Breakpoint 1 at delete.debugger.js:4:1 db> b 5 -Breakpoint 2 at delete.debugger.js:5:0 +Breakpoint 2 at delete.debugger.js:5:1 db> b 6 -Breakpoint 3 at delete.debugger.js:6:0 +Breakpoint 3 at delete.debugger.js:6:1 db> b 7 -Breakpoint 4 at delete.debugger.js:7:0 +Breakpoint 4 at delete.debugger.js:7:1 db> # Check that breakpoint 4 still remains after deleting 1-3 db> delete 1 -Breakpoint 1 at delete.debugger.js:4:0 deleted +Breakpoint 1 at delete.debugger.js:4:1 deleted db> del 2 -Breakpoint 2 at delete.debugger.js:5:0 deleted +Breakpoint 2 at delete.debugger.js:5:1 deleted db> d 3 -Breakpoint 3 at delete.debugger.js:6:0 deleted +Breakpoint 3 at delete.debugger.js:6:1 deleted db> c 1 2 3 4 -Breakpoint 4, toplevel at delete.debugger.js:7:0 +Breakpoint 4, toplevel at delete.debugger.js:7:1 db> c 5 Program exited with code 0 diff --git a/installed-tests/debugger/down-up.debugger.output b/installed-tests/debugger/down-up.debugger.output index c8b1a3bad..0c0a7f024 100644 --- a/installed-tests/debugger/down-up.debugger.output +++ b/installed-tests/debugger/down-up.debugger.output @@ -2,34 +2,34 @@ GJS debugger. Type "help" for help db> # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later db> # SPDX-FileCopyrightText: 2018 Philip Chimento db> c -Debugger statement, d() at down-up.debugger.js:16:4 +Debugger statement, d() at down-up.debugger.js:16:5 db> down Youngest frame selected; you cannot go down. db> up -#1 c() at down-up.debugger.js:12:4 +#1 c() at down-up.debugger.js:12:5 12 d(); db> up -#2 b() at down-up.debugger.js:8:4 +#2 b() at down-up.debugger.js:8:5 8 c(); db> up -#3 a() at down-up.debugger.js:4:4 +#3 a() at down-up.debugger.js:4:5 4 b(); db> up -#4 toplevel at down-up.debugger.js:19:0 +#4 toplevel at down-up.debugger.js:19:1 19 a(); db> up Initial frame selected; you cannot go up. db> down -#3 a() at down-up.debugger.js:4:4 +#3 a() at down-up.debugger.js:4:5 4 b(); db> dn -#2 b() at down-up.debugger.js:8:4 +#2 b() at down-up.debugger.js:8:5 8 c(); db> dn -#1 c() at down-up.debugger.js:12:4 +#1 c() at down-up.debugger.js:12:5 12 d(); db> dn -#0 d() at down-up.debugger.js:16:4 +#0 d() at down-up.debugger.js:16:5 16 debugger; db> c Program exited with code 0 diff --git a/installed-tests/debugger/finish.debugger.output b/installed-tests/debugger/finish.debugger.output index c33532ab7..8f612f50b 100644 --- a/installed-tests/debugger/finish.debugger.output +++ b/installed-tests/debugger/finish.debugger.output @@ -3,21 +3,21 @@ db> # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later db> # SPDX-FileCopyrightText: 2018 Philip Chimento db> c Print me -Debugger statement, foo() at finish.debugger.js:5:4 +Debugger statement, foo() at finish.debugger.js:5:5 db> finish -Run till exit from foo() at finish.debugger.js:5:4 +Run till exit from foo() at finish.debugger.js:5:5 Print me also No value returned. -toplevel at finish.debugger.js:16:0 +toplevel at finish.debugger.js:16:1 db> c Print me -Debugger statement, bar() at finish.debugger.js:11:4 +Debugger statement, bar() at finish.debugger.js:11:5 db> fin -Run till exit from bar() at finish.debugger.js:11:4 +Run till exit from bar() at finish.debugger.js:11:5 Print me also Value returned is: $1 = 5 -toplevel at finish.debugger.js:17:0 +toplevel at finish.debugger.js:17:1 db> c Print me at the end Program exited with code 0 diff --git a/installed-tests/debugger/frame.debugger.output b/installed-tests/debugger/frame.debugger.output index 9e456cda2..f40e1362f 100644 --- a/installed-tests/debugger/frame.debugger.output +++ b/installed-tests/debugger/frame.debugger.output @@ -2,12 +2,12 @@ GJS debugger. Type "help" for help db> # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later db> # SPDX-FileCopyrightText: 2018 Philip Chimento db> c -Debugger statement, b() at frame.debugger.js:8:4 +Debugger statement, b() at frame.debugger.js:8:5 db> frame 2 -#2 toplevel at frame.debugger.js:11:0 +#2 toplevel at frame.debugger.js:11:1 11 a(); db> f 1 -#1 a() at frame.debugger.js:4:4 +#1 a() at frame.debugger.js:4:5 4 b(); db> c Program exited with code 0 diff --git a/installed-tests/debugger/keys.debugger b/installed-tests/debugger/keys.debugger index 57559a888..595ae715b 100644 --- a/installed-tests/debugger/keys.debugger +++ b/installed-tests/debugger/keys.debugger @@ -3,4 +3,9 @@ c keys a k a +keys a.foo +keys {} +keys bar +keys ['a', 'b', 'c'] +keys c diff --git a/installed-tests/debugger/keys.debugger.output b/installed-tests/debugger/keys.debugger.output index 3a00736cd..4784c7e67 100644 --- a/installed-tests/debugger/keys.debugger.output +++ b/installed-tests/debugger/keys.debugger.output @@ -2,12 +2,20 @@ GJS debugger. Type "help" for help db> # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later db> # SPDX-FileCopyrightText: 2018 Philip Chimento db> c -Debugger statement, toplevel at keys.debugger.js:9:0 +Debugger statement, toplevel at keys.debugger.js:9:1 db> keys a -$1 = [object Array] -["foo", "bar", "tres", Symbol("s")] +"foo", "bar", "tres", Symbol("s") db> k a -$2 = [object Array] -["foo", "bar", "tres", Symbol("s")] +"foo", "bar", "tres", Symbol("s") +db> keys a.foo +a.foo is 1, not an object +db> keys {} +No own properties +db> keys bar +Exception caught while evaluating bar: [object ReferenceError] +db> keys ['a', 'b', 'c'] +"0", "1", "2", "length" +db> keys +Missing argument. See 'help keys' db> c Program exited with code 0 diff --git a/installed-tests/debugger/lastvalues.debugger.output b/installed-tests/debugger/lastvalues.debugger.output index 3d509f08c..6aa6a53b4 100644 --- a/installed-tests/debugger/lastvalues.debugger.output +++ b/installed-tests/debugger/lastvalues.debugger.output @@ -2,7 +2,7 @@ GJS debugger. Type "help" for help db> # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later db> # SPDX-FileCopyrightText: 2020 Philip Chimento db> c -Debugger statement, toplevel at lastvalues.debugger.js:6:0 +Debugger statement, toplevel at lastvalues.debugger.js:6:1 db> p a $1 = undefined db> p b diff --git a/installed-tests/debugger/list.debugger.output b/installed-tests/debugger/list.debugger.output index ce7857ab4..eaa483e2d 100644 --- a/installed-tests/debugger/list.debugger.output +++ b/installed-tests/debugger/list.debugger.output @@ -41,9 +41,9 @@ db> list 0 db> list divide Unknown option db> break 4 -Breakpoint 1 at list.debugger.js:4:8 +Breakpoint 1 at list.debugger.js:4:9 db> c -Breakpoint 1, divide() at list.debugger.js:4:8 +Breakpoint 1, divide() at list.debugger.js:4:9 db> list 1 // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later 2 // SPDX-FileCopyrightText: 2021 Mantoh Nasah Kuma diff --git a/installed-tests/debugger/next.debugger.output b/installed-tests/debugger/next.debugger.output index 7b8836db8..ab60091be 100644 --- a/installed-tests/debugger/next.debugger.output +++ b/installed-tests/debugger/next.debugger.output @@ -2,26 +2,26 @@ GJS debugger. Type "help" for help db> # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later db> # SPDX-FileCopyrightText: 2018 Philip Chimento db> c -Debugger statement, a() at next.debugger.js:4:4 +Debugger statement, a() at next.debugger.js:4:5 db> next -a() at next.debugger.js:4:4 +a() at next.debugger.js:4:5 db> n -a() at next.debugger.js:5:4 +a() at next.debugger.js:5:5 A line in b db> n -a() at next.debugger.js:6:4 +a() at next.debugger.js:6:5 A line in a db> n -a() at next.debugger.js:7:0 +a() at next.debugger.js:7:1 No value returned. db> n -a() at next.debugger.js:7:0 -toplevel at next.debugger.js:13:0 +a() at next.debugger.js:7:1 +toplevel at next.debugger.js:13:1 db> n -toplevel at next.debugger.js:13:0 +toplevel at next.debugger.js:13:1 db> n -toplevel at next.debugger.js:14:0 +toplevel at next.debugger.js:14:1 No value returned. db> n -toplevel at next.debugger.js:14:0 +toplevel at next.debugger.js:14:1 Program exited with code 0 diff --git a/installed-tests/debugger/print.debugger.output b/installed-tests/debugger/print.debugger.output index 3c65b0d58..90c80f877 100644 --- a/installed-tests/debugger/print.debugger.output +++ b/installed-tests/debugger/print.debugger.output @@ -2,7 +2,7 @@ GJS debugger. Type "help" for help db> # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later db> # SPDX-FileCopyrightText: 2018 Philip Chimento db> c -Debugger statement, toplevel at print.debugger.js:19:0 +Debugger statement, toplevel at print.debugger.js:19:1 db> # Simple types db> print a $1 = undefined diff --git a/installed-tests/debugger/return.debugger b/installed-tests/debugger/return.debugger index 162e4d1ff..4ed260623 100644 --- a/installed-tests/debugger/return.debugger +++ b/installed-tests/debugger/return.debugger @@ -4,7 +4,12 @@ b 4 b 8 b 12 c +f 1 +return +f 0 return ret 5 -ret `${4 * 10 + 2} is the answer` +ret foo +p 2 +ret `${4 * 10 + $1} is the answer` c diff --git a/installed-tests/debugger/return.debugger.output b/installed-tests/debugger/return.debugger.output index 0b0e6ba3d..7ba8bfe1e 100644 --- a/installed-tests/debugger/return.debugger.output +++ b/installed-tests/debugger/return.debugger.output @@ -2,19 +2,31 @@ GJS debugger. Type "help" for help db> # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later db> # SPDX-FileCopyrightText: 2018 Philip Chimento db> b 4 -Breakpoint 1 at return.debugger.js:4:4 +Breakpoint 1 at return.debugger.js:4:5 db> b 8 -Breakpoint 2 at return.debugger.js:8:4 +Breakpoint 2 at return.debugger.js:8:5 db> b 12 -Breakpoint 3 at return.debugger.js:12:4 +Breakpoint 3 at return.debugger.js:12:5 db> c -Breakpoint 1, func1() at return.debugger.js:4:4 +Breakpoint 1, func1() at return.debugger.js:4:5 +db> f 1 +#1 toplevel at return.debugger.js:15:7 + 15 print(func1()); +db> return +To return, you must select the newest frame (use 'frame 0') +db> f 0 +#0 func1() at return.debugger.js:4:5 + 4 return 1; db> return undefined -Breakpoint 2, func2() at return.debugger.js:8:4 +Breakpoint 2, func2() at return.debugger.js:8:5 db> ret 5 5 -Breakpoint 3, func3() at return.debugger.js:12:4 -db> ret `${4 * 10 + 2} is the answer` +Breakpoint 3, func3() at return.debugger.js:12:5 +db> ret foo +Exception caught while evaluating foo: [object ReferenceError] +db> p 2 +$1 = 2 +db> ret `${4 * 10 + $1} is the answer` 42 is the answer Program exited with code 0 diff --git a/installed-tests/debugger/set.debugger.output b/installed-tests/debugger/set.debugger.output index 613071d17..a85fe1052 100644 --- a/installed-tests/debugger/set.debugger.output +++ b/installed-tests/debugger/set.debugger.output @@ -4,7 +4,7 @@ db> # SPDX-FileCopyrightText: 2018 Philip Chimento db> # Currently the only option is "pretty" for pretty-printing. Set doesn't yet db> # allow setting variables in the program. db> c -Debugger statement, toplevel at set.debugger.js:4:0 +Debugger statement, toplevel at set.debugger.js:4:1 db> p a $1 = [object Object] {} diff --git a/installed-tests/debugger/step.debugger.output b/installed-tests/debugger/step.debugger.output index 47da89652..592e584c9 100644 --- a/installed-tests/debugger/step.debugger.output +++ b/installed-tests/debugger/step.debugger.output @@ -2,36 +2,36 @@ GJS debugger. Type "help" for help db> # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later db> # SPDX-FileCopyrightText: 2018 Philip Chimento db> s -toplevel at step.debugger.js:12:0 -entered frame: a() at step.debugger.js:4:4 +toplevel at step.debugger.js:12:1 +entered frame: a() at step.debugger.js:4:5 db> s -a() at step.debugger.js:4:4 -entered frame: b() at step.debugger.js:9:4 +a() at step.debugger.js:4:5 +entered frame: b() at step.debugger.js:9:5 db> s -b() at step.debugger.js:9:4 +b() at step.debugger.js:9:5 A line in b db> s -b() at step.debugger.js:10:0 +b() at step.debugger.js:10:1 No value returned. db> s -b() at step.debugger.js:10:0 -a() at step.debugger.js:4:4 +b() at step.debugger.js:10:1 +a() at step.debugger.js:4:5 db> s -a() at step.debugger.js:4:4 +a() at step.debugger.js:4:5 db> s -a() at step.debugger.js:5:4 +a() at step.debugger.js:5:5 A line in a db> s -a() at step.debugger.js:6:0 +a() at step.debugger.js:6:1 No value returned. db> s -a() at step.debugger.js:6:0 -toplevel at step.debugger.js:12:0 +a() at step.debugger.js:6:1 +toplevel at step.debugger.js:12:1 db> s -toplevel at step.debugger.js:12:0 +toplevel at step.debugger.js:12:1 db> s -toplevel at step.debugger.js:13:0 +toplevel at step.debugger.js:13:1 No value returned. db> s -toplevel at step.debugger.js:13:0 +toplevel at step.debugger.js:13:1 Program exited with code 0 diff --git a/installed-tests/debugger/throw-ignored.debugger.output b/installed-tests/debugger/throw-ignored.debugger.output index a2ac43d17..2e6bfb3e1 100644 --- a/installed-tests/debugger/throw-ignored.debugger.output +++ b/installed-tests/debugger/throw-ignored.debugger.output @@ -4,7 +4,7 @@ db> # SPDX-FileCopyrightText: 2021 Florian Müllner db> c Caught exception: Error: Exception nº 1 Unwinding due to exception. (Type 'c' to continue unwinding.) -#0 a() at throw-ignored.debugger.js:7:10 +#0 a() at throw-ignored.debugger.js:7:11 7 throw new Error(`Exception nº ${++count}`); Exception value is: $1 = [object Error] diff --git a/installed-tests/debugger/throw.debugger b/installed-tests/debugger/throw.debugger index b5e6dfb48..a3f9be397 100644 --- a/installed-tests/debugger/throw.debugger +++ b/installed-tests/debugger/throw.debugger @@ -2,6 +2,11 @@ # SPDX-FileCopyrightText: 2018 Philip Chimento set ignoreCaughtExceptions false c -throw 'foobar' + 3.14; +f 1 +throw {} +f 0 +p 3.14 +throw 'foobar' + $1 fin +throw foo throw diff --git a/installed-tests/debugger/throw.debugger.output b/installed-tests/debugger/throw.debugger.output index f3d4b1a4a..99876a96c 100644 --- a/installed-tests/debugger/throw.debugger.output +++ b/installed-tests/debugger/throw.debugger.output @@ -3,23 +3,35 @@ db> # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later db> # SPDX-FileCopyrightText: 2018 Philip Chimento db> set ignoreCaughtExceptions false db> c -Debugger statement, a() at throw.debugger.js:4:4 -db> throw 'foobar' + 3.14; +Debugger statement, a() at throw.debugger.js:4:5 +db> f 1 +#1 toplevel at throw.debugger.js:9:5 + 9 a(); +db> throw {} +To throw, you must select the newest frame (use 'frame 0') +db> f 0 +#0 a() at throw.debugger.js:4:5 + 4 debugger; +db> p 3.14 +$1 = 3.14 +db> throw 'foobar' + $1 Unwinding due to exception. (Type 'c' to continue unwinding.) -#0 a() at throw.debugger.js:4:4 +#0 a() at throw.debugger.js:4:5 4 debugger; Exception value is: -$1 = "foobar3.14" +$2 = "foobar3.14" db> fin -Run till exit from a() at throw.debugger.js:4:4 +Run till exit from a() at throw.debugger.js:4:5 Frame terminated by exception: -$2 = "foobar3.14" +$3 = "foobar3.14" (To rethrow it, type 'throw'.) Unwinding due to exception. (Type 'c' to continue unwinding.) -#0 toplevel at throw.debugger.js:9:4 +#0 toplevel at throw.debugger.js:9:5 9 a(); Exception value is: -$3 = "foobar3.14" +$4 = "foobar3.14" +db> throw foo +Exception caught while evaluating foo: [object ReferenceError] db> throw Exception: foobar3.14 Program exited with code 0 diff --git a/installed-tests/debugger/until.debugger.output b/installed-tests/debugger/until.debugger.output index 811362ae7..55dda3578 100644 --- a/installed-tests/debugger/until.debugger.output +++ b/installed-tests/debugger/until.debugger.output @@ -2,18 +2,18 @@ GJS debugger. Type "help" for help db> # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later db> # SPDX-FileCopyrightText: 2018 Philip Chimento db> until 5 -toplevel at until.debugger.js:3:0 +toplevel at until.debugger.js:3:1 1 2 db> upto 7 -toplevel at until.debugger.js:5:0 +toplevel at until.debugger.js:5:1 3 -entered frame: () at until.debugger.js:7:4 +entered frame: () at until.debugger.js:7:5 db> u 9 -() at until.debugger.js:7:4 +() at until.debugger.js:7:5 4 No value returned. -toplevel at until.debugger.js:9:0 +toplevel at until.debugger.js:9:1 db> c 5 Program exited with code 0 diff --git a/installed-tests/js/.eslintrc.yml b/installed-tests/js/.eslintrc.yml index 74a8a4f3e..77044c33e 100644 --- a/installed-tests/js/.eslintrc.yml +++ b/installed-tests/js/.eslintrc.yml @@ -35,8 +35,11 @@ overrides: - testEncoding.js - testGLibLogWriter.js - testTimers.js + - testWeakRef.js - modules/importmeta.js - modules/exports.js + - modules/greet.js - modules/say.js + - modules/sideEffect4.js parserOptions: sourceType: module diff --git a/installed-tests/js/jsunit.gresources.xml b/installed-tests/js/jsunit.gresources.xml index 75c54c901..aedbd588e 100644 --- a/installed-tests/js/jsunit.gresources.xml +++ b/installed-tests/js/jsunit.gresources.xml @@ -2,12 +2,12 @@ - + complex3.ui complex4.ui jasmine.js - minijasmine.js minijasmine-executor.js + minijasmine.js modules/alwaysThrows.js modules/badOverrides/GIMarshallingTests.js modules/badOverrides/Gio.js @@ -17,22 +17,27 @@ modules/badOverrides2/Gio.js modules/badOverrides2/Regress.js modules/badOverrides2/WarnLib.js - modules/subBadInit/__init__.js - modules/subErrorInit/__init__.js modules/data.txt - modules/encodings.json modules/dynamic.js - modules/importmeta.js + modules/encodings.json modules/exports.js modules/foobar.js + modules/greet.js + modules/importmeta.js modules/lexicalScope.js modules/modunicode.js modules/mutualImport/a.js modules/mutualImport/b.js modules/overrides/GIMarshallingTests.js modules/say.js + modules/sideEffect.js + modules/sideEffect2.js + modules/sideEffect3.js + modules/sideEffect4.js modules/subA/subB/__init__.js modules/subA/subB/baz.js modules/subA/subB/foobar.js + modules/subBadInit/__init__.js + modules/subErrorInit/__init__.js diff --git a/installed-tests/js/libgjstesttools/gjs-test-tools.cpp b/installed-tests/js/libgjstesttools/gjs-test-tools.cpp index 1679357f6..2e62f00e4 100644 --- a/installed-tests/js/libgjstesttools/gjs-test-tools.cpp +++ b/installed-tests/js/libgjstesttools/gjs-test-tools.cpp @@ -39,6 +39,10 @@ void gjs_test_tools_reset() { FinalizedObjectsLocked()->clear(); } +void gjs_test_tools_ref(GObject* object) { g_object_ref(object); } + +void gjs_test_tools_unref(GObject* object) { g_object_unref(object); } + // clang-format off static G_DEFINE_QUARK(gjs-test-utils::finalize, finalize); // clang-format on @@ -216,6 +220,7 @@ void gjs_test_tools_run_dispose_other_thread(GObject* object, GError** error) { object, error); // cppcheck-suppress leakNoVarFunctionCall g_thread_join(thread); + // cppcheck-suppress memleak } /** @@ -350,3 +355,37 @@ int gjs_test_tools_open_bytes(GBytes* bytes, GError** error) { g_error("%s is currently supported on UNIX only", __func__); #endif } + +/** + * gjs_test_tools_new_unaligned_bytes: + * @len: Length of buffer to allocate + * + * Creates a data buffer at a location 1 byte away from an 8-byte alignment + * boundary, to make sure that tests fail when SpiderMonkey enforces an + * alignment restriction on embedder data. + * + * The buffer is filled with repeated 0x00-0x07 bytes containing the least + * significant 3 bits of that byte's address. + * + * Returns: (transfer full): a #GBytes + */ +GBytes* gjs_test_tools_new_unaligned_bytes(size_t len) { + auto* buffer = static_cast(g_aligned_alloc0(1, len + 1, 8)); + for (size_t ix = 0; ix < len + 1; ix++) { + buffer[ix] = reinterpret_cast(buffer + ix) & 0x07; + } + return g_bytes_new_with_free_func(buffer + 1, len, g_aligned_free, buffer); +} + +alignas(8) static const char static_bytes[] = "hello"; + +/** + * gjs_test_tools_new_static_bytes: + * + * Returns a buffer that lives in static storage. + * + * Returns: (transfer full): a #GBytes + */ +GBytes* gjs_test_tools_new_static_bytes() { + return g_bytes_new_static(static_bytes, 6); +} diff --git a/installed-tests/js/libgjstesttools/gjs-test-tools.h b/installed-tests/js/libgjstesttools/gjs-test-tools.h index 13fcb7a80..722eee4fc 100644 --- a/installed-tests/js/libgjstesttools/gjs-test-tools.h +++ b/installed-tests/js/libgjstesttools/gjs-test-tools.h @@ -4,10 +4,8 @@ #pragma once -#ifdef _GI_EXTERN -#define _GJS_TEST_TOOL_EXTERN _GI_EXTERN -#else -#define _GJS_TEST_TOOL_EXTERN +#ifndef GJS_TEST_TOOL_EXTERN +# define GJS_TEST_TOOL_EXTERN #endif #include @@ -16,78 +14,90 @@ G_BEGIN_DECLS -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN void gjs_test_tools_init(void); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN void gjs_test_tools_reset(void); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN +void gjs_test_tools_ref(GObject* object); + +GJS_TEST_TOOL_EXTERN +void gjs_test_tools_unref(GObject* object); + +GJS_TEST_TOOL_EXTERN void gjs_test_tools_delayed_ref(GObject* object, int interval); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN void gjs_test_tools_delayed_unref(GObject* object, int interval); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN void gjs_test_tools_delayed_dispose(GObject* object, int interval); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN void gjs_test_tools_ref_other_thread(GObject* object, GError** error); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN GThread* gjs_test_tools_delayed_ref_other_thread(GObject* object, int interval, GError** error); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN void gjs_test_tools_unref_other_thread(GObject* object, GError** error); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN GThread* gjs_test_tools_delayed_unref_other_thread(GObject* object, int interval, GError** error); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN GThread* gjs_test_tools_delayed_ref_unref_other_thread(GObject* object, int interval, GError** error); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN void gjs_test_tools_run_dispose_other_thread(GObject* object, GError** error); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN void gjs_test_tools_save_object(GObject* object); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN void gjs_test_tools_save_object_unreffed(GObject* object); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN GObject* gjs_test_tools_get_saved(); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN GObject* gjs_test_tools_steal_saved(); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN GObject* gjs_test_tools_peek_saved(); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN int gjs_test_tools_get_saved_ref_count(); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN void gjs_test_tools_clear_saved(); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN void gjs_test_tools_save_weak(GObject* object); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN GObject* gjs_test_tools_get_weak(); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN GObject* gjs_test_tools_get_weak_other_thread(GError** error); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN GObject* gjs_test_tools_get_disposed(GObject* object); -_GJS_TEST_TOOL_EXTERN +GJS_TEST_TOOL_EXTERN int gjs_test_tools_open_bytes(GBytes* bytes, GError** error); +GJS_TEST_TOOL_EXTERN +GBytes* gjs_test_tools_new_unaligned_bytes(size_t len); + +GJS_TEST_TOOL_EXTERN +GBytes* gjs_test_tools_new_static_bytes(); + G_END_DECLS diff --git a/installed-tests/js/libgjstesttools/meson.build b/installed-tests/js/libgjstesttools/meson.build index e391844af..48cceee17 100644 --- a/installed-tests/js/libgjstesttools/meson.build +++ b/installed-tests/js/libgjstesttools/meson.build @@ -1,20 +1,26 @@ # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later # SPDX-FileCopyrightText: 2021 Marco Trevisan +libgjstesttools_extra_cpp_args = [] +if cc.get_argument_syntax() == 'msvc' + # We need to ensure the symbols in the test DLLs export in clang-cl builds + libgjstesttools_extra_cpp_args += ['-DGJS_TEST_TOOL_EXTERN=__declspec(dllexport)extern'] +endif + gjstest_tools_sources = [ 'gjs-test-tools.cpp', 'gjs-test-tools.h', ] libgjstesttools = library('gjstesttools', sources: gjstest_tools_sources, - include_directories: top_include, dependencies: libgjs_dep, - cpp_args: libgjs_cpp_args + test_gir_extra_c_args + test_gir_warning_c_args, + include_directories: top_include, dependencies: libcjs_dep, + cpp_args: libcjs_cpp_args + libgjstesttools_extra_cpp_args, install: get_option('installed_tests'), install_dir: installed_tests_execdir) gjstest_tools_gir = gnome.generate_gir(libgjstesttools, includes: ['GObject-2.0', 'Gio-2.0'], sources: gjstest_tools_sources, - namespace: 'GjsTestTools', nsversion: '1.0', + namespace: 'CjsTestTools', nsversion: '1.0', symbol_prefix: 'gjs_test_tools_', fatal_warnings: get_option('werror'), - install: get_option('installed_tests'), install_dir_gir: false, + install: get_option('installed_tests'), install_gir: false, install_dir_typelib: installed_tests_execdir) gjstest_tools_typelib = gjstest_tools_gir[1] libgjstesttools_dep = declare_dependency( diff --git a/installed-tests/js/meson.build b/installed-tests/js/meson.build index d78883a9b..aac965754 100644 --- a/installed-tests/js/meson.build +++ b/installed-tests/js/meson.build @@ -8,113 +8,18 @@ jsunit_resources_files = gnome.compile_resources('jsunit-resources', 'jsunit.gresources.xml', c_name: 'jsunit_resources') minijasmine = executable('minijasmine', '../minijasmine.cpp', - jsunit_resources_files, dependencies: libgjs_dep, + jsunit_resources_files, dependencies: libcjs_dep, cpp_args: [ - '-DINSTTESTDIR="@0@"'.format(installed_tests_execdir), + '-DINSTTESTDIR="@0@"'.format(prefix / installed_tests_execdir), ], include_directories: top_include, install: get_option('installed_tests'), install_dir: installed_tests_execdir) -# When building gobject-introspection as a subproject, use the variables -# exported by the subproject to find the locations of the test sources. -# Otherwise, get the locations from the pkgconfig file. -# -# The subproject does not yet export variables for warnlib's sources. -# See https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/287 -skip_warnlib = false -if gi.type_name() == 'internal' - gi_subproject = subproject('gobject-introspection') - regress_sources = (gi_subproject.get_variable('test_regress_sources') + - gi_subproject.get_variable('test_regress_headers')) - gimarshallingtests_sources = ( - gi_subproject.get_variable('test_marshalling_sources') + - gi_subproject.get_variable('test_marshalling_headers')) - gi_tests_include = gi_subproject.get_variable('test_regress_incdirs') - skip_warnlib = true -else - gidatadir = gi.get_variable(pkgconfig: 'gidatadir') - gi_tests = gidatadir / 'tests' - regress_sources = [gi_tests / 'regress.c', gi_tests / 'regress.h'] - warnlib_sources = [gi_tests / 'warnlib.c', gi_tests / 'warnlib.h'] - gimarshallingtests_sources = [ - gi_tests / 'gimarshallingtests.c', - gi_tests / 'gimarshallingtests.h', - ] - gi_tests_include = include_directories(gi_tests) -endif - -test_gir_extra_c_args = [] -test_gir_warning_c_args = [] - -if cc.get_argument_syntax() == 'msvc' - # We need to ensure the symbols in the test DLLs export in clang-cl builds - test_gir_extra_c_args += ['-D_GI_EXTERN=__declspec(dllexport)extern'] -else - # These consist of external code (from gobject-introspection) so they should not - # error out even when building with -Werror - test_gir_warning_c_args += ['-Wno-error'] -endif - -regress_dependencies = [glib, gobject, gio] -regress_gir_includes = ['Gio-2.0'] -regress_gir_c_args = test_gir_extra_c_args -if build_cairo - regress_gir_includes += 'cairo-1.0' - regress_dependencies += [cairo, cairo_gobject] -else - regress_gir_c_args += ['-D_GI_DISABLE_CAIRO'] -endif - -libregress = library('regress', regress_sources, - c_args: regress_gir_c_args + test_gir_warning_c_args, - include_directories: gi_tests_include, - dependencies: regress_dependencies, install: get_option('installed_tests'), - install_dir: installed_tests_execdir) -regress_gir = gnome.generate_gir(libregress, includes: regress_gir_includes, - sources: regress_sources, namespace: 'Regress', nsversion: '1.0', - identifier_prefix: 'Regress', symbol_prefix: 'regress_', - extra_args: ['--warn-all'] + regress_gir_c_args, - install: get_option('installed_tests'), install_dir_gir: false, - install_dir_typelib: installed_tests_execdir, - fatal_warnings: get_option('werror')) -regress_typelib = regress_gir[1] - -if not skip_warnlib - libwarnlib = library('warnlib', warnlib_sources, - c_args: test_gir_warning_c_args + test_gir_extra_c_args, - include_directories: gi_tests_include, - dependencies: [glib, gobject, gio], - install: get_option('installed_tests'), - install_dir: installed_tests_execdir) - # This should have --warn-all turned off, but there is currently no way to - # do so in gnome.generate_gir(). - # See https://github.com/mesonbuild/meson/issues/5876 - warnlib_gir = gnome.generate_gir(libwarnlib, includes: ['Gio-2.0'], - sources: warnlib_sources, namespace: 'WarnLib', nsversion: '1.0', - symbol_prefix: 'warnlib_', header: 'warnlib.h', - install: get_option('installed_tests'), install_dir_gir: false, - install_dir_typelib: installed_tests_execdir) - warnlib_typelib = warnlib_gir[1] -endif - -libgimarshallingtests = library('gimarshallingtests', - gimarshallingtests_sources, dependencies: [glib, gobject, gio], - include_directories: gi_tests_include, - c_args: test_gir_extra_c_args + test_gir_warning_c_args, - install: get_option('installed_tests'), install_dir: installed_tests_execdir) -gimarshallingtests_gir = gnome.generate_gir(libgimarshallingtests, - includes: ['Gio-2.0'], sources: gimarshallingtests_sources, - namespace: 'GIMarshallingTests', nsversion: '1.0', - symbol_prefix: 'gi_marshalling_tests_', fatal_warnings: get_option('werror'), - install: get_option('installed_tests'), install_dir_gir: false, - install_dir_typelib: installed_tests_execdir) -gimarshallingtests_typelib = gimarshallingtests_gir[1] - subdir('libgjstesttools') jasmine_tests = [ 'self', - 'ByteArray', + 'Cairo', 'Exceptions', 'Format', 'Fundamental', @@ -144,12 +49,9 @@ jasmine_tests = [ 'Signals', 'System', 'Tweener', + 'WarnLib', ] -if build_cairo - jasmine_tests += 'Cairo' -endif - if not get_option('skip_gtk_tests') jasmine_tests += [ 'Gtk3', @@ -165,17 +67,13 @@ gschemas_compiled = gnome.compile_schemas( tests_dependencies = [ gschemas_compiled, - gjs_private_typelib, + cjs_private_typelib, gjstest_tools_typelib, - gimarshallingtests_typelib, - regress_typelib, + gi_tests.get_variable('gimarshallingtests_typelib'), + gi_tests.get_variable('regress_typelib'), + gi_tests.get_variable('warnlib_typelib'), ] -if not skip_warnlib - jasmine_tests += 'WarnLib' - tests_dependencies += warnlib_typelib -endif - foreach test : jasmine_tests test_file = files('test@0@.js'.format(test)) @@ -184,9 +82,9 @@ foreach test : jasmine_tests test_description_subst = { 'name': 'test@0@.js'.format(test), - 'installed_tests_execdir': installed_tests_execdir, + 'installed_tests_execdir': prefix / installed_tests_execdir, } - test_description = configure_file(configuration: test_description_subst, + configure_file(configuration: test_description_subst, input: '../minijasmine.test.in', output: 'test@0@.test'.format(test), install: get_option('installed_tests'), @@ -208,7 +106,7 @@ dbus_tests = ['GDBus'] if not get_option('skip_gtk_tests') have_gtk4 = dependency('gtk4', required: false).found() - if have_gtk4 + if have_gtk4 # FIXME: find out why GTK4 tries to acquire a message bus dbus_tests += 'Gtk4' endif @@ -221,14 +119,15 @@ foreach test : dbus_tests if not get_option('skip_dbus_tests') test(test, dbus_run_session, args: ['--config-file', bus_config, '--', minijasmine, test_file], - env: tests_environment, protocol: 'tap', suite: 'dbus') + env: tests_environment, protocol: 'tap', suite: 'dbus', + depends: tests_dependencies) endif dbus_test_description_subst = { 'name': 'test@0@.js'.format(test), - 'installed_tests_execdir': installed_tests_execdir, + 'installed_tests_execdir': prefix / installed_tests_execdir, } - dbus_test_description = configure_file( + configure_file( configuration: dbus_test_description_subst, input: '../minijasmine.test.in', output: 'test@0@.test'.format(test), @@ -245,6 +144,7 @@ endforeach modules_tests = [ 'Async', + 'CairoModule', 'Console', 'ESModules', 'AsyncMainloop', @@ -252,10 +152,8 @@ modules_tests = [ 'GLibLogWriter', 'Global', 'Timers', + 'WeakRef', ] -if build_cairo - modules_tests += 'CairoModule' -endif foreach test : modules_tests test_file = files('test@0@.js'.format(test)) @@ -265,10 +163,9 @@ foreach test : modules_tests esm_test_description_subst = { 'name': 'test@0@.js'.format(test), - 'installed_tests_execdir': installed_tests_execdir, + 'installed_tests_execdir': prefix / installed_tests_execdir, } - esm_test_description = configure_file( - configuration: esm_test_description_subst, + configure_file(configuration: esm_test_description_subst, input: '../minijasmine-module.test.in', output: 'test@0@.test'.format(test), install: get_option('installed_tests'), diff --git a/installed-tests/js/minijasmine-executor.js b/installed-tests/js/minijasmine-executor.js index 1f1bb2229..f014cd2db 100644 --- a/installed-tests/js/minijasmine-executor.js +++ b/installed-tests/js/minijasmine-executor.js @@ -5,7 +5,13 @@ import * as system from 'system'; import GLib from 'gi://GLib'; -import {environment, retval, errorsOutput, mainloop, mainloopLock} from './minijasmine.js'; +import { + environment, + retval, + errorsOutput, + mainloop, + mainloopLock, +} from './minijasmine.js'; // environment.execute() queues up all the tests and runs them // asynchronously. This should start after the main loop starts, otherwise diff --git a/installed-tests/js/minijasmine.js b/installed-tests/js/minijasmine.js index 730aa212c..fa412fec5 100644 --- a/installed-tests/js/minijasmine.js +++ b/installed-tests/js/minijasmine.js @@ -1,4 +1,4 @@ -#!/usr/bin/env -S cjs -m +#!/usr/bin/env -S gjs -m // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later // SPDX-FileCopyrightText: 2016 Philip Chimento @@ -9,7 +9,7 @@ function _filterStack(stack) { return 'No stack'; return stack.split('\n') - .filter(stackLine => stackLine.indexOf('resource:///org/gjs/jsunit') === -1) + .filter(stackLine => stackLine.indexOf('resource:///org/cjs/jsunit') === -1) .join('\n'); } diff --git a/installed-tests/js/modules/greet.js b/installed-tests/js/modules/greet.js new file mode 100644 index 000000000..9d1fc7735 --- /dev/null +++ b/installed-tests/js/modules/greet.js @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later +// SPDX-FileCopyrightText: 2024 Philip Chimento + +import GLib from 'gi://GLib'; + +const uri = GLib.Uri.parse(import.meta.url, GLib.UriFlags.NONE); +const {greeting, name} = GLib.Uri.parse_params(uri.get_query(), -1, '&', GLib.UriParamsFlags.NONE); + +export default `${greeting}, ${name}`; diff --git a/installed-tests/js/modules/sideEffect.js b/installed-tests/js/modules/sideEffect.js new file mode 100644 index 000000000..5bfcfb258 --- /dev/null +++ b/installed-tests/js/modules/sideEffect.js @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later +// SPDX-FileCopyrightText: 2023 Philip Chimento + +globalThis.leakyState ??= 0; +globalThis.leakyState++; diff --git a/installed-tests/js/modules/sideEffect2.js b/installed-tests/js/modules/sideEffect2.js new file mode 100644 index 000000000..5bfcfb258 --- /dev/null +++ b/installed-tests/js/modules/sideEffect2.js @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later +// SPDX-FileCopyrightText: 2023 Philip Chimento + +globalThis.leakyState ??= 0; +globalThis.leakyState++; diff --git a/installed-tests/js/modules/sideEffect3.js b/installed-tests/js/modules/sideEffect3.js new file mode 100644 index 000000000..d27477b46 --- /dev/null +++ b/installed-tests/js/modules/sideEffect3.js @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later +// SPDX-FileCopyrightText: 2024 Gary Li + +globalThis.queryLeakyState ??= 0; +globalThis.queryLeakyState++; diff --git a/installed-tests/js/modules/sideEffect4.js b/installed-tests/js/modules/sideEffect4.js new file mode 100644 index 000000000..d7fc063bb --- /dev/null +++ b/installed-tests/js/modules/sideEffect4.js @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later +// SPDX-FileCopyrightText: 2024 Gary Li +const doImport = async () => { + await import('./sideEffect3.js?bar=baz'); +}; + +await doImport(); diff --git a/installed-tests/js/testAsyncMainloop.js b/installed-tests/js/testAsyncMainloop.js index ec36a3a21..9e1d61571 100644 --- a/installed-tests/js/testAsyncMainloop.js +++ b/installed-tests/js/testAsyncMainloop.js @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: 2022 Evan Welsh import GLib from 'gi://GLib'; -import {acquireMainloop} from 'resource:///org/gjs/jsunit/minijasmine.js'; +import {acquireMainloop} from 'resource:///org/cjs/jsunit/minijasmine.js'; describe('Async mainloop', function () { let loop, quit; diff --git a/installed-tests/js/testByteArray.js b/installed-tests/js/testByteArray.js deleted file mode 100644 index 4dd1ec912..000000000 --- a/installed-tests/js/testByteArray.js +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later -// SPDX-FileCopyrightText: 2010 litl, LLC -// SPDX-FileCopyrightText: 2017 Philip Chimento - -const ByteArray = imports.byteArray; -const {GIMarshallingTests, GLib} = imports.gi; - -describe('Byte array', function () { - it('can be created from a string', function () { - let a = ByteArray.fromString('abcd'); - expect(a.length).toEqual(4); - [97, 98, 99, 100].forEach((val, ix) => expect(a[ix]).toEqual(val)); - }); - - it('can be encoded from a string', function () { - // Pick a string likely to be stored internally as Latin1 - let a = ByteArray.fromString('äbcd', 'LATIN1'); - expect(a.length).toEqual(4); - [228, 98, 99, 100].forEach((val, ix) => expect(a[ix]).toEqual(val)); - - // Try again with a string not likely to be Latin1 internally - a = ByteArray.fromString('⅜', 'UTF-8'); - expect(a.length).toEqual(3); - [0xe2, 0x85, 0x9c].forEach((val, ix) => expect(a[ix]).toEqual(val)); - }); - - it('encodes as UTF-8 by default', function () { - let a = ByteArray.fromString('⅜'); - expect(a.length).toEqual(3); - [0xe2, 0x85, 0x9c].forEach((val, ix) => expect(a[ix]).toEqual(val)); - }); - - it('can be converted to a string of ASCII characters', function () { - let a = new Uint8Array(4); - a[0] = 97; - a[1] = 98; - a[2] = 99; - a[3] = 100; - let s = ByteArray.toString(a); - expect(s.length).toEqual(4); - expect(s).toEqual('abcd'); - }); - - it('can be converted to a string of UTF-8 characters even if it ends with a 0', function () { - const a = Uint8Array.of(97, 98, 99, 100, 0); - const s = ByteArray.toString(a); - expect(s.length).toEqual(4); - expect(s).toEqual('abcd'); - }); - - it('can be converted to a string of encoded characters even with a 0 byte', function () { - const a = Uint8Array.of(97, 98, 99, 100, 0); - const s = ByteArray.toString(a, 'LATIN1'); - expect(s.length).toEqual(4); - expect(s).toEqual('abcd'); - }); - - it('stops converting to a string at an embedded 0 byte', function () { - const a = Uint8Array.of(97, 98, 0, 99, 100); - const s = ByteArray.toString(a); - expect(s.length).toEqual(2); - expect(s).toEqual('ab'); - }); - - it('deals gracefully with a 0-length array', function () { - const a = new Uint8Array(0); - expect(ByteArray.toString(a)).toEqual(''); - expect(ByteArray.toGBytes(a).get_size()).toEqual(0); - }); - - it('deals gracefully with a 0-length GLib.Bytes', function () { - const noBytes = ByteArray.toGBytes(new Uint8Array(0)); - expect(ByteArray.fromGBytes(noBytes).length).toEqual(0); - }); - - it('deals gracefully with a 0-length string', function () { - expect(ByteArray.fromString('').length).toEqual(0); - expect(ByteArray.fromString('', 'LATIN1').length).toEqual(0); - }); - - it('deals gracefully with a non Uint8Array', function () { - const a = [97, 98, 99, 100, 0]; - expect(() => ByteArray.toString(a)).toThrow(); - expect(() => ByteArray.toGBytes(a)).toThrow(); - }); - - describe('legacy toString() behavior', function () { - beforeEach(function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, - 'Some code called array.toString()*'); - }); - - it('is preserved when created from a string', function () { - let a = ByteArray.fromString('⅜'); - expect(a.toString()).toEqual('⅜'); - }); - - it('is preserved when marshalled from GI', function () { - let a = GIMarshallingTests.bytearray_full_return(); - expect(a.toString()).toEqual(''); - }); - - afterEach(function () { - GLib.test_assert_expected_messages_internal('Gjs', - 'testByteArray.js', 0, 'testToStringCompatibility'); - }); - }); -}); diff --git a/installed-tests/js/testConsole.js b/installed-tests/js/testConsole.js index c999e9f35..f7110cfa2 100644 --- a/installed-tests/js/testConsole.js +++ b/installed-tests/js/testConsole.js @@ -121,6 +121,30 @@ describe('console', function () { writer_func.calls.reset(); }); + it('logs an empty object correctly', function () { + const emptyObject = {}; + console.log(emptyObject); + expectLog('{}'); + }); + + it('logs an object with custom constructor name', function () { + function CustomObject() {} + const customInstance = new CustomObject(); + console.log(customInstance); + expectLog('CustomObject {}'); + }); + + it('logs an object with undefined constructor', function () { + const objectWithUndefinedConstructor = Object.create(null); + console.log(objectWithUndefinedConstructor); + expectLog('{}'); + }); + + it('logs an object with Symbol.toStringTag and __name__', function () { + console.log(GLib); + expectLog('[GIRepositoryNamespace GLib]'); + }); + it('logs a warning', function () { console.warn('a warning'); diff --git a/installed-tests/js/testESModules.js b/installed-tests/js/testESModules.js index e727c7907..02bdf8681 100644 --- a/installed-tests/js/testESModules.js +++ b/installed-tests/js/testESModules.js @@ -8,9 +8,23 @@ import Gio from 'gi://Gio'; import system from 'system'; import {exit} from 'system'; -import $ from 'resource:///org/gjs/jsunit/modules/exports.js'; -import {NamedExport, data} from 'resource:///org/gjs/jsunit/modules/exports.js'; -import metaProperties from 'resource:///org/gjs/jsunit/modules/importmeta.js'; +import $ from 'resource:///org/cjs/jsunit/modules/exports.js'; +import {NamedExport, data} from 'resource:///org/cjs/jsunit/modules/exports.js'; +import metaProperties from 'resource:///org/cjs/jsunit/modules/importmeta.js'; + +// These imports should all refer to the same module and import it only once +import 'resource:///org/cjs/jsunit/modules/sideEffect.js'; +import 'resource://org/cjs/jsunit/modules/sideEffect.js'; +import 'resource:///org/cjs/jsunit/modules/../modules/sideEffect.js'; + +// Imports with query parameters should not fail and be imported uniquely +import 'resource:///org/cjs/jsunit/modules/sideEffect3.js?foo=bar&maple=syrup'; +// these should resolve to the same after being canonicalized +import 'resource://org/cjs/jsunit/modules/./sideEffect3.js?etag=1'; +import 'resource:///org/cjs/jsunit/modules/sideEffect3.js?etag=1'; + +import greeting1 from 'resource:///org/cjs/jsunit/modules/greet.js?greeting=Hello&name=Test%20Code'; +import greeting2 from 'resource:///org/cjs/jsunit/modules/greet.js?greeting=Bonjour&name=Code%20de%20Test'; describe('ES module imports', function () { it('default import', function () { @@ -67,6 +81,19 @@ describe('ES module imports', function () { it('does not expose internal import.meta properties to userland modules', function () { expect(metaProperties).toEqual(['url']); }); + + it('treats equivalent URIs as equal and does not load the module again', function () { + expect(globalThis.leakyState).toEqual(1); + }); + + it('can load modules with query parameters uniquely', function () { + expect(globalThis.queryLeakyState).toEqual(2); + }); + + it('passes query parameters to imported modules in import.meta.uri', function () { + expect(greeting1).toEqual('Hello, Test Code'); + expect(greeting2).toEqual('Bonjour, Code de Test'); + }); }); describe('Builtin ES modules', function () { @@ -112,7 +139,7 @@ describe('Dynamic imports', function () { let module; beforeEach(async function () { try { - module = await import('resource:///org/gjs/jsunit/modules/say.js'); + module = await import('resource:///org/cjs/jsunit/modules/say.js'); } catch (err) { logError(err); fail(); @@ -130,4 +157,55 @@ describe('Dynamic imports', function () { it('dynamic gi import matches static', async function () { expect((await import('gi://Gio')).default).toEqual(Gio); }); + + it('treats equivalent URIs as equal and does not load the module again', async function () { + delete globalThis.leakyState; + await import('resource:///org/cjs/jsunit/modules/sideEffect2.js'); + await import('resource://org/cjs/jsunit/modules/sideEffect2.js'); + await import('resource:///org/cjs/jsunit/modules/../modules/sideEffect2.js'); + expect(globalThis.leakyState).toEqual(1); + }); + + it('treats query parameters uniquely for absolute URIs', async function () { + delete globalThis.queryLeakyState; + await import('resource:///org/cjs/jsunit/modules/sideEffect3.js?maple=syrup'); + expect(globalThis.queryLeakyState).toEqual(1); + }); + + it('treats query parameters uniquely for relative URIs', async function () { + delete globalThis.queryLeakyState; + await import('resource:///org/cjs/jsunit/modules/sideEffect4.js'); + expect(globalThis.queryLeakyState).toEqual(1); + }); + + it('does not show internal stack frames in an import error', async function () { + try { + await import('resource:///org/cjs/jsunit/modules/doesNotExist.js'); + fail('should not be reached'); + } catch (e) { + expect(e.name).toBe('ImportError'); + expect(e.stack).not.toMatch('internal/'); + } + }); + + it('does not show internal stack frames in a module that throws an error', async function () { + try { + await import('resource:///org/cjs/jsunit/modules/alwaysThrows.js'); + fail('should not be reached'); + } catch (e) { + expect(e.constructor).toBe(Error); + expect(e.stack).not.toMatch('internal/'); + } + }); + + it('does not show internal stack frames in a module that fails to parse', async function () { + try { + // invalid JS + await import('resource:///org/cjs/jsunit/modules/data.txt'); + fail('should not be reached'); + } catch (e) { + expect(e.constructor).toBe(SyntaxError); + expect(e.stack).not.toMatch('internal/'); + } + }); }); diff --git a/installed-tests/js/testEncoding.js b/installed-tests/js/testEncoding.js index 55d65581e..fd007236e 100644 --- a/installed-tests/js/testEncoding.js +++ b/installed-tests/js/testEncoding.js @@ -4,6 +4,7 @@ // Some test inputs are derived from https://github.com/denoland/deno/blob/923214c53725651792f6d55c5401bf6b475622ea/op_crates/web/08_text_encoding.js // Data originally from https://encoding.spec.whatwg.org/encodings.json +import GLib from 'gi://GLib'; import Gio from 'gi://Gio'; import {arrayLikeWithExactContents} from './matchers.js'; @@ -184,6 +185,13 @@ describe('Text Encoding', function () { expect(decoder.decode(input)).toBe('𝓽𝓮𝔁𝓽'); }); + it('decodes GLib.Bytes', function () { + const decoder = new TextDecoder(); + const input = new GLib.Bytes(encodedMultibyteCharArray()); + + expect(decoder.decode(input)).toBe('𝓽𝓮𝔁𝓽'); + }); + it('ignores byte order marker (BOM)', function () { const decoder = new TextDecoder('utf-8', {ignoreBOM: true}); const input = new Uint8Array([ @@ -363,10 +371,7 @@ describe('Text Encoding', function () { expect(() => { decoder.decode(new Uint8Array([161, 200, 200])); - }).toThrowError( - TypeError, - 'Invalid byte sequence in conversion input' - ); + }).toThrowError(TypeError); }); it('can decode ASCII', function () { @@ -377,7 +382,7 @@ describe('Text Encoding', function () { // Straight from https://encoding.spec.whatwg.org/encodings.json const encodingsTable = loadJSONFromResource( - 'resource:///org/gjs/jsunit/modules/encodings.json' + 'resource:///org/cjs/jsunit/modules/encodings.json' ); const singleByteEncodings = encodingsTable.filter(group => { diff --git a/installed-tests/js/testExceptions.js b/installed-tests/js/testExceptions.js index 17c61da2f..391544b8f 100644 --- a/installed-tests/js/testExceptions.js +++ b/installed-tests/js/testExceptions.js @@ -39,12 +39,12 @@ describe('Exceptions', function () { // FIXME: In the next cases the errors aren't thrown but logged it('are logged from constructor', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'JS ERROR: Error: set*'); new Foo({prop: 'bar'}); - GLib.test_assert_expected_messages_internal('Gjs', 'testExceptions.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testExceptions.js', 0, 'testExceptionInPropertySetterFromConstructor'); }); @@ -55,13 +55,13 @@ describe('Exceptions', function () { bar.bind_property('prop', foo, 'prop', GObject.BindingFlags.DEFAULT); - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'JS ERROR: Error: set*'); // wake up the binding so that g_object_set() is called on foo bar.notify('prop'); - GLib.test_assert_expected_messages_internal('Gjs', 'testExceptions.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testExceptions.js', 0, 'testExceptionInPropertySetterWithBinding'); }); @@ -72,25 +72,25 @@ describe('Exceptions', function () { foo.bind_property('prop', bar, 'prop', GObject.BindingFlags.DEFAULT); - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'JS ERROR: Error: get*'); // wake up the binding so that g_object_get() is called on foo foo.notify('prop'); - GLib.test_assert_expected_messages_internal('Gjs', 'testExceptions.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testExceptions.js', 0, 'testExceptionInPropertyGetterWithBinding'); }); }); describe('logError', function () { afterEach(function () { - GLib.test_assert_expected_messages_internal('Gjs', 'testExceptions.js', + GLib.test_assert_expected_messages_internal('Cjs', 'testExceptions.js', 0, 'testGErrorMessages'); }); it('logs a warning for a GError', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: Gio.IOErrorEnum: *'); try { let file = Gio.file_new_for_path("\\/,.^!@&$_don't exist"); @@ -101,7 +101,7 @@ describe('logError', function () { }); it('logs a warning with a message if given', function marker() { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: Gio.IOErrorEnum: a message\nmarker@*'); try { throw new Gio.IOErrorEnum({message: 'a message', code: 0}); @@ -111,25 +111,25 @@ describe('logError', function () { }); it('also logs an error for a created GError that is not thrown', function marker() { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: Gio.IOErrorEnum: a message\nmarker@*'); logError(new Gio.IOErrorEnum({message: 'a message', code: 0})); }); it('logs an error created with the GLib.Error constructor', function marker() { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: Gio.IOErrorEnum: a message\nmarker@*'); logError(new GLib.Error(Gio.IOErrorEnum, 0, 'a message')); }); it('logs the quark for a JS-created GError type', function marker() { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: GLib.Error my-error: a message\nmarker@*'); logError(new GLib.Error(GLib.quark_from_string('my-error'), 0, 'a message')); }); it('logs with stack for a GError created from a C struct', function marker() { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: GLib.Error gi-marshalling-tests-gerror-domain: gi-marshalling-tests-gerror-message\nmarker@*'); logError(GIMarshallingTests.gerror_return()); }); @@ -137,7 +137,7 @@ describe('logError', function () { // Now with prefix it('logs an error with a prefix if given', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: prefix: Gio.IOErrorEnum: *'); try { let file = Gio.file_new_for_path("\\/,.^!@&$_don't exist"); @@ -148,7 +148,7 @@ describe('logError', function () { }); it('logs an error with prefix and message', function marker() { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: prefix: Gio.IOErrorEnum: a message\nmarker@*'); try { throw new Gio.IOErrorEnum({message: 'a message', code: 0}); @@ -157,18 +157,34 @@ describe('logError', function () { } }); - it('logs a SyntaxError', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, - 'JS ERROR: SyntaxError:*'); - try { + describe('Syntax Error', function () { + function throwSyntaxError() { Reflect.parse('!@#$%^&'); - } catch (e) { - logError(e); } + + it('logs a SyntaxError', function () { + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, + 'JS ERROR: SyntaxError:*'); + try { + throwSyntaxError(); + } catch (e) { + logError(e); + } + }); + + it('logs a stack trace with the SyntaxError', function () { + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, + 'JS ERROR: SyntaxError:*throwSyntaxError@*'); + try { + throwSyntaxError(); + } catch (e) { + logError(e); + } + }); }); it('logs an error with cause', function marker() { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: Error: an error\nmarker@*Caused by: Gio.IOErrorEnum: another error\nmarker2@*'); function marker2() { return new Gio.IOErrorEnum({message: 'another error', code: 0}); @@ -177,7 +193,7 @@ describe('logError', function () { }); it('logs a GError with cause', function marker() { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: Gio.IOErrorEnum: an error\nmarker@*Caused by: Error: another error\nmarker2@*'); function marker2() { return new Error('another error'); @@ -188,13 +204,13 @@ describe('logError', function () { }); it('logs an error with non-object cause', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: Error: an error\n*Caused by: 3'); logError(new Error('an error', {cause: 3})); }); it('logs an error with a cause tree', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: Error: one\n*Caused by: Error: two\n*Caused by: Error: three\n*'); const three = new Error('three'); const two = new Error('two', {cause: three}); @@ -205,7 +221,7 @@ describe('logError', function () { // We cannot assert here with GLib.test_expect_message that the * at the // end of the string doesn't match more causes, but at least the idea is // that it shouldn't go into an infinite loop - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: Error: one\n*Caused by: Error: two\n*'); const one = new Error('one'); one.cause = new Error('two', {cause: one}); diff --git a/installed-tests/js/testGDBus.js b/installed-tests/js/testGDBus.js index 25de96b6a..ed646bddf 100644 --- a/installed-tests/js/testGDBus.js +++ b/installed-tests/js/testGDBus.js @@ -1,15 +1,24 @@ // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later // SPDX-FileCopyrightText: 2008 litl, LLC -const ByteArray = imports.byteArray; -const {Gio, GjsTestTools, GLib} = imports.gi; +const {Gio, CjsTestTools, GLib} = imports.gi; + +// Adapter for compatibility with pre-GLib-2.80 +let GioUnix; +if (imports.gi.versions.GioUnix === '2.0') { + GioUnix = imports.gi.GioUnix; +} else { + GioUnix = { + InputStream: Gio.UnixInputStream, + }; +} /* The methods list with their signatures. * * *** NOTE: If you add stuff here, you need to update the Test class below. */ var TestIface = ` - + @@ -113,7 +122,7 @@ class Test { this._propReadWrite = PROP_READ_WRITE_INITIAL_VALUE; this._impl = Gio.DBusExportedObject.wrapJSObject(TestIface, this); - this._impl.export(Gio.DBus.session, '/org/gnome/gjs/Test'); + this._impl.export(Gio.DBus.session, '/org/cinnamon/cjs/Test'); } frobateStuff() { @@ -235,7 +244,7 @@ class Test { fdIn(fdIndex, fdList) { const fd = fdList.get(fdIndex); - const stream = new Gio.UnixInputStream({fd, closeFd: true}); + const stream = new GioUnix.InputStream({fd, closeFd: true}); const bytes = stream.read_bytes(4096, null); return bytes; } @@ -243,7 +252,7 @@ class Test { // Same as fdIn(), but implemented asynchronously fdIn2Async([fdIndex], invocation, fdList) { const fd = fdList.get(fdIndex); - const stream = new Gio.UnixInputStream({fd, closeFd: true}); + const stream = new GioUnix.InputStream({fd, closeFd: true}); stream.read_bytes_async(4096, GLib.PRIORITY_DEFAULT, null, (obj, res) => { const bytes = obj.read_bytes_finish(res); invocation.return_value(new GLib.Variant('(ay)', [bytes])); @@ -251,14 +260,14 @@ class Test { } fdOut(bytes) { - const fd = GjsTestTools.open_bytes(bytes); + const fd = CjsTestTools.open_bytes(bytes); const fdList = Gio.UnixFDList.new_from_array([fd]); return [0, fdList]; } fdOut2Async([bytes], invocation) { GLib.idle_add(GLib.PRIORITY_DEFAULT, function () { - const fd = GjsTestTools.open_bytes(bytes); + const fd = CjsTestTools.open_bytes(bytes); const fdList = Gio.UnixFDList.new_from_array([fd]); invocation.return_value_with_unix_fd_list(new GLib.Variant('(h)', [0]), fdList); @@ -274,6 +283,7 @@ describe('Exported DBus object', function () { var test; var proxy; let loop; + const expectedBytes = new TextEncoder().encode('some bytes'); function waitForServerProperty(property, value = undefined, timeout = 500) { let waitId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, timeout, () => { @@ -296,7 +306,7 @@ describe('Exported DBus object', function () { loop = new GLib.MainLoop(null, false); test = new Test(); - ownNameID = Gio.DBus.session.own_name('org.gnome.gjs.Test', + ownNameID = Gio.DBus.session.own_name('org.cinnamon.cjs.Test', Gio.BusNameOwnerFlags.NONE, name => { log(`Acquired name ${name}`); @@ -306,8 +316,8 @@ describe('Exported DBus object', function () { log(`Lost name ${name}`); }); loop.run(); - new ProxyClass(Gio.DBus.session, 'org.gnome.gjs.Test', - '/org/gnome/gjs/Test', + new ProxyClass(Gio.DBus.session, 'org.cinnamon.cjs.Test', + '/org/cinnamon/cjs/Test', (obj, error) => { expect(error).toBeNull(); proxy = obj; @@ -344,7 +354,7 @@ describe('Exported DBus object', function () { it('can initiate a proxy with promise and call a method with async/await', async function () { const asyncProxy = await ProxyClass.newAsync(Gio.DBus.session, - 'org.gnome.gjs.Test', '/org/gnome/gjs/Test'); + 'org.cinnamon.cjs.Test', '/org/cinnamon/cjs/Test'); expect(asyncProxy).toBeInstanceOf(Gio.DBusProxy); const [{hello}] = await asyncProxy.frobateStuffAsync({}); expect(hello.deepUnpack()).toEqual('world'); @@ -357,8 +367,8 @@ describe('Exported DBus object', function () { Gio.DBusProxy.new_for_bus(Gio.BusType.SESSION, Gio.DBusProxyFlags.DO_NOT_AUTO_START, iface, - 'org.gnome.gjs.Test', - '/org/gnome/gjs/Test', + 'org.cinnamon.cjs.Test', + '/org/cinnamon/cjs/Test', iface.name, null, (o, res) => { @@ -378,7 +388,7 @@ describe('Exported DBus object', function () { /* excp must be exactly the exception thrown by the remote method (more or less) */ it('can handle an exception thrown by a remote method', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: Exception in method call: alwaysThrowException: *'); proxy.alwaysThrowExceptionRemote({}, function (result, excp) { @@ -389,14 +399,14 @@ describe('Exported DBus object', function () { }); it('can handle an exception thrown by a method with async/await', async function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: Exception in method call: alwaysThrowException: *'); await expectAsync(proxy.alwaysThrowExceptionAsync({})).toBeRejected(); }); it('can still destructure the return value when an exception is thrown', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: Exception in method call: alwaysThrowException: *'); // This test will not fail, but instead if the functionality is not @@ -683,8 +693,7 @@ describe('Exported DBus object', function () { }); it('can call a remote method with a Unix FD', function (done) { - const expectedBytes = ByteArray.fromString('some bytes'); - const fd = GjsTestTools.open_bytes(expectedBytes); + const fd = CjsTestTools.open_bytes(expectedBytes); const fdList = Gio.UnixFDList.new_from_array([fd]); proxy.fdInRemote(0, fdList, ([bytes], exc, outFdList) => { expect(exc).toBeNull(); @@ -695,9 +704,7 @@ describe('Exported DBus object', function () { }); it('can call an async/await method with a Unix FD', async function () { - const encoder = new TextEncoder(); - const expectedBytes = encoder.encode('some bytes'); - const fd = GjsTestTools.open_bytes(expectedBytes); + const fd = CjsTestTools.open_bytes(expectedBytes); const fdList = Gio.UnixFDList.new_from_array([fd]); const [bytes, outFdList] = await proxy.fdInAsync(0, fdList); expect(outFdList).not.toBeDefined(); @@ -705,8 +712,7 @@ describe('Exported DBus object', function () { }); it('can call an asynchronously implemented remote method with a Unix FD', function (done) { - const expectedBytes = ByteArray.fromString('some bytes'); - const fd = GjsTestTools.open_bytes(expectedBytes); + const fd = CjsTestTools.open_bytes(expectedBytes); const fdList = Gio.UnixFDList.new_from_array([fd]); proxy.fdIn2Remote(0, fdList, ([bytes], exc, outFdList) => { expect(exc).toBeNull(); @@ -717,9 +723,7 @@ describe('Exported DBus object', function () { }); it('can call an asynchronously implemented async/await method with a Unix FD', async function () { - const encoder = new TextEncoder(); - const expectedBytes = encoder.encode('some bytes'); - const fd = GjsTestTools.open_bytes(expectedBytes); + const fd = CjsTestTools.open_bytes(expectedBytes); const fdList = Gio.UnixFDList.new_from_array([fd]); const [bytes, outFdList] = await proxy.fdIn2Async(0, fdList); expect(outFdList).not.toBeDefined(); @@ -727,13 +731,12 @@ describe('Exported DBus object', function () { }); function readBytesFromFdSync(fd) { - const stream = new Gio.UnixInputStream({fd, closeFd: true}); + const stream = new GioUnix.InputStream({fd, closeFd: true}); const bytes = stream.read_bytes(4096, null); - return ByteArray.fromGBytes(bytes); + return bytes.toArray(); } it('can call a remote method that returns a Unix FD', function (done) { - const expectedBytes = ByteArray.fromString('some bytes'); proxy.fdOutRemote(expectedBytes, ([fdIndex], exc, outFdList) => { expect(exc).toBeNull(); const bytes = readBytesFromFdSync(outFdList.get(fdIndex)); @@ -743,15 +746,12 @@ describe('Exported DBus object', function () { }); it('can call an async/await method that returns a Unix FD', async function () { - const encoder = new TextEncoder(); - const expectedBytes = encoder.encode('some bytes'); const [fdIndex, outFdList] = await proxy.fdOutAsync(expectedBytes); const bytes = readBytesFromFdSync(outFdList.get(fdIndex)); expect(bytes).toEqual(expectedBytes); }); it('can call an asynchronously implemented remote method that returns a Unix FD', function (done) { - const expectedBytes = ByteArray.fromString('some bytes'); proxy.fdOut2Remote(expectedBytes, ([fdIndex], exc, outFdList) => { expect(exc).toBeNull(); const bytes = readBytesFromFdSync(outFdList.get(fdIndex)); @@ -761,8 +761,6 @@ describe('Exported DBus object', function () { }); it('can call an asynchronously implemented asyc/await method that returns a Unix FD', async function () { - const encoder = new TextEncoder(); - const expectedBytes = encoder.encode('some bytes'); const [fdIndex, outFdList] = await proxy.fdOut2Async(expectedBytes); const bytes = readBytesFromFdSync(outFdList.get(fdIndex)); expect(bytes).toEqual(expectedBytes); @@ -787,10 +785,10 @@ describe('Exported DBus object', function () { }); it('Has defined properties', function () { - expect(proxy.hasOwnProperty('PropReadWrite')).toBeTruthy(); - expect(proxy.hasOwnProperty('PropReadOnly')).toBeTruthy(); - expect(proxy.hasOwnProperty('PropWriteOnly')).toBeTruthy(); - expect(proxy.hasOwnProperty('PropPrePacked')).toBeTruthy(); + expect(Object.hasOwn(proxy, 'PropReadWrite')).toBeTruthy(); + expect(Object.hasOwn(proxy, 'PropReadOnly')).toBeTruthy(); + expect(Object.hasOwn(proxy, 'PropWriteOnly')).toBeTruthy(); + expect(Object.hasOwn(proxy, 'PropPrePacked')).toBeTruthy(); }); it('reading readonly property works', function () { @@ -892,8 +890,8 @@ describe('DBus Proxy wrapper', function () { it('init failures are reported in sync mode', function () { const cancellable = new Gio.Cancellable(); cancellable.cancel(); - expect(() => new ProxyClass(Gio.DBus.session, 'org.gnome.gjs.Test', - '/org/gnome/gjs/Test', + expect(() => new ProxyClass(Gio.DBus.session, 'org.cinnamon.cjs.Test', + '/org/cinnamon/cjs/Test', Gio.DBusProxyFlags.NONE, cancellable)).toThrow(); }); @@ -904,8 +902,8 @@ describe('DBus Proxy wrapper', function () { const initDoneSpy = jasmine.createSpy( 'init finish func', () => loop.quit()); initDoneSpy.and.callThrough(); - new ProxyClass(Gio.DBus.session, 'org.gnome.gjs.Test', - '/org/gnome/gjs/Test', + new ProxyClass(Gio.DBus.session, 'org.cinnamon.cjs.Test', + '/org/cinnamon/cjs/Test', initDoneSpy, cancellable, Gio.DBusProxyFlags.NONE); loop.run(); @@ -917,8 +915,8 @@ describe('DBus Proxy wrapper', function () { }); it('can init a proxy asynchronously when promisified', function () { - new ProxyClass(Gio.DBus.session, 'org.gnome.gjs.Test', - '/org/gnome/gjs/Test', + new ProxyClass(Gio.DBus.session, 'org.cinnamon.cjs.Test', + '/org/cinnamon/cjs/Test', () => loop.quit(), Gio.DBusProxyFlags.NONE); loop.run(); @@ -927,16 +925,16 @@ describe('DBus Proxy wrapper', function () { }); it('can create a proxy from a promise', async function () { - const proxyPromise = ProxyClass.newAsync(Gio.DBus.session, 'org.gnome.gjs.Test', - '/org/gnome/gjs/Test'); + const proxyPromise = ProxyClass.newAsync(Gio.DBus.session, 'org.cinnamon.cjs.Test', + '/org/cinnamon/cjs/Test'); await expectAsync(proxyPromise).toBeResolved(); }); it('can create fail a proxy from a promise', async function () { const cancellable = new Gio.Cancellable(); cancellable.cancel(); - const proxyPromise = ProxyClass.newAsync(Gio.DBus.session, 'org.gnome.gjs.Test', - '/org/gnome/gjs/Test', cancellable); + const proxyPromise = ProxyClass.newAsync(Gio.DBus.session, 'org.cinnamon.cjs.Test', + '/org/cinnamon/cjs/Test', cancellable); await expectAsync(proxyPromise).toBeRejected(); }); diff --git a/installed-tests/js/testGIMarshalling.js b/installed-tests/js/testGIMarshalling.js index a6c5321a7..a4270a51c 100644 --- a/installed-tests/js/testGIMarshalling.js +++ b/installed-tests/js/testGIMarshalling.js @@ -7,9 +7,8 @@ // SPDX-FileCopyrightText: 2019 Philip Chimento // Load overrides for GIMarshallingTests -imports.overrides.searchPath.unshift('resource:///org/gjs/jsunit/modules/overrides'); +imports.overrides.searchPath.unshift('resource:///org/cjs/jsunit/modules/overrides'); -const ByteArray = imports.byteArray; const GIMarshallingTests = imports.gi.GIMarshallingTests; // We use Gio and GLib to have some objects that we know exist @@ -52,6 +51,18 @@ function testOutParameter(root, value, {omit, skip, funcName = `${root}_out`} = }); } +function testUninitializedOutParameter(root, defaultValue, {omit, skip, funcName = `${root}_out_uninitialized`} = {}) { + if (omit) + return; + it("picks a reasonable default value when the function doesn't set the out parameter", function () { + if (skip) + pending(skip); + const [success, defaultVal] = GIMarshallingTests[funcName](); + expect(success).toBeFalse(); + expect(defaultVal).toEqual(defaultValue); + }); +} + function testInoutParameter(root, inValue, outValue, {omit, skip, funcName = `${root}_inout`} = {}) { if (omit) @@ -63,16 +74,17 @@ function testInoutParameter(root, inValue, outValue, }); } -function testSimpleMarshalling(root, value, inoutValue, options = {}) { +function testSimpleMarshalling(root, value, inoutValue, defaultValue, options = {}) { testReturnValue(root, value, options.returnv); testInParameter(root, value, options.in); testOutParameter(root, value, options.out); + testUninitializedOutParameter(root, defaultValue, options.uninitOut); testInoutParameter(root, value, inoutValue, options.inout); } -function testTransferMarshalling(root, value, inoutValue, options = {}) { +function testTransferMarshalling(root, value, inoutValue, defaultValue, options = {}) { describe('with transfer none', function () { - testSimpleMarshalling(`${root}_none`, value, inoutValue, options.none); + testSimpleMarshalling(`${root}_none`, value, inoutValue, defaultValue, options.none); }); describe('with transfer full', function () { const fullOptions = { @@ -84,12 +96,12 @@ function testTransferMarshalling(root, value, inoutValue, options = {}) { }, }; Object.assign(fullOptions, options.full); - testSimpleMarshalling(`${root}_full`, value, inoutValue, fullOptions); + testSimpleMarshalling(`${root}_full`, value, inoutValue, defaultValue, fullOptions); }); } -function testContainerMarshalling(root, value, inoutValue, options = {}) { - testTransferMarshalling(root, value, inoutValue, options); +function testContainerMarshalling(root, value, inoutValue, defaultValue, options = {}) { + testTransferMarshalling(root, value, inoutValue, defaultValue, options); describe('with transfer container', function () { const containerOptions = { in: { @@ -100,7 +112,7 @@ function testContainerMarshalling(root, value, inoutValue, options = {}) { }, }; Object.assign(containerOptions, options.container); - testSimpleMarshalling(`${root}_container`, value, inoutValue, containerOptions); + testSimpleMarshalling(`${root}_container`, value, inoutValue, defaultValue, containerOptions); }); } @@ -166,12 +178,12 @@ if (GLib.SIZEOF_SSIZE_T === 8) { // each other. That's fine for now. Then we just have to suppress the warnings. function warn64(is64bit, func, ...args) { if (is64bit) { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, '*cannot be safely stored*'); } const retval = func(...args); if (is64bit) { - GLib.test_assert_expected_messages_internal('Gjs', + GLib.test_assert_expected_messages_internal('Cjs', 'testGIMarshalling.js', 0, 'Ignore message'); } return retval; @@ -187,7 +199,7 @@ function skip64(is64bit) { describe('Boolean', function () { [true, false].forEach(bool => { describe(`${bool}`, function () { - testSimpleMarshalling('boolean', bool, !bool, { + testSimpleMarshalling('boolean', bool, !bool, false, { returnv: { funcName: `boolean_return_${bool}`, }, @@ -197,12 +209,17 @@ describe('Boolean', function () { out: { funcName: `boolean_out_${bool}`, }, + uninitOut: { + omit: true, + }, inout: { funcName: `boolean_inout_${bool}_${!bool}`, }, }); }); }); + + testUninitializedOutParameter('boolean', false); }); describe('Integer', function () { @@ -224,6 +241,8 @@ describe('Integer', function () { expect(warn64(bit64, GIMarshallingTests[`${type}_out_min`])).toEqual(min); }); + testUninitializedOutParameter(type, 0); + it('marshals as an inout parameter', function () { skip64(bit64); expect(GIMarshallingTests[`${type}_inout_max_min`](max)).toEqual(min); @@ -243,6 +262,8 @@ describe('Integer', function () { expect(warn64(bit64, GIMarshallingTests[`${utype}_out`])).toEqual(umax); }); + testUninitializedOutParameter(utype, 0); + it('marshals unsigned value as an inout parameter', function () { skip64(bit64); expect(GIMarshallingTests[`${utype}_inout`](umax)).toEqual(0); @@ -292,25 +313,32 @@ describe('Floating point', function () { expect(GIMarshallingTests[`${type}_out`]()).toBeCloseTo(max, 10); }); + testUninitializedOutParameter(type, 0); + it('marshals value as an inout parameter', function () { expect(GIMarshallingTests[`${type}_inout`](max)).toBeCloseTo(min, 10); }); + + it('can handle noncanonical NaN', function () { + expect(GIMarshallingTests[`${type}_noncanonical_nan_out`]()).toBeNaN(); + }); }); }); }); describe('time_t', function () { - testSimpleMarshalling('time_t', 1234567890, 0); + testSimpleMarshalling('time_t', 1234567890, 0, 0); }); describe('GType', function () { describe('void', function () { - testSimpleMarshalling('gtype', GObject.TYPE_NONE, GObject.TYPE_INT); + testSimpleMarshalling('gtype', GObject.TYPE_NONE, GObject.TYPE_INT, null); }); describe('string', function () { - testSimpleMarshalling('gtype_string', GObject.TYPE_STRING, null, { + testSimpleMarshalling('gtype_string', GObject.TYPE_STRING, null, null, { inout: {omit: true}, + uninitOut: {omit: true}, }); }); @@ -324,7 +352,11 @@ describe('GType', function () { }); describe('UTF-8 string', function () { - testTransferMarshalling('utf8', 'const ♥ utf8', ''); + testTransferMarshalling('utf8', 'const ♥ utf8', '', null, { + full: { + uninitOut: {omit: true}, // covered by utf8_dangling_out() test below + }, + }); it('marshals value as a byte array', function () { expect(() => GIMarshallingTests.utf8_as_uint8array_in('const ♥ utf8')).not.toThrow(); @@ -341,15 +373,17 @@ describe('In-out array in the style of gtk_init()', function () { expect(newArray).toEqual([]); }); - xit('marshals an inout empty array', function () { - const [, newArray] = GIMarshallingTests.init_function([]); + it('marshals an inout empty array', function () { + const [ret, newArray] = GIMarshallingTests.init_function([]); + expect(ret).toBeTrue(); expect(newArray).toEqual([]); - }).pend('https://gitlab.gnome.org/GNOME/gjs/issues/88'); + }); - xit('marshals an inout array', function () { - const [, newArray] = GIMarshallingTests.init_function(['--foo', '--bar']); + it('marshals an inout array', function () { + const [ret, newArray] = GIMarshallingTests.init_function(['--foo', '--bar']); + expect(ret).toBeTrue(); expect(newArray).toEqual(['--foo']); - }).pend('https://gitlab.gnome.org/GNOME/gjs/issues/88'); + }); }); describe('Fixed-size C array', function () { @@ -357,10 +391,7 @@ describe('Fixed-size C array', function () { testReturnValue('array_fixed_int', [-1, 0, 1, 2]); testInParameter('array_fixed_int', [-1, 0, 1, 2]); testOutParameter('array_fixed', [-1, 0, 1, 2]); - testOutParameter('array_fixed_caller_allocated', [-1, 0, 1, 2], { - skip: GIMarshallingTests.array_fixed_caller_allocated_out - ? false : 'https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/370', - }); + testOutParameter('array_fixed_caller_allocated', [-1, 0, 1, 2]); testInoutParameter('array_fixed', [-1, 0, 1, 2], [2, 1, 0, -1]); }); @@ -377,9 +408,6 @@ describe('Fixed-size C array', function () { }); it('marshals a fixed-size struct array as caller allocated out param', function () { - if (!GIMarshallingTests.array_fixed_caller_allocated_struct_out) - pending('https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/370'); - expect(GIMarshallingTests.array_fixed_caller_allocated_struct_out()).toEqual([ jasmine.objectContaining({long_: -2, int8: -1}), jasmine.objectContaining({long_: 1, int8: 2}), @@ -398,7 +426,7 @@ describe('C array with length', function () { }); } - testSimpleMarshalling('array', [-1, 0, 1, 2], [-2, -1, 0, 1, 2]); + testSimpleMarshalling('array', [-1, 0, 1, 2], [-2, -1, 0, 1, 2], []); it('can be returned along with other arguments', function () { let [array, sum] = GIMarshallingTests.array_return_etc(9, 5); @@ -423,7 +451,7 @@ describe('C array with length', function () { it('marshals a byte array as an in parameter', function () { expect(() => GIMarshallingTests.array_uint8_in('abcd')).not.toThrow(); expect(() => GIMarshallingTests.array_uint8_in([97, 98, 99, 100])).not.toThrow(); - expect(() => GIMarshallingTests.array_uint8_in(ByteArray.fromString('abcd'))) + expect(() => GIMarshallingTests.array_uint8_in(new TextEncoder().encode('abcd'))) .not.toThrow(); }); @@ -510,6 +538,57 @@ describe('C array with length', function () { expect(() => GIMarshallingTests.array_in_guint8_len([-1, 0, 1, 2])).not.toThrow(); }); + it('can be an in-out argument', function () { + const array = GIMarshallingTests.array_inout([-1, 0, 1, 2]); + expect(array).toEqual([-2, -1, 0, 1, 2]); + }); + + it('can be an in-out argument with in length', function () { + if (!GIMarshallingTests.array_inout_length_in) + pending('https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/407'); + const array = GIMarshallingTests.array_inout_length_in([-1, 0, 1, 2]); + expect(array).toEqual([-2, -1, 1, 2]); + }); + + xit('can be an out argument with in-out length', function () { + const array = GIMarshallingTests.array_out_length_inout(5); + expect(array).toEqual([-2, -4, -6, 8, -10, -12]); + }).pend('https://gitlab.gnome.org/GNOME/gjs/-/issues/560'); + + it('cannot be an out argument with in-out length', function () { + // TODO(3v1n0): remove this test when fixing + // https://gitlab.gnome.org/GNOME/gjs/-/issues/560 + if (!GIMarshallingTests.array_out_length_inout) + pending('https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/407'); + expect(() => GIMarshallingTests.array_out_length_inout(5)).toThrow(); + }); + + xit('can be an in-out argument with out length', function () { + const array = GIMarshallingTests.array_inout_length_out([-1, 0, 1, 2]); + expect(array).toEqual([-2, -1, 0, 1, 2]); + }).pend('https://gitlab.gnome.org/GNOME/gjs/-/issues/560'); + + it('cannot be an in-out argument with out length', function () { + // TODO(3v1n0): remove this test when fixing + // https://gitlab.gnome.org/GNOME/gjs/-/issues/560 + if (!GIMarshallingTests.array_inout_length_out) + pending('https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/407'); + expect(() => GIMarshallingTests.array_inout_length_out([-1, 0, 1, 2])).toThrow(); + }); + + xit('can be an out argument with in length', function () { + const array = GIMarshallingTests.array_out_length_in([-1, 0, 1, 2]); + expect(array).toEqual([-2, 0, -2, -4]); + }).pend('https://gitlab.gnome.org/GNOME/gjs/-/issues/560'); + + it('cannot be an out argument with in length', function () { + // TODO(3v1n0): remove this test when fixing + // https://gitlab.gnome.org/GNOME/gjs/-/issues/560 + if (!GIMarshallingTests.array_out_length_in) + pending('https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/407'); + expect(() => GIMarshallingTests.array_out_length_in([-1, 0, 1, 2])).toThrow(); + }); + it('can be an out argument along with other arguments', function () { let [array, sum] = GIMarshallingTests.array_out_etc(9, 5); expect(sum).toEqual(14); @@ -530,7 +609,7 @@ describe('C array with length', function () { describe('Zero-terminated C array', function () { describe('of strings', function () { testSimpleMarshalling('array_zero_terminated', ['0', '1', '2'], - ['-1', '0', '1', '2']); + ['-1', '0', '1', '2'], null); }); it('marshals null as a zero-terminated array return value', function () { @@ -559,9 +638,6 @@ describe('Zero-terminated C array', function () { ['none', 'container', 'full'].forEach(transfer => { it(`marshals as a transfer-${transfer} in and out parameter`, function () { - if (transfer === 'full') - pending('https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/399'); - const returnedArray = GIMarshallingTests[`array_gvariant_${transfer}_in`](variantArray); expect(returnedArray.map(v => v.deepUnpack())).toEqual([27, 'Hello']); @@ -582,7 +658,7 @@ describe('GArray', function () { }); describe('of strings', function () { - testContainerMarshalling('garray_utf8', ['0', '1', '2'], ['-2', '-1', '0', '1']); + testContainerMarshalling('garray_utf8', ['0', '1', '2'], ['-2', '-1', '0', '1'], null); it('marshals as a transfer-full caller-allocated out parameter', function () { expect(GIMarshallingTests.garray_utf8_full_out_caller_allocated()) @@ -621,7 +697,7 @@ describe('GArray', function () { describe('GPtrArray', function () { describe('of strings', function () { - testContainerMarshalling('gptrarray_utf8', ['0', '1', '2'], ['-2', '-1', '0', '1']); + testContainerMarshalling('gptrarray_utf8', ['0', '1', '2'], ['-2', '-1', '0', '1'], null); }); describe('of structs', function () { @@ -663,7 +739,7 @@ describe('GBytes', function () { expect(bytes.toArray()).toEqual(refByteArray); }); - it('can be implicitly converted from a ByteArray', function () { + it('can be implicitly converted from a Uint8Array', function () { expect(() => GIMarshallingTests.gbytes_none_in(refByteArray)) .not.toThrow(); }); @@ -674,18 +750,6 @@ describe('GBytes', function () { .not.toThrow(); }); - it('turns into a GByteArray on assignment', function () { - let bytes = GIMarshallingTests.gbytes_full_return(); - let array = bytes.toArray(); // Array should just be holding a ref, not a copy - expect(array[1]).toEqual(49); - array[1] = 42; // Assignment should force to GByteArray - expect(array[1]).toEqual(42); - array[1] = 49; // Flip the value back - // Now convert back to GBytes - expect(() => GIMarshallingTests.gbytes_none_in(ByteArray.toGBytes(array))) - .not.toThrow(); - }); - it('cannot be passed to a function expecting a byte array', function () { let bytes = GLib.Bytes.new([97, 98, 99, 100]); expect(() => GIMarshallingTests.array_uint8_in(bytes.toArray())).not.toThrow(); @@ -694,7 +758,57 @@ describe('GBytes', function () { }); describe('GStrv', function () { - testSimpleMarshalling('gstrv', ['0', '1', '2'], ['-1', '0', '1', '2']); + testSimpleMarshalling('gstrv', ['0', '1', '2'], ['-1', '0', '1', '2'], null); +}); + +describe('Array of GStrv', function () { + ['length', 'fixed', 'zero_terminated'].forEach(arrayKind => + ['none', 'container', 'full'].forEach(transfer => { + const testFunction = returnMode => { + const commonName = 'array_of_gstrv_transfer'; + const funcName = [arrayKind, commonName, transfer, returnMode].join('_'); + const func = GIMarshallingTests[funcName]; + if (!func) + pending('https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/407'); + return func; + }; + + ['out', 'return'].forEach(returnMode => + it(`${arrayKind} ${returnMode} transfer ${transfer}`, function () { + const func = testFunction(returnMode); + expect(func()).toEqual([ + ['0', '1', '2'], ['3', '4', '5'], ['6', '7', '8'], + ]); + })); + + it(`${arrayKind} in transfer ${transfer}`, function () { + const func = testFunction('in'); + if (transfer === 'container') + pending('https://gitlab.gnome.org/GNOME/gjs/-/issues/44'); + + expect(() => func([ + ['0', '1', '2'], ['3', '4', '5'], ['6', '7', '8'], + ])).not.toThrow(); + }); + + it(`${arrayKind} inout transfer ${transfer}`, function () { + const func = testFunction('inout'); + + if (transfer === 'container') + pending('https://gitlab.gnome.org/GNOME/gjs/-/issues/44'); + + const expectedReturn = [ + ['-1', '0', '1', '2'], ['-1', '3', '4', '5'], ['-1', '6', '7', '8'], + ]; + + if (arrayKind !== 'fixed') + expectedReturn.push(['-1', '9', '10', '11']); + + expect(func([ + ['0', '1', '2'], ['3', '4', '5'], ['6', '7', '8'], + ])).toEqual(expectedReturn); + }); + })); }); ['GList', 'GSList'].forEach(listKind => { @@ -715,7 +829,7 @@ describe('GStrv', function () { describe('of strings', function () { testContainerMarshalling(`${list}_utf8`, ['0', '1', '2'], - ['-2', '-1', '0', '1']); + ['-2', '-1', '0', '1'], []); }); }); }); @@ -751,7 +865,7 @@ describe('GHashTable', function () { 0: '0', 1: '1', }; - testContainerMarshalling('ghashtable_utf8', stringDict, stringDictOut); + testContainerMarshalling('ghashtable_utf8', stringDict, stringDictOut, null); }); describe('with double values', function () { @@ -795,12 +909,20 @@ describe('GHashTable', function () { }); describe('GValue', function () { - testSimpleMarshalling('gvalue', 42, '42', { + testSimpleMarshalling('gvalue', 42, '42', null, { inout: { skip: 'https://gitlab.gnome.org/GNOME/gobject-introspection/issues/192', }, }); + it('can handle noncanonical float NaN', function () { + expect(GIMarshallingTests.gvalue_noncanonical_nan_float()).toBeNaN(); + }); + + it('can handle noncanonical double NaN', function () { + expect(GIMarshallingTests.gvalue_noncanonical_nan_double()).toBeNaN(); + }); + it('marshals as an int64 in parameter', function () { expect(() => GIMarshallingTests.gvalue_int64_in(BigIntLimits.int64.max)) .not.toThrow(); @@ -899,8 +1021,6 @@ describe('GValue', function () { }); it('array can be passed as an out argument and unpacked when zero-terminated', function () { - if (!GIMarshallingTests.return_gvalue_zero_terminated_array) - pending('https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/397'); expect(GIMarshallingTests.return_gvalue_zero_terminated_array()) .toEqual([42, '42', true]); }); @@ -1056,7 +1176,7 @@ describe('Raw pointers', function () { describe('Registered enum type', function () { testSimpleMarshalling('genum', GIMarshallingTests.GEnum.VALUE3, - GIMarshallingTests.GEnum.VALUE1, { + GIMarshallingTests.GEnum.VALUE1, 0, { returnv: { funcName: 'genum_returnv', }, @@ -1065,7 +1185,7 @@ describe('Registered enum type', function () { describe('Bare enum type', function () { testSimpleMarshalling('enum', GIMarshallingTests.Enum.VALUE3, - GIMarshallingTests.Enum.VALUE1, { + GIMarshallingTests.Enum.VALUE1, 0, { returnv: { funcName: 'enum_returnv', }, @@ -1074,7 +1194,7 @@ describe('Bare enum type', function () { describe('Registered flags type', function () { testSimpleMarshalling('flags', GIMarshallingTests.Flags.VALUE2, - GIMarshallingTests.Flags.VALUE1, { + GIMarshallingTests.Flags.VALUE1, 0, { returnv: { funcName: 'flags_returnv', }, @@ -1087,7 +1207,7 @@ describe('Registered flags type', function () { describe('Bare flags type', function () { testSimpleMarshalling('no_type_flags', GIMarshallingTests.NoTypeFlags.VALUE2, - GIMarshallingTests.NoTypeFlags.VALUE1, { + GIMarshallingTests.NoTypeFlags.VALUE1, 0, { returnv: { funcName: 'no_type_flags_returnv', }, @@ -1669,82 +1789,82 @@ describe('Wrong virtual functions', function () { }).pend('https://gitlab.gnome.org/GNOME/gjs/issues/311'); it('marshals multiple out parameters', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'JS ERROR: Error: *vfunc_vfunc_multiple_out_parameters*Array*'); expect(tester.vfunc_multiple_out_parameters()).toEqual([0, 0]); - GLib.test_assert_expected_messages_internal('Gjs', 'testGIMarshalling.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGIMarshalling.js', 0, 'testVFuncReturnWrongValue'); }); it('marshals a return value and one out parameter', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'JS ERROR: Error: *vfunc_return_value_and_one_out_parameter*Array*'); expect(tester.vfunc_return_value_and_one_out_parameter()).toEqual([0, 0]); - GLib.test_assert_expected_messages_internal('Gjs', 'testGIMarshalling.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGIMarshalling.js', 0, 'testVFuncReturnWrongValue'); }); it('marshals a return value and multiple out parameters', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'JS ERROR: Error: *vfunc_return_value_and_multiple_out_parameters*Array*'); expect(tester.vfunc_return_value_and_multiple_out_parameters()).toEqual([0, 0, 0]); - GLib.test_assert_expected_messages_internal('Gjs', 'testGIMarshalling.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGIMarshalling.js', 0, 'testVFuncReturnWrongValue'); }); it('marshals an array out parameter', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'JS ERROR: Error: Expected type gfloat for Argument*undefined*'); expect(tester.vfunc_array_out_parameter()).toEqual(null); - GLib.test_assert_expected_messages_internal('Gjs', 'testGIMarshalling.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGIMarshalling.js', 0, 'testVFuncReturnWrongValue'); }); it('marshals an enum return value', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'JS ERROR: Error: Expected type enum for Return*undefined*'); expect(tester.vfunc_return_enum()).toEqual(0); - GLib.test_assert_expected_messages_internal('Gjs', 'testGIMarshalling.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGIMarshalling.js', 0, 'testVFuncReturnWrongValue'); }); it('marshals an enum out parameter', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'JS ERROR: Error: Expected type enum for Argument*undefined*'); expect(tester.vfunc_out_enum()).toEqual(0); - GLib.test_assert_expected_messages_internal('Gjs', 'testGIMarshalling.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGIMarshalling.js', 0, 'testVFuncReturnWrongValue'); }); it('marshals a flags return value', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'JS ERROR: Error: Expected type flags for Return*undefined*'); expect(tester.vfunc_return_flags()).toEqual(0); - GLib.test_assert_expected_messages_internal('Gjs', 'testGIMarshalling.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGIMarshalling.js', 0, 'testVFuncReturnWrongValue'); }); it('marshals a flags out parameter', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'JS ERROR: Error: Expected type flags for Argument*undefined*'); expect(tester.vfunc_out_flags()).toEqual(0); - GLib.test_assert_expected_messages_internal('Gjs', 'testGIMarshalling.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGIMarshalling.js', 0, 'testVFuncReturnWrongValue'); }); }); @@ -1900,7 +2020,10 @@ describe('GError', function () { }); it('marshals a GError** at the end of the signature as an exception', function () { - expect(() => GIMarshallingTests.gerror_array_in([-1, 0, 1, 2])).toThrow(); + expect(() => GIMarshallingTests.gerror_array_in([-1, 0, 1, 2])).toThrowMatching(e => + e.matches(GLib.quark_from_static_string(GIMarshallingTests.CONSTANT_GERROR_DOMAIN), + GIMarshallingTests.CONSTANT_GERROR_CODE) && + e.message === GIMarshallingTests.CONSTANT_GERROR_MESSAGE); }); it('marshals a GError** elsewhere in the signature as an out parameter', function () { @@ -1983,22 +2106,47 @@ describe('GObject properties', function () { }); function testPropertyGetSet(type, value1, value2, skip = false) { - it(`gets and sets a ${type} property`, function () { - if (skip) - pending(skip); - obj[`some_${type}`] = value1; - expect(obj[`some_${type}`]).toEqual(value1); - obj[`some_${type}`] = value2; - expect(obj[`some_${type}`]).toEqual(value2); + const snakeCase = `some_${type}`; + const paramCase = snakeCase.replaceAll('_', '-'); + const camelCase = snakeCase.replace(/(_\w)/g, + match => match.toUpperCase().replace('_', '')); + + [snakeCase, paramCase, camelCase].forEach(propertyName => { + it(`gets and sets a ${type} property as ${propertyName}`, function () { + if (skip) + pending(skip); + const handler = jasmine.createSpy(`handle-${paramCase}`); + const id = obj.connect(`notify::${paramCase}`, handler); + + obj[propertyName] = value1; + expect(obj[propertyName]).toEqual(value1); + expect(handler).toHaveBeenCalledTimes(1); + + obj[propertyName] = value2; + expect(obj[propertyName]).toEqual(value2); + expect(handler).toHaveBeenCalledTimes(2); + + obj.disconnect(id); + }); }); } function testPropertyGetSetBigInt(type, value1, value2) { + const snakeCase = `some_${type}`; + const paramCase = snakeCase.replaceAll('_', '-'); it(`gets and sets a ${type} property with a bigint`, function () { - obj[`some_${type}`] = value1; - expect(obj[`some_${type}`]).toEqual(Number(value1)); - obj[`some_${type}`] = value2; - expect(obj[`some_${type}`]).toEqual(Number(value2)); + const handler = jasmine.createSpy(`handle-${paramCase}`); + const id = obj.connect(`notify::${paramCase}`, handler); + + obj[snakeCase] = value1; + expect(handler).toHaveBeenCalledTimes(1); + expect(obj[snakeCase]).toEqual(Number(value1)); + + obj[snakeCase] = value2; + expect(handler).toHaveBeenCalledTimes(2); + expect(obj[snakeCase]).toEqual(Number(value2)); + + obj.disconnect(id); }); } @@ -2014,7 +2162,8 @@ describe('GObject properties', function () { testPropertyGetSetBigInt('int64', BigIntLimits.int64.min, BigIntLimits.int64.max); testPropertyGetSet('uint64', 42, 64); testPropertyGetSetBigInt('uint64', BigIntLimits.int64.max, BigIntLimits.int64.umax); - testPropertyGetSet('string', 'Gjs', 'is cool!'); + testPropertyGetSet('string', 'Cjs', 'is cool!'); + testPropertyGetSet('string', 'and supports', null); it('get and sets out-of-range values throws', function () { expect(() => { @@ -2041,22 +2190,40 @@ describe('GObject properties', function () { }); it('gets and sets a float property', function () { + const handler = jasmine.createSpy('handle-some-float'); + const id = obj.connect('notify::some-float', handler); + obj.some_float = Math.E; + expect(handler).toHaveBeenCalledTimes(1); expect(obj.some_float).toBeCloseTo(Math.E); + obj.some_float = Math.PI; + expect(handler).toHaveBeenCalledTimes(2); expect(obj.some_float).toBeCloseTo(Math.PI); + + obj.disconnect(id); }); it('gets and sets a double property', function () { + const handler = jasmine.createSpy('handle-some-double'); + const id = obj.connect('notify::some-double', handler); + obj.some_double = Math.E; + expect(handler).toHaveBeenCalledTimes(1); expect(obj.some_double).toBeCloseTo(Math.E); + obj.some_double = Math.PI; + expect(handler).toHaveBeenCalledTimes(2); expect(obj.some_double).toBeCloseTo(Math.PI); + + obj.disconnect(id); }); testPropertyGetSet('strv', ['0', '1', '2'], []); testPropertyGetSet('boxed_struct', new GIMarshallingTests.BoxedStruct(), new GIMarshallingTests.BoxedStruct({long_: 42})); + testPropertyGetSet('boxed_struct', new GIMarshallingTests.BoxedStruct(), + null); testPropertyGetSet('boxed_glist', null, null); testPropertyGetSet('gvalue', 42, 'foo'); testPropertyGetSetBigInt('gvalue', BigIntLimits.int64.umax, BigIntLimits.int64.min); @@ -2068,12 +2235,16 @@ describe('GObject properties', function () { new GLib.Variant('t', BigIntLimits.int64.umax)); testPropertyGetSet('object', new GObject.Object(), new GIMarshallingTests.Object({int: 42})); + testPropertyGetSet('object', new GIMarshallingTests.PropertiesObject({ + 'some-int': 23, 'some-string': '👾', + }), null); testPropertyGetSet('flags', GIMarshallingTests.Flags.VALUE2, GIMarshallingTests.Flags.VALUE1 | GIMarshallingTests.Flags.VALUE2); testPropertyGetSet('enum', GIMarshallingTests.GEnum.VALUE2, GIMarshallingTests.GEnum.VALUE3); testPropertyGetSet('byte_array', Uint8Array.of(1, 2, 3), - ByteArray.fromString('👾')); + new TextEncoder().encode('👾')); + testPropertyGetSet('byte_array', Uint8Array.of(3, 2, 1), null); it('gets a read-only property', function () { expect(obj.some_readonly).toEqual(42); @@ -2082,6 +2253,114 @@ describe('GObject properties', function () { it('throws when setting a read-only property', function () { expect(() => (obj.some_readonly = 35)).toThrow(); }); + + it('allows to set/get deprecated properties', function () { + if (!GObject.Object.find_property.call( + GIMarshallingTests.PropertiesObject, 'some-deprecated-int')) + pending('https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/410'); + + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, + '*GObject property*.some-deprecated-int is deprecated*'); + obj.some_deprecated_int = 35; + GLib.test_assert_expected_messages_internal('Cjs', 'testGIMarshalling.js', 0, + 'testAllowToSetGetDeprecatedProperties'); + + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, + '*GObject property*.some-deprecated-int is deprecated*'); + expect(obj.some_deprecated_int).toBe(35); + GLib.test_assert_expected_messages_internal('Cjs', 'testGIMarshalling.js', 0, + 'testAllowToSetGetDeprecatedProperties'); + }); + + const JSOverridingProperty = GObject.registerClass( + class Overriding extends GIMarshallingTests.PropertiesObject { + constructor(params) { + super(params); + this.intValue = 55; + this.stringValue = 'a string'; + } + + set some_int(v) { + this.intValue = v; + } + + get someInt() { + return this.intValue; + } + + set someString(v) { + this.stringValue = v; + } + + get someString() { + return this.stringValue; + } + }); + + it('can be overridden from JS', function () { + const intHandler = jasmine.createSpy('handle-some-int'); + const stringHandler = jasmine.createSpy('handle-some-string'); + const overriding = new JSOverridingProperty({ + 'someInt': 45, + 'someString': 'other string', + }); + const ids = []; + ids.push(overriding.connect('notify::some-int', intHandler)); + ids.push(overriding.connect('notify::some-string', stringHandler)); + + expect(overriding['some-int']).toBe(45); + expect(overriding.someInt).toBe(55); + expect(overriding.some_int).toBeUndefined(); + expect(overriding.intValue).toBe(55); + expect(overriding.someString).toBe('a string'); + expect(overriding.some_string).toBe('other string'); + expect(intHandler).not.toHaveBeenCalled(); + expect(stringHandler).not.toHaveBeenCalled(); + + overriding.some_int = 35; + expect(overriding['some-int']).toBe(45); + expect(overriding.some_int).toBeUndefined(); + expect(overriding.someInt).toBe(35); + expect(overriding.intValue).toBe(35); + expect(intHandler).not.toHaveBeenCalled(); + + overriding.someInt = 85; + expect(overriding['some-int']).toBe(45); + expect(overriding.someInt).toBe(35); + expect(overriding.some_int).toBeUndefined(); + expect(overriding.intValue).toBe(35); + expect(intHandler).not.toHaveBeenCalled(); + + overriding['some-int'] = 123; + expect(overriding['some-int']).toBe(123); + expect(overriding.someInt).toBe(35); + expect(overriding.some_int).toBeUndefined(); + expect(overriding.intValue).toBe(35); + expect(intHandler).toHaveBeenCalledTimes(1); + + overriding['some-string'] = '🐧'; + expect(overriding['some-string']).toBe('🐧'); + expect(overriding.some_string).toBe('🐧'); + expect(overriding.someString).toBe('a string'); + expect(overriding.stringValue).toBe('a string'); + expect(stringHandler).toHaveBeenCalledTimes(1); + + overriding.some_string = '🍕'; + expect(overriding['some-string']).toBe('🍕'); + expect(overriding.some_string).toBe('🍕'); + expect(overriding.someString).toBe('a string'); + expect(overriding.stringValue).toBe('a string'); + expect(stringHandler).toHaveBeenCalledTimes(2); + + overriding.someString = '🍝'; + expect(overriding['some-string']).toBe('🍕'); + expect(overriding.some_string).toBe('🍕'); + expect(overriding.someString).toBe('🍝'); + expect(overriding.stringValue).toBe('🍝'); + expect(stringHandler).toHaveBeenCalledTimes(2); + + ids.forEach(id => overriding.disconnect(id)); + }); }); describe('GObject signals', function () { @@ -2090,12 +2369,16 @@ describe('GObject signals', function () { obj = new GIMarshallingTests.SignalsObject(); }); - function testSignalEmission(type, value, skip = false) { - it(`checks emission of signal with ${type} argument`, function () { + function testSignalEmission(type, transfer, value, skip = false) { + it(`checks emission of signal with ${type} argument and transfer ${transfer}`, function () { if (skip) pending(skip); const signalCallback = jasmine.createSpy('signalCallback'); + + if (transfer !== 'none') + type += `-${transfer}`; + const signalName = `some_${type}`; const funcName = `emit_${type}`.replaceAll('-', '_'); const signalId = obj.connect(signalName, signalCallback); @@ -2105,19 +2388,43 @@ describe('GObject signals', function () { }); } - testSignalEmission('boxed-gptrarray-utf8', ['0', '1', '2']); - testSignalEmission('boxed-gptrarray-boxed-struct', [ - new GIMarshallingTests.BoxedStruct({long_: 42}), - new GIMarshallingTests.BoxedStruct({long_: 43}), - new GIMarshallingTests.BoxedStruct({long_: 44}), - ]); - - testSignalEmission('hash-table-utf8-int', { - '-1': 1, - '0': 0, - '1': -1, - '2': -2, - }, !GIMarshallingTests.SignalsObject.prototype.emit_hash_table_utf8_int - ? 'https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/409' - : false); + ['none', 'container', 'none'].forEach(transfer => { + testSignalEmission('boxed-gptrarray-utf8', transfer, ['0', '1', '2']); + testSignalEmission('boxed-gptrarray-boxed-struct', transfer, [ + new GIMarshallingTests.BoxedStruct({long_: 42}), + new GIMarshallingTests.BoxedStruct({long_: 43}), + new GIMarshallingTests.BoxedStruct({long_: 44}), + ]); + + testSignalEmission('hash-table-utf8-int', transfer, { + '-1': 1, + '0': 0, + '1': -1, + '2': -2, + }); + }); + + ['none', 'full'].forEach(transfer => { + let skip = false; + if (transfer === 'full') + skip = 'https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/470'; + + testSignalEmission('boxed-struct', transfer, jasmine.objectContaining({ + long_: 99, + string_: 'a string', + g_strv: ['foo', 'bar', 'baz'], + }), skip); + }); + + it('with not-ref-counted boxed types with transfer full are properly handled', function () { + // When using JS side only we can handle properly the problems of + // https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/470 + const callbackFunc = jasmine.createSpy('callbackFunc'); + const signalId = obj.connect('some-boxed-struct-full', callbackFunc); + obj.emit('some-boxed-struct-full', + new GIMarshallingTests.BoxedStruct({long_: 44})); + obj.disconnect(signalId); + expect(callbackFunc).toHaveBeenCalledOnceWith(obj, + new GIMarshallingTests.BoxedStruct({long_: 44})); + }); }); diff --git a/installed-tests/js/testGLib.js b/installed-tests/js/testGLib.js index 4d048f951..f9a9aa551 100644 --- a/installed-tests/js/testGLib.js +++ b/installed-tests/js/testGLib.js @@ -1,8 +1,7 @@ // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later // SPDX-FileCopyrightText: 2011 Giovanni Campagna -// SPDX-FileCopyrightText: 2019 Philip Chimento +// SPDX-FileCopyrightText: 2019, 2023 Philip Chimento -const ByteArray = imports.byteArray; const GLib = imports.gi.GLib; describe('GVariant constructor', function () { @@ -47,16 +46,16 @@ describe('GVariant constructor', function () { }); it('constructs a byte array variant', function () { - const byteArray = Uint8Array.from('pizza', c => c.charCodeAt(0)); + const byteArray = new TextEncoder().encode('pizza'); const byteArrayVariant = new GLib.Variant('ay', byteArray); - expect(ByteArray.toString(byteArrayVariant.deepUnpack())) + expect(new TextDecoder().decode(byteArrayVariant.deepUnpack())) .toEqual('pizza'); }); it('constructs a byte array variant from a string', function () { const byteArrayVariant = new GLib.Variant('ay', 'pizza'); - expect(ByteArray.toString(byteArrayVariant.deepUnpack())) - .toEqual('pizza'); + expect(new TextDecoder().decode(byteArrayVariant.deepUnpack())) + .toEqual('pizza\0'); }); it('0-terminates a byte array variant constructed from a string', function () { @@ -67,7 +66,7 @@ describe('GVariant constructor', function () { }); it('does not 0-terminate a byte array variant constructed from a Uint8Array', function () { - const byteArray = Uint8Array.from('pizza', c => c.charCodeAt(0)); + const byteArray = new TextEncoder().encode('pizza'); const byteArrayVariant = new GLib.Variant('ay', byteArray); const a = byteArrayVariant.deepUnpack(); [112, 105, 122, 122, 97].forEach((val, ix) => @@ -133,20 +132,31 @@ describe('GVariantDict lookup', function () { }); }); +describe('GLib spawn processes', function () { + it('sync with null envp', function () { + const [ret, stdout, stderr, exit_status] = GLib.spawn_sync( + null, ['true'], null, GLib.SpawnFlags.SEARCH_PATH, null); + expect(ret).toBe(true); + expect(stdout).toEqual(new Uint8Array()); + expect(stderr).toEqual(new Uint8Array()); + expect(exit_status).toBe(0); + }).pend('https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3523'); +}); + describe('GLib string function overrides', function () { let numExpectedWarnings; function expectWarnings(count) { numExpectedWarnings = count; for (let c = 0; c < count; c++) { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, '*not introspectable*'); } } function assertWarnings(testName) { for (let c = 0; c < numExpectedWarnings; c++) { - GLib.test_assert_expected_messages_internal('Gjs', 'testGLib.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGLib.js', 0, `test GLib.${testName}`); } numExpectedWarnings = 0; @@ -271,3 +281,116 @@ describe('GLib string function overrides', function () { expect(GLib.base64_encode(encoded)).toBe(base64); }); }); + +describe('GLib.MatchInfo', function () { + let shouldBePatchedProtoype; + beforeAll(function () { + shouldBePatchedProtoype = GLib.MatchInfo.prototype; + }); + + let regex; + beforeEach(function () { + regex = new GLib.Regex('h(?el)lo', 0, 0); + }); + + it('cannot be constructed', function () { + expect(() => new GLib.MatchInfo()).toThrow(); + expect(() => new shouldBePatchedProtoype.constructor()).toThrow(); + }); + + it('is returned from GLib.Regex.match', function () { + const [, match] = regex.match('foo', 0); + expect(match).toBeInstanceOf(GLib.MatchInfo); + expect(match.toString()).toContain('CjsPrivate.MatchInfo'); + }); + + it('stores the string that was matched', function () { + const [, match] = regex.match('foo', 0); + expect(match.get_string()).toEqual('foo'); + }); + + it('truncates the string when it has zeroes as g_match_info_get_string() would', function () { + const [, match] = regex.match_full('ab\0cd', 0, 0); + expect(match.get_string()).toEqual('ab'); + }); + + it('is returned from GLib.Regex.match_all', function () { + const [, match] = regex.match_all('foo', 0); + expect(match).toBeInstanceOf(GLib.MatchInfo); + expect(match.toString()).toContain('CjsPrivate.MatchInfo'); + }); + + it('is returned from GLib.Regex.match_all_full', function () { + const [, match] = regex.match_all_full('foo', 0, 0); + expect(match).toBeInstanceOf(GLib.MatchInfo); + expect(match.toString()).toContain('CjsPrivate.MatchInfo'); + }); + + it('is returned from GLib.Regex.match_full', function () { + const [, match] = regex.match_full('foo', 0, 0); + expect(match).toBeInstanceOf(GLib.MatchInfo); + expect(match.toString()).toContain('CjsPrivate.MatchInfo'); + }); + + describe('method', function () { + let match; + beforeEach(function () { + [, match] = regex.match('hello hello world', 0); + }); + + it('expand_references', function () { + expect(match.expand_references('\\0-\\1')).toBe('hello-el'); + expect(shouldBePatchedProtoype.expand_references.call(match, '\\0-\\1')).toBe('hello-el'); + }); + + it('fetch', function () { + expect(match.fetch(0)).toBe('hello'); + expect(shouldBePatchedProtoype.fetch.call(match, 0)).toBe('hello'); + }); + + it('fetch_all', function () { + expect(match.fetch_all()).toEqual(['hello', 'el']); + expect(shouldBePatchedProtoype.fetch_all.call(match)).toEqual(['hello', 'el']); + }); + + it('fetch_named', function () { + expect(match.fetch_named('foo')).toBe('el'); + expect(shouldBePatchedProtoype.fetch_named.call(match, 'foo')).toBe('el'); + }); + + it('fetch_named_pos', function () { + expect(match.fetch_named_pos('foo')).toEqual([true, 1, 3]); + expect(shouldBePatchedProtoype.fetch_named_pos.call(match, 'foo')).toEqual([true, 1, 3]); + }); + + it('fetch_pos', function () { + expect(match.fetch_pos(1)).toEqual([true, 1, 3]); + expect(shouldBePatchedProtoype.fetch_pos.call(match, 1)).toEqual([true, 1, 3]); + }); + + it('get_match_count', function () { + expect(match.get_match_count()).toBe(2); + expect(shouldBePatchedProtoype.get_match_count.call(match)).toBe(2); + }); + + it('get_string', function () { + expect(match.get_string()).toBe('hello hello world'); + expect(shouldBePatchedProtoype.get_string.call(match)).toBe('hello hello world'); + }); + + it('is_partial_match', function () { + expect(match.is_partial_match()).toBeFalse(); + expect(shouldBePatchedProtoype.is_partial_match.call(match)).toBeFalse(); + }); + + it('matches', function () { + expect(match.matches()).toBeTrue(); + expect(shouldBePatchedProtoype.matches.call(match)).toBeTrue(); + }); + + it('next', function () { + expect(match.next()).toBeTrue(); + expect(shouldBePatchedProtoype.next.call(match)).toBeFalse(); + }); + }); +}); diff --git a/installed-tests/js/testGObject.js b/installed-tests/js/testGObject.js index 160f85abd..fd96f9a1f 100644 --- a/installed-tests/js/testGObject.js +++ b/installed-tests/js/testGObject.js @@ -155,3 +155,31 @@ describe('GObject.Object.new_with_properties()', function () { expect(o.constructor.$gtype.name).toBe('GObject'); }); }); + +describe('Unsupported methods', function () { + let o; + beforeEach(function () { + o = new GObject.Object(); + }); + + it('throws on data stashing methods', function () { + expect(() => o.get_data('foo')).toThrow(); + expect(() => o.get_qdata(1)).toThrow(); + expect(() => o.set_data('foo', 'bar')).toThrow(); + expect(() => o.steal_data('foo')).toThrow(); + expect(() => o.steal_qdata(1)).toThrow(); + }); + + it('throws on refcounting methods', function () { + const refcount = System.refcount(o); + const floating = o.is_floating(); + + expect(() => o.ref()).toThrow(); + expect(() => o.unref()).toThrow(); + expect(() => o.ref_sink()).toThrow(); + expect(() => o.force_floating()).toThrow(); + + expect(System.refcount(o)).toBe(refcount); + expect(o.is_floating()).toBe(floating); + }); +}); diff --git a/installed-tests/js/testGObjectClass.js b/installed-tests/js/testGObjectClass.js index 1e95e3a67..55aff9638 100644 --- a/installed-tests/js/testGObjectClass.js +++ b/installed-tests/js/testGObjectClass.js @@ -226,6 +226,11 @@ const MyAbstractObject = GObject.registerClass({ }, class MyAbstractObject extends GObject.Object { }); +const MyFinalObject = GObject.registerClass({ + GTypeFlags: GObject.TypeFlags.FINAL, +}, class extends GObject.Object { +}); + const MyApplication = GObject.registerClass({ Signals: {'custom': {param_types: [GObject.TYPE_INT]}}, }, class MyApplication extends Gio.Application { @@ -284,6 +289,15 @@ describe('GObject class with decorator', function () { expect(() => new MyAbstractObject()).toThrow(); }); + it('throws if final class is inherited from', function () { + try { + GObject.registerClass(class extends MyFinalObject {}); + fail(); + } catch (e) { + expect(e.message).toEqual('Cannot inherit from a final type'); + } + }); + it('constructs with default values for properties', function () { expect(myInstance.readwrite).toEqual('foo'); expect(myInstance.readonly).toEqual('bar'); @@ -298,12 +312,12 @@ describe('GObject class with decorator', function () { }); it('warns if more than one argument passed to the default constructor', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_MESSAGE, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_MESSAGE, '*Too many arguments*'); new ObjectWithDefaultConstructor({}, 'this is ignored', 123); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectClass.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectClass.js', 0, 'testGObjectClassTooManyArguments'); }); @@ -311,8 +325,8 @@ describe('GObject class with decorator', function () { expect(() => new MyObject('this is wrong')).toThrow(); }); - it('accepts a property hash that is not a plain object', function () { - expect(() => new MyObject(new GObject.Object())).not.toThrow(); + it('does not accept a property hash that is not a plain object', function () { + expect(() => new MyObject(new GObject.Object())).toThrow(); }); const ui = ` @@ -352,6 +366,36 @@ describe('GObject class with decorator', function () { expect(notifySpy).toHaveBeenCalledTimes(2); }); + function asyncIdle() { + return new Promise(resolve => { + GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { + resolve(); + return GLib.SOURCE_REMOVE; + }); + }); + } + + it('disconnects connect_object signals on destruction', async function () { + let callback = jasmine.createSpy('callback'); + callback.myInstance = myInstance; + const instance2 = new MyObject(); + instance2.connect_object('empty', callback, myInstance, 0); + + instance2.emitEmpty(); + instance2.emitEmpty(); + + expect(callback).toHaveBeenCalledTimes(2); + + const weakRef = new WeakRef(myInstance); + myInstance = null; + callback = null; + + await asyncIdle(); + System.gc(); + + expect(weakRef.deref()).toBeUndefined(); + }); + it('can define its own signals', function () { let emptySpy = jasmine.createSpy('emptySpy'); myInstance.connect('empty', emptySpy); @@ -581,7 +625,7 @@ describe('GObject class with decorator', function () { expect(() => (obj.anchors = 'foo')).not.toThrow(); expect(obj.anchors).toEqual('foo'); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectClass.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectClass.js', 0, 'testGObjectClassForgottenOverride'); }); @@ -994,7 +1038,7 @@ describe('Register GType name', function () { let gtypeName = 'GType$Test/WithLòt\'s of*bad§chars!'; let expectedSanitized = 'GType_Test_WithL_t_s_of_bad_chars_'; - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, `*RangeError: Provided GType name '${gtypeName}' is not valid; ` + `automatically sanitized to '${expectedSanitized}'*`); @@ -1002,7 +1046,7 @@ describe('Register GType name', function () { GTypeName: gtypeName, }, class extends GObject.Object {}); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectClass.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectClass.js', 0, 'testGObjectRegisterClassSanitize'); expect(GtypeClass.$gtype.name).toEqual(expectedSanitized); @@ -1685,38 +1729,38 @@ describe('GObject class with JSObject signals', function () { // be caught from signal handlers, so we check for logged messages instead it('throws an error when returning a boolean value', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, '*JSObject expected*'); myInstance.connect('get-object', () => true); myInstance.emit('get-object', {}); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectClass.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectClass.js', 0, 'throws an error when returning a boolean value'); }); it('throws an error when returning an int value', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, '*JSObject expected*'); myInstance.connect('get-object', () => 1); myInstance.emit('get-object', {}); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectClass.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectClass.js', 0, 'throws an error when returning a boolean value'); }); it('throws an error when returning a numeric value', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, '*JSObject expected*'); myInstance.connect('get-object', () => Math.PI); myInstance.emit('get-object', {}); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectClass.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectClass.js', 0, 'throws an error when returning a boolean value'); }); it('throws an error when returning a string value', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, '*JSObject expected*'); myInstance.connect('get-object', () => 'string'); myInstance.emit('get-object', {}); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectClass.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectClass.js', 0, 'throws an error when returning a boolean value'); }); }); diff --git a/installed-tests/js/testGObjectDestructionAccess.js b/installed-tests/js/testGObjectDestructionAccess.js index 32f5b0df6..586df4d96 100644 --- a/installed-tests/js/testGObjectDestructionAccess.js +++ b/installed-tests/js/testGObjectDestructionAccess.js @@ -4,7 +4,7 @@ imports.gi.versions.Gtk = '3.0'; -const {GLib, Gio, GjsTestTools, GObject, Gtk} = imports.gi; +const {GLib, Gio, CjsTestTools, GObject, Gtk} = imports.gi; const {system: System} = imports; describe('Access to destroyed GObject', function () { @@ -21,35 +21,35 @@ describe('Access to destroyed GObject', function () { }); it('Get property', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* disposed *'); expect(destroyedWindow.title).toBe('To be destroyed'); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectPropertyGet'); }); it('Set property', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* disposed *'); - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* disposed *'); destroyedWindow.title = 'I am dead'; expect(destroyedWindow.title).toBe('I am dead'); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectPropertySet'); }); it('Add expando property', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* disposed *'); destroyedWindow.expandoProperty = 'Hello!'; - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectExpandoPropertySet'); }); @@ -66,85 +66,85 @@ describe('Access to destroyed GObject', function () { }); it('Access to getter method', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* disposed *'); expect(destroyedWindow.get_title()).toBe('To be destroyed'); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectMethodGet'); }); it('Access to setter method', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* disposed *'); - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* disposed *'); destroyedWindow.set_title('I am dead'); expect(destroyedWindow.get_title()).toBe('I am dead'); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectMethodSet'); }); it('Proto function connect', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* disposed *'); expect(destroyedWindow.connect('foo-signal', () => {})).toBe(0); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectConnect'); }); it('Proto function connect_after', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* disposed *'); expect(destroyedWindow.connect_after('foo-signal', () => {})).toBe(0); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectConnectAfter'); }); it('Proto function emit', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* disposed *'); expect(destroyedWindow.emit('keys-changed')).toBeUndefined(); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectEmit'); }); it('Proto function signals_disconnect', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* disposed *'); expect(GObject.signal_handlers_disconnect_by_func(destroyedWindow, () => {})).toBe(0); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectSignalsDisconnect'); }); it('Proto function signals_block', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* disposed *'); expect(GObject.signal_handlers_block_by_func(destroyedWindow, () => {})).toBe(0); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectSignalsBlock'); }); it('Proto function signals_unblock', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* disposed *'); expect(GObject.signal_handlers_unblock_by_func(destroyedWindow, () => {})).toBe(0); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectSignalsUnblock'); }); @@ -178,52 +178,52 @@ describe('Access to finalized GObject', function () { destroyedWindow.set_title('To be destroyed'); destroyedWindow.destroy(); - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* disposed *'); - destroyedWindow.unref(); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + CjsTestTools.unref(destroyedWindow); + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectPropertyGet'); }); afterEach(function () { destroyedWindow = null; - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, '*Object 0x* has been finalized *'); System.gc(); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'generates a warn on object garbage collection'); }); it('Get property', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* finalized *'); expect(destroyedWindow.title).toBeUndefined(); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectPropertyGet'); }); it('Set property', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* finalized *'); - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* finalized *'); destroyedWindow.title = 'I am dead'; expect(destroyedWindow.title).toBeUndefined(); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectPropertySet'); }); it('Add expando property', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* finalized *'); destroyedWindow.expandoProperty = 'Hello!'; - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectExpandoPropertySet'); }); @@ -240,86 +240,86 @@ describe('Access to finalized GObject', function () { }); it('Access to getter method', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* finalized *'); GLib.test_expect_message('Gtk', GLib.LogLevelFlags.LEVEL_CRITICAL, '*GTK_IS_WINDOW*'); expect(destroyedWindow.get_title()).toBeNull(); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectMethodGet'); }); it('Access to setter method', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* finalized *'); GLib.test_expect_message('Gtk', GLib.LogLevelFlags.LEVEL_CRITICAL, '*GTK_IS_WINDOW*'); destroyedWindow.set_title('I am dead'); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectMethodSet'); }); it('Proto function connect', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* finalized *'); expect(destroyedWindow.connect('foo-signal', () => { })).toBe(0); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectConnect'); }); it('Proto function connect_after', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* finalized *'); expect(destroyedWindow.connect_after('foo-signal', () => { })).toBe(0); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectConnectAfter'); }); it('Proto function emit', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* finalized *'); expect(destroyedWindow.emit('keys-changed')).toBeUndefined(); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectEmit'); }); it('Proto function signals_disconnect', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* finalized *'); expect(GObject.signal_handlers_disconnect_by_func(destroyedWindow, () => { })).toBe(0); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectSignalsDisconnect'); }); it('Proto function signals_block', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* finalized *'); expect(GObject.signal_handlers_block_by_func(destroyedWindow, () => { })).toBe(0); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectSignalsBlock'); }); it('Proto function signals_unblock', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Window (0x* finalized *'); expect(GObject.signal_handlers_unblock_by_func(destroyedWindow, () => { })).toBe(0); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'testExceptionInDestroyedObjectSignalsUnblock'); }); @@ -331,11 +331,11 @@ describe('Access to finalized GObject', function () { describe('Disposed or finalized GObject', function () { beforeAll(function () { - GjsTestTools.init(); + CjsTestTools.init(); }); afterEach(function () { - GjsTestTools.reset(); + CjsTestTools.reset(); }); [true, false].forEach(gc => { @@ -380,36 +380,36 @@ describe('Disposed or finalized GObject', function () { expect(callSpy).toHaveBeenCalledTimes(2); file = null; - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, '*during garbage collection*offending callback was dispose()*'); System.gc(); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'calls dispose vfunc on explicit disposal only'); expect(callSpy).toHaveBeenCalledTimes(2); }); it('generates a warn on object garbage collection', function () { - Gio.File.new_for_path('/').unref(); + CjsTestTools.unref(Gio.File.new_for_path('/')); - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, '*Object 0x* has been finalized *'); System.gc(); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'generates a warn on object garbage collection'); }); it('generates a warn on object garbage collection if has expando property', function () { let file = Gio.File.new_for_path('/'); file.toggleReferenced = true; - file.unref(); + CjsTestTools.unref(file); expect(file.toString()).toMatch( /\[object \(FINALIZED\) instance wrapper GType:GLocalFile jsobj@0x[a-f0-9]+ native@0x[a-f0-9]+\]/); file = null; - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, '*Object 0x* has been finalized *'); System.gc(); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'generates a warn on object garbage collection if has expando property'); }); @@ -417,7 +417,7 @@ describe('Disposed or finalized GObject', function () { const loop = new GLib.MainLoop(null, false); let file = Gio.File.new_for_path('/'); - GjsTestTools.delayed_unref(file, 1); // Will happen after dispose + CjsTestTools.delayed_unref(file, 1); // Will happen after dispose file.run_dispose(); let done = false; @@ -426,17 +426,17 @@ describe('Disposed or finalized GObject', function () { loop.get_context().iteration(true); file = null; - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, '*Object 0x* has been finalized *'); System.gc(); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'generates a warn if already disposed at garbage collection'); }); [true, false].forEach(gc => { it(`created from other function is marked as disposed and ${gc ? '' : 'not '}garbage collected`, function () { let file = Gio.File.new_for_path('/'); - GjsTestTools.save_object(file); + CjsTestTools.save_object(file); file.run_dispose(); file = null; System.gc(); @@ -444,7 +444,7 @@ describe('Disposed or finalized GObject', function () { Array(10).fill().forEach(() => { // We need to repeat the test to ensure that we disassociate // wrappers from disposed objects on destruction. - expect(GjsTestTools.peek_saved()).toMatch( + expect(CjsTestTools.peek_saved()).toMatch( /\[object \(DISPOSED\) instance wrapper GType:GLocalFile jsobj@0x[a-f0-9]+ native@0x[a-f0-9]+\]/); if (gc) System.gc(); @@ -453,17 +453,17 @@ describe('Disposed or finalized GObject', function () { }); it('returned from function is marked as disposed', function () { - expect(GjsTestTools.get_disposed(Gio.File.new_for_path('/'))).toMatch( + expect(CjsTestTools.get_disposed(Gio.File.new_for_path('/'))).toMatch( /\[object \(DISPOSED\) instance wrapper GType:GLocalFile jsobj@0x[a-f0-9]+ native@0x[a-f0-9]+\]/); }); it('returned from function is marked as disposed and then as finalized', function () { let file = Gio.File.new_for_path('/'); - GjsTestTools.save_object(file); - GjsTestTools.delayed_unref(file, 30); + CjsTestTools.save_object(file); + CjsTestTools.delayed_unref(file, 30); file.run_dispose(); - let disposedFile = GjsTestTools.get_saved(); + let disposedFile = CjsTestTools.get_saved(); expect(disposedFile).toEqual(file); expect(disposedFile).toMatch( /\[object \(DISPOSED\) instance wrapper GType:GLocalFile jsobj@0x[a-f0-9]+ native@0x[a-f0-9]+\]/); @@ -478,42 +478,42 @@ describe('Disposed or finalized GObject', function () { expect(disposedFile).toMatch( /\[object \(FINALIZED\) instance wrapper GType:GLocalFile jsobj@0x[a-f0-9]+ native@0x[a-f0-9]+\]/); - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, '*Object 0x* has been finalized *'); disposedFile = null; System.gc(); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'returned from function is marked as disposed and then as finalized'); }); it('ignores toggling queued unref toggles', function () { let file = Gio.File.new_for_path('/'); file.expandMeWithToggleRef = true; - file.ref(); - GjsTestTools.unref_other_thread(file); + CjsTestTools.ref(file); + CjsTestTools.unref_other_thread(file); file.run_dispose(); }); it('ignores toggling queued toggles', function () { let file = Gio.File.new_for_path('/'); file.expandMeWithToggleRef = true; - GjsTestTools.ref_other_thread(file); - GjsTestTools.unref_other_thread(file); + CjsTestTools.ref_other_thread(file); + CjsTestTools.unref_other_thread(file); file.run_dispose(); }); it('can be disposed from other thread', function () { let file = Gio.File.new_for_path('/'); file.expandMeWithToggleRef = true; - file.ref(); - GjsTestTools.unref_other_thread(file); - GjsTestTools.run_dispose_other_thread(file); + CjsTestTools.ref(file); + CjsTestTools.unref_other_thread(file); + CjsTestTools.run_dispose_other_thread(file); }); it('can be garbage collected once disposed from other thread', function () { let file = Gio.File.new_for_path('/'); file.expandMeWithToggleRef = true; - GjsTestTools.run_dispose_other_thread(file); + CjsTestTools.run_dispose_other_thread(file); file = null; System.gc(); }); @@ -521,19 +521,19 @@ describe('Disposed or finalized GObject', function () { describe('GObject with toggle references', function () { beforeAll(function () { - GjsTestTools.init(); + CjsTestTools.init(); }); afterEach(function () { - GjsTestTools.reset(); + CjsTestTools.reset(); }); it('can be re-reffed from other thread delayed', function () { let file = Gio.File.new_for_path('/'); file.expandMeWithToggleRef = true; const objectAddress = System.addressOfGObject(file); - GjsTestTools.save_object_unreffed(file); - GjsTestTools.delayed_ref_other_thread(file, 10); + CjsTestTools.save_object_unreffed(file); + CjsTestTools.delayed_ref_other_thread(file, 10); file = null; System.gc(); @@ -545,11 +545,11 @@ describe('GObject with toggle references', function () { // However, depending on whether the thread ref happens the object // may be already finalized, and in such case we need to throw try { - file = GjsTestTools.steal_saved(); + file = CjsTestTools.steal_saved(); if (file) { expect(System.addressOfGObject(file)).toBe(objectAddress); expect(file instanceof Gio.File).toBeTruthy(); - file.unref(); + CjsTestTools.unref(file); } } catch (e) { expect(() => { @@ -562,8 +562,9 @@ describe('GObject with toggle references', function () { let file = Gio.File.new_for_path('/'); const objectAddress = System.addressOfGObject(file); file.expandMeWithToggleRef = true; - GjsTestTools.save_object(file); - GjsTestTools.delayed_unref_other_thread(file.ref(), 10); + CjsTestTools.save_object(file); + CjsTestTools.ref(file); + CjsTestTools.delayed_unref_other_thread(file, 10); file = null; System.gc(); @@ -571,7 +572,7 @@ describe('GObject with toggle references', function () { GLib.timeout_add(GLib.PRIORITY_DEFAULT, 50, () => loop.quit()); loop.run(); - file = GjsTestTools.get_saved(); + file = CjsTestTools.get_saved(); expect(System.addressOfGObject(file)).toBe(objectAddress); expect(file instanceof Gio.File).toBeTruthy(); }); @@ -579,7 +580,7 @@ describe('GObject with toggle references', function () { it('can be re-reffed and unreffed again from other thread with delay', function () { let file = Gio.File.new_for_path('/'); file.expandMeWithToggleRef = true; - GjsTestTools.delayed_ref_unref_other_thread(file, 10); + CjsTestTools.delayed_ref_unref_other_thread(file, 10); file = null; System.gc(); @@ -591,50 +592,50 @@ describe('GObject with toggle references', function () { it('can be toggled up by getting a GWeakRef', function () { let file = Gio.File.new_for_path('/'); file.expandMeWithToggleRef = true; - GjsTestTools.save_weak(file); - GjsTestTools.get_weak(); + CjsTestTools.save_weak(file); + CjsTestTools.get_weak(); }); it('can be toggled up by getting a GWeakRef from another thread', function () { let file = Gio.File.new_for_path('/'); file.expandMeWithToggleRef = true; - GjsTestTools.save_weak(file); - GjsTestTools.get_weak_other_thread(); + CjsTestTools.save_weak(file); + CjsTestTools.get_weak_other_thread(); }); it('can be toggled up by getting a GWeakRef from another thread and re-reffed in main thread', function () { let file = Gio.File.new_for_path('/'); file.expandMeWithToggleRef = true; - GjsTestTools.save_weak(file); - GjsTestTools.get_weak_other_thread(); + CjsTestTools.save_weak(file); + CjsTestTools.get_weak_other_thread(); // Ok, let's play more dirty now... - file.ref(); // toggle up - file.unref(); // toggle down + CjsTestTools.ref(file); // toggle up + CjsTestTools.unref(file); // toggle down - file.ref(); - file.ref(); - file.unref(); - file.unref(); + CjsTestTools.ref(file); + CjsTestTools.ref(file); + CjsTestTools.unref(file); + CjsTestTools.unref(file); }); it('can be toggled up by getting a GWeakRef from another and re-reffed from various threads', function () { let file = Gio.File.new_for_path('/'); file.expandMeWithToggleRef = true; - GjsTestTools.save_weak(file); - GjsTestTools.get_weak_other_thread(); + CjsTestTools.save_weak(file); + CjsTestTools.get_weak_other_thread(); - GjsTestTools.ref_other_thread(file); - GjsTestTools.unref_other_thread(file); + CjsTestTools.ref_other_thread(file); + CjsTestTools.unref_other_thread(file); - file.ref(); - file.unref(); + CjsTestTools.ref(file); + CjsTestTools.unref(file); - GjsTestTools.ref_other_thread(file); - file.unref(); + CjsTestTools.ref_other_thread(file); + CjsTestTools.unref(file); - file.ref(); - GjsTestTools.unref_other_thread(file); + CjsTestTools.ref(file); + CjsTestTools.unref_other_thread(file); }); it('can be toggled up-down from various threads when the wrapper is gone', function () { @@ -643,20 +644,20 @@ describe('GObject with toggle references', function () { // We also check that late thread events won't affect the destroyed wrapper const threads = []; - threads.push(GjsTestTools.delayed_ref_unref_other_thread(file, 0)); - threads.push(GjsTestTools.delayed_ref_unref_other_thread(file, 100000)); - threads.push(GjsTestTools.delayed_ref_unref_other_thread(file, 200000)); - threads.push(GjsTestTools.delayed_ref_unref_other_thread(file, 300000)); - GjsTestTools.save_object(file); - GjsTestTools.save_weak(file); + threads.push(CjsTestTools.delayed_ref_unref_other_thread(file, 0)); + threads.push(CjsTestTools.delayed_ref_unref_other_thread(file, 100000)); + threads.push(CjsTestTools.delayed_ref_unref_other_thread(file, 200000)); + threads.push(CjsTestTools.delayed_ref_unref_other_thread(file, 300000)); + CjsTestTools.save_object(file); + CjsTestTools.save_weak(file); file = null; System.gc(); threads.forEach(th => th.join()); - GjsTestTools.clear_saved(); + CjsTestTools.clear_saved(); System.gc(); - expect(GjsTestTools.get_weak()).toBeNull(); + expect(CjsTestTools.get_weak()).toBeNull(); }); it('can be toggled up-down from various threads when disposed and the wrapper is gone', function () { @@ -665,47 +666,47 @@ describe('GObject with toggle references', function () { // We also check that late thread events won't affect the destroyed wrapper const threads = []; - threads.push(GjsTestTools.delayed_ref_unref_other_thread(file, 0)); - threads.push(GjsTestTools.delayed_ref_unref_other_thread(file, 100000)); - threads.push(GjsTestTools.delayed_ref_unref_other_thread(file, 200000)); - threads.push(GjsTestTools.delayed_ref_unref_other_thread(file, 300000)); - GjsTestTools.save_object(file); - GjsTestTools.save_weak(file); + threads.push(CjsTestTools.delayed_ref_unref_other_thread(file, 0)); + threads.push(CjsTestTools.delayed_ref_unref_other_thread(file, 100000)); + threads.push(CjsTestTools.delayed_ref_unref_other_thread(file, 200000)); + threads.push(CjsTestTools.delayed_ref_unref_other_thread(file, 300000)); + CjsTestTools.save_object(file); + CjsTestTools.save_weak(file); file.run_dispose(); file = null; System.gc(); threads.forEach(th => th.join()); - GjsTestTools.clear_saved(); - expect(GjsTestTools.get_weak()).toBeNull(); + CjsTestTools.clear_saved(); + expect(CjsTestTools.get_weak()).toBeNull(); }); it('can be finalized while queued in toggle queue', function () { let file = Gio.File.new_for_path('/'); file.expandMeWithToggleRef = true; - file.ref(); - GjsTestTools.unref_other_thread(file); - GjsTestTools.unref_other_thread(file); + CjsTestTools.ref(file); + CjsTestTools.unref_other_thread(file); + CjsTestTools.unref_other_thread(file); - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, '*Object 0x* has been finalized *'); file = null; System.gc(); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectDestructionAccess.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectDestructionAccess.js', 0, 'can be finalized while queued in toggle queue'); }); xit('can be toggled up-down from various threads while getting a GWeakRef from main', function () { let file = Gio.File.new_for_path('/'); file.expandMeWithToggleRef = true; - GjsTestTools.save_weak(file); + CjsTestTools.save_weak(file); const ids = []; let threads = []; ids.push(GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { threads = threads.slice(-50); try { - threads.push(GjsTestTools.delayed_ref_unref_other_thread(file, 1)); + threads.push(CjsTestTools.delayed_ref_unref_other_thread(file, 1)); } catch (e) { // If creating the thread failed we're almost going out of memory // so let's first wait for the ones allocated to complete. @@ -717,7 +718,7 @@ describe('GObject with toggle references', function () { const loop = new GLib.MainLoop(null, false); ids.push(GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { - expect(GjsTestTools.get_weak()).toEqual(file); + expect(CjsTestTools.get_weak()).toEqual(file); return GLib.SOURCE_CONTINUE; })); @@ -727,14 +728,14 @@ describe('GObject with toggle references', function () { ids.forEach(id => GLib.source_remove(id)); // We also check that late thread events won't affect the destroyed wrapper - GjsTestTools.save_object(file); + CjsTestTools.save_object(file); file = null; System.gc(); threads.forEach(th => th.join()); - expect(GjsTestTools.get_saved_ref_count()).toBeGreaterThan(0); + expect(CjsTestTools.get_saved_ref_count()).toBeGreaterThan(0); - GjsTestTools.clear_saved(); + CjsTestTools.clear_saved(); System.gc(); - expect(GjsTestTools.get_weak()).toBeNull(); + expect(CjsTestTools.get_weak()).toBeNull(); }).pend('Flaky, see https://gitlab.gnome.org/GNOME/gjs/-/issues/NNN'); }); diff --git a/installed-tests/js/testGObjectInterface.js b/installed-tests/js/testGObjectInterface.js index 40f5eca82..0736b78aa 100644 --- a/installed-tests/js/testGObjectInterface.js +++ b/installed-tests/js/testGObjectInterface.js @@ -272,7 +272,7 @@ describe('GObject interface', function () { requiredG() {} }); // g_test_assert_expected_messages() is a macro, not introspectable - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectInterface.js', + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectInterface.js', 253, 'testGObjectMustOverrideInterfaceProperties'); }); diff --git a/installed-tests/js/testGio.js b/installed-tests/js/testGio.js index e70a95d65..908f906b5 100644 --- a/installed-tests/js/testGio.js +++ b/installed-tests/js/testGio.js @@ -105,18 +105,18 @@ describe('Gio.Settings overrides', function () { }); it("doesn't crash when specifying a schema ID that isn't installed", function () { - expect(() => new Gio.Settings({schema: 'com.example.ThisDoesntExist'})) + expect(() => new Gio.Settings({schemaId: 'com.example.ThisDoesntExist'})) .toThrowError(/schema/); }); it("doesn't crash when forgetting to specify a schema path", function () { - expect(() => new Gio.Settings({schema: 'org.cinnamon.CjsTest.Sub'})) + expect(() => new Gio.Settings({schemaId: 'org.cinnamon.CjsTest.Sub'})) .toThrowError(/schema/); }); it("doesn't crash when specifying conflicting schema paths", function () { expect(() => new Gio.Settings({ - schema: 'org.cinnamon.CjsTest', + schemaId: 'org.cinnamon.CjsTest', path: '/conflicting/path/', })).toThrowError(/schema/); }); @@ -139,7 +139,7 @@ describe('Gio.Settings overrides', function () { let settings; beforeEach(function () { - settings = new Gio.Settings({schema: 'org.cinnamon.CjsTest'}); + settings = new Gio.Settings({schemaId: 'org.cinnamon.CjsTest'}); }); it("doesn't crash when resetting a nonexistent key", function () { @@ -231,6 +231,12 @@ describe('Gio.Settings overrides', function () { }); }); +describe('Gio.content_type_set_mime_dirs', function () { + it('can be called with NULL argument', function () { + expect(() => Gio.content_type_set_mime_dirs(null)).not.toThrow(); + }); +}); + describe('Gio.add_action_entries override', function () { it('registers each entry as an action', function () { const app = new Gio.Application(); @@ -391,14 +397,14 @@ describe('Non-introspectable file attribute overrides', function () { function expectWarnings(count) { numExpectedWarnings = count; for (let c = 0; c < count; c++) { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, '*not introspectable*'); } } function assertWarnings(testName) { for (let c = 0; c < numExpectedWarnings; c++) { - GLib.test_assert_expected_messages_internal('Gjs', 'testGio.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGio.js', 0, `test Gio.${testName}`); } numExpectedWarnings = 0; diff --git a/installed-tests/js/testGtk3.js b/installed-tests/js/testGtk3.js index f409f255d..73462fa57 100644 --- a/installed-tests/js/testGtk3.js +++ b/installed-tests/js/testGtk3.js @@ -3,7 +3,6 @@ imports.gi.versions.Gtk = '3.0'; -const ByteArray = imports.byteArray; const {GLib, Gio, GObject, Gtk} = imports.gi; const System = imports.system; @@ -42,7 +41,7 @@ function createTemplate(className) { } const MyComplexGtkSubclass = GObject.registerClass({ - Template: ByteArray.fromString(createTemplate('Gjs_MyComplexGtkSubclass')), + Template: new TextEncoder().encode(createTemplate('Gjs_MyComplexGtkSubclass')), Children: ['label-child', 'label-child2'], InternalChildren: ['internal-label-child'], CssName: 'complex-subclass', @@ -65,7 +64,7 @@ const MyComplexGtkSubclass = GObject.registerClass({ }); const MyComplexGtkSubclassFromResource = GObject.registerClass({ - Template: 'resource:///org/gjs/jsunit/complex3.ui', + Template: 'resource:///org/cjs/jsunit/complex3.ui', Children: ['label-child', 'label-child2'], InternalChildren: ['internal-label-child'], }, class MyComplexGtkSubclassFromResource extends Gtk.Grid { @@ -176,7 +175,7 @@ describe('Gtk overrides', function () { }); it('avoid crashing when GTK vfuncs are called in garbage collection', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, '*during garbage collection*offending callback was destroy()*'); const BadLabel = GObject.registerClass(class BadLabel extends Gtk.Label { @@ -186,7 +185,7 @@ describe('Gtk overrides', function () { new BadLabel(); System.gc(); - GLib.test_assert_expected_messages_internal('Gjs', 'testGtk3.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGtk3.js', 0, 'Gtk overrides avoid crashing and print a stack trace'); }); @@ -203,11 +202,11 @@ describe('Gtk overrides', function () { label.destroy(); expect(spy).toHaveBeenCalledTimes(1); - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, '*during garbage collection*offending callback was destroy()*'); label = null; System.gc(); - GLib.test_assert_expected_messages_internal('Gjs', 'testGtk3.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGtk3.js', 0, 'GTK vfuncs are not called if the object is disposed'); }); @@ -221,13 +220,29 @@ describe('Gtk overrides', function () { expect(handleDispose).toHaveBeenCalledWith(label); - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_CRITICAL, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_CRITICAL, 'Object Gtk.Label (0x* disposed *'); expect(label.label).toBe('Hello'); - GLib.test_assert_expected_messages_internal('Gjs', 'testGtk3.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGtk3.js', 0, 'GTK destroy signal is emitted while disposing objects'); }); + it('destroy signal is not emitted when objects are garbage collected', function () { + let label = new Gtk.Label({label: 'Hello'}); + const handleDispose = jasmine.createSpy('handleDispose').and.callFake(() => { + expect(label.label).toBe('Hello'); + }); + label.connect('destroy', handleDispose); + + label = null; + + System.gc(); + + System.gc(); + + expect(handleDispose).not.toHaveBeenCalled(); + }); + it('accepts string in place of GdkAtom', function () { expect(() => Gtk.Clipboard.get(1)).toThrow(); expect(() => Gtk.Clipboard.get(true)).toThrow(); @@ -304,4 +319,36 @@ describe('Gtk overrides', function () { expect(() => widget.show()).not.toThrow(); expect(frameChild.visible).toBe(true); }); + + function asyncIdle() { + return new Promise(resolve => { + GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { + resolve(); + return GLib.SOURCE_REMOVE; + }); + }); + } + + it('does not leak instance when connecting template signal', async function () { + const LeakTestWidget = GObject.registerClass({ + Template: new TextEncoder().encode(` + + + `), + }, class LeakTestWidget extends Gtk.Button { + buttonClicked() {} + }); + + const weakRef = new WeakRef(new LeakTestWidget()); + + await asyncIdle(); + // It takes two GC cycles to free the widget, because of the tardy sweep + // problem (https://gitlab.gnome.org/GNOME/gjs/-/issues/217) + System.gc(); + System.gc(); + + expect(weakRef.deref()).toBeUndefined(); + }); }); diff --git a/installed-tests/js/testGtk4.js b/installed-tests/js/testGtk4.js index 810145422..b21d63612 100644 --- a/installed-tests/js/testGtk4.js +++ b/installed-tests/js/testGtk4.js @@ -4,8 +4,13 @@ imports.gi.versions.Gdk = '4.0'; imports.gi.versions.Gtk = '4.0'; -const ByteArray = imports.byteArray; -const {Gdk, Gio, GObject, Gtk} = imports.gi; +const {Gdk, Gio, GObject, Gtk, GLib, CjsTestTools} = imports.gi; +const System = imports.system; + +// Set up log writer for tests to override +const writerFunc = jasmine.createSpy('log writer', () => GLib.LogWriterOutput.UNHANDLED); +writerFunc.and.callThrough(); +GLib.log_set_writer_func(writerFunc); // This is ugly here, but usually it would be in a resource function createTemplate(className) { @@ -38,7 +43,7 @@ function createTemplate(className) { } const MyComplexGtkSubclass = GObject.registerClass({ - Template: ByteArray.fromString(createTemplate('Gjs_MyComplexGtkSubclass')), + Template: new TextEncoder().encode(createTemplate('Gjs_MyComplexGtkSubclass')), Children: ['label-child', 'label-child2'], InternalChildren: ['internal-label-child'], CssName: 'complex-subclass', @@ -61,7 +66,7 @@ const MyComplexGtkSubclass = GObject.registerClass({ }); const MyComplexGtkSubclassFromResource = GObject.registerClass({ - Template: 'resource:///org/gjs/jsunit/complex4.ui', + Template: 'resource:///org/cjs/jsunit/complex4.ui', Children: ['label-child', 'label-child2'], InternalChildren: ['internal-label-child'], }, class MyComplexGtkSubclassFromResource extends Gtk.Grid { @@ -80,6 +85,26 @@ const MyComplexGtkSubclassFromResource = GObject.registerClass({ } }); +const MyComplexGtkSubclassFromString = GObject.registerClass({ + Template: createTemplate('Gjs_MyComplexGtkSubclassFromString'), + Children: ['label-child', 'label-child2'], + InternalChildren: ['internal-label-child'], +}, class MyComplexGtkSubclassFromString extends Gtk.Grid { + testChildrenExist() { + expect(this.label_child).toEqual(jasmine.anything()); + expect(this.label_child2).toEqual(jasmine.anything()); + expect(this._internal_label_child).toEqual(jasmine.anything()); + } + + templateCallback(widget) { + this.callbackEmittedBy = widget; + } + + boundCallback(widget) { + widget.callbackBoundTo = this; + } +}); + const [templateFile, stream] = Gio.File.new_tmp(null); const baseStream = stream.get_output_stream(); const out = new Gio.DataOutputStream({baseStream}); @@ -174,9 +199,50 @@ describe('Gtk overrides', function () { validateTemplate('UI template', MyComplexGtkSubclass); validateTemplate('UI template from resource', MyComplexGtkSubclassFromResource); + validateTemplate('UI template from string', MyComplexGtkSubclassFromString); validateTemplate('UI template from file', MyComplexGtkSubclassFromFile); validateTemplate('Class inheriting from template class', SubclassSubclass, true); + it('ensures signal handlers are callable', function () { + const ClassWithUncallableHandler = GObject.registerClass({ + Template: createTemplate('Gjs_ClassWithUncallableHandler'), + Children: ['label-child', 'label-child2'], + InternalChildren: ['internal-label-child'], + }, class ClassWithUncallableHandler extends Gtk.Grid { + templateCallback() {} + get boundCallback() { + return 'who ya gonna call?'; + } + }); + + // The exception is thrown inside a vfunc with a GError out parameter, + // and Gtk logs a critical. + writerFunc.calls.reset(); + writerFunc.and.callFake((level, fields) => { + const decoder = new TextDecoder('utf-8'); + const domain = decoder.decode(fields?.GLIB_DOMAIN); + const message = decoder.decode(fields?.MESSAGE); + expect(level).toBe(GLib.LogLevelFlags.LEVEL_CRITICAL); + expect(domain).toBe('Gtk'); + expect(message).toMatch('is not a function'); + return GLib.LogWriterOutput.HANDLED; + }); + + void new ClassWithUncallableHandler(); + + expect(writerFunc).toHaveBeenCalled(); + writerFunc.and.callThrough(); + }); + + it('rejects unsupported template URIs', function () { + expect(() => { + return GObject.registerClass({ + Template: 'https://gnome.org', + }, class GtkTemplateInvalid extends Gtk.Widget { + }); + }).toThrowError(TypeError, /Invalid template URI/); + }); + it('sets CSS names on classes', function () { expect(Gtk.Widget.get_css_name.call(MyComplexGtkSubclass)).toEqual('complex-subclass'); }); @@ -224,4 +290,80 @@ describe('Gtk 4 regressions', function () { custom.activate_action('custom.action', null); expect(custom.action).toEqual(42); }).pend('https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/3796'); + + it('Gdk.NoSelection section returns valid start/end values', function () { + if (!Gtk.NoSelection.prototype.get_section) + pending('Gtk 4.12 is required'); + + let result; + try { + result = new Gtk.NoSelection().get_section(0); + } catch (err) { + if (err.message.includes('not introspectable')) + pending('This version of GTK has the annotation bug'); + throw err; + } + expect(result).toEqual([0, GLib.MAXUINT32]); + }); + + function createSurface(shouldStash) { + // Create a Gdk.Surface that is unreachable after this function ends + const display = Gdk.Display.get_default(); + const surface = Gdk.Surface.new_toplevel(display); + if (shouldStash) + CjsTestTools.save_object(surface); + } + + it('Gdk.Surface is destroyed properly', function () { + createSurface(false); + System.gc(); + }); + + it('Gdk.Surface is not destroyed if a ref is held from C', function () { + createSurface(true); + System.gc(); + const surface = CjsTestTools.steal_saved(); + expect(surface.is_destroyed()).toBeFalsy(); + }); +}); + +class LeakTestWidget extends Gtk.Button { + buttonClicked() {} +} + +GObject.registerClass({ + Template: new TextEncoder().encode(` + + +`), +}, LeakTestWidget); + + +describe('Gtk template signal', function () { + beforeAll(function () { + Gtk.init(); + }); + + function asyncIdle() { + return new Promise(resolve => { + GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { + resolve(); + return GLib.SOURCE_REMOVE; + }); + }); + } + + it('does not leak', async function () { + const weakRef = new WeakRef(new LeakTestWidget()); + + await asyncIdle(); + // It takes two GC cycles to free the widget, because of the tardy sweep + // problem (https://gitlab.gnome.org/GNOME/gjs/-/issues/217) + System.gc(); + System.gc(); + + expect(weakRef.deref()).toBeUndefined(); + }); }); diff --git a/installed-tests/js/testImporter.js b/installed-tests/js/testImporter.js index f03bf634b..af5b5c29f 100644 --- a/installed-tests/js/testImporter.js +++ b/installed-tests/js/testImporter.js @@ -9,11 +9,11 @@ describe('GI importer', function () { describe('on failure', function () { // For these tests, we provide special overrides files to sabotage the - // import, at the path resource:///org/gjs/jsunit/modules/badOverrides. + // import, at the path resource:///org/cjs/jsunit/modules/badOverrides. let oldSearchPath; beforeAll(function () { oldSearchPath = imports.overrides.searchPath.slice(); - imports.overrides.searchPath = ['resource:///org/gjs/jsunit/modules/badOverrides']; + imports.overrides.searchPath = ['resource:///org/cjs/jsunit/modules/badOverrides']; }); afterAll(function () { @@ -54,7 +54,7 @@ describe('Importer', function () { beforeAll(function () { oldSearchPath = imports.searchPath.slice(); - imports.searchPath = ['resource:///org/gjs/jsunit/modules']; + imports.searchPath = ['resource:///org/cjs/jsunit/modules']; foobar = imports.foobar; subA = imports.subA; @@ -205,10 +205,10 @@ describe('Importer', function () { it('will log a compatibility warning when accessed', function () { const GLib = imports.gi.GLib; - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, "Some code accessed the property 'b' on the module " + "'lexicalScope'.*"); - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, "Some code accessed the property 'c' on the module " + "'lexicalScope'.*"); @@ -216,7 +216,7 @@ describe('Importer', function () { void LexicalScope.c; // g_test_assert_expected_messages() is a macro, not introspectable - GLib.test_assert_expected_messages_internal('Gjs', + GLib.test_assert_expected_messages_internal('Cjs', 'testImporter.js', 179, ''); }); diff --git a/installed-tests/js/testImporter2.js b/installed-tests/js/testImporter2.js index b4e71225d..52deadb5d 100644 --- a/installed-tests/js/testImporter2.js +++ b/installed-tests/js/testImporter2.js @@ -9,11 +9,11 @@ describe('GI importer', function () { describe('on failure', function () { // For these tests, we provide special overrides files to sabotage the - // import, at the path resource:///org/gjs/jsunit/modules/badOverrides2. + // import, at the path resource:///org/cjs/jsunit/modules/badOverrides2. let oldSearchPath; beforeAll(function () { oldSearchPath = imports.overrides.searchPath.slice(); - imports.overrides.searchPath = ['resource:///org/gjs/jsunit/modules/badOverrides2']; + imports.overrides.searchPath = ['resource:///org/cjs/jsunit/modules/badOverrides2']; }); afterAll(function () { diff --git a/installed-tests/js/testIntrospection.js b/installed-tests/js/testIntrospection.js index aa0d25522..de76bd645 100644 --- a/installed-tests/js/testIntrospection.js +++ b/installed-tests/js/testIntrospection.js @@ -23,16 +23,16 @@ describe('GLib.DestroyNotify parameter', function () { describe('Unsafe integer marshalling', function () { it('warns when conversion is lossy', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, '*cannot be safely stored*'); - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, '*cannot be safely stored*'); - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, '*cannot be safely stored*'); void GLib.MININT64; void GLib.MAXINT64; void GLib.MAXUINT64; - GLib.test_assert_expected_messages_internal('Gjs', + GLib.test_assert_expected_messages_internal('Cjs', 'testEverythingBasic.js', 0, 'Limits warns when conversion is lossy'); }); @@ -155,10 +155,10 @@ describe('Garbage collection of introspected objects', function () { } } - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, '*property screenfull*'); - const settings = new Gio.Settings({schema: 'org.cinnamon.CjsTest'}); + const settings = new Gio.Settings({schemaId: 'org.cinnamon.CjsTest'}); let obj = new SomeObject(); settings.bind('fullscreen', obj, 'screenfull', Gio.SettingsBindFlags.DEFAULT); const handler = settings.connect('changed::fullscreen', () => { @@ -166,7 +166,7 @@ describe('Garbage collection of introspected objects', function () { obj = null; settings.disconnect(handler); GLib.idle_add(GLib.PRIORITY_LOW, () => { - GLib.test_assert_expected_messages_internal('Gjs', + GLib.test_assert_expected_messages_internal('Cjs', 'testIntrospection.js', 0, 'Warn about setting property on disposed JS object'); done(); @@ -210,3 +210,50 @@ describe('Complete enumeration of GIRepositoryNamespace (new_enumerate)', functi }).not.toThrowError(/API of type .* not implemented, cannot define .*/); }); }); + +describe('Backwards compatibility for GLib/Gio platform specific GIRs', function () { + // Only test this if GioUnix is available + const skip = imports.gi.versions.GioUnix !== '2.0'; + + it('GioUnix objects are looked up in GioUnix, not Gio', function () { + if (skip) { + pending('GioUnix required for this test'); + return; + } + + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, + '*Gio.UnixMountMonitor*'); + + const monitor = Gio.UnixMountMonitor.get(); + expect(monitor.toString()).toContain('GIName:GioUnix.MountMonitor'); + + GLib.test_assert_expected_messages_internal('Cjs', + 'testIntrospection.js', 0, + 'Expected deprecation message for Gio.Unix -> GioUnix'); + }); + + it("doesn't print the message if the type isn't resolved directly", function () { + if (skip) { + pending('GioUnix required for this test'); + return; + } + + const launcher = new Gio.SubprocessLauncher({flags: Gio.SubprocessFlags.STDOUT_PIPE}); + const proc = launcher.spawnv(['ls', '/dev/null']); + + expect(proc.get_stdout_pipe().toString()).toContain('GIName:GioUnix.InputStream'); + }); + + it('has some exceptions', function () { + expect(Gio.UnixConnection.toString()).toContain('Gio_UnixConnection'); + + const credentialsMessage = new Gio.UnixCredentialsMessage(); + expect(credentialsMessage.toString()).toContain('GIName:Gio.UnixCredentials'); + + const fdList = new Gio.UnixFDList(); + expect(fdList.toString()).toContain('GIName:Gio.UnixFDList'); + + const socketAddress = Gio.UnixSocketAddress.new_with_type('', Gio.UnixSocketAddressType.ANONYMOUS); + expect(socketAddress.toString()).toContain('GIName:Gio.UnixSocketAddress'); + }); +}); diff --git a/installed-tests/js/testLegacyByteArray.js b/installed-tests/js/testLegacyByteArray.js index e13ff3688..3ae2fb04f 100644 --- a/installed-tests/js/testLegacyByteArray.js +++ b/installed-tests/js/testLegacyByteArray.js @@ -1,10 +1,128 @@ // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later // SPDX-FileCopyrightText: 2010 litl, LLC +// SPDX-FileCopyrightText: 2017 Philip Chimento const ByteArray = imports.byteArray; -const GIMarshallingTests = imports.gi.GIMarshallingTests; +const {GIMarshallingTests, CjsTestTools, GLib} = imports.gi; -describe('Legacy byte array', function () { +describe('Uint8Array with legacy ByteArray functions', function () { + it('can be created from a string', function () { + let a = ByteArray.fromString('abcd'); + expect(a.length).toEqual(4); + [97, 98, 99, 100].forEach((val, ix) => expect(a[ix]).toEqual(val)); + }); + + it('can be encoded from a string', function () { + // Pick a string likely to be stored internally as Latin1 + let a = ByteArray.fromString('äbcd', 'LATIN1'); + expect(a.length).toEqual(4); + [228, 98, 99, 100].forEach((val, ix) => expect(a[ix]).toEqual(val)); + + // Try again with a string not likely to be Latin1 internally + a = ByteArray.fromString('⅜', 'UTF-8'); + expect(a.length).toEqual(3); + [0xe2, 0x85, 0x9c].forEach((val, ix) => expect(a[ix]).toEqual(val)); + }); + + it('encodes as UTF-8 by default', function () { + let a = ByteArray.fromString('⅜'); + expect(a.length).toEqual(3); + [0xe2, 0x85, 0x9c].forEach((val, ix) => expect(a[ix]).toEqual(val)); + }); + + it('can be converted to a string of ASCII characters', function () { + let a = new Uint8Array(4); + a[0] = 97; + a[1] = 98; + a[2] = 99; + a[3] = 100; + let s = ByteArray.toString(a); + expect(s.length).toEqual(4); + expect(s).toEqual('abcd'); + }); + + it('can be converted to a string of UTF-8 characters even if it ends with a 0', function () { + const a = Uint8Array.of(97, 98, 99, 100, 0); + const s = ByteArray.toString(a); + expect(s.length).toEqual(4); + expect(s).toEqual('abcd'); + }); + + it('can be converted to a string of encoded characters even with a 0 byte', function () { + const a = Uint8Array.of(97, 98, 99, 100, 0); + const s = ByteArray.toString(a, 'LATIN1'); + expect(s.length).toEqual(4); + expect(s).toEqual('abcd'); + }); + + it('stops converting to a string at an embedded 0 byte', function () { + const a = Uint8Array.of(97, 98, 0, 99, 100); + const s = ByteArray.toString(a); + expect(s.length).toEqual(2); + expect(s).toEqual('ab'); + }); + + it('deals gracefully with a 0-length array', function () { + const a = new Uint8Array(0); + expect(ByteArray.toString(a)).toEqual(''); + expect(ByteArray.toGBytes(a).get_size()).toEqual(0); + }); + + it('deals gracefully with a 0-length GLib.Bytes', function () { + const noBytes = ByteArray.toGBytes(new Uint8Array(0)); + expect(ByteArray.fromGBytes(noBytes).length).toEqual(0); + }); + + it('deals gracefully with a non-aligned GBytes', function () { + const unalignedBytes = CjsTestTools.new_unaligned_bytes(48); + const arr = ByteArray.fromGBytes(unalignedBytes); + expect(arr.length).toEqual(48); + expect(Array.prototype.slice.call(arr, 0, 4)).toEqual([1, 2, 3, 4]); + }); + + it('deals gracefully with a GBytes in static storage', function () { + const staticBytes = CjsTestTools.new_static_bytes(); + const arr = ByteArray.fromGBytes(staticBytes); + arr[2] = 42; + expect(Array.from(arr)).toEqual([104, 101, 42, 108, 111, 0]); + }); + + it('deals gracefully with a 0-length string', function () { + expect(ByteArray.fromString('').length).toEqual(0); + expect(ByteArray.fromString('', 'LATIN1').length).toEqual(0); + }); + + it('deals gracefully with a non Uint8Array', function () { + const a = [97, 98, 99, 100, 0]; + expect(() => ByteArray.toString(a)).toThrow(); + expect(() => ByteArray.toGBytes(a)).toThrow(); + }); + + describe('legacy toString() behavior', function () { + beforeEach(function () { + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, + 'Some code called array.toString()*'); + }); + + it('is preserved when created from a string', function () { + let a = ByteArray.fromString('⅜'); + expect(a.toString()).toEqual('⅜'); + }); + + it('is preserved when marshalled from GI', function () { + let a = GIMarshallingTests.bytearray_full_return(); + expect(a.toString()).toEqual(''); + }); + + afterEach(function () { + GLib.test_assert_expected_messages_internal('Cjs', + 'testByteArray.js', 0, 'testToStringCompatibility'); + }); + }); +}); + + +describe('Legacy byte array object', function () { it('has length 0 for empty array', function () { let a = new ByteArray.ByteArray(); expect(a.length).toEqual(0); diff --git a/installed-tests/js/testLegacyGObject.js b/installed-tests/js/testLegacyGObject.js index 2f113cadb..75cc3db19 100644 --- a/installed-tests/js/testLegacyGObject.js +++ b/installed-tests/js/testLegacyGObject.js @@ -400,7 +400,7 @@ describe('GObject class', function () { expect(() => (obj.anchors = 'foo')).not.toThrow(); expect(obj.anchors).toEqual('foo'); - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectClass.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectClass.js', 0, 'testGObjectClassForgottenOverride'); }); @@ -750,7 +750,7 @@ describe('GObject interface', function () { requiredG() {}, }); // g_test_assert_expected_messages() is a macro, not introspectable - GLib.test_assert_expected_messages_internal('Gjs', 'testGObjectInterface.js', + GLib.test_assert_expected_messages_internal('Cjs', 'testGObjectInterface.js', 416, 'testGObjectMustOverrideInterfaceProperties'); }); diff --git a/installed-tests/js/testLegacyGtk.js b/installed-tests/js/testLegacyGtk.js index 9e3827fbb..914a2cc17 100644 --- a/installed-tests/js/testLegacyGtk.js +++ b/installed-tests/js/testLegacyGtk.js @@ -5,9 +5,9 @@ imports.gi.versions.Gtk = '3.0'; -const ByteArray = imports.byteArray; -const Gtk = imports.gi.Gtk; +const {GLib, Gtk} = imports.gi; const Lang = imports.lang; +const System = imports.system; const template = ` @@ -41,7 +41,7 @@ const template = ` const MyComplexGtkSubclass = new Lang.Class({ Name: 'MyComplexGtkSubclass', Extends: Gtk.Grid, - Template: ByteArray.fromString(template), + Template: new TextEncoder().encode(template), Children: ['label-child', 'label-child2'], InternalChildren: ['internal-label-child'], CssName: 'complex-subclass', @@ -58,7 +58,7 @@ const MyComplexGtkSubclass = new Lang.Class({ const MyComplexGtkSubclassFromResource = new Lang.Class({ Name: 'MyComplexGtkSubclassFromResource', Extends: Gtk.Grid, - Template: 'resource:///org/gjs/jsunit/complex3.ui', + Template: 'resource:///org/cjs/jsunit/complex3.ui', Children: ['label-child', 'label-child2'], InternalChildren: ['internal-label-child'], @@ -112,4 +112,38 @@ describe('Legacy Gtk overrides', function () { it('sets CSS names on classes', function () { expect(Gtk.Widget.get_css_name.call(MyComplexGtkSubclass)).toEqual('complex-subclass'); }); + + function asyncIdle() { + return new Promise(resolve => { + GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { + resolve(); + return GLib.SOURCE_REMOVE; + }); + }); + } + + it('does not leak instance when connecting template signal', async function () { + const LeakTestWidget = new Lang.Class({ + Name: 'LeakTestWidget', + Extends: Gtk.Button, + Template: new TextEncoder().encode(` + + + `), + + buttonClicked() {}, + }); + + const weakRef = new WeakRef(new LeakTestWidget()); + + await asyncIdle(); + // It takes two GC cycles to free the widget, because of the tardy sweep + // problem (https://gitlab.gnome.org/GNOME/gjs/-/issues/217) + System.gc(); + System.gc(); + + expect(weakRef.deref()).toBeUndefined(); + }); }); diff --git a/installed-tests/js/testParamSpec.js b/installed-tests/js/testParamSpec.js index be64a34a6..cc2ebabfb 100644 --- a/installed-tests/js/testParamSpec.js +++ b/installed-tests/js/testParamSpec.js @@ -49,4 +49,9 @@ describe('GObject.ParamSpec object', function () { let paramSpec = GObject.ParamSpec.string(name, nick, blurb, flags, ''); expect(paramSpec[0]).not.toBeDefined(); }); + + it('has correct object tag', function () { + const paramSpec = GObject.ParamSpec.string(name, nick, blurb, flags, ''); + expect(paramSpec.toString()).toEqual('[object GObject_ParamSpec]'); + }); }); diff --git a/installed-tests/js/testPrint.js b/installed-tests/js/testPrint.js index e84e3f717..558de6640 100644 --- a/installed-tests/js/testPrint.js +++ b/installed-tests/js/testPrint.js @@ -4,6 +4,7 @@ imports.gi.versions.Gdk = '3.0'; const Gdk = imports.gi.Gdk; +const ByteArray = imports.byteArray; const {getPrettyPrintFunction} = imports._print; let prettyPrint = getPrettyPrintFunction(globalThis); @@ -202,4 +203,47 @@ describe('prettyPrint', function () { it('null', function () { expect(prettyPrint(null)).toEqual('null'); }); + + it('nested null', function () { + expect(prettyPrint({'foo': null})).toEqual('{ foo: null }'); + }); + + it('imports root in object', function () { + expect(prettyPrint({'foo': imports})) + .toEqual('{ foo: [GjsFileImporter root] }'); + }); + + describe('TypedArrays', () => { + [ + Int8Array, + Uint8Array, + Uint16Array, + Uint8ClampedArray, + Int16Array, + Uint16Array, + Int32Array, + Uint32Array, + Float32Array, + Float64Array, + ].forEach(constructor => { + it(constructor.name, function () { + const arr = new constructor([1, 2, 3]); + expect(prettyPrint(arr)) + .toEqual('[1, 2, 3]'); + }); + }); + + [BigInt64Array, BigUint64Array].forEach(constructor => { + it(constructor.name, function () { + const arr = new constructor([1n, 2n, 3n]); + expect(prettyPrint(arr)) + .toEqual('[1, 2, 3]'); + }); + }); + }); + + it('Uint8Array returned from introspected function', function () { + let a = ByteArray.fromString('⅜'); + expect(prettyPrint(a)).toEqual('[226, 133, 156]'); + }); }); diff --git a/installed-tests/js/testPromise.js b/installed-tests/js/testPromise.js index df302bac2..02c35cf4b 100644 --- a/installed-tests/js/testPromise.js +++ b/installed-tests/js/testPromise.js @@ -82,10 +82,10 @@ describe('Promise', function () { expect(thenHandler).not.toHaveBeenCalled(); GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => loop.quit()); - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'Unhandled promise rejection.*'); loop.run(); - GLib.test_assert_expected_messages_internal('Gjs', 'testPromise.js', 0, + GLib.test_assert_expected_messages_internal('Cjs', 'testPromise.js', 0, 'warnsIfRejected'); }); diff --git a/installed-tests/js/testRegress.js b/installed-tests/js/testRegress.js index 813ab538f..a4589c8cd 100644 --- a/installed-tests/js/testRegress.js +++ b/installed-tests/js/testRegress.js @@ -11,10 +11,10 @@ const Gio = imports.gi.Gio; const GObject = imports.gi.GObject; function expectWarn64(callable) { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, '*cannot be safely stored*'); const ret = callable(); - GLib.test_assert_expected_messages_internal('Gjs', + GLib.test_assert_expected_messages_internal('Cjs', 'testRegress.js', 0, 'Ignore message'); return ret; } @@ -534,6 +534,25 @@ describe('Life, the Universe and Everything', function () { }); }); + it('enum that references its own members has correct values', function () { + expect(Regress.TestReferenceEnum.ZERO).toEqual(4); + expect(Regress.TestReferenceEnum.ONE).toEqual(2); + expect(Regress.TestReferenceEnum.TWO).toEqual(54); + expect(Regress.TestReferenceEnum.THREE).toEqual(4); + expect(Regress.TestReferenceEnum.FOUR).toEqual(216); + expect(Regress.TestReferenceEnum.FIVE).toEqual(-217); + }); + + it('unregistered enum works', function () { + expect(Regress.TestEnumNoGEnum.EVALUE1).toEqual(0); + expect(Regress.TestEnumNoGEnum.EVALUE2).toEqual(42); + expect(Regress.TestEnumNoGEnum.EVALUE3).toEqual('0'.charCodeAt()); + }); + + it('value is not added to enum with #define', function () { + expect(Regress.TestEnumNoGEnum.EVALUE_DEPRECATED).not.toBeDefined(); + }); + it('enum parameter', function () { expect(Regress.test_enum_param(Regress.TestEnum.VALUE1)).toEqual('value1'); expect(Regress.test_enum_param(Regress.TestEnum.VALUE3)).toEqual('value3'); @@ -947,6 +966,12 @@ describe('Life, the Universe and Everything', function () { expect(() => new Regress.TestBoxedD()).toThrow(); }); }); + + xit('methods take priority over fields in a name conflict', function () { + const boxed = new Regress.TestBoxedC({name_conflict: true}); + expect(boxed.name_conflict).not.toBeTrue(); + expect(boxed.name_conflict()).toBeTrue(); + }).pend('https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/454'); }); describe('wrong type for GBoxed', function () { @@ -1227,6 +1252,23 @@ describe('Life, the Universe and Everything', function () { o.emit('sig-with-obj', testObj); }); + it('signal with object with full transport gets correct arguments', function (done) { + o.connect('sig-with-obj-full', (self, objectParam) => { + expect(objectParam.int).toEqual(5); + done(); + }); + o.emit_sig_with_obj_full(); + }); + + it('signal with object with full transport gets correct arguments from JS', function (done) { + o.connect('sig-with-obj-full', (self, objectParam) => { + expect(objectParam.int).toEqual(55); + done(); + }); + const testObj = new Regress.TestObj({int: 55}); + o.emit('sig-with-obj-full', testObj); + }); + // See testCairo.js for a test of // Regress.TestObj::sig-with-foreign-struct. @@ -1287,6 +1329,26 @@ describe('Life, the Universe and Everything', function () { o.emit('sig-with-strv', ['a', 'bb', 'ccc']); }); + it('signal with GStrv parameter and transfer full is properly handled from JS', function (done) { + o.connect('sig-with-strv-full', (signalObj, signalArray, shouldBeUndefined) => { + expect(signalObj).toBe(o); + expect(shouldBeUndefined).not.toBeDefined(); + expect(signalArray).toEqual(['a', 'bb', 'ccc']); + done(); + }); + o.emit('sig-with-strv-full', ['a', 'bb', 'ccc']); + }); + + xit('signal with GStrv parameter and transfer full is properly handled', function (done) { + o.connect('sig-with-strv-full', (signalObj, signalArray, shouldBeUndefined) => { + expect(signalObj).toBe(o); + expect(shouldBeUndefined).not.toBeDefined(); + expect(signalArray).toEqual(['foo', 'bar', 'baz']); + done(); + }); + o.emit_sig_with_gstrv_full(); + }).pend('https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/470'); + xit('signal with int array ret parameter is properly handled', function (done) { o.connect('sig-with-intarray-ret', (signalObj, signalInt, shouldBeUndefined) => { expect(signalObj).toBe(o); diff --git a/installed-tests/js/testSignals.js b/installed-tests/js/testSignals.js index b3684546d..4a04174ea 100644 --- a/installed-tests/js/testSignals.js +++ b/installed-tests/js/testSignals.js @@ -92,7 +92,7 @@ function testSignals(klass) { expect(() => foo.disconnect(firstId)).toThrowError( `No signal connection ${firstId} found`); - // poke in private implementation to sanity-check no handlers left + // poke in private implementation to verify no handlers left expect(Object.keys(foo._signalConnections).length).toEqual(0); }); @@ -151,7 +151,7 @@ function testSignals(klass) { bar2 = jasmine.createSpy('bar'); foo[connectMethod]('bar', bar); foo[connectMethod]('bar', bar2); - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: Exception in callback for signal: *'); foo.emit('bar'); }); @@ -162,7 +162,7 @@ function testSignals(klass) { }); it('does not disconnect the callback', function () { - GLib.test_expect_message('Gjs', GLib.LogLevelFlags.LEVEL_WARNING, + GLib.test_expect_message('Cjs', GLib.LogLevelFlags.LEVEL_WARNING, 'JS ERROR: Exception in callback for signal: *'); foo.emit('bar'); expect(bar).toHaveBeenCalledTimes(2); diff --git a/installed-tests/js/testWarnLib.js b/installed-tests/js/testWarnLib.js index 21d0c6187..ddb549985 100644 --- a/installed-tests/js/testWarnLib.js +++ b/installed-tests/js/testWarnLib.js @@ -39,4 +39,8 @@ describe('WarnLib', function () { expect(o.mooCalled).toBeTruthy(); // spies don't work on vfuncs expect(o.booCalled).toBeTruthy(); }); + + it('handles enum members that start with a digit', function () { + expect(WarnLib.NumericEnum['1ST']).toEqual(1); + }); }); diff --git a/installed-tests/js/testWeakRef.js b/installed-tests/js/testWeakRef.js new file mode 100644 index 000000000..a4bc25a96 --- /dev/null +++ b/installed-tests/js/testWeakRef.js @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later +// SPDX-FileCopyrightText: 2023 Philip Chimento + +import System from 'system'; + +const PromiseInternal = imports._promiseNative; + +describe('WeakRef', function () { + it('works', function () { + let obj = {}; + const weakRef = new WeakRef(obj); + expect(weakRef.deref()).toBe(obj); + obj = null; + + // Do not use this in real code to process microtasks. This is only for + // making the test execute synchronously. Instead, in real code, return + // control to the event loop, e.g. with setTimeout(). + PromiseInternal.drainMicrotaskQueue(); + System.gc(); + + expect(weakRef.deref()).not.toBeDefined(); + }); +}); + +describe('FinalizationRegistry', function () { + let registry, callback; + beforeEach(function () { + callback = jasmine.createSpy('FinalizationRegistry callback'); + registry = new FinalizationRegistry(callback); + }); + + it('works', function () { + let obj = {}; + registry.register(obj, 'marker'); + obj = null; + System.gc(); + PromiseInternal.drainMicrotaskQueue(); + expect(callback).toHaveBeenCalledOnceWith('marker'); + }); + + it('works if a microtask is enqueued from the callback', function () { + let obj = {}; + let secondCallback = jasmine.createSpy('async callback'); + callback.and.callFake(function () { + return Promise.resolve().then(secondCallback); + }); + registry.register(obj); + obj = null; + System.gc(); + PromiseInternal.drainMicrotaskQueue(); + expect(callback).toHaveBeenCalled(); + expect(secondCallback).toHaveBeenCalled(); + }); + + it('works if the object is collected in a microtask', async function () { + let obj = {}; + registry.register(obj, 'marker'); + await Promise.resolve(); + obj = null; + System.gc(); + await Promise.resolve(); + expect(callback).toHaveBeenCalled(); + }); + + it('works if another collection is queued from the callback', function () { + let obj = {}; + let obj2 = {}; + callback.and.callFake(function () { + obj2 = null; + System.gc(); + }); + registry.register(obj, 'marker'); + registry.register(obj2, 'marker2'); + obj = null; + System.gc(); + PromiseInternal.drainMicrotaskQueue(); + expect(callback).toHaveBeenCalledTimes(2); + }); +}); diff --git a/installed-tests/meson.build b/installed-tests/meson.build index d270cb4a7..a56e0373a 100644 --- a/installed-tests/meson.build +++ b/installed-tests/meson.build @@ -4,15 +4,12 @@ ### Installed tests ############################################################ -installed_tests_execdir = get_option('prefix') / get_option('libexecdir') / 'installed-tests' / meson.project_name() -installed_tests_metadir = abs_datadir / 'installed-tests' / meson.project_name() - # Simple shell script tests # simple_tests = [] tests_dependencies = [ - gjs_console, - gjs_private_typelib, + cjs_console, + cjs_private_typelib, ] # The test scripts need to be ported from shell scripts @@ -33,9 +30,9 @@ foreach test : simple_tests test_description_subst = { 'name': 'test@0@.sh'.format(test), - 'installed_tests_execdir': installed_tests_execdir, + 'installed_tests_execdir': prefix / installed_tests_execdir, } - test_description = configure_file(configuration: test_description_subst, + configure_file(configuration: test_description_subst, input: 'script.test.in', output: 'test@0@.sh.test'.format(test), install: get_option('installed_tests'), install_dir: installed_tests_metadir) @@ -88,9 +85,9 @@ foreach test : debugger_tests test_description_subst = { 'name': '@0@.debugger'.format(test), - 'installed_tests_execdir': installed_tests_execdir, + 'installed_tests_execdir': prefix / installed_tests_execdir, } - test_description = configure_file(configuration: test_description_subst, + configure_file(configuration: test_description_subst, input: 'debugger.test.in', output: '@0@.test'.format(test), install: get_option('installed_tests'), diff --git a/installed-tests/minijasmine.cpp b/installed-tests/minijasmine.cpp index 9c916795e..00488e6db 100644 --- a/installed-tests/minijasmine.cpp +++ b/installed-tests/minijasmine.cpp @@ -46,7 +46,7 @@ main(int argc, char **argv) const char *coverage_prefix = g_getenv("GJS_UNIT_COVERAGE_PREFIX"); const char *coverage_output_path = g_getenv("GJS_UNIT_COVERAGE_OUTPUT"); - const char *search_path[] = { "resource:///org/gjs/jsunit", NULL }; + const char *search_path[] = { "resource:///org/cjs/jsunit", NULL }; if (coverage_prefix) gjs_coverage_enable(); @@ -72,7 +72,7 @@ main(int argc, char **argv) uint8_t u8_exitcode_ignored; int exitcode_ignored; if (!gjs_context_eval_module_file( - cx, "resource:///org/gjs/jsunit/minijasmine.js", + cx, "resource:///org/cjs/jsunit/minijasmine.js", &u8_exitcode_ignored, &error)) bail_out(cx, error); @@ -87,7 +87,7 @@ main(int argc, char **argv) bail_out(cx, error); success = gjs_context_eval_module_file( - cx, "resource:///org/gjs/jsunit/minijasmine-executor.js", &code, + cx, "resource:///org/cjs/jsunit/minijasmine-executor.js", &code, &error); if (!success) bail_out(cx, error); diff --git a/installed-tests/script.test.in b/installed-tests/script.test.in index 96a91b881..debefc4c2 100644 --- a/installed-tests/script.test.in +++ b/installed-tests/script.test.in @@ -3,5 +3,5 @@ [Test] Type=session -Exec=sh @installed_tests_execdir@/scripts/@name@ +Exec=sh @prefix@/@installed_tests_execdir@/scripts/@name@ Output=TAP diff --git a/installed-tests/scripts/common.sh b/installed-tests/scripts/common.sh old mode 100755 new mode 100644 diff --git a/installed-tests/scripts/testCommandLine.sh b/installed-tests/scripts/testCommandLine.sh old mode 100755 new mode 100644 index b3796f4ea..4a06e8d25 --- a/installed-tests/scripts/testCommandLine.sh +++ b/installed-tests/scripts/testCommandLine.sh @@ -227,11 +227,11 @@ report "--help after -c should not print anything" # report_xfail "-I after script file should not be added to search path" # fi G_DEBUG=$(echo "$G_DEBUG" | sed -e 's/fatal-warnings,\{0,1\}//') -$gjs help.js --help -I sentinel 2>&1 | grep -q 'Gjs-WARNING.*--include-path' +$gjs help.js --help -I sentinel 2>&1 | grep -q 'Cjs-WARNING.*--include-path' report "-I after script should succeed but give a warning" -$gjs -c 'imports.system.exit(0)' --coverage-prefix=foo --coverage-output=foo 2>&1 | grep -q 'Gjs-WARNING.*--coverage-prefix' +$gjs -c 'imports.system.exit(0)' --coverage-prefix=foo --coverage-output=foo 2>&1 | grep -q 'Cjs-WARNING.*--coverage-prefix' report "--coverage-prefix after script should succeed but give a warning" -$gjs -c 'imports.system.exit(0)' --coverage-prefix=foo --coverage-output=foo 2>&1 | grep -q 'Gjs-WARNING.*--coverage-output' +$gjs -c 'imports.system.exit(0)' --coverage-prefix=foo --coverage-output=foo 2>&1 | grep -q 'Cjs-WARNING.*--coverage-output' report "--coverage-output after script should succeed but give a warning" rm -f foo/coverage.lcov G_DEBUG="$OLD_G_DEBUG" @@ -257,7 +257,7 @@ $gjs -c 'imports.system.exit(0)' && ! stat gjs-*.syscap > /dev/null 2>&1 report "no profiling data should be dumped without --profile" # Skip some tests if built without profiler support -if $gjs --profile -c 1 2>&1 | grep -q 'Gjs-Message.*Profiler is disabled'; then +if $gjs --profile -c 1 2>&1 | grep -q 'Cjs-Message.*Profiler is disabled'; then reason="profiler is disabled" skip "--profile should dump profiling data to the default file name" "$reason" skip "--profile with argument should dump profiling data to the named file" "$reason" @@ -284,7 +284,7 @@ report "interpreter should run queued promise jobs before finishing" test -n "${output##*Should not be printed*}" report "interpreter should stop running jobs when one calls System.exit()" -$gjs -c "Promise.resolve().then(() => { throw new Error(); });" 2>&1 | grep -q 'Gjs-WARNING.*Unhandled promise rejection.*[sS]tack trace' +$gjs -c "Promise.resolve().then(() => { throw new Error(); });" 2>&1 | grep -q 'Cjs-WARNING.*Unhandled promise rejection.*[sS]tack trace' report "unhandled promise rejection should be reported" test -z "$($gjs awaitcatch.js)" report "catching an await expression should not cause unhandled rejection" diff --git a/installed-tests/scripts/testCommandLineModules.sh b/installed-tests/scripts/testCommandLineModules.sh old mode 100755 new mode 100644 diff --git a/installed-tests/scripts/testExamples.sh b/installed-tests/scripts/testExamples.sh old mode 100755 new mode 100644 diff --git a/installed-tests/scripts/testWarnings.sh b/installed-tests/scripts/testWarnings.sh old mode 100755 new mode 100644 index d54123fbd..c80d6d9d4 --- a/installed-tests/scripts/testWarnings.sh +++ b/installed-tests/scripts/testWarnings.sh @@ -29,7 +29,7 @@ $gjs -c 'imports.gi.GLib.get_home_dir("foobar")' 2>&1 | \ report "passing too many arguments to a GI function should warn" $gjs -c '**' 2>&1 | \ - grep -q 'SyntaxError.*@ :1:0' + grep -q 'SyntaxError.*@ :1:1' report "file and line number are logged for syntax errors" echo "1..$total" diff --git a/js.gresource.xml b/js.gresource.xml index e12dea125..e26c392ba 100644 --- a/js.gresource.xml +++ b/js.gresource.xml @@ -2,7 +2,7 @@ - + modules/internal/loader.js diff --git a/libgjs.map b/libcjs.map similarity index 100% rename from libgjs.map rename to libcjs.map diff --git a/libgjs.symbols b/libcjs.symbols similarity index 100% rename from libgjs.symbols rename to libcjs.symbols diff --git a/libgjs-private/gjs-gdbus-wrapper.c b/libgjs-private/gjs-gdbus-wrapper.c index 9d405901c..24a11af23 100644 --- a/libgjs-private/gjs-gdbus-wrapper.c +++ b/libgjs-private/gjs-gdbus-wrapper.c @@ -4,6 +4,8 @@ * SPDX-FileCopyrightText: 2011 Giovanni Campagna */ +#include + #include // for strcmp #include diff --git a/libgjs-private/gjs-match-info.c b/libgjs-private/gjs-match-info.c new file mode 100644 index 000000000..977589cf7 --- /dev/null +++ b/libgjs-private/gjs-match-info.c @@ -0,0 +1,357 @@ +/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ +/* + * SPDX-License-Identifier: MIT OR LGPL-2.0-or-later + * SPDX-FileCopyrightText: 2023 Philip Chimento + */ + +#include + +#include +#include /* for NULL */ +#include +#include /* for ssize_t */ + +#include +#include + +#include "libgjs-private/gjs-match-info.h" + +G_DEFINE_BOXED_TYPE(GjsMatchInfo, gjs_match_info, gjs_match_info_ref, + gjs_match_info_unref) + +struct _GjsMatchInfo { + gatomicrefcount refcount; + GMatchInfo* base; /* owned */ + char* str; +}; + +/* Takes ownership of string */ +static GjsMatchInfo* new_match_info(GMatchInfo* base, char* s) { + GjsMatchInfo* retval = g_new0(GjsMatchInfo, 1); + g_atomic_ref_count_init(&retval->refcount); + retval->base = base; + retval->str = s; + return retval; +} + +/** + * gjs_match_info_get_regex: + * @self: a #GjsMatchInfo + * + * Wrapper for g_match_info_get_regex(). + * + * Returns: (transfer none): #GRegex object + */ +GRegex* gjs_match_info_get_regex(const GjsMatchInfo* self) { + g_return_val_if_fail(self != NULL, NULL); + return g_match_info_get_regex(self->base); +} + +/** + * gjs_match_info_get_string: + * @self: a #GjsMatchInfo + * + * Replacement for g_match_info_get_string(), but the string is owned by @self. + * + * Returns: (transfer none): the string searched with @match_info + */ +const char* gjs_match_info_get_string(const GjsMatchInfo* self) { + g_return_val_if_fail(self != NULL, NULL); + return self->str; +} + +/** + * gjs_match_info_ref: + * @self: a #GjsMatchInfo + * + * Replacement for g_match_info_ref(). + * + * Returns: @self + */ +GjsMatchInfo* gjs_match_info_ref(GjsMatchInfo* self) { + g_return_val_if_fail(self != NULL, NULL); + g_atomic_ref_count_inc(&self->refcount); + return self; +} + +/** + * gjs_match_info_unref: + * @self: a #GjsMatchInfo + * + * Replacement for g_match_info_unref(). + */ +void gjs_match_info_unref(GjsMatchInfo* self) { + g_return_if_fail(self != NULL); + if (g_atomic_ref_count_dec(&self->refcount)) { + g_match_info_unref(self->base); + g_free(self->str); + g_free(self); + } +} + +/** + * gjs_match_info_free: + * @self: (nullable): a #GjsMatchInfo, or %NULL + * + * Replacement for g_match_info_free(). + */ +void gjs_match_info_free(GjsMatchInfo* self) { + g_return_if_fail(self != NULL); + if (self == NULL) + return; + + gjs_match_info_unref(self); +} + +/** + * gjs_match_info_next: + * @self: a #GjsMatchInfo + * @error: location to store the error occurring, or %NULL to ignore errors + * + * Wrapper for g_match_info_next(). + * + * Returns: %TRUE or %FALSE + */ +gboolean gjs_match_info_next(GjsMatchInfo* self, GError** error) { + g_return_val_if_fail(self != NULL, FALSE); + return g_match_info_next(self->base, error); +} + +/** + * gjs_match_info_matches: + * @self: a #GjsMatchInfo + * + * Wrapper for g_match_info_matches(). + * + * Returns: %TRUE or %FALSE + */ +gboolean gjs_match_info_matches(const GjsMatchInfo* self) { + g_return_val_if_fail(self != NULL, FALSE); + return g_match_info_matches(self->base); +} + +/** + * gjs_match_info_get_match_count: + * @self: a #GjsMatchInfo + * + * Wrapper for g_match_info_get_match_count(). + * + * Returns: Number of matched substrings, or -1 if an error occurred + */ +int gjs_match_info_get_match_count(const GjsMatchInfo* self) { + g_return_val_if_fail(self != NULL, -1); + return g_match_info_get_match_count(self->base); +} + +/** + * gjs_match_info_is_partial_match: + * @self: a #GjsMatchInfo + * + * Wrapper for g_match_info_is_partial_match(). + * + * Returns: %TRUE or %FALSE + */ +gboolean gjs_match_info_is_partial_match(const GjsMatchInfo* self) { + g_return_val_if_fail(self != NULL, FALSE); + return g_match_info_is_partial_match(self->base); +} + +/** + * gjs_match_info_expand_references: + * @self: (nullable): a #GjsMatchInfo or %NULL + * @string_to_expand: the string to expand + * @error: location to store the error occurring, or %NULL to ignore errors + * + * Wrapper for g_match_info_expand_references(). + * + * Returns: (nullable): the expanded string, or %NULL if an error occurred + */ +char* gjs_match_info_expand_references(const GjsMatchInfo* self, + const char* string_to_expand, + GError** error) { + return g_match_info_expand_references(self->base, string_to_expand, error); +} + +/** + * gjs_match_info_fetch: + * @self: a #GjsMatchInfo + * @match_num: number of the sub expression + * + * Wrapper for g_match_info_fetch(). + * + * Returns: (nullable): The matched substring, or %NULL if an error occurred. + */ +char* gjs_match_info_fetch(const GjsMatchInfo* self, int match_num) { + g_return_val_if_fail(self != NULL, NULL); + return g_match_info_fetch(self->base, match_num); +} + +/** + * gjs_match_info_fetch_pos: + * @self: a #GMatchInfo + * @match_num: number of the sub expression + * @start_pos: (out) (optional): pointer to location for the start position + * @end_pos: (out) (optional): pointer to location for the end position + * + * Wrapper for g_match_info_fetch_pos(). + * + * Returns: %TRUE or %FALSE + */ +gboolean gjs_match_info_fetch_pos(const GjsMatchInfo* self, int match_num, + int* start_pos, int* end_pos) { + g_return_val_if_fail(self != NULL, FALSE); + return g_match_info_fetch_pos(self->base, match_num, start_pos, end_pos); +} + +/** + * gjs_match_info_fetch_named: + * @self: a #GjsMatchInfo + * @name: name of the subexpression + * + * Wrapper for g_match_info_fetch_named(). + * + * Returns: (nullable): The matched substring, or %NULL if an error occurred. + */ +char* gjs_match_info_fetch_named(const GjsMatchInfo* self, const char* name) { + g_return_val_if_fail(self != NULL, NULL); + return g_match_info_fetch_named(self->base, name); +} + +/** + * gjs_match_info_fetch_named_pos: + * @self: a #GMatchInfo + * @name: name of the subexpression + * @start_pos: (out) (optional): pointer to location for the start position + * @end_pos: (out) (optional): pointer to location for the end position + * + * Wrapper for g_match_info_fetch_named_pos(). + * + * Returns: %TRUE or %FALSE + */ +gboolean gjs_match_info_fetch_named_pos(const GjsMatchInfo* self, + const char* name, int* start_pos, + int* end_pos) { + g_return_val_if_fail(self != NULL, FALSE); + return g_match_info_fetch_named_pos(self->base, name, start_pos, end_pos); +} + +/** + * gjs_match_info_fetch_all: + * @self: a #GMatchInfo + * + * Wrapper for g_match_info_fetch_all(). + * + * Returns: (transfer full): a %NULL-terminated array of strings. If the + * previous match failed %NULL is returned + */ +char** gjs_match_info_fetch_all(const GjsMatchInfo* self) { + g_return_val_if_fail(self != NULL, NULL); + return g_match_info_fetch_all(self->base); +} + +/** + * gjs_regex_match: + * @regex: a #GRegex + * @s: the string to scan for matches + * @match_options: match options + * @match_info: (out) (optional): pointer to location for the #GjsMatchInfo + * + * Wrapper for g_regex_match() that doesn't require the string to be kept alive. + * + * Returns: %TRUE or %FALSE + */ +gboolean gjs_regex_match(const GRegex* regex, const char* s, + GRegexMatchFlags match_options, + GjsMatchInfo** match_info) { + return gjs_regex_match_full(regex, (const uint8_t*)s, -1, 0, match_options, + match_info, NULL); +} + +/** + * gjs_regex_match_full: + * @regex: a #GRegex + * @bytes: (array length=len): the string to scan for matches + * @len: the length of @bytes + * @start_position: starting index of the string to match, in bytes + * @match_options: match options + * @match_info: (out) (optional): pointer to location for the #GjsMatchInfo + * @error: location to store the error occurring, or %NULL to ignore errors + * + * Wrapper for g_regex_match_full() that doesn't require the string to be kept + * alive. + * + * Returns: %TRUE or %FALSE + */ +gboolean gjs_regex_match_full(const GRegex* regex, const uint8_t* bytes, + ssize_t len, int start_position, + GRegexMatchFlags match_options, + GjsMatchInfo** match_info, GError** error) { + const char* s = (const char*)bytes; + if (match_info == NULL) + return g_regex_match_full(regex, s, len, start_position, match_options, + NULL, error); + + char* string_copy = len < 0 ? g_strdup(s) : g_strndup(s, len); + GMatchInfo* base = NULL; + bool retval = g_regex_match_full(regex, string_copy, len, start_position, + match_options, &base, error); + + if (base) + *match_info = new_match_info(base, string_copy); + + return retval; +} + +/** + * gjs_regex_match_all: + * @regex: a #GRegex + * @s: the string to scan for matches + * @match_options: match options + * @match_info: (out) (optional): pointer to location for the #GjsMatchInfo + * + * Wrapper for g_regex_match_all() that doesn't require the string to be kept + * alive. + * + * Returns: %TRUE or %FALSE + */ +gboolean gjs_regex_match_all(const GRegex* regex, const char* s, + GRegexMatchFlags match_options, + GjsMatchInfo** match_info) { + return gjs_regex_match_all_full(regex, (const uint8_t*)s, -1, 0, + match_options, match_info, NULL); +} + +/** + * gjs_regex_match_all_full: + * @regex: a #GRegex + * @bytes: (array length=len): the string to scan for matches + * @len: the length of @bytes + * @start_position: starting index of the string to match, in bytes + * @match_options: match options + * @match_info: (out) (optional): pointer to location for the #GMatchInfo + * @error: location to store the error occurring, or %NULL to ignore errors + * + * Wrapper for g_regex_match_all_full() that doesn't require the string to be + * kept alive. + * + * Returns: %TRUE or %FALSE + */ +gboolean gjs_regex_match_all_full(const GRegex* regex, const uint8_t* bytes, + ssize_t len, int start_position, + GRegexMatchFlags match_options, + GjsMatchInfo** match_info, GError** error) { + const char* s = (const char*)bytes; + if (match_info == NULL) + return g_regex_match_all_full(regex, s, len, start_position, + match_options, NULL, error); + + char* string_copy = len < 0 ? g_strdup(s) : g_strndup(s, len); + GMatchInfo* base = NULL; + bool retval = g_regex_match_all_full( + regex, string_copy, len, start_position, match_options, &base, error); + + if (base) + *match_info = new_match_info(base, string_copy); + + return retval; +} diff --git a/libgjs-private/gjs-match-info.h b/libgjs-private/gjs-match-info.h new file mode 100644 index 000000000..2aa2ef63f --- /dev/null +++ b/libgjs-private/gjs-match-info.h @@ -0,0 +1,93 @@ +/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ +/* + * SPDX-License-Identifier: MIT OR LGPL-2.0-or-later + * SPDX-FileCopyrightText: 2023 Philip Chimento + */ + +#pragma once + +#include +#include /* for ssize_t */ + +#include +#include + +#include "cjs/macros.h" + +G_BEGIN_DECLS + +/** + * GjsMatchInfo: + * + * A GjsMatchInfo is an opaque struct used to return information about + * matches. + */ +typedef struct _GjsMatchInfo GjsMatchInfo; + +/** + * GJS_TYPE_MATCH_INFO: + * + * The #GType for a boxed type holding a #GjsMatchInfo reference. + */ +#define GJS_TYPE_MATCH_INFO (gjs_match_info_get_type()) + +GJS_EXPORT +GType gjs_match_info_get_type(void) G_GNUC_CONST; + +GJS_EXPORT +GRegex* gjs_match_info_get_regex(const GjsMatchInfo* self); +GJS_EXPORT +const char* gjs_match_info_get_string(const GjsMatchInfo* self); + +GJS_EXPORT +GjsMatchInfo* gjs_match_info_ref(GjsMatchInfo* self); +GJS_EXPORT +void gjs_match_info_unref(GjsMatchInfo* self); +GJS_EXPORT +void gjs_match_info_free(GjsMatchInfo* self); +GJS_EXPORT +gboolean gjs_match_info_next(GjsMatchInfo* self, GError** error); +GJS_EXPORT +gboolean gjs_match_info_matches(const GjsMatchInfo* self); +GJS_EXPORT +int gjs_match_info_get_match_count(const GjsMatchInfo* self); +GJS_EXPORT +gboolean gjs_match_info_is_partial_match(const GjsMatchInfo* self); +GJS_EXPORT +char* gjs_match_info_expand_references(const GjsMatchInfo* self, + const char* string_to_expand, + GError** error); +GJS_EXPORT +char* gjs_match_info_fetch(const GjsMatchInfo* self, int match_num); +GJS_EXPORT +gboolean gjs_match_info_fetch_pos(const GjsMatchInfo* self, int match_num, + int* start_pos, int* end_pos); +GJS_EXPORT +char* gjs_match_info_fetch_named(const GjsMatchInfo* self, const char* name); +GJS_EXPORT +gboolean gjs_match_info_fetch_named_pos(const GjsMatchInfo* self, + const char* name, int* start_pos, + int* end_pos); +GJS_EXPORT +char** gjs_match_info_fetch_all(const GjsMatchInfo* self); + +GJS_EXPORT +gboolean gjs_regex_match(const GRegex* regex, const char* s, + GRegexMatchFlags match_options, + GjsMatchInfo** match_info); +GJS_EXPORT +gboolean gjs_regex_match_full(const GRegex* regex, const uint8_t* bytes, + ssize_t len, int start_position, + GRegexMatchFlags match_options, + GjsMatchInfo** match_info, GError** error); +GJS_EXPORT +gboolean gjs_regex_match_all(const GRegex* regex, const char* s, + GRegexMatchFlags match_options, + GjsMatchInfo** match_info); +GJS_EXPORT +gboolean gjs_regex_match_all_full(const GRegex* regex, const uint8_t* bytes, + ssize_t len, int start_position, + GRegexMatchFlags match_options, + GjsMatchInfo** match_info, GError** error); + +G_END_DECLS diff --git a/meson.build b/meson.build index 134c062af..a7d394dd9 100644 --- a/meson.build +++ b/meson.build @@ -2,15 +2,10 @@ # SPDX-FileCopyrightText: 2019 Philip Chimento # SPDX-FileCopyrightText: 2019 Chun-wei Fan -project( - 'cjs', - 'cpp', - 'c', -version : '6.4.0', -license : ['MIT', 'LGPL2+'], -meson_version : '>=0.56.0', -default_options : ['cpp_std=c++17', 'cpp_rtti=false', 'c_std=c99', 'warning_level=2', 'b_pch=true'] -) +project('cjs', 'cpp', 'c', version: '6.5.0', license: ['MIT', 'LGPL2+'], + meson_version: '>= 0.62.0', + default_options: ['cpp_std=c++17', 'cpp_rtti=false', 'cpp_eh=none', + 'c_std=c99', 'warning_level=2', 'b_pch=true' ]) # cpp_rtti: SpiderMonkey can be compiled with or without runtime type # information, and the default is without. We must match that option because we @@ -23,6 +18,15 @@ gnome = import('gnome') pkg = import('pkgconfig') top_include = include_directories('.') +prefix = get_option('prefix') +bindir = get_option('bindir') +libdir = get_option('libdir') +datadir = get_option('datadir') +libexecdir = get_option('libexecdir') +cjsjsdir = datadir / api_name +pkglibdir = libdir / meson.project_name() +installed_tests_execdir = libexecdir / 'installed-tests' / meson.project_name() +installed_tests_metadir = datadir / 'installed-tests' / meson.project_name() ### Check for conflicting build options ######################################## @@ -44,7 +48,7 @@ if cc.get_id() == 'msvc' add_project_arguments(cxx.get_supported_arguments([ '-utf-8', # Use UTF-8 mode '/Zc:externConstexpr', # Required for 'extern constexpr' on MSVC - '/Zc:preprocessor', # Required to consume the mozjs-115 headers on MSVC + '/Zc:preprocessor', # Required to consume the mozjs-128 headers on MSVC # Ignore spurious compiler warnings for things that GLib and SpiderMonkey # header files commonly do @@ -133,22 +137,11 @@ gio = dependency('gio-2.0', version: glib_required_version, ffi = dependency('libffi', fallback: ['libffi', 'ffi_dep']) gi = dependency('gobject-introspection-1.0', version: '>= 1.66.0', fallback: ['gobject-introspection', 'girepo_dep']) -spidermonkey = dependency('mozjs-115') - -# We might need to look for the headers and lib's for Cairo -# manually on MSVC/clang-cl builds... -cairo = dependency('cairo', required: get_option('cairo').enabled() and cxx.get_argument_syntax() != 'msvc') -cairo_gobject = dependency('cairo-gobject', required: cairo.found() and cxx.get_argument_syntax() != 'msvc') +cairo = dependency('cairo', fallback: ['cairo', 'libcairo_dep']) +cairo_gobject = dependency('cairo-gobject', + fallback: ['cairo', 'libcairogobject_dep']) cairo_xlib = dependency('cairo-xlib', required: false) - -if cxx.get_argument_syntax() == 'msvc' - if not cairo.found() - cairo = cc.find_library('cairo', has_headers: ['cairo.h'], required: get_option('cairo').enabled()) - endif - if not cairo_gobject.found() - cairo_gobject = cc.find_library('cairo-gobject', has_headers: ['cairo-gobject.h'], required: cairo.found()) - endif -endif +spidermonkey = dependency('mozjs-128') sysprof_capture = dependency('sysprof-capture-4', required: get_option('profiler'), include_type: 'system', @@ -206,7 +199,7 @@ else libatomic = cc.find_library('atomic', required: false) endif -build_profiler = sysprof_capture.found() and not get_option('profiler').disabled() +build_profiler = sysprof_capture.found() profiler_deps = [sysprof_capture] if build_profiler and not cxx.has_function('timer_settime') extra_timer_libs = ['rt', 'posix4'] @@ -230,8 +223,7 @@ it on other platforms.''') endif endif -build_cairo = cairo.found() and not get_option('cairo').disabled() -build_readline = readline.found() and not get_option('readline').disabled() +build_readline = readline.found() ### Check for library features ################################################# @@ -323,8 +315,6 @@ header_conf.set('GJS_VERSION', int_version, header_conf.set_quoted('PACKAGE_STRING', '@0@ @1@'.format(meson.project_name(), meson.project_version())) -header_conf.set('ENABLE_CAIRO', build_cairo, - description: 'Build with Cairo support') header_conf.set('ENABLE_PROFILER', build_profiler, description: 'Build the profiler') # COMPAT: SpiderMonkey headers in some places use DEBUG instead of JS_DEBUG @@ -335,9 +325,6 @@ header_conf.set('HAVE_DTRACE', get_option('dtrace'), description: 'Using dtrace probes') header_conf.set('HAVE_PRINTF_ALTERNATIVE_INT', have_printf_alternative_int, description: 'printf() accepts "%Id" for alternative integer output') -header_conf.set('HAVE_OPEN_MEMSTREAM', - cxx.has_function('open_memstream', prefix : '#include '), - description: 'open_memstream() is available') if build_readline header_conf.set('HAVE_READLINE_READLINE_H', cxx.check_header('readline/readline.h', prefix: '#include ', @@ -354,12 +341,6 @@ header_conf.set('_GNU_SOURCE', 1) configure_file(output: 'config.h', configuration: header_conf) -### Check for environment ###################################################### - -gjsjsdir = get_option('datadir') / api_name -abs_datadir = get_option('prefix') / get_option('datadir') -pkglibdir = get_option('libdir') / meson.project_name() - ### Build dtrace probes ######################################################## if get_option('dtrace') @@ -367,31 +348,28 @@ if get_option('dtrace') arguments: ['-C', '-h', '-s', '@INPUT@', '-o', '@OUTPUT@']) probes_objfile_gen = generator(dtrace, output: '@BASENAME@.o', arguments: ['-G', '-s', '@INPUT@', '-o', '@OUTPUT@']) - probes_header = probes_header_gen.process('gi/gjs_gi_probes.d') - probes_objfile = probes_objfile_gen.process('gi/gjs_gi_probes.d') + probes_header = probes_header_gen.process('gi/cjs_gi_probes.d') + probes_objfile = probes_objfile_gen.process('gi/cjs_gi_probes.d') else probes_header = [] probes_objfile = [] endif -tapset_subst = configuration_data({ - 'EXPANDED_LIBDIR': get_option('libdir'), -}) -tapset = configure_file(input: 'cjs/gjs.stp.in', output: 'gjs.stp', +tapset_subst = configuration_data({'EXPANDED_LIBDIR': libdir}) +tapset = configure_file(input: 'cjs/cjs.stp.in', output: 'cjs.stp', configuration: tapset_subst) if get_option('systemtap') - install_data(tapset, - install_dir: get_option('datadir') / 'systemtap/tapset') + install_data(tapset, install_dir: datadir / 'systemtap' / 'tapset') endif ### Build library ############################################################## directory_defines = [ - '-DGJS_JS_DIR="@0@"'.format(get_option('prefix') / gjsjsdir), - '-DPKGLIBDIR="@0@"'.format(get_option('prefix') / pkglibdir), + '-DGJS_JS_DIR="@0@"'.format(prefix / cjsjsdir), + '-DPKGLIBDIR="@0@"'.format(prefix / pkglibdir), ] -gjs_public_headers = [ +cjs_public_headers = [ 'cjs/context.h', 'cjs/coverage.h', 'cjs/error-types.h', @@ -404,7 +382,7 @@ gjs_public_headers = [ # For historical reasons, some files live in gi/ # Some headers in the following list were formerly public -libgjs_sources = [ +libcjs_sources = [ 'gi/arg.cpp', 'gi/arg.h', 'gi/arg-inl.h', 'gi/arg-cache.cpp', 'gi/arg-cache.h', 'gi/boxed.cpp', 'gi/boxed.h', @@ -415,7 +393,7 @@ libgjs_sources = [ 'gi/fundamental.cpp', 'gi/fundamental.h', 'gi/function.cpp', 'gi/function.h', 'gi/gerror.cpp', 'gi/gerror.h', - 'gi/gjs_gi_trace.h', + 'gi/cjs_gi_trace.h', 'gi/gobject.cpp', 'gi/gobject.h', 'gi/gtype.cpp', 'gi/gtype.h', 'gi/interface.cpp', 'gi/interface.h', @@ -450,31 +428,8 @@ libgjs_sources = [ 'cjs/promise.cpp', 'cjs/promise.h', 'cjs/stack.cpp', 'modules/console.cpp', 'modules/console.h', - 'modules/modules.cpp', 'modules/modules.h', 'modules/print.cpp', 'modules/print.h', 'modules/system.cpp', 'modules/system.h', -] - -# CjsPrivate introspection sources -libgjs_private_sources = [ - 'libgjs-private/gjs-gdbus-wrapper.c', 'libgjs-private/gjs-gdbus-wrapper.h', - 'libgjs-private/gjs-util.c', 'libgjs-private/gjs-util.h', -] - -libgjs_jsapi_sources = [ - 'cjs/jsapi-class.h', - 'cjs/jsapi-dynamic-class.cpp', - 'cjs/jsapi-util-args.h', - 'cjs/jsapi-util-error.cpp', - 'cjs/jsapi-util-root.h', - 'cjs/jsapi-util-string.cpp', - 'cjs/jsapi-util.cpp', 'cjs/jsapi-util.h', - 'util/console.cpp', 'util/console.h', - 'util/log.cpp', 'util/log.h', - 'util/misc.cpp', 'util/misc.h', -] - -module_cairo_srcs = [ 'modules/cairo-private.h', 'modules/cairo-module.h', 'modules/cairo-region.cpp', @@ -494,54 +449,62 @@ module_cairo_srcs = [ 'modules/cairo.cpp', ] +# CjsPrivate introspection sources +libcjs_private_sources = [ + 'libgjs-private/gjs-gdbus-wrapper.c', 'libgjs-private/gjs-gdbus-wrapper.h', + 'libgjs-private/gjs-match-info.c', 'libgjs-private/gjs-match-info.h', + 'libgjs-private/gjs-util.c', 'libgjs-private/gjs-util.h', +] + +libcjs_jsapi_sources = [ + 'cjs/jsapi-class.h', + 'cjs/jsapi-dynamic-class.cpp', + 'cjs/jsapi-util-args.h', + 'cjs/jsapi-util-error.cpp', + 'cjs/jsapi-util-root.h', + 'cjs/jsapi-util-string.cpp', + 'cjs/jsapi-util.cpp', 'cjs/jsapi-util.h', + 'util/console.cpp', 'util/console.h', + 'util/log.cpp', 'util/log.h', + 'util/misc.cpp', 'util/misc.h', +] + module_resource_srcs = gnome.compile_resources('js-resources', 'js.gresource.xml', c_name: 'js_resources') +module_resource_lib = static_library('js-resources', module_resource_srcs, + dependencies: gio, override_options: ['unity=off']) -libgjs_dependencies = [glib, gobject, gthread, gio, gi, ffi, spidermonkey, - readline, libatomic] -pkg_dependencies = [glib, gobject, gthread, gio, gi, ffi, spidermonkey] -libraries_private = [] - -if build_cairo - libgjs_sources += module_cairo_srcs - libgjs_dependencies += [cairo, cairo_gobject] - if cairo.type_name() == 'pkgconfig' - pkg_dependencies += [cairo] - elif cairo.type_name() == 'library' - libraries_private += cairo - endif - if cairo_gobject.type_name() == 'pkgconfig' - pkg_dependencies += [cairo_gobject] - elif cairo_gobject.type_name() == 'library' - libraries_private += cairo_gobject - endif - if cairo_xlib.found() - libgjs_dependencies += cairo_xlib - pkg_dependencies += cairo_xlib - endif +libcjs_dependencies = [glib, gobject, gthread, gio, gi, ffi, cairo, + cairo_gobject, spidermonkey, readline, libatomic] +pkg_dependencies = [glib, gobject, gthread, gio, gi, ffi, cairo, cairo_gobject, + spidermonkey] + +if cairo_xlib.found() + libcjs_dependencies += cairo_xlib + pkg_dependencies += cairo_xlib endif if build_readline - libgjs_dependencies += readline_deps + libcjs_dependencies += readline_deps endif -libgjs_cpp_args = ['-DGJS_COMPILATION'] + directory_defines +libcjs_cpp_args = ['-DGJS_COMPILATION'] + directory_defines # Check G-I and/or Meson on this one. -libgjs_cpp_args += ['-DG_LOG_DOMAIN="Gjs"'] +libcjs_cpp_args += ['-DG_LOG_DOMAIN="Cjs"'] if host_machine.system() == 'windows' # We need these defines to build properly for all Windows builds - libgjs_cpp_args += ['-DWIN32', '-DXP_WIN', '-DWIN32_LEAN_AND_MEAN'] + libcjs_cpp_args += ['-DWIN32', '-DXP_WIN', '-DWIN32_LEAN_AND_MEAN'] endif -# This dependency should provide everything that is needed to compile gjs except -# the sources themselves, is used to copmile both the static libraries and the +# This dependency should provide everything that is needed to compile cjs except +# the sources themselves, is used to compile both the static libraries and the # tests base_build_dep = declare_dependency( - compile_args: libgjs_cpp_args, - dependencies: libgjs_dependencies) + compile_args: libcjs_cpp_args, + dependencies: libcjs_dependencies) internal_build_dep = declare_dependency( compile_args: (release_build ? ['-DG_DISABLE_ASSERT'] : []), @@ -550,96 +513,92 @@ internal_build_dep = declare_dependency( build_profiler ? profiler_deps : [], ]) -libgjs_jsapi = static_library(meson.project_name() + '-jsapi', - libgjs_jsapi_sources, probes_header, probes_objfile, - cpp_pch: 'cjs/gjs_pch.hh', +libcjs_jsapi = static_library(meson.project_name() + '-jsapi', + libcjs_jsapi_sources, probes_header, probes_objfile, + cpp_pch: 'cjs/cjs_pch.hh', dependencies: internal_build_dep, install: false) # We need to create an internal static library to be able to link with the tests # that may use internal APIs. This is also used to generate the actual shared # library so that we compile its sources just once. -libgjs_internal = static_library('gjs-internal', - libgjs_sources, probes_header, probes_objfile, - cpp_pch: 'cjs/gjs_pch.hh', +libcjs_internal = static_library('cjs-internal', + libcjs_sources, probes_header, probes_objfile, + cpp_pch: 'cjs/cjs_pch.hh', dependencies: internal_build_dep, - link_with: libgjs_jsapi) + link_with: libcjs_jsapi) link_args = [] -symbol_map = files('libgjs.map') -symbol_list = files('libgjs.symbols') +symbol_map = 'libcjs.map' +symbol_list = 'libcjs.symbols' link_args += cxx.get_supported_link_arguments([ '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), - symbol_map[0]), + symbol_map), '-Wl,-exported_symbols_list,@0@/@1@'.format(meson.current_source_dir(), - symbol_list[0]), # macOS linker + symbol_list), # macOS linker ]) -libgjs = shared_library(meson.project_name(), - sources: [ libgjs_private_sources, module_resource_srcs ], +libcjs = shared_library(meson.project_name(), + sources: libcjs_private_sources, link_args: link_args, link_depends: [symbol_map, symbol_list], - link_whole: libgjs_internal, + link_whole: [libcjs_internal, module_resource_lib], dependencies: base_build_dep, version: '0.0.0', soversion: '0', gnu_symbol_visibility: 'hidden', install: true) -install_headers(gjs_public_headers, subdir: api_name / 'cjs') +install_headers(cjs_public_headers, subdir: api_name / 'cjs') -# Allow using libgjs as a subproject -libgjs_dep = declare_dependency(link_with: [libgjs, libgjs_jsapi], +# Allow using libcjs as a subproject +libcjs_dep = declare_dependency(link_with: [libcjs, libcjs_jsapi], dependencies: base_build_dep, include_directories: top_include) ### Build CjsPrivate introspection library ##################################### -gjs_private_gir = gnome.generate_gir(libgjs, - includes: ['GObject-2.0', 'Gio-2.0'], sources: libgjs_private_sources, +cjs_private_gir = gnome.generate_gir(libcjs, + includes: ['GObject-2.0', 'Gio-2.0'], sources: libcjs_private_sources, namespace: 'CjsPrivate', nsversion: '1.0', identifier_prefix: 'Gjs', symbol_prefix: 'gjs_', fatal_warnings: get_option('werror'), install: true, - install_dir_gir: false, install_dir_typelib: pkglibdir / 'girepository-1.0') -gjs_private_typelib = gjs_private_gir[1] + install_gir: false, install_dir_typelib: pkglibdir / 'girepository-1.0') +cjs_private_typelib = cjs_private_gir[1] ### Build cjs-console interpreter ############################################## -gjs_console_srcs = ['cjs/console.cpp'] +cjs_console_srcs = ['cjs/console.cpp'] -gjs_console = executable('cjs-console', gjs_console_srcs, - dependencies: libgjs_dep, install: true) +cjs_console = executable('cjs-console', cjs_console_srcs, + dependencies: libcjs_dep, install: true) -meson.add_install_script('build/symlink-gjs.py', get_option('bindir')) +meson.add_install_script('build/symlink-cjs.py', bindir) ### Install data files ######################################################### -install_data('installed-tests/extra/gjs.supp', - install_dir: get_option('datadir') / api_name / 'valgrind') -install_data('installed-tests/extra/lsan.supp', - install_dir: get_option('datadir') / api_name / 'lsan') +install_data('installed-tests/extra/gjs.supp', install_dir: cjsjsdir / 'valgrind') +install_data('installed-tests/extra/lsan.supp', install_dir: cjsjsdir / 'lsan') if get_option('installed_tests') - schemadir = abs_datadir / 'glib-2.0' / 'schemas' + schemadir = datadir / 'glib-2.0' / 'schemas' install_data('installed-tests/js/org.cinnamon.CjsTest.gschema.xml', install_dir: schemadir) - meson.add_install_script('build/compile-gschemas.py', schemadir) + meson.add_install_script(glib_compile_schemas, prefix / schemadir, skip_if_destdir: true) endif ### Generate pkg-config file ################################################### -pkg.generate(libgjs, name: api_name, description: 'JS bindings for GObjects', +pkg.generate(libcjs, name: api_name, description: 'JS bindings for GObjects', requires: [glib, gobject, gio], requires_private: pkg_dependencies, - libraries_private: libraries_private, subdirs: api_name, variables: [ 'exec_prefix=${prefix}', - 'bindir=${exec_prefix}' / get_option('bindir'), - 'datarootdir=${prefix}' / get_option('datadir'), - 'datadir=${datarootdir}', - 'gjs_console=${bindir}/cjs-console', + 'datarootdir=${datadir}', + 'cjs_console=${bindir}/cjs-console', ]) ### Test environment ########################################################### tests_environment = environment() +gi_tests_builddir = meson.project_build_root() / 'subprojects' / 'gobject-introspection-tests' js_tests_builddir = meson.current_build_dir() / 'installed-tests' / 'js' -libgjs_test_tools_builddir = js_tests_builddir / 'libgjstesttools' +libcjs_test_tools_builddir = js_tests_builddir / 'libgjstesttools' # GJS_PATH is empty here since we want to force the use of our own # resources. G_FILENAME_ENCODING ensures filenames are not UTF-8 tests_environment.set('TOP_BUILDDIR', meson.project_build_root()) @@ -647,11 +606,11 @@ tests_environment.set('GJS_USE_UNINSTALLED_FILES', '1') tests_environment.set('GJS_PATH', '') tests_environment.set('GJS_DEBUG_OUTPUT', 'stderr') tests_environment.prepend('GI_TYPELIB_PATH', meson.current_build_dir(), - js_tests_builddir, libgjs_test_tools_builddir) + gi_tests_builddir, js_tests_builddir, libcjs_test_tools_builddir) tests_environment.prepend('LD_LIBRARY_PATH', meson.current_build_dir(), - js_tests_builddir, libgjs_test_tools_builddir) -tests_environment.prepend('DYLD_FALLBACK_LIBRARY_PATH', meson.current_build_dir(), - js_tests_builddir, libgjs_test_tools_builddir) + gi_tests_builddir, js_tests_builddir, libcjs_test_tools_builddir) +tests_environment.prepend('DYLD_LIBRARY_PATH', meson.current_build_dir(), + gi_tests_builddir, js_tests_builddir, libcjs_test_tools_builddir) tests_environment.set('G_FILENAME_ENCODING', 'latin1') # Workaround for https://github.com/google/sanitizers/issues/1322 tests_environment.set('ASAN_OPTIONS', 'intercept_tls_get_addr=0') @@ -683,11 +642,16 @@ endif if get_option('b_coverage') tests_environment.set('GJS_UNIT_COVERAGE_OUTPUT', 'lcov') tests_environment.set('GJS_UNIT_COVERAGE_PREFIX', - 'resource:///org/gnome/gjs') + 'resource:///org/cinnamon/cjs') endif ### Tests and test setups ###################################################### +# External code should not error out even when building with -Werror +gi_tests = subproject('gobject-introspection-tests', + default_options: ['werror=false', 'cairo=true', + 'install_dir=@0@'.format(installed_tests_execdir)]) + subdir('installed-tests') # Note: The test program in test/ needs to be ported @@ -705,11 +669,11 @@ valgrind_environment.set('VALGRIND', 'valgrind') glib_prefix = glib.get_variable(pkgconfig: 'prefix', default_value: '/usr') glib_suppresssions = (glib_prefix / 'share' / 'glib-2.0' / 'valgrind' / 'glib.supp') -gjs_suppressions = (meson.current_source_dir() / 'installed-tests' / 'extra' / +cjs_suppressions = (meson.current_source_dir() / 'installed-tests' / 'extra' / 'cjs.supp') valgrind_args = [ '--suppressions=@0@'.format(glib_suppresssions), - '--suppressions=@0@'.format(gjs_suppressions), + '--suppressions=@0@'.format(cjs_suppressions), '--leak-check=full', '--num-callers=15', '--trace-children=yes', @@ -737,12 +701,6 @@ add_test_setup('post_verify', timeout_multiplier: 2, env: zeal11_environment) ### Warn about conditions that may affect runtime ############################## -if gi.version().version_compare('<1.71.0') - warning('''You do not have a new enough version of -gobject-introspection to run the tests. You can still build GJS, but some -tests will fail.''') -endif - if tests_locale == 'C' or tests_locale == 'N/A' warning('''Your libc does not have the C.UTF-8 locale and no other suitable UTF-8 fallback locale could be found. You can still build GJS, but @@ -755,10 +713,6 @@ building a debug or debugoptimized build. This will make development more difficult. Consider reconfiguring SpiderMonkey with --enable-debug.''') endif -if not build_cairo - warning('Building without Cairo support, not all tests will be run.') -endif - if get_option('skip_gtk_tests') warning('Not using GTK, not all tests will be run.') endif @@ -769,15 +723,12 @@ endif ### Summarize options ########################################################## -prefix = get_option('prefix') -bindir = get_option('bindir') -libdir = get_option('libdir') -datadir = get_option('datadir') summary({ 'prefix': prefix, 'bindir': prefix / bindir, 'libdir': prefix / libdir, 'datadir': prefix / datadir, + 'libexecdir': prefix / libexecdir, }, section: 'Directories') locations = [] foreach dep: [ffi, glib, gi, spidermonkey, readline, sysprof_capture] @@ -812,13 +763,16 @@ summary({ 'Precompiled headers': get_option('b_pch'), }, section: 'Build options', bool_yn: true) summary({ - 'Cairo module': build_cairo, 'Use readline for input': build_readline, 'Profiler (Linux only)': build_profiler, 'Dtrace debugging': get_option('dtrace'), 'Systemtap debugging': get_option('systemtap'), }, section: 'Optional features', bool_yn: true) +### Development environment #################################################### + +meson.add_devenv({'GJS_USE_UNINSTALLED_FILES': '1'}) + ### Maintainer scripts ######################################################### run_target('maintainer-upload-release', diff --git a/meson_options.txt b/meson_options.txt index c6404278c..fe425efd2 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -3,8 +3,6 @@ # Features -option('cairo', type: 'feature', value: 'auto', - description: 'Build cairo module') option('readline', type: 'feature', value: 'auto', description: 'Use readline for input in interactive shell and debugger') option('profiler', type: 'feature', value: 'auto', @@ -12,7 +10,7 @@ option('profiler', type: 'feature', value: 'auto', # Flags -option('installed_tests', type: 'boolean', value: false, +option('installed_tests', type: 'boolean', value: true, description: 'Install test programs') option('dtrace', type: 'boolean', value: false, description: 'Include dtrace trace support') diff --git a/modules/cairo-context.cpp b/modules/cairo-context.cpp index 84b32387c..05a031819 100644 --- a/modules/cairo-context.cpp +++ b/modules/cairo-context.cpp @@ -90,10 +90,11 @@ _GJS_CAIRO_CONTEXT_DEFINE_FUNC_END JS::RootedObject array(context, JS::NewArrayObject(context, 2)); \ if (!array) \ return false; \ - JS::RootedValue r(context, JS::NumberValue(arg1)); \ + JS::RootedValue r{context, \ + JS::NumberValue(JS::CanonicalizeNaN(arg1))}; \ if (!JS_SetElement(context, array, 0, r)) \ return false; \ - r.setNumber(arg2); \ + r.setNumber(JS::CanonicalizeNaN(arg2)); \ if (!JS_SetElement(context, array, 1, r)) \ return false; \ argv.rval().setObject(*array); \ @@ -109,10 +110,11 @@ _GJS_CAIRO_CONTEXT_DEFINE_FUNC_END JS::RootedObject array(context, JS::NewArrayObject(context, 2)); \ if (!array) \ return false; \ - JS::RootedValue r(context, JS::NumberValue(arg1)); \ + JS::RootedValue r{context, \ + JS::NumberValue(JS::CanonicalizeNaN(arg1))}; \ if (!JS_SetElement(context, array, 0, r)) \ return false; \ - r.setNumber(arg2); \ + r.setNumber(JS::CanonicalizeNaN(arg2)); \ if (!JS_SetElement(context, array, 1, r)) \ return false; \ argv.rval().setObject(*array); \ @@ -128,16 +130,17 @@ _GJS_CAIRO_CONTEXT_DEFINE_FUNC_END JS::RootedObject array(context, JS::NewArrayObject(context, 4)); \ if (!array) \ return false; \ - JS::RootedValue r(context, JS::NumberValue(arg1)); \ + JS::RootedValue r{context, \ + JS::NumberValue(JS::CanonicalizeNaN(arg1))}; \ if (!JS_SetElement(context, array, 0, r)) \ return false; \ - r.setNumber(arg2); \ + r.setNumber(JS::CanonicalizeNaN(arg2)); \ if (!JS_SetElement(context, array, 1, r)) \ return false; \ - r.setNumber(arg3); \ + r.setNumber(JS::CanonicalizeNaN(arg3)); \ if (!JS_SetElement(context, array, 2, r)) \ return false; \ - r.setNumber(arg4); \ + r.setNumber(JS::CanonicalizeNaN(arg4)); \ if (!JS_SetElement(context, array, 3, r)) \ return false; \ argv.rval().setObject(*array); \ @@ -149,7 +152,7 @@ _GJS_CAIRO_CONTEXT_DEFINE_FUNC_BEGIN(method) \ double ret; \ _GJS_CAIRO_CONTEXT_CHECK_NO_ARGS(method) \ ret = cfunc(cr); \ - argv.rval().setNumber(ret); \ + argv.rval().setNumber(JS::CanonicalizeNaN(ret)); \ _GJS_CAIRO_CONTEXT_DEFINE_FUNC_END #define _GJS_CAIRO_CONTEXT_DEFINE_FUNC1(method, cfunc, fmt, t1, n1) \ @@ -919,7 +922,7 @@ const JSFunctionSpec CairoContext::proto_funcs[] = { JS_FS_END}; // clang-format on -[[nodiscard]] static bool context_to_g_argument( +[[nodiscard]] static bool context_to_gi_argument( JSContext* context, JS::Value value, const char* arg_name, GjsArgumentType argument_type, GITransfer transfer, GjsArgumentFlags flags, GIArgument* arg) { @@ -947,11 +950,9 @@ const JSFunctionSpec CairoContext::proto_funcs[] = { } GJS_JSAPI_RETURN_CONVENTION -static bool -context_from_g_argument(JSContext *context, - JS::MutableHandleValue value_p, - GIArgument *arg) -{ +static bool context_from_gi_argument(JSContext* context, + JS::MutableHandleValue value_p, + GIArgument* arg) { JSObject* obj = CairoContext::from_c_ptr( context, static_cast(arg->v_pointer)); if (!obj) { @@ -971,8 +972,8 @@ static bool context_release_argument(JSContext*, GITransfer transfer, } void gjs_cairo_context_init(void) { - static GjsForeignInfo foreign_info = {context_to_g_argument, - context_from_g_argument, + static GjsForeignInfo foreign_info = {context_to_gi_argument, + context_from_gi_argument, context_release_argument}; gjs_struct_foreign_register("cairo", "Context", &foreign_info); diff --git a/modules/cairo-pdf-surface.cpp b/modules/cairo-pdf-surface.cpp index 4ec22b69f..b0070d0b9 100644 --- a/modules/cairo-pdf-surface.cpp +++ b/modules/cairo-pdf-surface.cpp @@ -8,19 +8,23 @@ #include // for CAIRO_HAS_PDF_SURFACE #include -#include - -#include "cjs/jsapi-util.h" - #if CAIRO_HAS_PDF_SURFACE # include +#endif + +#include +#if CAIRO_HAS_PDF_SURFACE # include // for JSPROP_READONLY # include # include -# include // for JS_NewObjectWithGivenProto +# include // for JS_NewObjectWithGivenProto # include // for JSProtoKey +#endif +#include "cjs/jsapi-util.h" + +#if CAIRO_HAS_PDF_SURFACE # include "cjs/jsapi-util-args.h" # include "modules/cairo-private.h" diff --git a/modules/cairo-ps-surface.cpp b/modules/cairo-ps-surface.cpp index 56d45908f..a1f396b3f 100644 --- a/modules/cairo-ps-surface.cpp +++ b/modules/cairo-ps-surface.cpp @@ -8,19 +8,23 @@ #include // for CAIRO_HAS_PS_SURFACE #include -#include - -#include "cjs/jsapi-util.h" - #if CAIRO_HAS_PS_SURFACE # include +#endif + +#include +#if CAIRO_HAS_PS_SURFACE # include // for JSPROP_READONLY # include # include -# include // for JS_NewObjectWithGivenProto +# include // for JS_NewObjectWithGivenProto # include // for JSProtoKey +#endif +#include "cjs/jsapi-util.h" + +#if CAIRO_HAS_PS_SURFACE # include "cjs/jsapi-util-args.h" # include "modules/cairo-private.h" diff --git a/modules/cairo-region.cpp b/modules/cairo-region.cpp index 98cbe104b..570887985 100644 --- a/modules/cairo-region.cpp +++ b/modules/cairo-region.cpp @@ -227,7 +227,7 @@ void CairoRegion::finalize_impl(JS::GCContext*, cairo_region_t* region) { cairo_region_destroy(region); } -[[nodiscard]] static bool region_to_g_argument( +[[nodiscard]] static bool region_to_gi_argument( JSContext* context, JS::Value value, const char* arg_name, GjsArgumentType argument_type, GITransfer transfer, GjsArgumentFlags flags, GIArgument* arg) { @@ -256,11 +256,9 @@ void CairoRegion::finalize_impl(JS::GCContext*, cairo_region_t* region) { } GJS_JSAPI_RETURN_CONVENTION -static bool -region_from_g_argument(JSContext *context, - JS::MutableHandleValue value_p, - GIArgument *arg) -{ +static bool region_from_gi_argument(JSContext* context, + JS::MutableHandleValue value_p, + GIArgument* arg) { JSObject* obj = CairoRegion::from_c_ptr(context, gjs_arg_get(arg)); if (!obj) @@ -279,8 +277,9 @@ static bool region_release_argument(JSContext*, GITransfer transfer, void gjs_cairo_region_init(void) { - static GjsForeignInfo foreign_info = { - region_to_g_argument, region_from_g_argument, region_release_argument}; + static GjsForeignInfo foreign_info = {region_to_gi_argument, + region_from_gi_argument, + region_release_argument}; gjs_struct_foreign_register("cairo", "Region", &foreign_info); } diff --git a/modules/cairo-surface.cpp b/modules/cairo-surface.cpp index d6ad15a72..5369d3b5d 100644 --- a/modules/cairo-surface.cpp +++ b/modules/cairo-surface.cpp @@ -173,8 +173,8 @@ static bool getDeviceOffset_func(JSContext* cx, unsigned argc, JS::Value* vp) { // cannot error JS::RootedValueArray<2> elements(cx); - elements[0].setNumber(x_offset); - elements[1].setNumber(y_offset); + elements[0].setNumber(JS::CanonicalizeNaN(x_offset)); + elements[1].setNumber(JS::CanonicalizeNaN(y_offset)); JS::RootedObject retval(cx, JS::NewArrayObject(cx, elements)); if (!retval) return false; @@ -223,8 +223,8 @@ static bool getDeviceScale_func(JSContext* cx, unsigned argc, JS::Value* vp) { // cannot error JS::RootedValueArray<2> elements(cx); - elements[0].setNumber(x_scale); - elements[1].setNumber(y_scale); + elements[0].setNumber(JS::CanonicalizeNaN(x_scale)); + elements[1].setNumber(JS::CanonicalizeNaN(y_scale)); JS::RootedObject retval(cx, JS::NewArrayObject(cx, elements)); if (!retval) return false; @@ -324,7 +324,7 @@ cairo_surface_t* CairoSurface::for_js(JSContext* cx, surface_wrapper, CairoSurface::POINTER); } -[[nodiscard]] static bool surface_to_g_argument( +[[nodiscard]] static bool surface_to_gi_argument( JSContext* context, JS::Value value, const char* arg_name, GjsArgumentType argument_type, GITransfer transfer, GjsArgumentFlags flags, GIArgument* arg) { @@ -359,9 +359,9 @@ cairo_surface_t* CairoSurface::for_js(JSContext* cx, } GJS_JSAPI_RETURN_CONVENTION -static bool surface_from_g_argument(JSContext* cx, - JS::MutableHandleValue value_p, - GIArgument* arg) { +static bool surface_from_gi_argument(JSContext* cx, + JS::MutableHandleValue value_p, + GIArgument* arg) { JSObject* obj = CairoSurface::from_c_ptr(cx, gjs_arg_get(arg)); if (!obj) @@ -379,8 +379,8 @@ static bool surface_release_argument(JSContext*, GITransfer transfer, } void gjs_cairo_surface_init(void) { - static GjsForeignInfo foreign_info = {surface_to_g_argument, - surface_from_g_argument, + static GjsForeignInfo foreign_info = {surface_to_gi_argument, + surface_from_gi_argument, surface_release_argument}; gjs_struct_foreign_register("cairo", "Surface", &foreign_info); } diff --git a/modules/cairo-svg-surface.cpp b/modules/cairo-svg-surface.cpp index 62385d461..d8ccedf56 100644 --- a/modules/cairo-svg-surface.cpp +++ b/modules/cairo-svg-surface.cpp @@ -8,19 +8,23 @@ #include // for CAIRO_HAS_SVG_SURFACE #include -#include - -#include "cjs/jsapi-util.h" - #if CAIRO_HAS_SVG_SURFACE # include +#endif + +#include +#if CAIRO_HAS_SVG_SURFACE # include // for JSPROP_READONLY # include # include -# include // for JS_NewObjectWithGivenProto +# include // for JS_NewObjectWithGivenProto # include // for JSProtoKey +#endif +#include "cjs/jsapi-util.h" + +#if CAIRO_HAS_SVG_SURFACE # include "cjs/jsapi-util-args.h" # include "modules/cairo-private.h" diff --git a/modules/cairo.cpp b/modules/cairo.cpp index 82fe4d9e1..482d141fc 100644 --- a/modules/cairo.cpp +++ b/modules/cairo.cpp @@ -7,6 +7,13 @@ #include // for CAIRO_HAS_PDF_SURFACE, CAIRO_HAS_PS_SURFA... #include +#ifdef CAIRO_HAS_XLIB_SURFACE +# include +# undef None +// X11 defines a global None macro. Rude! This conflicts with None used as an +// enum member in SpiderMonkey headers, e.g. JS::ExceptionStatus::None. +#endif + #include #include #include // for JS_NewPlainObject @@ -15,8 +22,6 @@ #include "modules/cairo-private.h" #ifdef CAIRO_HAS_XLIB_SURFACE -# include - class XLibConstructor { public: XLibConstructor() { diff --git a/modules/console.cpp b/modules/console.cpp index f13a2b87f..860254c3c 100644 --- a/modules/console.cpp +++ b/modules/console.cpp @@ -87,12 +87,18 @@ class AutoReportException { JS::PrintError(stderr, report, /* reportWarnings = */ false); if (exnStack.stack()) { - GjsAutoChar stack_str = - gjs_format_stack_trace(m_cx, exnStack.stack()); - if (!stack_str) + JS::UniqueChars stack_str{ + format_saved_frame(m_cx, exnStack.stack(), 2)}; + if (!stack_str) { g_printerr("(Unable to print stack trace)\n"); - else - g_printerr("%s", stack_str.get()); + } else { + GjsAutoChar encoded_stack_str{g_filename_from_utf8( + stack_str.get(), -1, nullptr, nullptr, nullptr)}; + if (!encoded_stack_str) + g_printerr("(Unable to print stack trace)\n"); + else + g_printerr("%s", stack_str.get()); + } } JS_ClearPendingException(m_cx); @@ -194,9 +200,6 @@ std::string print_string_value(JSContext* cx, JS::HandleValue v_string) { GjsContextPrivate* gjs = GjsContextPrivate::from_cx(cx); gjs->schedule_gc_if_needed(); - if (result.isUndefined()) - return true; - JS::AutoSaveExceptionState exc_state(cx); JS::RootedValue v_printed_string(cx); JS::RootedValue v_pretty_print( diff --git a/modules/core/_common.js b/modules/core/_common.js index 1a7fe7724..1078e4aad 100644 --- a/modules/core/_common.js +++ b/modules/core/_common.js @@ -3,7 +3,8 @@ // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later // SPDX-FileCopyrightText: 2020 Philip Chimento -/* exported _checkAccessors, _registerType */ +/* exported _checkAccessors, _createBuilderConnectFunc, _createClosure, +_registerType */ // This is a helper module in which to put code that is common between the // legacy GObject.Class system and the new GObject.registerClass system. @@ -92,3 +93,32 @@ function _checkAccessors(proto, pspec, GObject) { Object.defineProperty(proto, camelName, propdesc); } } + +function _createClosure(builder, thisArg, handlerName, swapped, connectObject) { + connectObject ??= thisArg; + + if (swapped) { + throw new Error('Unsupported template signal flag "swapped"'); + } else if (typeof thisArg[handlerName] === 'undefined') { + throw new Error(`A handler called ${handlerName} was not ` + + `defined on ${thisArg}`); + } + + return thisArg[handlerName].bind(connectObject); +} + +function _createBuilderConnectFunc(klass) { + const {GObject} = imports.gi; + return function (builder, obj, signalName, handlerName, connectObj, flags) { + const objects = builder.get_objects(); + const thisObj = objects.find(o => o instanceof klass); + const swapped = flags & GObject.ConnectFlags.SWAPPED; + const closure = _createClosure(builder, thisObj, handlerName, swapped, + connectObj); + + if (flags & GObject.ConnectFlags.AFTER) + obj.connect_after(signalName, closure); + else + obj.connect(signalName, closure); + }; +} diff --git a/modules/core/overrides/GLib.js b/modules/core/overrides/GLib.js index 774cdf1e3..90dba115a 100644 --- a/modules/core/overrides/GLib.js +++ b/modules/core/overrides/GLib.js @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later // SPDX-FileCopyrightText: 2011 Giovanni Campagna +// SPDX-FileCopyrightText: 2023 Philip Chimento -const ByteArray = imports._byteArrayNative; const {setMainLoopHook} = imports._promiseNative; let GLib; @@ -100,11 +100,8 @@ function _packVariant(signature, value) { } if (arrayType[0] === 'y') { // special case for array of bytes - if (typeof value === 'string') { - value = ByteArray.fromString(value); - if (value[value.length - 1] !== 0) - value = Uint8Array.of(...value, 0); - } + if (typeof value === 'string') + value = Uint8Array.of(...new TextEncoder().encode(value), 0); const bytes = new GLib.Bytes(value); return GLib.Variant.new_from_bytes(new GLib.VariantType('ay'), bytes, true); @@ -538,4 +535,67 @@ function _init() { this.Thread.prototype.unref = function () { throw new Error('\'GLib.Thread.unref()\' may not be called in GJS'); }; + + // Override GLib.MatchInfo with a type that keeps the UTF-8 encoded search + // string alive. + const oldMatchInfo = this.MatchInfo; + let matchInfoPatched = false; + function patchMatchInfo(GLibModule) { + if (matchInfoPatched) + return; + + const {MatchInfo} = imports.gi.CjsPrivate; + + const originalMatchInfoMethods = new Set(Object.keys(oldMatchInfo.prototype)); + const overriddenMatchInfoMethods = new Set(Object.keys(MatchInfo.prototype)); + const symmetricDifference = new Set(originalMatchInfoMethods); + for (const method of overriddenMatchInfoMethods) { + if (symmetricDifference.has(method)) + symmetricDifference.delete(method); + else + symmetricDifference.add(method); + } + if (symmetricDifference.size !== 0) + throw new Error(`Methods of GMatchInfo and GjsMatchInfo don't match: ${[...symmetricDifference]}`); + + GLibModule.MatchInfo = MatchInfo; + matchInfoPatched = true; + } + + // We can't monkeypatch GLib.MatchInfo directly at override time, because + // importing CjsPrivate requires GLib. So this monkeypatches GLib.MatchInfo + // with a Proxy that overwrites itself with the real CjsPrivate.MatchInfo + // as soon as you try to do anything with it. + const allProxyOperations = ['apply', 'construct', 'defineProperty', + 'deleteProperty', 'get', 'getOwnPropertyDescriptor', 'getPrototypeOf', + 'has', 'isExtensible', 'ownKeys', 'preventExtensions', 'set', + 'setPrototypeOf']; + function delegateToMatchInfo(op) { + return function (target, ...params) { + patchMatchInfo(GLib); + return Reflect[op](GLib.MatchInfo, ...params); + }; + } + this.MatchInfo = new Proxy(function () {}, + Object.fromEntries(allProxyOperations.map(op => [op, delegateToMatchInfo(op)]))); + + this.Regex.prototype.match = function (...args) { + patchMatchInfo(GLib); + return imports.gi.CjsPrivate.regex_match(this, ...args); + }; + + this.Regex.prototype.match_full = function (...args) { + patchMatchInfo(GLib); + return imports.gi.CjsPrivate.regex_match_full(this, ...args); + }; + + this.Regex.prototype.match_all = function (...args) { + patchMatchInfo(GLib); + return imports.gi.CjsPrivate.regex_match_all(this, ...args); + }; + + this.Regex.prototype.match_all_full = function (...args) { + patchMatchInfo(GLib); + return imports.gi.CjsPrivate.regex_match_all_full(this, ...args); + }; } diff --git a/modules/core/overrides/GObject.js b/modules/core/overrides/GObject.js index 47dbe419a..2cdb1aa11 100644 --- a/modules/core/overrides/GObject.js +++ b/modules/core/overrides/GObject.js @@ -161,7 +161,7 @@ function _getCallerBasename() { if (scriptDir === thisDir && scriptBasename === thisFile) continue; - if (scriptDir && scriptDir.startsWith('/org/gnome/gjs/')) + if (scriptDir && scriptDir.startsWith('/org/cinnamon/cjs/')) continue; let basename = scriptBasename; @@ -179,7 +179,7 @@ function _getCallerBasename() { function _createGTypeName(klass) { const sanitizeGType = s => s.replace(/[^a-z0-9+_-]/gi, '_'); - if (klass.hasOwnProperty(GTypeName)) { + if (Object.hasOwn(klass, GTypeName)) { let sanitized = sanitizeGType(klass[GTypeName]); if (sanitized !== klass[GTypeName]) { logError(new RangeError(`Provided GType name '${klass[GTypeName]}' ` + @@ -203,7 +203,7 @@ function _createGTypeName(klass) { function _propertiesAsArray(klass) { let propertiesArray = []; - if (klass.hasOwnProperty(properties)) { + if (Object.hasOwn(klass, properties)) { for (let prop in klass[properties]) propertiesArray.push(klass[properties][prop]); } @@ -218,7 +218,7 @@ function _copyInterfacePrototypeDescriptors(targetPrototype, sourceInterface) { // Ignore properties starting with __ (typeof key !== 'string' || !key.startsWith('__')) && // Don't override an implementation on the target - !targetPrototype.hasOwnProperty(key) && + !Object.hasOwn(targetPrototype, key) && descriptor && // Only copy if the descriptor has a getter, is a function, or is enumerable. (typeof descriptor.value === 'function' || descriptor.get || descriptor.enumerable)) @@ -273,8 +273,90 @@ function _checkInterface(iface, proto) { } } +function _registerGObjectType(klass) { + const gtypename = _createGTypeName(klass); + const gflags = Object.hasOwn(klass, GTypeFlags) ? klass[GTypeFlags] : 0; + const gobjectInterfaces = Object.hasOwn(klass, interfaces) ? klass[interfaces] : []; + const propertiesArray = _propertiesAsArray(klass); + const parent = Object.getPrototypeOf(klass); + const gobjectSignals = Object.hasOwn(klass, signals) ? klass[signals] : []; + + // Default to the GObject-specific prototype, fallback on the JS prototype + // for GI native classes. + const parentPrototype = parent.prototype[Gi.gobject_prototype_symbol] ?? parent.prototype; + + const [giPrototype, registeredType] = Gi.register_type_with_class(klass, + parentPrototype, gtypename, gflags, gobjectInterfaces, propertiesArray); + + _defineGType(klass, giPrototype, registeredType); + _createSignals(klass.$gtype, gobjectSignals); + + // Reverse the interface array to give the last required interface + // precedence over the first. + const requiredInterfaces = [...gobjectInterfaces].reverse(); + requiredInterfaces.forEach(iface => + _copyInterfacePrototypeDescriptors(klass, iface)); + requiredInterfaces.forEach(iface => + _copyInterfacePrototypeDescriptors(klass.prototype, iface.prototype)); + + Object.getOwnPropertyNames(klass.prototype) + .filter(name => name.startsWith('vfunc_') || name.startsWith('on_')) + .forEach(name => { + let descr = Object.getOwnPropertyDescriptor(klass.prototype, name); + if (typeof descr.value !== 'function') + return; + + let func = klass.prototype[name]; + + if (name.startsWith('vfunc_')) { + giPrototype[Gi.hook_up_vfunc_symbol](name.slice(6), func); + } else if (name.startsWith('on_')) { + let id = GObject.signal_lookup(name.slice(3).replace('_', '-'), + klass.$gtype); + if (id !== 0) { + GObject.signal_override_class_closure(id, klass.$gtype, function (...argArray) { + let emitter = argArray.shift(); + + return func.apply(emitter, argArray); + }); + } + } + }); + + gobjectInterfaces.forEach(iface => _checkInterface(iface, klass.prototype)); + + // Lang.Class parent classes don't support static inheritance + if (!('implements' in klass)) + klass.implements = GObject.Object.implements; +} + +function _interfaceInstanceOf(instance) { + if (instance && typeof instance === 'object' && + GObject.Interface.prototype.isPrototypeOf(this.prototype)) + return GObject.type_is_a(instance, this); + + return false; +} + +function _registerInterfaceType(klass) { + const gtypename = _createGTypeName(klass); + const gobjectInterfaces = Object.hasOwn(klass, requires) ? klass[requires] : []; + const props = _propertiesAsArray(klass); + const gobjectSignals = Object.hasOwn(klass, signals) ? klass[signals] : []; + + const [giPrototype, registeredType] = Gi.register_interface_with_class( + klass, gtypename, gobjectInterfaces, props); + + _defineGType(klass, giPrototype, registeredType); + _createSignals(klass.$gtype, gobjectSignals); + + Object.defineProperty(klass, Symbol.hasInstance, { + value: _interfaceInstanceOf, + }); +} + function _checkProperties(klass) { - if (!klass.hasOwnProperty(properties)) + if (!Object.hasOwn(klass, properties)) return; for (let pspec of Object.values(klass[properties])) @@ -512,9 +594,9 @@ function _init() { _checkProperties(klass); if (_registerType in klass) - klass[_registerType](); + klass[_registerType](klass); else - _resolveLegacyClassFunction(klass, _registerType).call(klass); + _resolveLegacyClassFunction(klass, _registerType)(klass); return klass; }; @@ -526,103 +608,15 @@ function _init() { return false; }; - function registerGObjectType() { - let klass = this; - - let gtypename = _createGTypeName(klass); - let gflags = klass.hasOwnProperty(GTypeFlags) ? klass[GTypeFlags] : 0; - let gobjectInterfaces = klass.hasOwnProperty(interfaces) ? klass[interfaces] : []; - let propertiesArray = _propertiesAsArray(klass); - let parent = Object.getPrototypeOf(klass); - let gobjectSignals = klass.hasOwnProperty(signals) ? klass[signals] : []; - - // Default to the GObject-specific prototype, fallback on the JS prototype for GI native classes. - const parentPrototype = parent.prototype[Gi.gobject_prototype_symbol] ?? parent.prototype; - - const [giPrototype, registeredType] = Gi.register_type_with_class( - klass, parentPrototype, gtypename, gflags, - gobjectInterfaces, propertiesArray); - - _defineGType(klass, giPrototype, registeredType); - _createSignals(klass.$gtype, gobjectSignals); - - // Reverse the interface array to give the last required interface precedence over the first. - const requiredInterfaces = [...gobjectInterfaces].reverse(); - requiredInterfaces.forEach(iface => - _copyInterfacePrototypeDescriptors(klass, iface)); - requiredInterfaces.forEach(iface => - _copyInterfacePrototypeDescriptors(klass.prototype, iface.prototype)); - - Object.getOwnPropertyNames(klass.prototype) - .filter(name => name.startsWith('vfunc_') || name.startsWith('on_')) - .forEach(name => { - let descr = Object.getOwnPropertyDescriptor(klass.prototype, name); - if (typeof descr.value !== 'function') - return; - - let func = klass.prototype[name]; - - if (name.startsWith('vfunc_')) { - giPrototype[Gi.hook_up_vfunc_symbol](name.slice(6), func); - } else if (name.startsWith('on_')) { - let id = GObject.signal_lookup(name.slice(3).replace('_', '-'), - klass.$gtype); - if (id !== 0) { - GObject.signal_override_class_closure(id, klass.$gtype, function (...argArray) { - let emitter = argArray.shift(); - - return func.apply(emitter, argArray); - }); - } - } - }); - - gobjectInterfaces.forEach(iface => - _checkInterface(iface, klass.prototype)); - - // Lang.Class parent classes don't support static inheritance - if (!('implements' in klass)) - klass.implements = GObject.Object.implements; - } - Object.defineProperty(GObject.Object, _registerType, { - value: registerGObjectType, + value: _registerGObjectType, writable: false, configurable: false, enumerable: false, }); - function interfaceInstanceOf(instance) { - if (instance && typeof instance === 'object' && - GObject.Interface.prototype.isPrototypeOf(this.prototype)) - return GObject.type_is_a(instance, this); - - return false; - } - - function registerInterfaceType() { - let klass = this; - - let gtypename = _createGTypeName(klass); - let gobjectInterfaces = klass.hasOwnProperty(requires) ? klass[requires] : []; - let props = _propertiesAsArray(klass); - let gobjectSignals = klass.hasOwnProperty(signals) ? klass[signals] : []; - - const [giPrototype, registeredType] = Gi.register_interface_with_class(klass, gtypename, gobjectInterfaces, - props); - - _defineGType(klass, giPrototype, registeredType); - _createSignals(klass.$gtype, gobjectSignals); - - Object.defineProperty(klass, Symbol.hasInstance, { - value: interfaceInstanceOf, - }); - - return klass; - } - Object.defineProperty(GObject.Interface, _registerType, { - value: registerInterfaceType, + value: _registerInterfaceType, writable: false, configurable: false, enumerable: false, @@ -630,9 +624,9 @@ function _init() { GObject.Interface._classInit = function (klass) { if (_registerType in klass) - klass[_registerType](); + klass[_registerType](klass); else - _resolveLegacyClassFunction(klass, _registerType).call(klass); + _resolveLegacyClassFunction(klass, _registerType)(klass); Object.getOwnPropertyNames(klass.prototype) .filter(key => key !== 'constructor') @@ -890,4 +884,21 @@ function _init() { throw new Error('GObject.signal_handlers_disconnect_by_data() is not \ introspectable. Use GObject.signal_handlers_disconnect_by_func() instead.'); }; + + function unsupportedDataMethod() { + throw new Error('Data access methods are unsupported. Use normal JS properties instead.'); + } + GObject.Object.prototype.get_data = unsupportedDataMethod; + GObject.Object.prototype.get_qdata = unsupportedDataMethod; + GObject.Object.prototype.set_data = unsupportedDataMethod; + GObject.Object.prototype.steal_data = unsupportedDataMethod; + GObject.Object.prototype.steal_qdata = unsupportedDataMethod; + + function unsupportedRefcountingMethod() { + throw new Error("Don't modify an object's reference count in JS."); + } + GObject.Object.prototype.force_floating = unsupportedRefcountingMethod; + GObject.Object.prototype.ref = unsupportedRefcountingMethod; + GObject.Object.prototype.ref_sink = unsupportedRefcountingMethod; + GObject.Object.prototype.unref = unsupportedRefcountingMethod; } diff --git a/modules/core/overrides/Gtk.js b/modules/core/overrides/Gtk.js index 9d5aff6d6..27b650bff 100644 --- a/modules/core/overrides/Gtk.js +++ b/modules/core/overrides/Gtk.js @@ -3,8 +3,9 @@ // SPDX-FileCopyrightText: 2013 Giovanni Campagna const Legacy = imports._legacy; -const {Gio, CjsPrivate, GObject} = imports.gi; -const {_registerType} = imports._common; +const {Gio, CjsPrivate, GLib, GObject} = imports.gi; +const {_createBuilderConnectFunc, _createClosure, _registerType} = imports._common; +const Gi = imports._gi; let Gtk; let BuilderScope; @@ -34,37 +35,20 @@ function _init() { } Gtk.Widget.prototype._init = function (params) { - let wrapper = this; - - if (wrapper.constructor[Gtk.template]) { - if (!BuilderScope) { - Gtk.Widget.set_connect_func.call(wrapper.constructor, - (builder, obj, signalName, handlerName, connectObj, flags) => { - const swapped = flags & GObject.ConnectFlags.SWAPPED; - const closure = _createClosure( - builder, wrapper, handlerName, swapped, connectObj); - - if (flags & GObject.ConnectFlags.AFTER) - obj.connect_after(signalName, closure); - else - obj.connect(signalName, closure); - }); - } - } - - wrapper = GObject.Object.prototype._init.call(wrapper, params) ?? wrapper; + const klass = this.constructor; + const wrapper = GObject.Object.prototype._init.call(this, params) ?? this; - if (wrapper.constructor[Gtk.template]) { - let children = wrapper.constructor[Gtk.children] || []; + if (klass[Gtk.template]) { + let children = klass[Gtk.children] ?? []; for (let child of children) { wrapper[child.replace(/-/g, '_')] = - wrapper.get_template_child(wrapper.constructor, child); + wrapper.get_template_child(klass, child); } - let internalChildren = wrapper.constructor[Gtk.internalChildren] || []; + let internalChildren = klass[Gtk.internalChildren] ?? []; for (let child of internalChildren) { wrapper[`_${child.replace(/-/g, '_')}`] = - wrapper.get_template_child(wrapper.constructor, child); + wrapper.get_template_child(klass, child); } } @@ -75,56 +59,8 @@ function _init() { return GObject.Object._classInit(klass); }; - function registerWidgetType() { - let klass = this; - - let template = klass[Gtk.template]; - let cssName = klass[Gtk.cssName]; - let children = klass[Gtk.children]; - let internalChildren = klass[Gtk.internalChildren]; - - if (template) { - klass.prototype._instance_init = function () { - this.init_template(); - }; - } - - GObject.Object[_registerType].call(klass); - - if (cssName) - Gtk.Widget.set_css_name.call(klass, cssName); - - if (template) { - if (typeof template === 'string') { - if (template.startsWith('resource:///')) { - Gtk.Widget.set_template_from_resource.call(klass, - template.slice(11)); - } else if (template.startsWith('file:///')) { - let file = Gio.File.new_for_uri(template); - let [, contents] = file.load_contents(null); - Gtk.Widget.set_template.call(klass, contents); - } - } else { - Gtk.Widget.set_template.call(klass, template); - } - - if (BuilderScope) - Gtk.Widget.set_template_scope.call(klass, new BuilderScope()); - } - - if (children) { - children.forEach(child => - Gtk.Widget.bind_template_child_full.call(klass, child, false, 0)); - } - - if (internalChildren) { - internalChildren.forEach(child => - Gtk.Widget.bind_template_child_full.call(klass, child, true, 0)); - } - } - Object.defineProperty(Gtk.Widget, _registerType, { - value: registerWidgetType, + value: _registerWidgetType, writable: false, configurable: false, enumerable: false, @@ -143,23 +79,72 @@ function _init() { }, class extends GObject.Object { vfunc_create_closure(builder, handlerName, flags, connectObject) { const swapped = flags & Gtk.BuilderClosureFlags.SWAPPED; - return _createClosure( - builder, builder.get_current_object(), - handlerName, swapped, connectObject); + const thisArg = builder.get_current_object(); + return Gi.associateClosure( + connectObject ?? thisArg, + _createClosure(builder, thisArg, handlerName, swapped, connectObject) + ); } }); } } -function _createClosure(builder, thisArg, handlerName, swapped, connectObject) { - connectObject = connectObject || thisArg; +function _registerWidgetType(klass) { + const template = klass[Gtk.template]; + const cssName = klass[Gtk.cssName]; + const children = klass[Gtk.children]; + const internalChildren = klass[Gtk.internalChildren]; - if (swapped) { - throw new Error('Unsupported template signal flag "swapped"'); - } else if (typeof thisArg[handlerName] === 'undefined') { - throw new Error(`A handler called ${handlerName} was not ` + - `defined on ${thisArg}`); + if (template) { + klass.prototype._instance_init = function () { + this.init_template(); + }; } - return thisArg[handlerName].bind(connectObject); + GObject.Object[_registerType](klass); + + if (cssName) + Gtk.Widget.set_css_name.call(klass, cssName); + + if (template) { + if (typeof template === 'string') { + try { + const uri = GLib.Uri.parse(template, GLib.UriFlags.NONE); + const scheme = uri.get_scheme(); + + if (scheme === 'resource') { + Gtk.Widget.set_template_from_resource.call(klass, uri.get_path()); + } else if (scheme === 'file') { + const file = Gio.File.new_for_uri(template); + const [, contents] = file.load_contents(null); + Gtk.Widget.set_template.call(klass, contents); + } else { + throw new TypeError(`Invalid template URI: ${template}`); + } + } catch (err) { + if (!(err instanceof GLib.UriError)) + throw err; + + const contents = new TextEncoder().encode(template); + Gtk.Widget.set_template.call(klass, contents); + } + } else { + Gtk.Widget.set_template.call(klass, template); + } + + if (BuilderScope) + Gtk.Widget.set_template_scope.call(klass, new BuilderScope()); + else + Gtk.Widget.set_connect_func.call(klass, _createBuilderConnectFunc(klass)); + } + + if (children) { + children.forEach(child => + Gtk.Widget.bind_template_child_full.call(klass, child, false, 0)); + } + + if (internalChildren) { + internalChildren.forEach(child => + Gtk.Widget.bind_template_child_full.call(klass, child, true, 0)); + } } diff --git a/modules/esm/_encoding/encoding.js b/modules/esm/_encoding/encoding.js index 60cc04942..28284f847 100644 --- a/modules/esm/_encoding/encoding.js +++ b/modules/esm/_encoding/encoding.js @@ -106,6 +106,8 @@ class TextDecoder { input = new Uint8Array(buffer, byteOffset, byteLength); } else if (bytes === undefined) { input = new Uint8Array(0); + } else if (bytes instanceof import.meta.importSync('gi').GLib.Bytes) { + input = bytes.toArray(); } else { throw new Error( 'Provided input cannot be converted to ArrayBufferView or ArrayBuffer' diff --git a/modules/esm/console.js b/modules/esm/console.js index 8e872c0c6..c38604a0b 100644 --- a/modules/esm/console.js +++ b/modules/esm/console.js @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later // SPDX-FileCopyrightText: 2021 Evan Welsh -const DEFAULT_LOG_DOMAIN = 'Gjs-Console'; +const DEFAULT_LOG_DOMAIN = 'Cjs-Console'; // A line-by-line implementation of https://console.spec.whatwg.org/. @@ -40,8 +40,9 @@ function formatGenerically(item) { * @returns {string} */ function formatOptimally(item) { + const GLib = imports.gi.GLib; // Handle optimal error formatting. - if (item instanceof Error) { + if (item instanceof Error || item instanceof GLib.Error) { return `${item.toString()}${item.stack ? '\n' : ''}${item.stack ?.split('\n') // Pad each stacktrace line. @@ -52,6 +53,12 @@ function formatOptimally(item) { // TODO: Enhance 'optimal' formatting. // There is a current work on a better object formatter for GJS in // https://gitlab.gnome.org/GNOME/gjs/-/merge_requests/587 + if (typeof item === 'object' && item !== null) { + if (item.constructor?.name !== 'Object') + return `${item.constructor?.name} ${JSON.stringify(item, null, 4)}`; + else if (item[Symbol.toStringTag] === 'GIRepositoryNamespace') + return `[${item[Symbol.toStringTag]} ${item.__name__}]`; + } return JSON.stringify(item, null, 4); } diff --git a/modules/internal/loader.js b/modules/internal/loader.js index 5a5c065bf..03aa8f698 100644 --- a/modules/internal/loader.js +++ b/modules/internal/loader.js @@ -18,14 +18,7 @@ * Thrown when there is an error importing a module. */ class ImportError extends moduleGlobalThis.Error { - /** - * @param {string | undefined} message the import error message - */ - constructor(message) { - super(message); - - this.name = 'ImportError'; - } + name = 'ImportError'; } /** @@ -170,7 +163,7 @@ class InternalModuleLoader { // 1) Resolve path and URI-based imports. const uri = this.resolveSpecifier(specifier, importingModuleURI); if (uri) { - module = registry.get(uri.uri); + module = registry.get(uri.uriWithQuery); // Check if module is already loaded (relative handling) if (module) @@ -182,10 +175,10 @@ class InternalModuleLoader { const [text, internal = false] = result; - const priv = new ModulePrivate(uri.uri, uri.uri, internal); + const priv = new ModulePrivate(uri.uriWithQuery, uri.uri, internal); const compiled = this.compileModule(priv, text); - registry.set(uri.uri, compiled); + registry.set(uri.uriWithQuery, compiled); return compiled; } @@ -230,16 +223,16 @@ class ModuleLoader extends InternalModuleLoader { /** * The set of "module" URI globs (the module search path) * - * For example, having `"resource:///org/gnome/gjs/modules/esm/*.js"` in this + * For example, having `"resource:///org/cinnamon/cjs/modules/esm/*.js"` in this * set allows `import "system"` if - * `"resource:///org/gnome/gjs/modules/esm/system.js"` exists. + * `"resource:///org/cinnamon/cjs/modules/esm/system.js"` exists. * * Only `*` is supported as a replacement character, `**` is not supported. * * @type {Set} */ this.moduleURIs = new Set([ - 'resource:///org/gnome/gjs/modules/esm/*.js', + 'resource:///org/cinnamon/cjs/modules/esm/*.js', ]); /** @@ -365,7 +358,7 @@ class ModuleLoader extends InternalModuleLoader { // 1) Resolve path and URI-based imports. const uri = this.resolveSpecifier(specifier, importingModuleURI); if (uri) { - module = registry.get(uri.uri); + module = registry.get(uri.uriWithQuery); // Check if module is already loaded (relative handling) if (module) @@ -376,16 +369,16 @@ class ModuleLoader extends InternalModuleLoader { return null; // Check if module loaded while awaiting. - module = registry.get(uri.uri); + module = registry.get(uri.uriWithQuery); if (module) return module; const [text, internal = false] = result; - const priv = new ModulePrivate(uri.uri, uri.uri, internal); + const priv = new ModulePrivate(uri.uriWithQuery, uri.uri, internal); const compiled = this.compileModule(priv, text); - registry.set(uri.uri, compiled); + registry.set(uri.uriWithQuery, compiled); return compiled; } diff --git a/modules/modules.cpp b/modules/modules.cpp deleted file mode 100644 index 103f9cfc0..000000000 --- a/modules/modules.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later -// SPDX-FileCopyrightText: 2013 Red Hat, Inc. - -#include // for ENABLE_CAIRO - -#include "cjs/native.h" -#include "modules/console.h" -#include "modules/modules.h" -#include "modules/print.h" -#include "modules/system.h" - -#ifdef ENABLE_CAIRO -# include "modules/cairo-module.h" -#endif - -void gjs_register_static_modules(void) { - Gjs::NativeModuleRegistry& registry = Gjs::NativeModuleRegistry::get(); -#ifdef ENABLE_CAIRO - registry.add("cairoNative", gjs_js_define_cairo_stuff); -#endif - registry.add("system", gjs_js_define_system_stuff); - registry.add("console", gjs_define_console_stuff); - registry.add("_print", gjs_define_print_stuff); -} diff --git a/modules/modules.h b/modules/modules.h deleted file mode 100644 index bb2a38e9a..000000000 --- a/modules/modules.h +++ /dev/null @@ -1,10 +0,0 @@ -/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later -// SPDX-FileCopyrightText: 2013 Red Hat, Inc. - -#ifndef MODULES_MODULES_H_ -#define MODULES_MODULES_H_ - -void gjs_register_static_modules (void); - -#endif // MODULES_MODULES_H_ diff --git a/modules/script/_bootstrap/debugger.js b/modules/script/_bootstrap/debugger.js index e57d6c3ca..84fd8d7f0 100644 --- a/modules/script/_bootstrap/debugger.js +++ b/modules/script/_bootstrap/debugger.js @@ -23,6 +23,7 @@ var nextDebuggeeValueIndex = 1; var lastExc = null; var options = {pretty: true, colors: true, ignoreCaughtExceptions: true}; var breakpoints = [undefined]; // Breakpoint numbers start at 1 +var skipUnwindHandler = false; // Cleanup functions to run when we next re-enter the repl. var replCleanups = []; @@ -31,9 +32,12 @@ var replCleanups = []; function dvToString(v) { if (typeof v === 'undefined') return 'undefined'; // uneval(undefined) === '(void 0)', confusing - if (v === null) - return 'null'; // typeof null === 'object', so avoid that case - return typeof v !== 'object' || v === null ? uneval(v) : `[object ${v.class}]`; + if (typeof v === 'object' && v !== null) + return `[object ${v.class}]`; + const s = uneval(v); + if (s.length > 400) + return `${s.substr(0, 400)}...<${s.length - 400} more bytes>...`; + return s; } function debuggeeValueToString(dv, style = {pretty: options.pretty}) { @@ -50,21 +54,20 @@ function debuggeeValueToString(dv, style = {pretty: options.pretty}) { } const dvrepr = dvToString(dv); - if (!style.pretty || dv === null || typeof dv !== 'object') + if (!style.pretty || (typeof dv !== 'object') || (dv === null)) return [dvrepr, undefined]; + const exec = debuggeeGlobalWrapper.executeInGlobalWithBindings.bind(debuggeeGlobalWrapper); + if (['TypeError', 'Error', 'GIRespositoryNamespace', 'GObject_Object'].includes(dv.class)) { - const errval = debuggeeGlobalWrapper.executeInGlobalWithBindings( - 'v.toString()', {v: dv}); + const errval = exec('v.toString()', {v: dv}); return [dvrepr, errval['return']]; } if (style.brief) return [dvrepr, dvrepr]; - const str = debuggeeGlobalWrapper.executeInGlobalWithBindings( - 'imports._print.getPrettyPrintFunction(globalThis)(v)', {v: dv}); - + const str = exec('imports._print.getPrettyPrintFunction(globalThis)(v)', {v: dv}); if ('throw' in str) { if (style.noerror) return [dvrepr, undefined]; @@ -183,6 +186,36 @@ function saveExcursion(fn) { } } +// Evaluate @expr in the current frame, logging and suppressing any exceptions +function evalInFrame(expr) { + if (!focusedFrame) { + print('No stack'); + return; + } + + skipUnwindHandler = true; + let cv; + try { + cv = saveExcursion( + () => focusedFrame.evalWithBindings(`(${expr})`, debuggeeValues)); + } finally { + skipUnwindHandler = false; + } + + if (cv === null) { + print(`Debuggee died while evaluating ${expr}`); + return; + } + + const {throw: exc, return: dv} = cv; + if (exc) { + print(`Exception caught while evaluating ${expr}: ${dvToString(exc)}`); + return; + } + + return {value: dv}; +} + // Accept debugger commands starting with '#' so that scripting the debugger // can be annotated function commentCommand(comment) { @@ -346,13 +379,32 @@ expr may also reference the variables $1, $2, ... for already printed expressions, or $$ for the most recently printed expression.`; function keysCommand(rest) { - return doPrint(` - (o => Object.getOwnPropertyNames(o) - .concat(Object.getOwnPropertySymbols(o))) - (${rest}) - `); + if (!rest) { + print("Missing argument. See 'help keys'"); + return; + } + + const result = evalInFrame(rest); + if (!result) + return; + + const dv = result.value; + if (!(dv instanceof Debugger.Object)) { + print(`${rest} is ${dvToString(dv)}, not an object`); + return; + } + const names = dv.getOwnPropertyNames(); + const symbols = dv.getOwnPropertySymbols(); + const keys = [ + ...names.map(s => `"${s}"`), + ...symbols.map(s => `Symbol("${s.description}")`), + ]; + if (keys.length === 0) + print('No own properties'); + else + print(keys.join(', ')); } -keysCommand.summary = 'Prints keys of the given object'; +keysCommand.summary = 'Prints own properties of the given object'; keysCommand.helpText = `USAGE keys @@ -380,25 +432,15 @@ continueCommand.helpText = `USAGE function throwOrReturn(rest, action, defaultCompletion) { if (focusedFrame !== topFrame) { - print("To throw, you must select the newest frame (use 'frame 0')."); - return; - } - if (focusedFrame === null) { - print('No stack.'); + print(`To ${action}, you must select the newest frame (use 'frame 0')`); return; } if (rest === '') return [defaultCompletion]; - const cv = saveExcursion(() => focusedFrame.eval(rest)); - if (cv === null) { - print(`Debuggee died while determining what to ${action}. Stopped.`); - return; - } - if ('return' in cv) - return [{[action]: cv['return']}]; - print(`Exception determining what to ${action}. Stopped.`); - showDebuggeeValue(cv.throw); + const result = evalInFrame(rest); + if (result) + return [{[action]: result.value}]; } function throwCommand(rest) { @@ -838,7 +880,7 @@ function runcmd(cmd) { return undefined; var first = pieces[0], rest = pieces[1]; - if (!commands.hasOwnProperty(first)) { + if (!Object.hasOwn(commands, first)) { print(`unrecognized command '${first}'`); return undefined; } @@ -927,6 +969,9 @@ dbg.onDebuggerStatement = function (frame) { }); }; dbg.onExceptionUnwind = function (frame, value) { + if (skipUnwindHandler) + return undefined; + const willBeCaught = currentFrame => { while (currentFrame) { if (currentFrame.script.isInCatchScope(currentFrame.offset)) diff --git a/modules/script/_bootstrap/default.js b/modules/script/_bootstrap/default.js index df8054011..871d2bf74 100644 --- a/modules/script/_bootstrap/default.js +++ b/modules/script/_bootstrap/default.js @@ -23,15 +23,28 @@ return nativeLogError(e, args.map(arg => typeof arg === 'string' ? arg : prettyPrint(arg)).join(' ')); } + // compare against the %TypedArray% intrinsic object all typed array constructors inherit from + function _isTypedArray(value) { + return value instanceof Object.getPrototypeOf(Uint8Array); + } + + function _hasStandardToString(value) { + return value.toString === Object.prototype.toString || + value.toString === Array.prototype.toString || + // although TypedArrays have a standard Array.prototype.toString, we currently enforce an override to warn + // for legacy behaviour, making the toString non-standard for + // "any Uint8Array instances created in situations where previously a ByteArray would have been created" + _isTypedArray(value) || + value.toString === Date.prototype.toString; + } + function prettyPrint(value) { switch (typeof value) { case 'object': if (value === null) return 'null'; - if (value.toString === Object.prototype.toString || - value.toString === Array.prototype.toString || - value.toString === Date.prototype.toString) { + if (_hasStandardToString(value)) { const printedObjects = new WeakSet(); return formatObject(value, printedObjects); } @@ -60,15 +73,12 @@ function formatObject(obj, printedObjects) { printedObjects.add(obj); - if (Array.isArray(obj)) + if (Array.isArray(obj) || _isTypedArray(obj)) return formatArray(obj, printedObjects).toString(); if (obj instanceof Date) return formatDate(obj); - if (obj[Symbol.toStringTag] === 'GIRepositoryNamespace') - return obj.toString(); - const formattedObject = []; const keys = Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj)); for (const propertyKey of keys) { @@ -78,8 +88,12 @@ case 'object': if (printedObjects.has(value)) formattedObject.push(`${key}: [Circular]`); - else + else if (value === null) + formattedObject.push(`${key}: null`); + else if (_hasStandardToString(value)) formattedObject.push(`${key}: ${formatObject(value, printedObjects)}`); + else + formattedObject.push(`${key}: ${value.toString()}`); break; case 'function': formattedObject.push(`${key}: ${formatFunction(value)}`); diff --git a/modules/script/_legacy.js b/modules/script/_legacy.js index 135d25177..31877911c 100644 --- a/modules/script/_legacy.js +++ b/modules/script/_legacy.js @@ -246,7 +246,7 @@ function _getMetaInterface(params) { return req.__super__; for (let metaclass = req.prototype.__metaclass__; metaclass; metaclass = metaclass.__super__) { - if (metaclass.hasOwnProperty('MetaInterface')) + if (Object.hasOwn(metaclass, 'MetaInterface')) return metaclass.MetaInterface; } return null; @@ -441,7 +441,7 @@ function defineGObjectLegacyObjects(GObject) { } function _getGObjectInterfaces(interfaces) { - return interfaces.filter(iface => iface.hasOwnProperty('$gtype')); + return interfaces.filter(iface => Object.hasOwn(iface, '$gtype')); } function _propertiesAsArray(params) { @@ -647,6 +647,8 @@ function defineGObjectLegacyObjects(GObject) { } function defineGtkLegacyObjects(GObject, Gtk) { + const {_createBuilderConnectFunc} = imports._common; + const GtkWidgetClass = new Class({ Name: 'GtkWidgetClass', Extends: GObject.Class, @@ -683,6 +685,8 @@ function defineGtkLegacyObjects(GObject, Gtk) { Gtk.Widget.set_template.call(this, template); } + Gtk.Widget.set_connect_func.call(this, _createBuilderConnectFunc(this)); + this[Gtk.template] = template; this[Gtk.children] = children; this[Gtk.internalChildren] = internalChildren; diff --git a/modules/script/lang.js b/modules/script/lang.js index 98082995f..9aba87047 100644 --- a/modules/script/lang.js +++ b/modules/script/lang.js @@ -16,7 +16,7 @@ function countProperties(obj) { } function getPropertyDescriptor(obj, property) { - if (obj.hasOwnProperty(property)) + if (Object.hasOwn(obj, property)) return Object.getOwnPropertyDescriptor(obj, property); return getPropertyDescriptor(Object.getPrototypeOf(obj), property); } diff --git a/modules/script/package.js b/modules/script/package.js index 1491b0639..cc308f8db 100644 --- a/modules/script/package.js +++ b/modules/script/package.js @@ -9,6 +9,7 @@ requireSymbol, run, start, version */ * This module provides a set of convenience APIs for building packaged * applications. */ +imports.gi.versions.GIRepository = '2.0'; const GLib = imports.gi.GLib; const GIRepository = imports.gi.GIRepository; diff --git a/subprojects/cairo.wrap b/subprojects/cairo.wrap new file mode 100644 index 000000000..9039262f0 --- /dev/null +++ b/subprojects/cairo.wrap @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: MIT OR LGPL-2.0-or-later +# SPDX-FileCopyrightText: 2024 Philip Chimento + +[wrap-git] +directory = cairo +url = https://gitlab.freedesktop.org/cairo/cairo.git +push-url = git@gitlab.freedesktop.org:cairo/cairo.git +revision = master +depth = 1 + +[provide] +cairo = libcairo_dep +cairo-gobject = libcairogobject_dep diff --git a/subprojects/gobject-introspection-tests.wrap b/subprojects/gobject-introspection-tests.wrap new file mode 100644 index 000000000..9f288cb82 --- /dev/null +++ b/subprojects/gobject-introspection-tests.wrap @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: MIT OR LGPL-2.0-or-later +# SPDX-FileCopyrightText: 2024 Philip Chimento + +[wrap-git] +directory=gobject-introspection-tests +url=https://gitlab.gnome.org/GNOME/gobject-introspection-tests.git +revision=7adb7396928a0964a9d3ef7626f8d2b9639be50d +depth=1 + +[provide] +dependency_names = gimarshallingtests_typelib, regress_typelib, utility_typelib, warnlib_typelib diff --git a/subprojects/gobject-introspection-tests/.clang-format b/subprojects/gobject-introspection-tests/.clang-format new file mode 100644 index 000000000..8e24c324d --- /dev/null +++ b/subprojects/gobject-introspection-tests/.clang-format @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: MIT OR LGPL-2.0-or-later +# SPDX-FileCopyrightText: 2024 Philip Chimento + +BasedOnStyle: GNU +BinPackParameters: false +BreakBeforeBinaryOperators: None +ContinuationIndentWidth: 2 +SpaceAfterCStyleCast: true + +# clang-format makes weird choices re. enforcing line limits. +# Currently, humans can still do this better. +ColumnLimit: 0 diff --git a/subprojects/gobject-introspection-tests/.editorconfig b/subprojects/gobject-introspection-tests/.editorconfig new file mode 100644 index 000000000..7d46d89e3 --- /dev/null +++ b/subprojects/gobject-introspection-tests/.editorconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: MIT OR LGPL-2.0-or-later +# SPDX-FileCopyrightText: 2024 Philip Chimento + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{c,h}] +indent_size = 2 +indent_style = space diff --git a/subprojects/gobject-introspection-tests/COPYING b/subprojects/gobject-introspection-tests/COPYING new file mode 100644 index 000000000..2f70ea47c --- /dev/null +++ b/subprojects/gobject-introspection-tests/COPYING @@ -0,0 +1,13 @@ +gobject-introspection has two licenses; one for the typelib library, +and one for the tools. + +* The typelib libraries (girepository/) are licensed under the LGPLv2+. + See the file COPYING.LGPL. + +* The remaining code is GPLv2+ compatible (see the file COPYING.GPL) and + consists of a mix of GPLv2+, LGPLv2+ and MIT. See the license headers in + each file for details. + +In general where applicable files should have headers denoting their license +status; if they do not, please file a bug at +https://gitlab.gnome.org/GNOME/gobject-introspection/issues. diff --git a/subprojects/gobject-introspection-tests/COPYING.GPL b/subprojects/gobject-introspection-tests/COPYING.GPL new file mode 100644 index 000000000..7ac467c0e --- /dev/null +++ b/subprojects/gobject-introspection-tests/COPYING.GPL @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 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. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, 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 or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +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 give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. However, as a +special exception, the source code 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. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program 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 to +this License. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 Program +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 Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, 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 + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), 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 Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. 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 program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; 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. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/subprojects/gobject-introspection-tests/COPYING.LGPL b/subprojects/gobject-introspection-tests/COPYING.LGPL new file mode 100644 index 000000000..2d8788b4d --- /dev/null +++ b/subprojects/gobject-introspection-tests/COPYING.LGPL @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 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 library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + 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 Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, 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 or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the 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 a program 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. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + 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, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +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 compile 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) 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. + + c) 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. + + d) 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 source code 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 to +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 Library 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 Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library 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! diff --git a/subprojects/gobject-introspection-tests/README.md b/subprojects/gobject-introspection-tests/README.md new file mode 100644 index 000000000..898e36317 --- /dev/null +++ b/subprojects/gobject-introspection-tests/README.md @@ -0,0 +1,77 @@ +# GObject Introspection Tests + +This is a git submodule containing C source files. +These files are compiled into shared libraries intended for testing language +bindings for the GNOME platform. +They are also used to test the `g-ir-scanner` tool from [gobject-introspection]. + +[gobject-introspection]: https://gitlab.gnome.org/GNOME/gobject-introspection + +## Available modules + +**Regress** test suite — a library designed as a general regression test suite, +accumulated over the lifetime of gobject-introspection. +Consists of `regress.c`, `annotation.c`, `drawable.c`, `foo.c`, and their +associated header files. + +**GIMarshallingTests** suite — a library designed to exercise how every kind +of C value used in GNOME platform APIs is converted to and from native values +from the language binding. + +**Utility** test suite — a library for testing external type references. + +**WarnLib** test suite — a library with a number of conditions that +`g-ir-scanner` will warn about, used to test how language bindings deal with +typelibs that contain non-ideal C code. + +## How to Use in a Dynamic Language Binding + +Include this repository as a git submodule in your sources. + +```sh +git submodule add https://gitlab.gnome.org/GNOME/gobject-introspection-tests.git +``` + +If you use the Meson build system, you can also add it as a Meson subproject, +and simply write: + +```meson +gi_tests = subproject('gobject-introspection-tests') +``` + +The subproject exports variables `gimarshallingtests_typelib`, +`regress_typelib`, `utility_typelib`, and `warnlib_typelib` which you can access +with `gi_tests.get_variable('regress_typelib')` etc. +You will have to decide which modules you want to use. +Most language bindings will want to use at least Regress and GIMarshallingTests. + +Now you can write tests that load the module, call each of its functions with +the expected input, and check for the expected output. +You will need to add the build folder to the environment variables +`LD_LIBRARY_PATH` and `GI_TYPELIB_PATH`, something like this: + +```meson +tests_environment = environment() +gi_tests_builddir = meson.project_build_root() / 'subprojects' / 'gobject-introspection-tests' +tests_environment.prepend('LD_LIBRARY_PATH', gi_tests_builddir) +tests_environment.prepend('GI_TYPELIB_PATH', gi_tests_builddir) +``` + +and then pass `env: tests_environment` in your call to `test()`. + +If your language binding supports installed tests, you will have to install the +built modules manually, to a private location where your installed tests can +find them. +Do not install them in the default typelibs directory, where they may conflict +with other language bindings' installed tests. +Depending on how your build system is structured it might look something like +this, using GIMarshallingTests as an example: + +```meson +gi_tests = subproject('gobject-introspection-tests', + default_options: ['install_dir=@0@'.format(installed_tests_dir)]) +``` + +For build systems other than Meson, simply ignore the `meson.build` file and add +code to your build system to build the modules as if it was a regular +subdirectory. diff --git a/subprojects/gobject-introspection-tests/annotation.c b/subprojects/gobject-introspection-tests/annotation.c new file mode 100644 index 000000000..a60239adf --- /dev/null +++ b/subprojects/gobject-introspection-tests/annotation.c @@ -0,0 +1,841 @@ +/* +SPDX-FileCopyrightText: 2008-2009 Dan Winship +SPDX-FileCopyrightText: 2008-2010 Colin Walters +SPDX-FileCopyrightText: 2008-2011 Johan Dahlin +SPDX-FileCopyrightText: 2008 Owen Taylor +SPDX-FileCopyrightText: 2008 Tristan Van Berkom +SPDX-FileCopyrightText: 2009 Andreas Rottmann +SPDX-FileCopyrightText: 2010 litl, LLC +SPDX-FileCopyrightText: 2010 Pavel Holejsovsky +SPDX-FileCopyrightText: 2010 Red Hat, Inc. +SPDX-FileCopyrightText: 2011 Jasper St. Pierre +SPDX-FileCopyrightText: 2015 Christoph Reiter +*/ + +#include + +#include "annotation.h" + +char backslash_parsing_tester = '\\'; + +G_DEFINE_TYPE (RegressAnnotationObject, regress_annotation_object, G_TYPE_OBJECT); + +enum +{ + PROP_0, + PROP_STRING_PROPERTY, + PROP_FUNCTION_PROPERTY, + PROP_TAB_PROPERTY +}; + +enum +{ + STRING_SIGNAL, + LIST_SIGNAL, + DOC_EMPTY_ARG_PARSING, + ATTRIBUTE_SIGNAL, + LAST_SIGNAL +}; + +static guint regress_annotation_object_signals[LAST_SIGNAL] = { 0 }; + +static void +regress_annotation_object_set_property (GObject *object, + guint prop_id, + const GValue *value G_GNUC_UNUSED, + GParamSpec *pspec) +{ + switch (prop_id) + { + case PROP_STRING_PROPERTY: + break; + case PROP_FUNCTION_PROPERTY: + break; + case PROP_TAB_PROPERTY: + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +regress_annotation_object_get_property (GObject *object, + guint prop_id, + GValue *value G_GNUC_UNUSED, + GParamSpec *pspec) +{ + switch (prop_id) + { + case PROP_STRING_PROPERTY: + break; + case PROP_FUNCTION_PROPERTY: + break; + case PROP_TAB_PROPERTY: + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +regress_annotation_object_class_init (RegressAnnotationObjectClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->set_property = regress_annotation_object_set_property; + gobject_class->get_property = regress_annotation_object_get_property; + + /** + * RegressAnnotationObject::string-signal: + * @regress_annotation: the regress_annotation object + * @string: (type utf8): a string + * + * This is a signal which has a broken signal handler, + * it says it's pointer but it's actually a string. + * + * Since: 1.0 + * Deprecated: 1.2: Use other-signal instead + */ + regress_annotation_object_signals[STRING_SIGNAL] = + g_signal_new ("string-signal", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + (GSignalCMarshaller) g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + + /** + * RegressAnnotationObject::list-signal: + * @regress_annotation: the regress_annotation object + * @list: (type GLib.List) (element-type utf8) (transfer container): a list of strings + * + * This is a signal which takes a list of strings, but it's not + * known by GObject as it's only marked as G_TYPE_POINTER + */ + regress_annotation_object_signals[LIST_SIGNAL] = + g_signal_new ("list-signal", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + (GSignalCMarshaller) g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + + /** + * RegressAnnotationObject::doc-empty-arg-parsing: + * @regress_annotation: the regress_annotation object + * @arg1: + * + * This signal tests an empty document argument (@arg1) + */ + regress_annotation_object_signals[DOC_EMPTY_ARG_PARSING] = + g_signal_new ("doc-empty-arg-parsing", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + (GSignalCMarshaller) g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + + /** + * RegressAnnotationObject::attribute-signal: + * @regress_annotation: the regress_annotation object + * @arg1: (attributes some.annotation.foo1=val1): a value + * @arg2: (attributes some.annotation.foo2=val2): another value + * + * This signal tests a signal with attributes. + * + * Returns: (attributes some.annotation.foo3=val3): the return value + */ + regress_annotation_object_signals[ATTRIBUTE_SIGNAL] = + g_signal_new ("attribute-signal", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, /* marshaller */ + G_TYPE_STRING, + 2, + G_TYPE_STRING, + G_TYPE_STRING); + + /** + * RegressAnnotationObject:string-property: + * + * This is a property which is a string + * + * Since: 1.0 + * Deprecated: 1.2: Use better-string-property instead + */ + g_object_class_install_property (gobject_class, + PROP_STRING_PROPERTY, + g_param_spec_string ("string-property", + "String property", + "This property is a string", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + /** + * RegressAnnotationObject:function-property: (type RegressAnnotationCallback) + */ + g_object_class_install_property (gobject_class, + PROP_FUNCTION_PROPERTY, + g_param_spec_pointer ("function-property", + "Function property", + "This property is a function pointer", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + /* clang-format off */ + + /** + * RegressAnnotationObject:tab-property: + * + * This is a property annotation intentionally indented with a mix + * of tabs and strings to test the tab handling capabilities of the scanner. + * + * Since: 1.2 + */ + g_object_class_install_property (gobject_class, + PROP_TAB_PROPERTY, + g_param_spec_string ("tab-property", + "Tab property", + "This property is a thing", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + /* clang-format on */ +} + +static void +regress_annotation_object_init (RegressAnnotationObject *object G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_object_method: + * @object: a #GObject + * + * Return value: an int + **/ +gint +regress_annotation_object_method (RegressAnnotationObject *object G_GNUC_UNUSED) +{ + return 1; +} + +/** + * regress_annotation_object_out: + * @object: a #GObject + * @outarg: (out): This is an argument test + * + * This is a test for out arguments + * + * Return value: an int + */ +gint +regress_annotation_object_out (RegressAnnotationObject *object G_GNUC_UNUSED, + int *outarg) +{ + *outarg = 2; + return 1; +} + +/** + * regress_annotation_object_in: + * @object: a #GObject + * @inarg: (in) (transfer none): This is an argument test + * + * This is a test for in arguments + * + * Return value: an int + */ +gint +regress_annotation_object_in (RegressAnnotationObject *object G_GNUC_UNUSED, + int *inarg) +{ + return *inarg; +} + +/** + * regress_annotation_object_inout: + * @object: a #GObject + * @inoutarg: (inout): This is an argument test + * + * This is a test for out arguments + * + * Return value: an int + */ +gint +regress_annotation_object_inout (RegressAnnotationObject *object G_GNUC_UNUSED, + int *inoutarg) +{ + return *inoutarg += 1; +} + +/** + * regress_annotation_object_inout2: + * @object: a #GObject + * @inoutarg: (inout): This is an argument test + * + * This is a second test for out arguments + * + * Return value: an int + */ +gint +regress_annotation_object_inout2 (RegressAnnotationObject *object G_GNUC_UNUSED, + int *inoutarg) +{ + return *inoutarg += 1; +} + +/** + * regress_annotation_object_inout3: + * @object: a #GObject + * @inoutarg: (inout) (allow-none): This is an argument test + * + * This is a 3th test for out arguments + * + * Return value: an int + */ +gint +regress_annotation_object_inout3 (RegressAnnotationObject *object G_GNUC_UNUSED, + int *inoutarg) +{ + if (inoutarg) + return *inoutarg + 1; + return 1; +} + +/** + * regress_annotation_object_calleeowns: + * @object: a #GObject + * @toown: (out): a #GObject + * + * This is a test for out arguments; GObject defaults to transfer + * + * Return value: an int + */ +gint +regress_annotation_object_calleeowns (RegressAnnotationObject *object G_GNUC_UNUSED, + GObject **toown G_GNUC_UNUSED) +{ + return 1; +} + +/** + * regress_annotation_object_calleesowns: + * @object: a #GObject + * @toown1: (out) (transfer full): a #GObject + * @toown2: (out) (transfer none): a #GObject + * + * This is a test for out arguments, one transferred, other not + * + * Return value: an int + */ +gint +regress_annotation_object_calleesowns (RegressAnnotationObject *object G_GNUC_UNUSED, + GObject **toown1 G_GNUC_UNUSED, + GObject **toown2 G_GNUC_UNUSED) +{ + return 1; +} + +/** + * regress_annotation_object_get_strings: + * @object: a #GObject + * + * This is a test for returning a list of strings, where + * each string needs to be freed. + * + * Return value: (element-type utf8) (transfer full): list of strings + */ +GList * +regress_annotation_object_get_strings (RegressAnnotationObject *object G_GNUC_UNUSED) +{ + GList *list = NULL; + list = g_list_prepend (list, g_strdup ("regress_annotation")); + list = g_list_prepend (list, g_strdup ("bar")); + return list; +} + +/** + * regress_annotation_object_get_hash: + * @object: a #GObject + * + * This is a test for returning a hash table mapping strings to + * objects. + * + * Return value: (element-type utf8 GObject) (transfer full): hash table + */ +GHashTable * +regress_annotation_object_get_hash (RegressAnnotationObject *object) +{ + GHashTable *hash = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_object_unref); + g_hash_table_insert (hash, g_strdup ("one"), g_object_ref (object)); + g_hash_table_insert (hash, g_strdup ("two"), g_object_ref (object)); + return hash; +} + +/** + * regress_annotation_object_with_voidp: + * @data: Opaque pointer handle + */ +void +regress_annotation_object_with_voidp (RegressAnnotationObject *object G_GNUC_UNUSED, + void *data G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_object_get_objects: + * @object: a #GObject + * + * This is a test for returning a list of objects. + * The list itself should be freed, but not the internal objects, + * intentionally similar example to gtk_container_get_children + * + * Return value: (element-type RegressAnnotationObject) (transfer container): list of objects + */ +GSList * +regress_annotation_object_get_objects (RegressAnnotationObject *object) +{ + GSList *list = NULL; + list = g_slist_prepend (list, object); + return list; +} + +/** + * regress_annotation_object_create_object: + * @object: a #GObject + * + * Test returning a caller-owned object + * + * Return value: (transfer full): The object + **/ +GObject * +regress_annotation_object_create_object (RegressAnnotationObject *object) +{ + return G_OBJECT (g_object_ref (object)); +} + +/** + * regress_annotation_object_use_buffer: + * @object: a #GObject + * + **/ +void +regress_annotation_object_use_buffer (RegressAnnotationObject *object G_GNUC_UNUSED, + guchar *bytes G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_object_compute_sum: + * @object: a #GObject + * @nums: (array): Sequence of numbers + * + * Test taking a zero-terminated array + **/ +void +regress_annotation_object_compute_sum (RegressAnnotationObject *object G_GNUC_UNUSED, + int *nums G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_object_compute_sum_n: + * @object: a #GObject + * @nums: (array length=n_nums zero-terminated=0): Sequence of + * numbers that are zero-terminated + * @n_nums: Length of number array + * + * Test taking an array with length parameter + **/ +void +regress_annotation_object_compute_sum_n (RegressAnnotationObject *object G_GNUC_UNUSED, + int *nums G_GNUC_UNUSED, + int n_nums G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_object_compute_sum_nz: + * @object: a #RegressAnnotationObject + * @nums: (array length=n_nums zero-terminated): Sequence of numbers that + * are zero-terminated + * @n_nums: Length of number array + * + * Test taking a zero-terminated array with length parameter + **/ +void +regress_annotation_object_compute_sum_nz (RegressAnnotationObject *object G_GNUC_UNUSED, + int *nums G_GNUC_UNUSED, + int n_nums G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_object_parse_args: + * @object: a #RegressAnnotationObject + * @argc: (inout): Length of the argument vector + * @argv: (inout) (array length=argc zero-terminated=1): Argument vector + * + * Test taking a zero-terminated array with length parameter + **/ +void +regress_annotation_object_parse_args (RegressAnnotationObject *object G_GNUC_UNUSED, + int *argc G_GNUC_UNUSED, + char ***argv G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_object_string_out: + * @object: a #RegressAnnotationObject + * @str_out: (out) (transfer full): string return value + * + * Test returning a string as an out parameter + * + * Returns: some boolean + **/ +gboolean +regress_annotation_object_string_out (RegressAnnotationObject *object G_GNUC_UNUSED, + char **str_out G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * regress_annotation_object_foreach: + * @object: a #RegressAnnotationObject + * @func: (scope call): Callback to invoke + * @user_data: Callback user data + * + * Test taking a call-scoped callback + **/ +void +regress_annotation_object_foreach (RegressAnnotationObject *object G_GNUC_UNUSED, + RegressAnnotationForeachFunc func G_GNUC_UNUSED, + gpointer user_data G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_object_set_data: + * @object: a #RegressAnnotationObject + * @data: (array length=length): The data + * @length: Length of the data + * + * Test taking a guchar * with a length. + **/ +void +regress_annotation_object_set_data (RegressAnnotationObject *object G_GNUC_UNUSED, + const guchar *data G_GNUC_UNUSED, + gsize length G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_object_set_data2: + * @object: a #RegressAnnotationObject + * @data: (array length=length) (element-type gint8): The data + * @length: Length of the data + * + * Test taking a gchar * with a length. + **/ +void +regress_annotation_object_set_data2 (RegressAnnotationObject *object G_GNUC_UNUSED, + const gchar *data G_GNUC_UNUSED, + gsize length G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_object_set_data3: + * @object: a #RegressAnnotationObject + * @data: (array length=length) (element-type guint8): The data + * @length: Length of the data + * + * Test taking a gchar * with a length, overriding the array element + * type. + **/ +void +regress_annotation_object_set_data3 (RegressAnnotationObject *object G_GNUC_UNUSED, + gpointer data G_GNUC_UNUSED, + gsize length G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_object_allow_none: + * @object: a #GObject + * @somearg: (allow-none): + * + * Returns: (transfer none): %NULL always + **/ +GObject * +regress_annotation_object_allow_none (RegressAnnotationObject *object G_GNUC_UNUSED, + const gchar *somearg G_GNUC_UNUSED) +{ + return NULL; +} + +/** + * regress_annotation_object_notrans: + * @object: a #GObject + * + * Returns: (transfer none): An object, not referenced + **/ + +GObject * +regress_annotation_object_notrans (RegressAnnotationObject *object G_GNUC_UNUSED) +{ + return NULL; +} + +/** + * regress_annotation_object_do_not_use: + * @object: a #GObject + * + * Returns: (transfer none): %NULL always + * Deprecated: 0.12: Use regress_annotation_object_create_object() instead. + **/ +GObject * +regress_annotation_object_do_not_use (RegressAnnotationObject *object G_GNUC_UNUSED) +{ + return NULL; +} + +/** + * regress_annotation_object_watch: (skip) + * @object: A #RegressAnnotationObject + * @func: The callback + * @user_data: The callback data + * + * This is here just for the sake of being overriden by its + * regress_annotation_object_watch_full(). + */ +void +regress_annotation_object_watch (RegressAnnotationObject *object G_GNUC_UNUSED, + RegressAnnotationForeachFunc func G_GNUC_UNUSED, + gpointer user_data G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_object_watch_full: (rename-to regress_annotation_object_watch) + * @object: A #RegressAnnotationObject + * @func: The callback + * @user_data: The callback data + * @destroy: Destroy notification + * + * Test overriding via the "Rename To" annotation. + */ +void +regress_annotation_object_watch_full (RegressAnnotationObject *object G_GNUC_UNUSED, + RegressAnnotationForeachFunc func G_GNUC_UNUSED, + gpointer user_data G_GNUC_UNUSED, + GDestroyNotify destroy G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_object_hidden_self: + * @object: (type RegressAnnotationObject): A #RegressAnnotationObject + **/ +void +regress_annotation_object_hidden_self (gpointer object G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_init: + * @argc: (inout): The number of args. + * @argv: (inout) (array length=argc): The arguments. + **/ +void +regress_annotation_init (int *argc G_GNUC_UNUSED, + char ***argv G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_return_array: + * @length: (out): Number of return values + * + * Return value: (transfer full) (array length=length): The return value + **/ +char ** +regress_annotation_return_array (int *length G_GNUC_UNUSED) +{ + return NULL; +} + +/** + * regress_annotation_string_zero_terminated: + * + * Return value: (transfer full) (array zero-terminated=1): The return value + **/ +char ** +regress_annotation_string_zero_terminated (void) +{ + return NULL; +} + +/** + * regress_annotation_string_zero_terminated_out: + * @out: (array zero-terminated=1) (inout): + **/ +void +regress_annotation_string_zero_terminated_out (char ***out G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_versioned: + * + * Since: 0.6 + **/ +void +regress_annotation_versioned (void) +{ +} + +/** + * regress_annotation_string_array_length: + * @n_properties: + * @properties: (array length=n_properties) (element-type utf8): + */ +void +regress_annotation_string_array_length (guint n_properties G_GNUC_UNUSED, + const gchar *const properties[] G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_object_extra_annos: (attributes org.foobar=testvalue) + */ +void +regress_annotation_object_extra_annos (RegressAnnotationObject *object G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_custom_destroy: + * @callback: (destroy destroy) (closure data): Destroy notification + * + * Test messing up the heuristic of closure/destroy-notification + * detection, and fixing it via annotations. + */ +void +regress_annotation_custom_destroy (RegressAnnotationCallback callback G_GNUC_UNUSED, + RegressAnnotationNotifyFunc destroy G_GNUC_UNUSED, + gpointer data G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_get_source_file: + * + * Return value: (type filename) (transfer full): Source file + */ +char * +regress_annotation_get_source_file (void) +{ + return NULL; +} + +/** + * regress_annotation_set_source_file: + * @fname: (type filename): Source file + * + */ +void +regress_annotation_set_source_file (const char *fname G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_ptr_array: + * @array: (element-type GObject.Value): the array + */ +void +regress_annotation_ptr_array (GPtrArray *array G_GNUC_UNUSED) +{ +} + +/** + * regress_annotation_attribute_func: + * @object: A #RegressAnnotationObject. + * @data: (attributes some.annotation=value another.annotation=blahvalue): Some data. + * + * Returns: (attributes some.other.annotation=value2 yet.another.annotation=another_value): The return value. + */ +gint +regress_annotation_attribute_func (RegressAnnotationObject *object G_GNUC_UNUSED, + const gchar *data G_GNUC_UNUSED) +{ + return 42; +} + +/** + * regress_annotation_invalid_regress_annotation: + * @foo: some text (e.g. example) or else + */ +void +regress_annotation_invalid_regress_annotation (int foo G_GNUC_UNUSED) +{ +} + +char backslash_parsing_tester_2 = '\\'; + +/** + * regress_annotation_test_parsing_bug630862: + * + * See https://bugzilla.gnome.org/show_bug.cgi?id=630862 + * + * Returns: (transfer none): An object, note the colon:in here + */ +GObject * +regress_annotation_test_parsing_bug630862 (void) +{ + return NULL; +} + +/** + * regress_annotation_space_after_comment_bug631690: + * + * Explicitly test having a space after the ** here. + */ +void +regress_annotation_space_after_comment_bug631690 (void) +{ +} + +/** + * regress_annotation_return_filename: + * + * Returns: (type filename): An annotated filename + */ +gchar * +regress_annotation_return_filename (void) +{ + return g_strdup ("a utf-8 filename"); +} + +/** + * regress_annotation_transfer_floating: + * @object: (in) (transfer floating): an object + * + * Returns: (transfer floating): A floating object + */ +GObject * +regress_annotation_transfer_floating (GObject *object G_GNUC_UNUSED) +{ + return NULL; +} diff --git a/subprojects/gobject-introspection-tests/annotation.h b/subprojects/gobject-introspection-tests/annotation.h new file mode 100644 index 000000000..7a620d3e2 --- /dev/null +++ b/subprojects/gobject-introspection-tests/annotation.h @@ -0,0 +1,313 @@ +/* +SPDX-FileCopyrightText: 2008-2009 Dan Winship +SPDX-FileCopyrightText: 2008-2010 Colin Walters +SPDX-FileCopyrightText: 2008-2011 Johan Dahlin +SPDX-FileCopyrightText: 2008 Owen Taylor +SPDX-FileCopyrightText: 2008 Tommi Komulainen +SPDX-FileCopyrightText: 2008 Tristan Van Berkom +SPDX-FileCopyrightText: 2009-2010 Andreas Rottmann +SPDX-FileCopyrightText: 2010 litl, LLC +SPDX-FileCopyrightText: 2010 Pavel Holejsovsky +SPDX-FileCopyrightText: 2010 Red Hat, Inc. +SPDX-FileCopyrightText: 2011 Jasper St. Pierre +SPDX-FileCopyrightText: 2013 Stef Walter +SPDX-FileCopyrightText: 2015 Christoph Reiter +SPDX-FileCopyrightText: 2020 Centricular +*/ + +#pragma once + +#include +#include + +#include "gitestmacros.h" + +typedef enum /*< flags,prefix=ANN >*/ +{ + ANN_FLAG_FOO = 1, + ANN_FLAG_BAR = 2, + /** + * ANN_FLAG_FOOBAR: + * + * Since: 1.4 + */ + ANN_FLAG_FOOBAR = 3, +} RegressAnnotationBitfield; + +/** + * RegressAnnotationCallback: + * @in: (in) (transfer none): array of ints + * + * This is a callback. + * Return value: (transfer none): array of ints + */ +typedef const gint *(*RegressAnnotationCallback) (const gint *in); + +/** + * RegressAnnotationListCallback: + * @in: (in) (transfer none) (element-type utf8): list of strings + * + * This is a callback taking a list. + * Return value: (transfer container) (element-type utf8): list of strings + */ +typedef GList *(*RegressAnnotationListCallback) (GList *in); + +/** + * RegressAnnotationNotifyFunc: + * @data: (closure): The user data + * + * This is a callback with a 'closure' argument that is not named + * 'user_data' and hence has to be annotated. + */ +typedef void (*RegressAnnotationNotifyFunc) (gpointer data); + +/** + * RegressAnnotationObject: (attributes org.example.Test=cows) + * + * This is an object used to test annotations. + */ +typedef struct _RegressAnnotationObject RegressAnnotationObject; +typedef struct _RegressAnnotationObjectClass RegressAnnotationObjectClass; + +typedef void (*RegressAnnotationForeachFunc) (RegressAnnotationObject *object, + const char *item, + gpointer user_data); + +struct _RegressAnnotationObject +{ + GObject parent_instance; +}; + +struct _RegressAnnotationObjectClass +{ + GObjectClass parent_class; +}; + +GI_TEST_EXTERN +GType regress_annotation_object_get_type (void); + +GI_TEST_EXTERN +gint regress_annotation_object_method (RegressAnnotationObject *object); + +GI_TEST_EXTERN +gint regress_annotation_object_out (RegressAnnotationObject *object, + int *outarg); + +GI_TEST_EXTERN +GObject *regress_annotation_object_create_object (RegressAnnotationObject *object); + +GI_TEST_EXTERN +GObject *regress_annotation_object_allow_none (RegressAnnotationObject *object, + const gchar *somearg); + +GI_TEST_EXTERN +GObject *regress_annotation_object_notrans (RegressAnnotationObject *object); + +GI_TEST_EXTERN +gint regress_annotation_object_inout (RegressAnnotationObject *object, + int *inoutarg); + +GI_TEST_EXTERN +gint regress_annotation_object_inout2 (RegressAnnotationObject *object, + int *inoutarg); + +GI_TEST_EXTERN +gint regress_annotation_object_inout3 (RegressAnnotationObject *object, + int *inoutarg); + +GI_TEST_EXTERN +gint regress_annotation_object_in (RegressAnnotationObject *object, + int *inarg); + +GI_TEST_EXTERN +gint regress_annotation_object_calleeowns (RegressAnnotationObject *object, + GObject **toown); + +GI_TEST_EXTERN +gint regress_annotation_object_calleesowns (RegressAnnotationObject *object, + GObject **toown1, + GObject **toown2); + +GI_TEST_EXTERN +GList *regress_annotation_object_get_strings (RegressAnnotationObject *object); + +GI_TEST_EXTERN +GHashTable *regress_annotation_object_get_hash (RegressAnnotationObject *object); + +GI_TEST_EXTERN +void regress_annotation_object_with_voidp (RegressAnnotationObject *object, + void *data); + +GI_TEST_EXTERN +GSList *regress_annotation_object_get_objects (RegressAnnotationObject *object); + +GI_TEST_EXTERN +void regress_annotation_object_use_buffer (RegressAnnotationObject *object, + guchar *bytes); + +GI_TEST_EXTERN +void regress_annotation_object_compute_sum (RegressAnnotationObject *object, + int *nums); + +GI_TEST_EXTERN +void regress_annotation_object_compute_sum_n (RegressAnnotationObject *object, + int *nums, + int n_nums); + +GI_TEST_EXTERN +void regress_annotation_object_compute_sum_nz (RegressAnnotationObject *object, + int *nums, + int n_nums); + +GI_TEST_EXTERN +void regress_annotation_object_parse_args (RegressAnnotationObject *object, + int *argc, + char ***argv); + +GI_TEST_EXTERN +gboolean regress_annotation_object_string_out (RegressAnnotationObject *object, + char **str_out); + +GI_TEST_EXTERN +void regress_annotation_object_foreach (RegressAnnotationObject *object, + RegressAnnotationForeachFunc func, + gpointer user_data); + +GI_TEST_EXTERN +void regress_annotation_object_set_data (RegressAnnotationObject *object, + const guchar *data, + gsize length); + +GI_TEST_EXTERN +void regress_annotation_object_set_data2 (RegressAnnotationObject *object, + const gchar *data, + gsize length); + +GI_TEST_EXTERN +void regress_annotation_object_set_data3 (RegressAnnotationObject *object, + gpointer data, + gsize length); + +GI_TEST_EXTERN +GObject *regress_annotation_object_do_not_use (RegressAnnotationObject *object); + +GI_TEST_EXTERN +void regress_annotation_object_watch (RegressAnnotationObject *object, + RegressAnnotationForeachFunc func, + gpointer user_data); + +GI_TEST_EXTERN +void regress_annotation_object_watch_full (RegressAnnotationObject *object, + RegressAnnotationForeachFunc func, + gpointer user_data, + GDestroyNotify destroy); + +GI_TEST_EXTERN +void regress_annotation_object_hidden_self (gpointer object); + +GI_TEST_EXTERN +void regress_annotation_init (int *argc, + char ***argv); + +GI_TEST_EXTERN +char **regress_annotation_return_array (int *length); + +GI_TEST_EXTERN +void regress_annotation_versioned (void); + +GI_TEST_EXTERN +char **regress_annotation_string_zero_terminated (void); + +GI_TEST_EXTERN +void regress_annotation_string_zero_terminated_out (char ***out); + +GI_TEST_EXTERN +void regress_annotation_string_array_length (guint n_properties, const gchar *const properties[]); + +GI_TEST_EXTERN +void regress_annotation_object_extra_annos (RegressAnnotationObject *object); + +GI_TEST_EXTERN +void regress_annotation_custom_destroy (RegressAnnotationCallback callback, + RegressAnnotationNotifyFunc destroy, + gpointer data); + +GI_TEST_EXTERN +char *regress_annotation_get_source_file (void); + +GI_TEST_EXTERN +void regress_annotation_set_source_file (const char *fname); + +GI_TEST_EXTERN +gint regress_annotation_attribute_func (RegressAnnotationObject *object, + const gchar *data); + +GI_TEST_EXTERN +void regress_annotation_invalid_regress_annotation (int foo); + +/** + * RegressAnnotationStruct: + * + * This is a test of an array of object in an field of a struct. + */ +struct RegressAnnotationStruct +{ + RegressAnnotationObject *objects[10]; +}; + +/** + * RegressAnnotationFields: + * @field1: Some documentation + * @arr: (array length=len): an array of length @len + * @len: the length of array + * + * This is a struct for testing field documentation and annotations + */ +struct RegressAnnotationFields +{ + int field1; + guchar *arr; + gulong len; + /** + * RegressAnnotationFields.field4: + * + * A new field, breaking ABI is fun! + * + * Since: 1.4 + */ + guint field4; +}; + +GI_TEST_EXTERN +void regress_annotation_ptr_array (GPtrArray *array); + +GI_TEST_EXTERN +GObject *regress_annotation_test_parsing_bug630862 (void); + +GI_TEST_EXTERN +void regress_annotation_space_after_comment_bug631690 (void); + +GI_TEST_EXTERN +gchar *regress_annotation_return_filename (void); + +GI_TEST_EXTERN +GObject *regress_annotation_transfer_floating (GObject *object); + +/* This one we can handle properly */ +#define REGRESS_ANNOTATION_CALCULATED_DEFINE (10 * 10) + +/** + * REGRESS_ANNOTATION_CALCULATED_LARGE: (value 10000000000UL) + * + * Constant to define a calculated large value + * + * Since: 1.4 + */ +#define REGRESS_ANNOTATION_CALCULATED_LARGE (1000 * G_GINT64_CONSTANT (10000000)) + +/** + * REGRESS_ANNOTATION_CALCULATED_LARGE_DIV: (value 1000000UL) + * + * Constant to define a calculated large value + */ +#define REGRESS_ANNOTATION_CALCULATED_LARGE_DIV (1000 / G_GINT64_CONSTANT (10000000)) diff --git a/subprojects/gobject-introspection-tests/docs/provenance.txt b/subprojects/gobject-introspection-tests/docs/provenance.txt new file mode 100644 index 000000000..d1bf79d96 --- /dev/null +++ b/subprojects/gobject-introspection-tests/docs/provenance.txt @@ -0,0 +1,103 @@ +This repository was split off of gobject-introspection at commit c39cb45. + +All commits not containing tests were pruned from the history using +git-filter-repo (https://github.com/newren/git-filter-repo/) at commit ac50405. + +Created by: + +$ git clone git@ssh.gitlab.gnome.org:GNOME/gobject-introspection.git gobject-introspection-tests +$ cd gobject-introspection-tests +$ git filter-repo --paths-from-file ../renames.txt +$ git filter-repo --invert-paths --paths-from-file ../removals.txt +$ git branch | grep -v main | xargs git branch -D +$ git tag | xargs git tag -d + +Contents of renames.txt: + +gir/everything.c==>everything.c +gir/everything.h==>everything.h +gir/gimarshallingtests.c==>gimarshallingtests.c +gir/gimarshallingtests.h==>gimarshallingtests.h +tests/everything/everything.c==>everything.c +tests/everything/everything.h==>everything.h +tests/everything/gitesttypes.c==>gitesttypes.c +tests/everything/gitesttypes.h==>gitesttypes.h +tests/gimarshallingtests.c==>gimarshallingtests.c +tests/gimarshallingtests.h==>gimarshallingtests.h +tests/gitestmacros.h==>gitestmacros.h +tests/parser/foo-object.h==>foo.h +tests/parser/foo.c==>foo.c +tests/parser/utility.c==>utility.c +tests/parser/utility.h==>utility.h +tests/scanner/annotation.c==>annotation.c +tests/scanner/annotation.h==>annotation.h +tests/scanner/drawable.c==>drawable.c +tests/scanner/drawable.h==>drawable.h +tests/scanner/everything.c==>everything.c +tests/scanner/everything.h==>everything.h +tests/scanner/foo-object.h==>foo.h +tests/scanner/foo.c==>foo.c +tests/scanner/foo.h==>foo.h +tests/scanner/regress.c==>regress.c +tests/scanner/regress.h==>regress.h +tests/scanner/warnlib.c==>warnlib.c +tests/scanner/warnlib.h==>warnlib.h +tests/scanner/utility.c==>utility.c +tests/scanner/utility.h==>utility.h +tests/types/gitesttypes.c==>gitesttypes.c +tests/types/gitesttypes.h==>gitesttypes.h + +Contents of removals.txt: + +glob:*.am +glob:*.pc.in +glob:*.rst +glob:*.txt +.dir-locals.el +.flake8 +.gitignore +.gitlab-ci +.gitlab-ci.yml +.readthedocs.yaml +.topdeps +.topmsg +acinclude.m4 +AUTHORS +autogen.sh +build +ChangeLog +ChangeLog.pre-git +common.mk +config.h.win32.in +configure.ac +CONTRIBUTORS +COPYING.tools +docs +examples +g-ir-diff +gcov.mak +gidl +gidl.dtd +gir +girepository +giscanner +gobject-introspection.doap +gtk-doc-shave.patch +HACKING +m4 +MAINTAINERS +Makefile.introspection +meson.build +misc +mypy.ini +NEWS +README +README.msvc +relaxng +scripts +src +subprojects +tests +TODO +tools +win32 diff --git a/subprojects/gobject-introspection-tests/drawable.c b/subprojects/gobject-introspection-tests/drawable.c new file mode 100644 index 000000000..0c64159b3 --- /dev/null +++ b/subprojects/gobject-introspection-tests/drawable.c @@ -0,0 +1,64 @@ +/* +SPDX-FileCopyrightText: 2008 Colin Walters +SPDX-FileCopyrightText: 2008 Johan Bilien +SPDX-FileCopyrightText: 2008 Johan Dahlin +*/ + +#include "drawable.h" + +G_DEFINE_ABSTRACT_TYPE (RegressTestInheritDrawable, regress_test_inherit_drawable, G_TYPE_OBJECT); + +static void +regress_test_inherit_drawable_class_init (RegressTestInheritDrawableClass *klass G_GNUC_UNUSED) +{ +} + +static void +regress_test_inherit_drawable_init (RegressTestInheritDrawable *drawable G_GNUC_UNUSED) +{ +} + +void +regress_test_inherit_drawable_do_foo (RegressTestInheritDrawable *drawable G_GNUC_UNUSED, + int x G_GNUC_UNUSED) +{ +} + +/** + * regress_test_inherit_drawable_get_origin: + * @drawable: + * @x: (out): + * @y: (out): + */ +void +regress_test_inherit_drawable_get_origin (RegressTestInheritDrawable *drawable G_GNUC_UNUSED, + int *x, + int *y) +{ + *x = 0; + *y = 0; +} + +/** + * regress_test_inherit_drawable_get_size: + * @drawable: + * @width: (out): + * @height: (out): + */ +void +regress_test_inherit_drawable_get_size (RegressTestInheritDrawable *drawable G_GNUC_UNUSED, + guint *width, + guint *height) +{ + *width = 42; + *height = 42; +} + +void +regress_test_inherit_drawable_do_foo_maybe_throw (RegressTestInheritDrawable *drawable G_GNUC_UNUSED, + int x, + GError **error) +{ + if (x != 42) + g_set_error (error, 0, 12, "The answer should be 42!"); +} diff --git a/subprojects/gobject-introspection-tests/drawable.h b/subprojects/gobject-introspection-tests/drawable.h new file mode 100644 index 000000000..95bd9dc79 --- /dev/null +++ b/subprojects/gobject-introspection-tests/drawable.h @@ -0,0 +1,47 @@ +/* +SPDX-FileCopyrightText: 2008 Colin Walters +SPDX-FileCopyrightText: 2008 Johan Bilien +SPDX-FileCopyrightText: 2008 Johan Dahlin +*/ + +#pragma once + +#include +#include + +#include "gitestmacros.h" + +typedef struct _RegressTestInheritDrawable RegressTestInheritDrawable; +typedef struct _RegressTestInheritDrawableClass RegressTestInheritDrawableClass; + +struct _RegressTestInheritDrawable +{ + GObject parent_instance; +}; + +struct _RegressTestInheritDrawableClass +{ + GObjectClass parent_class; +}; + +GI_TEST_EXTERN +GType regress_test_inherit_drawable_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +void regress_test_inherit_drawable_do_foo (RegressTestInheritDrawable *drawable, int x); + +GI_TEST_EXTERN +void regress_test_inherit_drawable_get_origin (RegressTestInheritDrawable *drawable, int *x, int *y); + +GI_TEST_EXTERN +void regress_test_inherit_drawable_get_size (RegressTestInheritDrawable *drawable, guint *width, guint *height); + +GI_TEST_EXTERN +void regress_test_inherit_drawable_do_foo_maybe_throw (RegressTestInheritDrawable *drawable, int x, GError **error); + +typedef struct _RegressTestInheritPixmapObjectClass RegressTestInheritPixmapObjectClass; + +struct _RegressTestInheritPixmapObjectClass +{ + RegressTestInheritDrawableClass parent_class; +}; diff --git a/subprojects/gobject-introspection-tests/foo.c b/subprojects/gobject-introspection-tests/foo.c new file mode 100644 index 000000000..ad5b2c318 --- /dev/null +++ b/subprojects/gobject-introspection-tests/foo.c @@ -0,0 +1,853 @@ +/* +SPDX-FileCopyrightText: 2007-2010 Johan Dahlin +SPDX-FileCopyrightText: 2008-2010 Colin Walters +SPDX-FileCopyrightText: 2008 Jürg Billeter +SPDX-FileCopyrightText: 2008 Philip Van Hoof +SPDX-FileCopyrightText: 2009, 2011-2012 Dan Winship +SPDX-FileCopyrightText: 2010 Collabora, Ltd. +SPDX-FileCopyrightText: 2010 litl, LLC +SPDX-FileCopyrightText: 2010 Sugar Labs +SPDX-FileCopyrightText: 2011 Owen Taylor +SPDX-FileCopyrightText: 2011 Red Hat, Inc. +SPDX-FileCopyrightText: 2011 Torsten Schönfeld +SPDX-FileCopyrightText: 2018 Christoph Reiter +SPDX-FileCopyrightText: 2020 Centricular +SPDX-FileCopyrightText: 2024 Simon McVittie +*/ + +#include + +#include "foo.h" + +/** + * SECTION:standalone_section + * + * This documentation section isn't associated with an object + * in particular, but it should be serialized in the gir nevertheless. + */ + +/* A hidden type not exposed publicly, similar to GUPNP's XML wrapper + object */ +typedef struct _RegressFooHidden RegressFooHidden; + +int regress_foo_init_argv (int argc, char **argv); +int regress_foo_init_argv_address (int *argc, char ***argv); +void regress_foo_private_function (RegressFooObject *regress_foo); +void regress_foo_test_unsigned (unsigned int uint); +void regress_foo_do_regress_foo (RegressFooInterface *self, int x); +int regress_foo_enum_method (RegressFooEnumType regress_foo_enum); +RegressFooHidden *regress_foo_hidden_copy (const RegressFooHidden *boxed); +void regress_foo_hidden_free (RegressFooHidden *boxed); +GType regress_foo_hidden_get_type (void); +RegressFooBoxed *regress_foo_boxed_copy (const RegressFooBoxed *boxed); +void regress_foo_boxed_free (RegressFooBoxed *boxed); +void regress_foo_dbus_data_free (RegressFooDBusData *boxed); +RegressFooDBusData *regress_foo_dbus_data_copy (const RegressFooDBusData *boxed); + +typedef struct +{ + int i; +} PrivateStruct; + +void +regress_foo_private_function (RegressFooObject *regress_foo G_GNUC_UNUSED) +{ +} + +GType +regress_foo_interface_get_type (void) +{ + static GType object_type = 0; + + if (!object_type) + { + object_type = g_type_register_static_simple (G_TYPE_INTERFACE, + "RegressFooInterface", + sizeof (RegressFooInterfaceIface), + NULL, 0, NULL, 0); + + g_type_interface_add_prerequisite (object_type, G_TYPE_OBJECT); + } + + return object_type; +} + +void +regress_foo_interface_do_regress_foo (RegressFooInterface *self, int x) +{ + REGRESS_FOO_INTERFACE_GET_INTERFACE (self)->do_regress_foo (self, x); +} + +void +regress_foo_interface_static_method (int x G_GNUC_UNUSED) +{ +} + +enum +{ + PROP_0, + PROP_STRING, + PROP_HIDDEN +}; + +enum +{ + SIGNAL, + LAST_SIGNAL +}; + +static guint regress_foo_object_signals[LAST_SIGNAL] = { 0 }; + +static void +regress_foo_regress_foo_interface_init (gpointer g_iface, + gpointer iface_data G_GNUC_UNUSED) +{ + RegressFooInterfaceIface *iface = (RegressFooInterfaceIface *) g_iface; + iface->do_regress_foo = regress_foo_do_regress_foo; +} + +enum +{ + SUBIFACE_DESTROY_EVENT, + SUBIFACE_LAST_SIGNAL +}; + +static void +regress_foo_sub_interface_class_init (gpointer g_class, gpointer class_data); + +static guint regress_foo_subiface_signals[SUBIFACE_LAST_SIGNAL] = { 0 }; + +GType +regress_foo_sub_interface_get_type (void) +{ + static GType object_type = 0; + + if (!object_type) + { + object_type = g_type_register_static_simple (G_TYPE_INTERFACE, + "RegressFooSubInterface", + sizeof (RegressFooSubInterfaceIface), + regress_foo_sub_interface_class_init, 0, NULL, 0); + + g_type_interface_add_prerequisite (object_type, REGRESS_FOO_TYPE_INTERFACE); + } + + return object_type; +} + +static void +regress_foo_sub_interface_class_init (gpointer g_class G_GNUC_UNUSED, + gpointer class_data G_GNUC_UNUSED) +{ + regress_foo_subiface_signals[SUBIFACE_DESTROY_EVENT] = + g_signal_new ("destroy-event", REGRESS_FOO_TYPE_SUBINTERFACE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (RegressFooSubInterfaceIface, destroy_event), + NULL, NULL, NULL, + G_TYPE_NONE, + 0, + G_TYPE_NONE); +} + +void +regress_foo_sub_interface_do_bar (RegressFooSubInterface *self) +{ + REGRESS_FOO_SUBINTERFACE_GET_INTERFACE (self)->do_bar (self); +} + +/** + * regress_foo_sub_interface_do_baz: + * @self: + * @callback: (scope call): + * @user_data: + */ +void +regress_foo_sub_interface_do_baz (RegressFooSubInterface *self, GCallback callback, gpointer user_data) +{ + REGRESS_FOO_SUBINTERFACE_GET_INTERFACE (self)->do_baz (self, callback, user_data); +} + +G_DEFINE_TYPE_EXTENDED (RegressFooObject, regress_foo_object, G_TYPE_OBJECT, 0, G_IMPLEMENT_INTERFACE (REGRESS_FOO_TYPE_INTERFACE, regress_foo_regress_foo_interface_init)); + +static void +regress_foo_object_set_property (GObject *object, + guint prop_id, + const GValue *value G_GNUC_UNUSED, + GParamSpec *pspec) +{ + switch (prop_id) + { + case PROP_STRING: + break; + case PROP_HIDDEN: + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +regress_foo_object_get_property (GObject *object, + guint prop_id, + GValue *value G_GNUC_UNUSED, + GParamSpec *pspec) +{ + switch (prop_id) + { + case PROP_STRING: + break; + case PROP_HIDDEN: + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +regress_foo_object_class_init (RegressFooObjectClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->set_property = regress_foo_object_set_property; + gobject_class->get_property = regress_foo_object_get_property; + + g_object_class_install_property (gobject_class, + PROP_STRING, + g_param_spec_string ("string", + "String nick", + "The String Property Blurb", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + g_object_class_install_property (gobject_class, + PROP_HIDDEN, + g_param_spec_boxed ("hidden", + "hidden property", + "should not be exposed", + regress_foo_hidden_get_type (), + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + regress_foo_object_signals[SIGNAL] = + g_signal_new ("signal", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + (GSignalCMarshaller) g_cclosure_marshal_STRING__OBJECT_POINTER, + G_TYPE_STRING, 2, G_TYPE_OBJECT, G_TYPE_POINTER); +} + +static void +regress_foo_object_init (RegressFooObject *object G_GNUC_UNUSED) +{ +} + +RegressFooObject * +regress_foo_object_new (void) +{ + return g_object_new (REGRESS_FOO_TYPE_OBJECT, NULL); +} + +GObject * +regress_foo_object_new_as_super (void) +{ + return g_object_new (REGRESS_FOO_TYPE_OBJECT, NULL); +} + +/** + * regress_foo_object_external_type: + * @object: a #RegressFooObject + * + * Returns: (transfer none): %NULL always + */ +UtilityObject * +regress_foo_object_external_type (RegressFooObject *object G_GNUC_UNUSED) +{ + return NULL; +} + +void +regress_foo_object_take_all (RegressFooObject *object G_GNUC_UNUSED, + int x G_GNUC_UNUSED, + ...) +{ +} + +void +regress_foo_do_regress_foo (RegressFooInterface *self G_GNUC_UNUSED, + int x G_GNUC_UNUSED) +{ +} + +void +regress_foo_object_is_it_time_yet (RegressFooObject *object G_GNUC_UNUSED, + time_t time G_GNUC_UNUSED) +{ +} + +void +regress_foo_object_seek (RegressFooObject *object G_GNUC_UNUSED, off_t offset G_GNUC_UNUSED) +{ +} + +/** + * regress_foo_object_new_cookie: (skip) + * @object: + * @target: + * + * Not sure why this test is here... + */ +RegressFooObjectCookie +regress_foo_object_new_cookie (RegressFooObject *object G_GNUC_UNUSED, + const char *target G_GNUC_UNUSED) +{ + return NULL; +} + +const char * +regress_foo_object_get_name (RegressFooObject *object G_GNUC_UNUSED) +{ + return "regress_foo"; +} + +char * +regress_foo_object_dup_name (RegressFooObject *object G_GNUC_UNUSED) +{ + return g_strdup ("regress_foo"); +} + +/** + * regress_foo_object_read: (virtual read_fn) + * @object: obj + * @offset: offset + * @length: length + * + * Read some stuff. + */ +void +regress_foo_object_read (RegressFooObject *object G_GNUC_UNUSED, + int offset G_GNUC_UNUSED, + int length G_GNUC_UNUSED) +{ +} + +/** + * regress_foo_object_skipped_method: (skip) + * @object: obj + * + * This is only useful from C. + */ +void +regress_foo_object_skipped_method (RegressFooObject *object G_GNUC_UNUSED) +{ +} + +G_DEFINE_ABSTRACT_TYPE (RegressFooSubobject, regress_foo_subobject, REGRESS_FOO_TYPE_OBJECT); + +static void +regress_foo_subobject_class_init (RegressFooSubobjectClass *klass G_GNUC_UNUSED) +{ +} + +static void +regress_foo_subobject_init (RegressFooSubobject *object G_GNUC_UNUSED) +{ +} + +/** + * regress_foo_object_get_default: + * + * This function is intended to match clutter_stage_get_default which + * uses a C sugar return type. + * + * Return value: (type RegressFooSubobject) (transfer none): The global #RegressFooSubobject + */ +RegressFooObject * +regress_foo_object_get_default (void) +{ + return NULL; +} + +int +regress_foo_init (void) +{ + return REGRESS_FOO_SUCCESS_INT; +} + +int +regress_foo_init_argv (int argc G_GNUC_UNUSED, + char **argv G_GNUC_UNUSED) +{ + return REGRESS_FOO_SUCCESS_INT; +} + +int +regress_foo_init_argv_address (int *argc G_GNUC_UNUSED, + char ***argv G_GNUC_UNUSED) +{ + return REGRESS_FOO_SUCCESS_INT; +} + +GType +regress_foo_enum_type_get_type (void) +{ + static GType etype = 0; + if (G_UNLIKELY (etype == 0)) + { + static const GEnumValue values[] = { + { REGRESS_FOO_ENUM_ALPHA, "REGRESS_FOO_ENUM_ALPHA", "alpha" }, + { REGRESS_FOO_ENUM_BETA, "REGRESS_FOO_ENUM_BETA", "beta" }, + { REGRESS_FOO_ENUM_DELTA, "REGRESS_FOO_ENUM_DELTA", "delta" }, + { 0, NULL, NULL } + }; + etype = g_enum_register_static (g_intern_static_string ("RegressFooEnumType"), values); + } + return etype; +} + +int +regress_foo_enum_method (RegressFooEnumType regress_foo_enum G_GNUC_UNUSED) +{ + return 0; +} + +GType +regress_foo_flags_type_get_type (void) +{ + static GType etype = 0; + if (G_UNLIKELY (etype == 0)) + { + static const GFlagsValue values[] = { + { REGRESS_FOO_FLAGS_FIRST, "REGRESS_FOO_FLAGS_FIRST", "first" }, + { REGRESS_FOO_FLAGS_SECOND, "REGRESS_FOO_FLAGS_SECOND", "second" }, + { REGRESS_FOO_FLAGS_THIRD, "REGRESS_FOO_FLAGS_THIRD", "third" }, + { 0, NULL, NULL } + }; + etype = g_flags_register_static (g_intern_static_string ("RegressFooFlagsType"), values); + } + return etype; +} + +struct _RegressFooBoxed +{ + int private; +}; + +RegressFooBoxed * +regress_foo_boxed_copy (const RegressFooBoxed *boxed) +{ +#if GLIB_CHECK_VERSION(2, 67, 5) + return (RegressFooBoxed *) g_memdup2 (boxed, sizeof (RegressFooBoxed)); +#else + return (RegressFooBoxed *) g_memdup (boxed, sizeof (RegressFooBoxed)); +#endif +} + +void +regress_foo_boxed_free (RegressFooBoxed *boxed) +{ + g_slice_free (RegressFooBoxed, boxed); +} + +GType +regress_foo_boxed_get_type (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_boxed_type_register_static ("RegressFooBoxed", + (GBoxedCopyFunc) regress_foo_boxed_copy, + (GBoxedFreeFunc) regress_foo_boxed_free); + return our_type; +} + +RegressFooBoxed * +regress_foo_boxed_new (void) +{ + return g_slice_new0 (RegressFooBoxed); +} + +void +regress_foo_boxed_method (RegressFooBoxed *boxed G_GNUC_UNUSED) +{ +} + +/* RegressFooDbus */ +struct _RegressFooDBusData +{ + double private; +}; + +RegressFooDBusData * +regress_foo_dbus_data_copy (const RegressFooDBusData *boxed) +{ +#if GLIB_CHECK_VERSION(2, 67, 5) + return (RegressFooDBusData *) g_memdup2 (boxed, sizeof (RegressFooDBusData)); +#else + return (RegressFooDBusData *) g_memdup (boxed, sizeof (RegressFooDBusData)); +#endif +} + +void +regress_foo_dbus_data_free (RegressFooDBusData *boxed) +{ + g_slice_free (RegressFooDBusData, boxed); +} + +GType +regress_foo_dbus_data_get_type (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_boxed_type_register_static ("RegressFooDBusData", + (GBoxedCopyFunc) regress_foo_dbus_data_copy, + (GBoxedFreeFunc) regress_foo_dbus_data_free); + return our_type; +} + +static RegressFooBRect * +regress_foo_brect_copy (const RegressFooBRect *boxed) +{ +#if GLIB_CHECK_VERSION(2, 67, 5) + return (RegressFooBRect *) g_memdup2 (boxed, sizeof (RegressFooBRect)); +#else + return (RegressFooBRect *) g_memdup (boxed, sizeof (RegressFooBRect)); +#endif +} + +GType +regress_foo_brect_get_type (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_boxed_type_register_static ("RegressFooBRect", + (GBoxedCopyFunc) regress_foo_brect_copy, + (GBoxedFreeFunc) g_free); + return our_type; +} + +static RegressFooBUnion * +regress_foo_bunion_copy (const RegressFooBUnion *boxed) +{ +#if GLIB_CHECK_VERSION(2, 67, 5) + return (RegressFooBUnion *) g_memdup2 (boxed, sizeof (RegressFooBUnion)); +#else + return (RegressFooBUnion *) g_memdup (boxed, sizeof (RegressFooBUnion)); +#endif +} + +GType +regress_foo_bunion_get_type (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_boxed_type_register_static ("RegressFooBUnion", + (GBoxedCopyFunc) regress_foo_bunion_copy, + (GBoxedFreeFunc) g_free); + return our_type; +} + +void +regress_foo_test_unsigned (unsigned int uint G_GNUC_UNUSED) +{ +} + +/** + * regress_foo_test_string_array: + * @array: (array zero-terminated=1): + */ +void +regress_foo_test_string_array (char **array G_GNUC_UNUSED) +{ +} + +/** + * regress_foo_test_string_array_with_g: + * @array: (array zero-terminated=1): + */ +void +regress_foo_test_string_array_with_g (gchar **array G_GNUC_UNUSED) +{ +} + +/** + * regress_foo_test_array: + * + * Returns: (element-type utf8) (transfer container): + */ +GArray * +regress_foo_test_array (void) +{ + return NULL; +} + +/** + * regress_foo_rectangle_new: (skip) + * + * This is a C convenience constructor; we have to (skip) + * it because it's not a boxed type. + */ +RegressFooRectangle * +regress_foo_rectangle_new (int x, int y, int width, int height) +{ + RegressFooRectangle *r = g_slice_new (RegressFooRectangle); + r->x = x; + r->y = y; + r->width = width; + r->height = height; + return r; +} + +/** + * regress_foo_rectangle_add: + * @r1: (inout): add to this rect + * @r2: source rectangle + */ +void +regress_foo_rectangle_add (RegressFooRectangle *r1 G_GNUC_UNUSED, + const RegressFooRectangle *r2 G_GNUC_UNUSED) +{ +} + +/* RegressFooHidden */ + +struct _RegressFooHidden +{ + char *frob; +}; + +RegressFooHidden * +regress_foo_hidden_copy (const RegressFooHidden *boxed) +{ +#if GLIB_CHECK_VERSION(2, 67, 5) + return (RegressFooHidden *) g_memdup2 (boxed, sizeof (RegressFooHidden)); +#else + return (RegressFooHidden *) g_memdup (boxed, sizeof (RegressFooHidden)); +#endif +} + +void +regress_foo_hidden_free (RegressFooHidden *boxed) +{ + g_slice_free (RegressFooHidden, boxed); +} + +GType +regress_foo_hidden_get_type (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_boxed_type_register_static ("RegressFooHidden", + (GBoxedCopyFunc) regress_foo_hidden_copy, + (GBoxedFreeFunc) regress_foo_hidden_free); + return our_type; +} + +GType +regress_foo_error_get_type (void) +{ + static GType etype = 0; + if (G_UNLIKELY (etype == 0)) + { + static const GEnumValue values[] = { + { REGRESS_FOO_ERROR_GOOD, "REGRESS_FOO_ERROR_GOOD", "good" }, + { REGRESS_FOO_ERROR_BAD, "REGRESS_FOO_ERROR_BAD", "bad" }, + { REGRESS_FOO_ERROR_UGLY, "REGRESS_FOO_ERROR_UGLY", "ugly" }, + { 0, NULL, NULL } + }; + etype = g_enum_register_static (g_intern_static_string ("RegressFooError"), values); + } + return etype; +} + +GQuark +regress_foo_error_quark (void) +{ + return g_quark_from_static_string ("regress_foo-error-quark"); +} + +void +regress_foo_some_variant (guint x G_GNUC_UNUSED, + va_list args G_GNUC_UNUSED) +{ +} + +GType regress_foo_tile_handler_get_type (void); + +/* This setup of a totally hidden parent class matches + * http://bugzilla.gnome.org/show_bug.cgi?id=561360 + */ +#define REGRESS_FOO_TYPE_TILE_HANDLER (regress_foo_tile_handler_get_type ()) +#define REGRESS_FOO_TILE_HANDLER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), REGRESS_FOO_TYPE_TILE_HANDLER, RegressFooTileHandler)) +#define REGRESS_FOO_IS_TILE_HANDLER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), REGRESS_FOO_TYPE_TILE_HANDLER)) + +struct _RegressFooTileHandler +{ + RegressFooObject parent_instance; +}; + +struct _RegressFooTileHandlerClass +{ + RegressFooObjectClass parent_class; +}; + +typedef struct _RegressFooTileHandler RegressFooTileHandler; +typedef struct _RegressFooTileHandlerClass RegressFooTileHandlerClass; + +G_DEFINE_TYPE (RegressFooTileHandler, regress_foo_tile_handler, REGRESS_FOO_TYPE_OBJECT); + +static void +regress_foo_tile_handler_class_init (RegressFooTileHandlerClass *klass G_GNUC_UNUSED) +{ +} + +static void +regress_foo_tile_handler_init (RegressFooTileHandler *object G_GNUC_UNUSED) +{ +} + +struct _RegressFooBuffer +{ + RegressFooTileHandler parent_instance; +}; + +struct _RegressFooBufferClass +{ + RegressFooTileHandlerClass parent_class; +}; + +G_DEFINE_TYPE (RegressFooBuffer, regress_foo_buffer, REGRESS_FOO_TYPE_TILE_HANDLER); + +static void +regress_foo_buffer_class_init (RegressFooBufferClass *klass G_GNUC_UNUSED) +{ +} + +static void +regress_foo_buffer_init (RegressFooBuffer *object G_GNUC_UNUSED) +{ +} + +void +regress_foo_buffer_some_method (RegressFooBuffer *buffer G_GNUC_UNUSED) +{ +} + +struct _RegressFooOtherObject +{ + GObject parent_instance; +}; + +struct _RegressFooOtherObjectClass +{ + GObjectClass parent_class; +}; + +G_DEFINE_TYPE (RegressFooOtherObject, regress_foo_other_object, G_TYPE_OBJECT); + +static void +regress_foo_other_object_class_init (RegressFooOtherObjectClass *klass G_GNUC_UNUSED) +{ +} + +static void +regress_foo_other_object_init (RegressFooOtherObject *object G_GNUC_UNUSED) +{ +} + +#define REGRESS_FOO_DEFINE_SHOULD_NOT_BE_EXPOSED "should not be exposed" + +/** + * regress_foo_skip_me: (skip) + * @fs: a #RegressFooSkippable + * + * Does something that's only interesting from C and should not be + * exposed to language bindings. + */ +void +regress_foo_skip_me (RegressFooSkippable fs G_GNUC_UNUSED) +{ +} + +/** + * RegressFooForeignStruct: (foreign) + * + */ + +RegressFooForeignStruct * +regress_foo_foreign_struct_new (void) +{ + return g_slice_new0 (RegressFooForeignStruct); +} + +RegressFooForeignStruct * +regress_foo_foreign_struct_copy (RegressFooForeignStruct *original) +{ + RegressFooForeignStruct *copy; + copy = regress_foo_foreign_struct_new (); + copy->regress_foo = original->regress_foo; + return copy; +} + +/** + * regress_foo_test_varargs_callback: (skip) + * + */ +void +regress_foo_test_varargs_callback (gint i G_GNUC_UNUSED, + RegressFooVarargsCallback callback G_GNUC_UNUSED) +{ +} + +/** + * regress_foo_test_varargs_callback2: (skip) + * + */ +void +regress_foo_test_varargs_callback2 (RegressFooVarargsCallback callback G_GNUC_UNUSED) +{ +} + +/** + * regress_foo_test_varargs_callback3: (skip) + * + */ +void +regress_foo_test_varargs_callback3 (RegressFooVarargsCallback callback G_GNUC_UNUSED, + RegressFooVarargsCallback callback2 G_GNUC_UNUSED) +{ +} + +/** + * regress_foo_object_append_new_stack_layer: + * + * This shouldn't be scanned as a constructor. + * + * Returns: (transfer none): + */ +RegressFooOtherObject * +regress_foo_object_append_new_stack_layer (RegressFooObject *obj G_GNUC_UNUSED, + int x G_GNUC_UNUSED) +{ + return NULL; +} + +/** + * regress_foo_not_a_constructor_new: + * + * This should be scanned as a top-level function, and shouldn't cause + * a "Can't find matching type for constructor" warning. + * + * Returns: (transfer none): + */ +RegressFooObject * +regress_foo_not_a_constructor_new (void) +{ + return NULL; +} diff --git a/subprojects/gobject-introspection-tests/foo.h b/subprojects/gobject-introspection-tests/foo.h new file mode 100644 index 000000000..baaf92384 --- /dev/null +++ b/subprojects/gobject-introspection-tests/foo.h @@ -0,0 +1,563 @@ +/* +SPDX-FileCopyrightText: 2007-2010 Johan Dahlin +SPDX-FileCopyrightText: 2008-2010 Colin Walters +SPDX-FileCopyrightText: 2008-2009, 2011-2012 Dan Winship +SPDX-FileCopyrightText: 2008 Jürg Billeter +SPDX-FileCopyrightText: 2008 Lucas Rocha +SPDX-FileCopyrightText: 2008 Marc-Andre Lureau +SPDX-FileCopyrightText: 2008 Philip Van Hoof +SPDX-FileCopyrightText: 2008 Tommi Komulainen +SPDX-FileCopyrightText: 2009 Andreas Rottmann +SPDX-FileCopyrightText: 2009 Robert Carr +SPDX-FileCopyrightText: 2010 Collabora, Ltd. +SPDX-FileCopyrightText: 2010 litl, LLC +SPDX-FileCopyrightText: 2010 Sugar Labs +SPDX-FileCopyrightText: 2011 Red Hat, Inc. +SPDX-FileCopyrightText: 2011 Torsten Schönfeld +SPDX-FileCopyrightText: 2018 Philip Chimento +SPDX-FileCopyrightText: 2018 Tomasz Miąsko +SPDX-FileCopyrightText: 2024 Simon McVittie +*/ + +#pragma once + +#include +#include /* off_t, time_t */ + +#include /* GAsyncReadyCallback */ +#include +#include + +#include "gitestmacros.h" +#include "utility.h" + +#define REGRESS_FOO_SUCCESS_INT 0x1138 + +#define REGRESS_FOO_DEFINE_SHOULD_BE_EXPOSED "should be exposed" + +#define REGRESS_FOO_PIE_IS_TASTY 3.14159 + +#define REGRESS_FOO_TYPE_INTERFACE (regress_foo_interface_get_type ()) +#define REGRESS_FOO_INTERFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), REGRESS_FOO_TYPE_INTERFACE, RegressFooInterface)) +#define REGRESS_FOO_IS_INTERFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), REGRESS_FOO_TYPE_INTERFACE)) +#define REGRESS_FOO_INTERFACE_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), REGRESS_FOO_TYPE_INTERFACE, RegressFooInterfaceIface)) + +#define REGRESS_FOO_TYPE_SUBINTERFACE (regress_foo_sub_interface_get_type ()) +#define REGRESS_FOO_SUBINTERFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), REGRESS_FOO_TYPE_SUBINTERFACE, RegressFooSubInterface)) +#define REGRESS_FOO_IS_SUBINTERFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), REGRESS_FOO_TYPE_SUBINTERFACE)) +#define REGRESS_FOO_SUBINTERFACE_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), REGRESS_FOO_TYPE_SUBINTERFACE, RegressFooSubInterfaceIface)) + +#define REGRESS_FOO_TYPE_OBJECT (regress_foo_object_get_type ()) +#define REGRESS_FOO_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), REGRESS_FOO_TYPE_OBJECT, RegressFooObject)) +#define REGRESS_FOO_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), REGRESS_FOO_TYPE_OBJECT)) + +#define REGRESS_FOO_TYPE_SUBOBJECT (regress_foo_subobject_get_type ()) +#define REGRESS_FOO_SUBOBJECT(subobject) (G_TYPE_CHECK_INSTANCE_CAST ((subobject), REGRESS_FOO_TYPE_SUBOBJECT, RegressFooSubobject)) +#define REGRESS_FOO_IS_SUBOBJECT(subobject) (G_TYPE_CHECK_INSTANCE_TYPE ((subobject), REGRESS_FOO_TYPE_SUBOBJECT)) + +#define REGRESS_FOO_TYPE_BUFFER (regress_foo_buffer_get_type ()) +#define REGRESS_FOO_BUFFER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), REGRESS_FOO_TYPE_BUFFER, RegressFooBuffer)) +#define REGRESS_FOO_IS_BUFFER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), REGRESS_FOO_TYPE_BUFFER)) + +#define REGRESS_FOO_TYPE_OTHER_OBJECT (regress_foo_other_object_get_type ()) +#define REGRESS_FOO_OTHER_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), REGRESS_FOO_TYPE_OTHER_OBJECT, RegressFooOtherObject)) +#define REGRESS_FOO_IS_OTHER_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), REGRESS_FOO_TYPE_OTHER_OBJECT)) + +typedef struct _RegressFooInterface RegressFooInterface; +typedef struct _RegressFooInterfaceIface RegressFooInterfaceIface; +typedef struct _RegressFooSubInterface RegressFooSubInterface; +typedef struct _RegressFooSubInterfaceIface RegressFooSubInterfaceIface; +typedef struct _RegressFooObject RegressFooObject; +typedef struct _RegressFooObjectClass RegressFooObjectClass; +typedef struct _RegressFooSubobject RegressFooSubobject; +typedef struct _RegressFooSubobjectClass RegressFooSubobjectClass; +typedef struct _RegressFooBuffer RegressFooBuffer; +typedef struct _RegressFooBufferClass RegressFooBufferClass; +typedef struct _RegressFooOtherObject RegressFooOtherObject; +typedef struct _RegressFooOtherObjectClass RegressFooOtherObjectClass; + +struct _RegressFooInterfaceIface +{ + GTypeInterface parent_iface; + + void (*do_regress_foo) (RegressFooInterface *self, int x); +}; + +GI_TEST_EXTERN +GType regress_foo_interface_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +void regress_foo_interface_do_regress_foo (RegressFooInterface *iface, int x); + +GI_TEST_EXTERN +void regress_foo_interface_static_method (int x); + +struct _RegressFooSubInterfaceIface +{ + GTypeInterface parent_iface; + + /* signals */ + + void (*destroy_event) (RegressFooSubInterface *self); + + /* virtual table */ + + void (*do_bar) (RegressFooSubInterface *self); + + void (*do_baz) (RegressFooSubInterface *self, GCallback callback, gpointer user_data); +}; + +GI_TEST_EXTERN +GType regress_foo_sub_interface_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +void regress_foo_sub_interface_do_bar (RegressFooSubInterface *self); + +GI_TEST_EXTERN +void regress_foo_sub_interface_do_baz (RegressFooSubInterface *self, + GCallback callback, + gpointer user_data); + +struct _RegressFooObject +{ + GObject parent_instance; + + int some_int; +}; + +struct _RegressFooObjectClass +{ + GObjectClass parent_class; + + gboolean (*virtual_method) (RegressFooObject *object, int first_param); + + /* Intended to match GFile */ + void (*read_fn) (RegressFooObject *object, int offset, int length); + + /* Test reserved stuff */ + GCallback _reserved[4]; +}; + +GI_TEST_EXTERN +gint regress_foo_init (void); + +GI_TEST_EXTERN +GType regress_foo_object_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +RegressFooObject *regress_foo_object_new (void); + +GI_TEST_EXTERN +UtilityObject *regress_foo_object_external_type (RegressFooObject *object); + +GI_TEST_EXTERN +GObject *regress_foo_object_new_as_super (void); + +GI_TEST_EXTERN +void regress_foo_object_various (RegressFooObject *object, void *data, GType some_type); + +GI_TEST_EXTERN +void regress_foo_object_take_all (RegressFooObject *object, int x, ...); + +typedef gpointer RegressFooObjectCookie; + +GI_TEST_EXTERN +RegressFooObjectCookie regress_foo_object_new_cookie (RegressFooObject *object, const char *target); + +GI_TEST_EXTERN +void regress_foo_object_is_it_time_yet (RegressFooObject *object, time_t time); + +GI_TEST_EXTERN +void regress_foo_object_seek (RegressFooObject *object, off_t offset); + +GI_TEST_EXTERN +const char *regress_foo_object_get_name (RegressFooObject *object); + +GI_TEST_EXTERN +char *regress_foo_object_dup_name (RegressFooObject *object); + +GI_TEST_EXTERN +void regress_foo_object_handle_glyph (RegressFooObject *object, UtilityGlyph glyph); + +GI_TEST_EXTERN +gboolean regress_foo_object_virtual_method (RegressFooObject *object, int first_param); + +GI_TEST_EXTERN +void regress_foo_object_read (RegressFooObject *object, int offset, int length); + +GI_TEST_EXTERN +int regress_foo_object_static_meth (void); + +GI_TEST_EXTERN +void regress_foo_object_skipped_method (RegressFooObject *object); + +struct _RegressFooSubobject +{ + RegressFooObject parent_instance; +}; + +struct _RegressFooSubobjectClass +{ + RegressFooObjectClass parent_class; +}; + +GI_TEST_EXTERN +GType regress_foo_subobject_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +RegressFooSubobject *regress_foo_subobject_new (void); + +GI_TEST_EXTERN +RegressFooObject *regress_foo_object_get_default (void); + +GI_TEST_EXTERN +GType regress_foo_buffer_get_type (void); + +GI_TEST_EXTERN +void regress_foo_buffer_some_method (RegressFooBuffer *buffer); + +GI_TEST_EXTERN +GType regress_foo_other_object_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +RegressFooObject *regress_foo_not_a_constructor_new (void); + +typedef enum +{ + REGRESS_FOO_ENUM_ALPHA, + REGRESS_FOO_ENUM_BETA, + REGRESS_FOO_ENUM_DELTA +} RegressFooEnumType; + +GI_TEST_EXTERN +GType regress_foo_enum_type_get_type (void); + +GI_TEST_EXTERN +int regress_foo_enum_type_method (RegressFooEnumType regress_foo_enum); + +GI_TEST_EXTERN +RegressFooEnumType regress_foo_enum_type_returnv (int x); + +typedef enum +{ + REGRESS_FOO_FLAGS_FIRST = 1 << 0, + REGRESS_FOO_FLAGS_SECOND = 1 << 1, + REGRESS_FOO_FLAGS_THIRD = 1 << 2 +} RegressFooFlagsType; + +#define REGRESS_FOO_FLAGS_SECOND_AND_THIRD (REGRESS_FOO_FLAGS_SECOND | REGRESS_FOO_FLAGS_THIRD) + +GI_TEST_EXTERN +GType regress_foo_flags_type_get_type (void); + +typedef enum +{ + REGRESS_FOO_ENUM_UN = 1, + REGRESS_FOO_ENUM_DEUX = 2, + REGRESS_FOO_ENUM_TROIS = 3, + REGRESS_FOO_ENUM_NEUF = 9 +} RegressFooEnumNoType; + +typedef enum +{ + REGRESS_FOO_FLAGS_ETT = 1 << 0, + REGRESS_FOO_FLAGS_TVA = 1 << 1, + REGRESS_FOO_FLAGS_FYRA = 1 << 2 +} RegressFooFlagsNoType; + +typedef enum +{ + REGRESS_FOO_ENUM_FULLNAME_ONE = 1, + REGRESS_FOO_ENUM_FULLNAME_TWO, + REGRESS_FOO_ENUM_FULLNAME_THREE +} RegressFooEnumFullname; + +typedef enum +{ + REGRESS_FOO_ADDRESS_INVALID, + REGRESS_FOO_ADDRESS_IPV4, + REGRESS_FOO_ADDRESS_IPV6 +} RegressFooAddressType; + +typedef struct _RegressFooBoxed RegressFooBoxed; + +GI_TEST_EXTERN +GType regress_foo_boxed_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +RegressFooBoxed *regress_foo_boxed_new (void); + +GI_TEST_EXTERN +void regress_foo_boxed_method (RegressFooBoxed *boxed); + +/* This one tests capitalization handling with respect to DBus */ +typedef struct _RegressFooDBusData RegressFooDBusData; + +GI_TEST_EXTERN +GType regress_foo_dbus_data_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +void regress_foo_dbus_data_method (RegressFooDBusData *dbusdata); + +/* FIXME: Scanner does not support this yet + +GI_TEST_EXTERN +const char *REGRESS_FOO_CONSTANT_STR = "regress_foo-constant-str"; + +GI_TEST_EXTERN +const int REGRESS_FOO_CONSTANT_INT = 10; + +GI_TEST_EXTERN +const float REGRESS_FOO_CONSTANT_FLOAT = 10; +*/ + +/* Callback */ +typedef gboolean (*RegressFooCallback) (RegressFooObject *regress_foo, gboolean b, gpointer data); + +/* Invalid comments, should be ignored */ + +/* @ */ +/* @: */ + +typedef struct _RegressFooStruct RegressFooStruct; +typedef struct _RegressFooStructPrivate RegressFooStructPrivate; + +struct _RegressFooStruct +{ + RegressFooStructPrivate *priv; + int member; +}; + +typedef struct _RegressFooRectangle RegressFooRectangle; + +struct _RegressFooRectangle +{ + gint x; + gint y; + gint width; + gint height; +}; + +GI_TEST_EXTERN +void +regress_foo_method_external_references (UtilityObject *object, + UtilityEnumType e, + UtilityFlagType f, + UtilityStruct s); + +GI_TEST_EXTERN +void regress_foo_rectangle_add (RegressFooRectangle *r1, const RegressFooRectangle *r2); + +GI_TEST_EXTERN +RegressFooRectangle *regress_foo_rectangle_new (int x, int y, int width, int height); + +typedef struct _RegressFooEventAny RegressFooEventAny; +typedef struct _RegressFooEventExpose RegressFooEventExpose; + +typedef union _RegressFooEvent RegressFooEvent; + +struct _RegressFooEventAny +{ + gint8 send_event; +}; + +struct _RegressFooEventExpose +{ + gint8 send_event; + gint count; +}; + +union _RegressFooEvent +{ + int type; + RegressFooEventAny any; + RegressFooEventExpose expose; +}; + +typedef void RegressFooXEvent; + +/* And now some boxed variants */ + +typedef struct _RegressFooBRect RegressFooBRect; + +struct _RegressFooBRect +{ + double x; + double y; +}; + +GI_TEST_EXTERN +GType regress_foo_brect_get_type (void); + +GI_TEST_EXTERN +RegressFooBRect *regress_foo_brect_new (double x, double y); + +GI_TEST_EXTERN +void regress_foo_brect_add (RegressFooBRect *b1, RegressFooBRect *b2); + +typedef union _RegressFooBUnion RegressFooBUnion; + +union _RegressFooBUnion +{ + int type; + double v; + RegressFooBRect *rect; +}; + +typedef union _RegressFooUnion RegressFooUnion; + +union _RegressFooUnion +{ + int regress_foo; +}; + +typedef struct _RegressFooUtilityStruct RegressFooUtilityStruct; +struct _RegressFooUtilityStruct +{ + UtilityStruct bar; +}; + +typedef struct _RegressFooThingWithArray RegressFooThingWithArray; +struct _RegressFooThingWithArray +{ + int x; + int y; + char lines[80]; + guchar *data; +}; + +GI_TEST_EXTERN +RegressFooBUnion *regress_foo_bunion_new (void); + +GI_TEST_EXTERN +GType regress_foo_bunion_get_type (void); + +GI_TEST_EXTERN +int regress_foo_bunion_get_contained_type (RegressFooBUnion *bunion); + +GI_TEST_EXTERN +void regress_foo_test_unsigned_qualifier (unsigned int unsigned_param); + +GI_TEST_EXTERN +void regress_foo_test_unsigned_type (unsigned unsigned_param); + +GI_TEST_EXTERN +void regress_foo_test_string_array (char **array); + +GI_TEST_EXTERN +void regress_foo_test_string_array_with_g (gchar **array); + +GI_TEST_EXTERN +GArray *regress_foo_test_array (void); + +GI_TEST_EXTERN +const char *regress_foo_test_const_char_retval (void); + +GI_TEST_EXTERN +const RegressFooStruct *regress_foo_test_const_struct_retval (void); + +GI_TEST_EXTERN +void regress_foo_test_const_char_param (const char *param); + +GI_TEST_EXTERN +void regress_foo_test_const_struct_param (const RegressFooStruct *param); + +typedef void (*RegressFooVarargsCallback) (const char *param, ...); + +GI_TEST_EXTERN +void regress_foo_test_varargs_callback (gint i, RegressFooVarargsCallback callback); + +GI_TEST_EXTERN +void regress_foo_test_varargs_callback2 (RegressFooVarargsCallback callback); + +GI_TEST_EXTERN +void regress_foo_test_varargs_callback3 (RegressFooVarargsCallback callback, + RegressFooVarargsCallback callback2); + +/* Make sure callbacks get the right scope by default */ +GI_TEST_EXTERN +void regress_foo_async_ready_callback (GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GI_TEST_EXTERN +void regress_foo_destroy_notify_callback (RegressFooCallback callback, + gpointer data, + GDestroyNotify destroy); + +typedef enum +{ + REGRESS_FOO_ERROR_GOOD, + REGRESS_FOO_ERROR_BAD, + REGRESS_FOO_ERROR_UGLY +} RegressFooError; + +GI_TEST_EXTERN +GType regress_foo_error_get_type (void); + +GI_TEST_EXTERN +GQuark regress_foo_error_quark (void); + +typedef enum +{ + REGRESS_FOO_LAYER_DESKTOP = 0, + REGRESS_FOO_LAYER_BOTTOM = 1, + REGRESS_FOO_LAYER_NORMAL = 2, + REGRESS_FOO_LAYER_TOP = 4, /* Same as DOCK; see EWMH and bug 330717 */ + REGRESS_FOO_LAYER_DOCK = 4, + REGRESS_FOO_LAYER_FULLSCREEN = 5, + REGRESS_FOO_LAYER_FOCUSED_WINDOW = 6, + REGRESS_FOO_LAYER_OVERRIDE_REDIRECT = 7, + REGRESS_FOO_LAYER_LAST = 8 +} RegressFooStackLayer; + +typedef enum +{ + REGRESS_FOO_SOME_SINGLE_ENUM +} RegressFooASingle; + +/* Should be skipped */ + +GI_TEST_EXTERN +void regress_foo_some_variant (guint x, va_list args); + +GI_TEST_EXTERN +void regress_foo_some_variant_ptr (guint x, va_list *args); + +/** + * RegressFooSkippable: (skip) + * @REGRESS_FOO_SKIPPABLE_ONE: a skippable enum value + * @REGRESS_FOO_SKIPPABLE_TWO: another skippable enum value + * + * Some type that is only interesting from C and should not be + * exposed to language bindings. + */ +typedef enum +{ + REGRESS_FOO_SKIPPABLE_ONE, + REGRESS_FOO_SKIPPABLE_TWO +} RegressFooSkippable; +void regress_foo_skip_me (RegressFooSkippable fs); + +typedef struct _RegressFooForeignStruct RegressFooForeignStruct; + +struct _RegressFooForeignStruct +{ + int regress_foo; +}; + +GI_TEST_EXTERN +RegressFooForeignStruct *regress_foo_foreign_struct_new (void); + +GI_TEST_EXTERN +RegressFooForeignStruct *regress_foo_foreign_struct_copy (RegressFooForeignStruct *original); + +/* This one should be a global, not a method on UtilityObject since + * it's a separate namespace. + */ + +GI_TEST_EXTERN +void regress_foo_object_a_global_method (UtilityObject *obj); + +GI_TEST_EXTERN +RegressFooOtherObject *regress_foo_object_append_new_stack_layer (RegressFooObject *obj, int x); diff --git a/subprojects/gobject-introspection-tests/gimarshallingtests.c b/subprojects/gobject-introspection-tests/gimarshallingtests.c new file mode 100644 index 000000000..9b9b1d4da --- /dev/null +++ b/subprojects/gobject-introspection-tests/gimarshallingtests.c @@ -0,0 +1,7316 @@ +/* +SPDX-FileCopyrightText: 2010-2012 Collabora, Ltd. +SPDX-FileCopyrightText: 2010 Johan Dahlin +SPDX-FileCopyrightText: 2010 Sugar Labs +SPDX-FileCopyrightText: 2010 Zach Goldberg +SPDX-FileCopyrightText: 2011 Alex Eftimie +SPDX-FileCopyrightText: 2011-2012 Canonical Ltd. +SPDX-FileCopyrightText: 2011-2012 Colin Walters +SPDX-FileCopyrightText: 2011 Dan Winship +SPDX-FileCopyrightText: 2011-2012 Giovanni Campagna +SPDX-FileCopyrightText: 2011 Ignacio Casal Quinteiro +SPDX-FileCopyrightText: 2011-2012 Jasper St. Pierre +SPDX-FileCopyrightText: 2011 Laszlo Pandy +SPDX-FileCopyrightText: 2011 Red Hat, Inc. +SPDX-FileCopyrightText: 2012 Bastian Winkler +SPDX-FileCopyrightText: 2012 Epitech +SPDX-FileCopyrightText: 2012 Gonzalo Odiard +SPDX-FileCopyrightText: 2012-2013 Martin Pitt +SPDX-FileCopyrightText: 2012-2013 Paolo Borelli +SPDX-FileCopyrightText: 2012 Sebastian Pölsterl +SPDX-FileCopyrightText: 2013 Simon Feltman +SPDX-FileCopyrightText: 2014 Lionel Landwerlin +SPDX-FileCopyrightText: 2014 RIFT.io, Inc. +SPDX-FileCopyrightText: 2014 SuSE +SPDX-FileCopyrightText: 2016 Endless Mobile, Inc. +SPDX-FileCopyrightText: 2016-2018, 2023 Philip Chimento +SPDX-FileCopyrightText: 2017 Christoph Reiter +SPDX-FileCopyrightText: 2018 Tomasz Miąsko +SPDX-FileCopyrightText: 2019 Stéphane Seng +SPDX-FileCopyrightText: 2020-2023 Marco Trevisan +SPDX-FileCopyrightText: 2020, 2024 Simon McVittie +SPDX-FileCopyrightText: 2021 Carlos Garnacho +*/ + +#include + +#include "gimarshallingtests.h" + +static void gi_marshalling_tests_boxed_struct_free (GIMarshallingTestsBoxedStruct *v); + +/* Booleans */ + +gboolean +gi_marshalling_tests_boolean_return_true (void) +{ + return TRUE; +} + +gboolean +gi_marshalling_tests_boolean_return_false (void) +{ + return FALSE; +} + +void +gi_marshalling_tests_boolean_in_true (gboolean v) +{ + g_assert (v == TRUE); +} + +void +gi_marshalling_tests_boolean_in_false (gboolean v) +{ + g_assert (v == FALSE); +} + +/** + * gi_marshalling_tests_boolean_out_true: + * @v: (out): + */ +void +gi_marshalling_tests_boolean_out_true (gboolean *v) +{ + *v = TRUE; +} + +/** + * gi_marshalling_tests_boolean_out_false: + * @v: (out): + */ +void +gi_marshalling_tests_boolean_out_false (gboolean *v) +{ + *v = FALSE; +} + +/** + * gi_marshalling_tests_boolean_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_boolean_out_uninitialized (gboolean *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_boolean_inout_true_false: + * @v: (inout): + */ +void +gi_marshalling_tests_boolean_inout_true_false (gboolean *v) +{ + g_assert (*v == TRUE); + *v = FALSE; +} + +/** + * gi_marshalling_tests_boolean_inout_false_true: + * @v: (inout): + */ +void +gi_marshalling_tests_boolean_inout_false_true (gboolean *v) +{ + g_assert (*v == FALSE); + *v = TRUE; +} + +/* Integers */ + +gint8 +gi_marshalling_tests_int8_return_max (void) +{ + return G_MAXINT8; +} + +gint8 +gi_marshalling_tests_int8_return_min (void) +{ + return G_MININT8; +} + +void +gi_marshalling_tests_int8_in_max (gint8 v) +{ + g_assert_cmpint (v, ==, G_MAXINT8); +} + +void +gi_marshalling_tests_int8_in_min (gint8 v) +{ + g_assert_cmpint (v, ==, G_MININT8); +} + +/** + * gi_marshalling_tests_int8_out_max: + * @v: (out): + */ +void +gi_marshalling_tests_int8_out_max (gint8 *v) +{ + *v = G_MAXINT8; +} + +/** + * gi_marshalling_tests_int8_out_min: + * @v: (out): + */ +void +gi_marshalling_tests_int8_out_min (gint8 *v) +{ + *v = G_MININT8; +} + +/** + * gi_marshalling_tests_int8_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_int8_out_uninitialized (gint8 *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_int8_inout_max_min: + * @v: (inout): + */ +void +gi_marshalling_tests_int8_inout_max_min (gint8 *v) +{ + g_assert_cmpint (*v, ==, G_MAXINT8); + *v = G_MININT8; +} + +/** + * gi_marshalling_tests_int8_inout_min_max: + * @v: (inout): + */ +void +gi_marshalling_tests_int8_inout_min_max (gint8 *v) +{ + g_assert_cmpint (*v, ==, G_MININT8); + *v = G_MAXINT8; +} + +guint8 +gi_marshalling_tests_uint8_return (void) +{ + return G_MAXUINT8; +} + +void +gi_marshalling_tests_uint8_in (guint8 v) +{ + g_assert_cmpuint (v, ==, G_MAXUINT8); +} + +/** + * gi_marshalling_tests_uint8_out: + * @v: (out): + */ +void +gi_marshalling_tests_uint8_out (guint8 *v) +{ + *v = G_MAXUINT8; +} + +/** + * gi_marshalling_tests_uint8_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_uint8_out_uninitialized (guint8 *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_uint8_inout: + * @v: (inout): + */ +void +gi_marshalling_tests_uint8_inout (guint8 *v) +{ + g_assert_cmpuint (*v, ==, G_MAXUINT8); + *v = 0; +} + +gint16 +gi_marshalling_tests_int16_return_max (void) +{ + return G_MAXINT16; +} + +gint16 +gi_marshalling_tests_int16_return_min (void) +{ + return G_MININT16; +} + +void +gi_marshalling_tests_int16_in_max (gint16 v) +{ + g_assert_cmpint (v, ==, G_MAXINT16); +} + +void +gi_marshalling_tests_int16_in_min (gint16 v) +{ + g_assert_cmpint (v, ==, G_MININT16); +} + +/** + * gi_marshalling_tests_int16_out_max: + * @v: (out): + */ +void +gi_marshalling_tests_int16_out_max (gint16 *v) +{ + *v = G_MAXINT16; +} + +/** + * gi_marshalling_tests_int16_out_min: + * @v: (out): + */ +void +gi_marshalling_tests_int16_out_min (gint16 *v) +{ + *v = G_MININT16; +} + +/** + * gi_marshalling_tests_int16_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_int16_out_uninitialized (gint16 *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_int16_inout_max_min: + * @v: (inout): + */ +void +gi_marshalling_tests_int16_inout_max_min (gint16 *v) +{ + g_assert_cmpint (*v, ==, G_MAXINT16); + *v = G_MININT16; +} + +/** + * gi_marshalling_tests_int16_inout_min_max: + * @v: (inout): + */ +void +gi_marshalling_tests_int16_inout_min_max (gint16 *v) +{ + g_assert_cmpint (*v, ==, G_MININT16); + *v = G_MAXINT16; +} + +guint16 +gi_marshalling_tests_uint16_return (void) +{ + return G_MAXUINT16; +} + +void +gi_marshalling_tests_uint16_in (guint16 v) +{ + g_assert_cmpuint (v, ==, G_MAXUINT16); +} + +/** + * gi_marshalling_tests_uint16_out: + * @v: (out): + */ +void +gi_marshalling_tests_uint16_out (guint16 *v) +{ + *v = G_MAXUINT16; +} + +/** + * gi_marshalling_tests_uint16_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_uint16_out_uninitialized (guint16 *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_uint16_inout: + * @v: (inout): + */ +void +gi_marshalling_tests_uint16_inout (guint16 *v) +{ + g_assert_cmpuint (*v, ==, G_MAXUINT16); + *v = 0; +} + +gint32 +gi_marshalling_tests_int32_return_max (void) +{ + return G_MAXINT32; +} + +gint32 +gi_marshalling_tests_int32_return_min (void) +{ + return G_MININT32; +} + +void +gi_marshalling_tests_int32_in_max (gint32 v) +{ + g_assert_cmpint (v, ==, G_MAXINT32); +} + +void +gi_marshalling_tests_int32_in_min (gint32 v) +{ + g_assert_cmpint (v, ==, G_MININT32); +} + +/** + * gi_marshalling_tests_int32_out_max: + * @v: (out): + */ +void +gi_marshalling_tests_int32_out_max (gint32 *v) +{ + *v = G_MAXINT32; +} + +/** + * gi_marshalling_tests_int32_out_min: + * @v: (out): + */ +void +gi_marshalling_tests_int32_out_min (gint32 *v) +{ + *v = G_MININT32; +} + +/** + * gi_marshalling_tests_int32_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_int32_out_uninitialized (gint32 *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_int32_inout_max_min: + * @v: (inout): + */ +void +gi_marshalling_tests_int32_inout_max_min (gint32 *v) +{ + g_assert_cmpint (*v, ==, G_MAXINT32); + *v = G_MININT32; +} + +/** + * gi_marshalling_tests_int32_inout_min_max: + * @v: (inout): + */ +void +gi_marshalling_tests_int32_inout_min_max (gint32 *v) +{ + g_assert_cmpint (*v, ==, G_MININT32); + *v = G_MAXINT32; +} + +guint32 +gi_marshalling_tests_uint32_return (void) +{ + return G_MAXUINT32; +} + +void +gi_marshalling_tests_uint32_in (guint32 v) +{ + g_assert_cmpuint (v, ==, G_MAXUINT32); +} + +/** + * gi_marshalling_tests_uint32_out: + * @v: (out): + */ +void +gi_marshalling_tests_uint32_out (guint32 *v) +{ + *v = G_MAXUINT32; +} + +/** + * gi_marshalling_tests_uint32_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_uint32_out_uninitialized (guint32 *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_uint32_inout: + * @v: (inout): + */ +void +gi_marshalling_tests_uint32_inout (guint32 *v) +{ + g_assert_cmpuint (*v, ==, G_MAXUINT32); + *v = 0; +} + +gint64 +gi_marshalling_tests_int64_return_max (void) +{ + return G_MAXINT64; +} + +gint64 +gi_marshalling_tests_int64_return_min (void) +{ + return G_MININT64; +} + +void +gi_marshalling_tests_int64_in_max (gint64 v) +{ + g_assert_cmpint (v, ==, G_MAXINT64); +} + +void +gi_marshalling_tests_int64_in_min (gint64 v) +{ + g_assert_cmpint (v, ==, G_MININT64); +} + +/** + * gi_marshalling_tests_int64_out_max: + * @v: (out): + */ +void +gi_marshalling_tests_int64_out_max (gint64 *v) +{ + *v = G_MAXINT64; +} + +/** + * gi_marshalling_tests_int64_out_min: + * @v: (out): + */ +void +gi_marshalling_tests_int64_out_min (gint64 *v) +{ + *v = G_MININT64; +} + +/** + * gi_marshalling_tests_int64_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_int64_out_uninitialized (gint64 *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_int64_inout_max_min: + * @v: (inout): + */ +void +gi_marshalling_tests_int64_inout_max_min (gint64 *v) +{ + g_assert_cmpint (*v, ==, G_MAXINT64); + *v = G_MININT64; +} + +/** + * gi_marshalling_tests_int64_inout_min_max: + * @v: (inout): + */ +void +gi_marshalling_tests_int64_inout_min_max (gint64 *v) +{ + g_assert_cmpint (*v, ==, G_MININT64); + *v = G_MAXINT64; +} + +guint64 +gi_marshalling_tests_uint64_return (void) +{ + return G_MAXUINT64; +} + +void +gi_marshalling_tests_uint64_in (guint64 v) +{ + g_assert_cmpuint (v, ==, G_MAXUINT64); +} + +/** + * gi_marshalling_tests_uint64_out: + * @v: (out): + */ +void +gi_marshalling_tests_uint64_out (guint64 *v) +{ + *v = G_MAXUINT64; +} + +/** + * gi_marshalling_tests_uint64_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_uint64_out_uninitialized (guint64 *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_uint64_inout: + * @v: (inout): + */ +void +gi_marshalling_tests_uint64_inout (guint64 *v) +{ + g_assert_cmpuint (*v, ==, G_MAXUINT64); + *v = 0; +} + +gshort +gi_marshalling_tests_short_return_max (void) +{ + return G_MAXSHORT; +} + +gshort +gi_marshalling_tests_short_return_min (void) +{ + return G_MINSHORT; +} + +void +gi_marshalling_tests_short_in_max (gshort short_) +{ + g_assert_cmpint (short_, ==, G_MAXSHORT); +} + +void +gi_marshalling_tests_short_in_min (gshort short_) +{ + g_assert_cmpint (short_, ==, G_MINSHORT); +} + +/** + * gi_marshalling_tests_short_out_max: + * @short_: (out): + */ +void +gi_marshalling_tests_short_out_max (gshort *short_) +{ + *short_ = G_MAXSHORT; +} + +/** + * gi_marshalling_tests_short_out_min: + * @short_: (out): + */ +void +gi_marshalling_tests_short_out_min (gshort *short_) +{ + *short_ = G_MINSHORT; +} + +/** + * gi_marshalling_tests_short_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_short_out_uninitialized (gshort *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_short_inout_max_min: + * @short_: (inout): + */ +void +gi_marshalling_tests_short_inout_max_min (gshort *short_) +{ + g_assert_cmpint (*short_, ==, G_MAXSHORT); + *short_ = G_MINSHORT; +} + +/** + * gi_marshalling_tests_short_inout_min_max: + * @short_: (inout): + */ +void +gi_marshalling_tests_short_inout_min_max (gshort *short_) +{ + g_assert_cmpint (*short_, ==, G_MINSHORT); + *short_ = G_MAXSHORT; +} + +gushort +gi_marshalling_tests_ushort_return (void) +{ + return G_MAXUSHORT; +} + +void +gi_marshalling_tests_ushort_in (gushort ushort_) +{ + g_assert_cmpuint (ushort_, ==, G_MAXUSHORT); +} + +/** + * gi_marshalling_tests_ushort_out: + * @ushort_: (out): + */ +void +gi_marshalling_tests_ushort_out (gushort *ushort_) +{ + *ushort_ = G_MAXUSHORT; +} + +/** + * gi_marshalling_tests_ushort_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_ushort_out_uninitialized (gushort *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_ushort_inout: + * @ushort_: (inout): + */ +void +gi_marshalling_tests_ushort_inout (gushort *ushort_) +{ + g_assert_cmpuint (*ushort_, ==, G_MAXUSHORT); + *ushort_ = 0; +} + +gint +gi_marshalling_tests_int_return_max (void) +{ + return G_MAXINT; +} + +gint +gi_marshalling_tests_int_return_min (void) +{ + return G_MININT; +} + +void +gi_marshalling_tests_int_in_max (gint int_) +{ + g_assert_cmpint (int_, ==, G_MAXINT); +} + +void +gi_marshalling_tests_int_in_min (gint int_) +{ + g_assert_cmpint (int_, ==, G_MININT); +} + +/** + * gi_marshalling_tests_int_out_max: + * @int_: (out): + */ +void +gi_marshalling_tests_int_out_max (gint *int_) +{ + *int_ = G_MAXINT; +} + +/** + * gi_marshalling_tests_int_out_min: + * @int_: (out): + */ +void +gi_marshalling_tests_int_out_min (gint *int_) +{ + *int_ = G_MININT; +} + +/** + * gi_marshalling_tests_int_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_int_out_uninitialized (gint *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_int_inout_max_min: + * @int_: (inout): + */ +void +gi_marshalling_tests_int_inout_max_min (gint *int_) +{ + g_assert_cmpint (*int_, ==, G_MAXINT); + *int_ = G_MININT; +} + +/** + * gi_marshalling_tests_int_inout_min_max: + * @int_: (inout): + */ +void +gi_marshalling_tests_int_inout_min_max (gint *int_) +{ + g_assert_cmpint (*int_, ==, G_MININT); + *int_ = G_MAXINT; +} + +guint +gi_marshalling_tests_uint_return (void) +{ + return G_MAXUINT; +} + +void +gi_marshalling_tests_uint_in (guint uint_) +{ + g_assert_cmpuint (uint_, ==, G_MAXUINT); +} + +/** + * gi_marshalling_tests_uint_out: + * @uint_: (out): + */ +void +gi_marshalling_tests_uint_out (guint *uint_) +{ + *uint_ = G_MAXUINT; +} + +/** + * gi_marshalling_tests_uint_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_uint_out_uninitialized (guint *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_uint_inout: + * @uint_: (inout): + */ +void +gi_marshalling_tests_uint_inout (guint *uint_) +{ + g_assert_cmpuint (*uint_, ==, G_MAXUINT); + *uint_ = 0; +} + +glong +gi_marshalling_tests_long_return_max (void) +{ + return G_MAXLONG; +} + +glong +gi_marshalling_tests_long_return_min (void) +{ + return G_MINLONG; +} + +void +gi_marshalling_tests_long_in_max (glong long_) +{ + g_assert_cmpint (long_, ==, G_MAXLONG); +} + +void +gi_marshalling_tests_long_in_min (glong long_) +{ + g_assert_cmpint (long_, ==, G_MINLONG); +} + +/** + * gi_marshalling_tests_long_out_max: + * @long_: (out): + */ +void +gi_marshalling_tests_long_out_max (glong *long_) +{ + *long_ = G_MAXLONG; +} + +/** + * gi_marshalling_tests_long_out_min: + * @long_: (out): + */ +void +gi_marshalling_tests_long_out_min (glong *long_) +{ + *long_ = G_MINLONG; +} + +/** + * gi_marshalling_tests_long_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_long_out_uninitialized (glong *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_long_inout_max_min: + * @long_: (inout): + */ +void +gi_marshalling_tests_long_inout_max_min (glong *long_) +{ + g_assert_cmpint (*long_, ==, G_MAXLONG); + *long_ = G_MINLONG; +} + +/** + * gi_marshalling_tests_long_inout_min_max: + * @long_: (inout): + */ +void +gi_marshalling_tests_long_inout_min_max (glong *long_) +{ + g_assert_cmpint (*long_, ==, G_MINLONG); + *long_ = G_MAXLONG; +} + +gulong +gi_marshalling_tests_ulong_return (void) +{ + return G_MAXULONG; +} + +void +gi_marshalling_tests_ulong_in (gulong ulong_) +{ + g_assert_cmpuint (ulong_, ==, G_MAXULONG); +} + +/** + * gi_marshalling_tests_ulong_out: + * @ulong_: (out): + */ +void +gi_marshalling_tests_ulong_out (gulong *ulong_) +{ + *ulong_ = G_MAXULONG; +} + +/** + * gi_marshalling_tests_ulong_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_ulong_out_uninitialized (gulong *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_ulong_inout: + * @ulong_: (inout): + */ +void +gi_marshalling_tests_ulong_inout (gulong *ulong_) +{ + g_assert_cmpuint (*ulong_, ==, G_MAXULONG); + *ulong_ = 0; +} + +gssize +gi_marshalling_tests_ssize_return_max (void) +{ + return G_MAXSSIZE; +} + +gssize +gi_marshalling_tests_ssize_return_min (void) +{ + return G_MINSSIZE; +} + +void +gi_marshalling_tests_ssize_in_max (gssize ssize) +{ + g_assert_cmpint (ssize, ==, G_MAXSSIZE); +} + +void +gi_marshalling_tests_ssize_in_min (gssize ssize) +{ + g_assert_cmpint (ssize, ==, G_MINSSIZE); +} + +/** + * gi_marshalling_tests_ssize_out_max: + * @ssize: (out): + */ +void +gi_marshalling_tests_ssize_out_max (gssize *ssize) +{ + *ssize = G_MAXSSIZE; +} + +/** + * gi_marshalling_tests_ssize_out_min: + * @ssize: (out): + */ +void +gi_marshalling_tests_ssize_out_min (gssize *ssize) +{ + *ssize = G_MINSSIZE; +} + +/** + * gi_marshalling_tests_ssize_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_ssize_out_uninitialized (gssize *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_ssize_inout_max_min: + * @ssize: (inout): + */ +void +gi_marshalling_tests_ssize_inout_max_min (gssize *ssize) +{ + g_assert_cmpint (*ssize, ==, G_MAXSSIZE); + *ssize = G_MINSSIZE; +} + +/** + * gi_marshalling_tests_ssize_inout_min_max: + * @ssize: (inout): + */ +void +gi_marshalling_tests_ssize_inout_min_max (gssize *ssize) +{ + g_assert_cmpint (*ssize, ==, G_MINSSIZE); + *ssize = G_MAXSSIZE; +} + +gsize +gi_marshalling_tests_size_return (void) +{ + return G_MAXSIZE; +} + +void +gi_marshalling_tests_size_in (gsize size) +{ + g_assert_cmpuint (size, ==, G_MAXSIZE); +} + +/** + * gi_marshalling_tests_size_out: + * @size: (out): + */ +void +gi_marshalling_tests_size_out (gsize *size) +{ + *size = G_MAXSIZE; +} + +/** + * gi_marshalling_tests_size_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_size_out_uninitialized (gsize *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_size_inout: + * @size: (inout): + */ +void +gi_marshalling_tests_size_inout (gsize *size) +{ + g_assert_cmpuint (*size, ==, G_MAXSIZE); + *size = 0; +} + +gfloat +gi_marshalling_tests_float_return (void) +{ + return G_MAXFLOAT; +} + +void +gi_marshalling_tests_float_in (gfloat v) +{ + g_assert_cmpfloat (v, ==, G_MAXFLOAT); +} + +/** + * gi_marshalling_tests_float_out: + * @v: (out): + */ +void +gi_marshalling_tests_float_out (gfloat *v) +{ + *v = G_MAXFLOAT; +} + +#define NONCANONICAL_NAN_BIT_PATTERN_32 0xfffb1236; +#define NONCANONICAL_NAN_BIT_PATTERN_64 0xfffb1236fedcba98; + +static gfloat +noncanonical_nan_float (void) +{ + gfloat retval; + + if (sizeof (gfloat) == sizeof (guint32)) + { + guint32 bit_pattern = NONCANONICAL_NAN_BIT_PATTERN_32; + memcpy (&retval, &bit_pattern, sizeof (gfloat)); + } + else + { + g_assert (sizeof (gfloat) == sizeof (guint64) && "gfloat must be 32 or 64 bits"); + guint64 bit_pattern = NONCANONICAL_NAN_BIT_PATTERN_64; + memcpy (&retval, &bit_pattern, sizeof (gfloat)); + } + + return retval; +} + +/** + * gi_marshalling_tests_float_noncanonical_nan_out: + * @v: (out): + */ +void +gi_marshalling_tests_float_noncanonical_nan_out (gfloat *v) +{ + *v = noncanonical_nan_float (); +} + +/** + * gi_marshalling_tests_float_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_float_out_uninitialized (gfloat *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_float_inout: + * @v: (inout): + */ +void +gi_marshalling_tests_float_inout (gfloat *v) +{ + g_assert_cmpfloat (*v, ==, G_MAXFLOAT); + *v = G_MINFLOAT; +} + +gdouble +gi_marshalling_tests_double_return (void) +{ + return G_MAXDOUBLE; +} + +void +gi_marshalling_tests_double_in (gdouble v) +{ + g_assert_cmpfloat (v, ==, G_MAXDOUBLE); +} + +/** + * gi_marshalling_tests_double_out: + * @v: (out): + */ +void +gi_marshalling_tests_double_out (gdouble *v) +{ + *v = G_MAXDOUBLE; +} + +static gdouble +noncanonical_nan_double (void) +{ + gdouble retval; + + g_assert (sizeof (gdouble) == sizeof (guint64) && "gdouble must be 64 bits"); + + guint64 bit_pattern = NONCANONICAL_NAN_BIT_PATTERN_64; + memcpy (&retval, &bit_pattern, sizeof (gdouble)); + + return retval; +} + +/** + * gi_marshalling_tests_double_noncanonical_nan_out: + * @v: (out): + */ +void +gi_marshalling_tests_double_noncanonical_nan_out (gdouble *v) +{ + *v = noncanonical_nan_double (); +} + +/** + * gi_marshalling_tests_double_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_double_out_uninitialized (gdouble *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_double_inout: + * @v: (inout): + */ +void +gi_marshalling_tests_double_inout (gdouble *v) +{ + g_assert_cmpfloat (*v, ==, G_MAXDOUBLE); + *v = G_MINDOUBLE; +} + +time_t +gi_marshalling_tests_time_t_return (void) +{ + return 1234567890; +} + +void +gi_marshalling_tests_time_t_in (time_t v) +{ + g_assert_cmpuint (v, ==, 1234567890); +} + +/** + * gi_marshalling_tests_time_t_out: + * @v: (out): + */ +void +gi_marshalling_tests_time_t_out (time_t *v) +{ + *v = 1234567890; +} + +/** + * gi_marshalling_tests_time_t_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_time_t_out_uninitialized (time_t *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_time_t_inout: + * @v: (inout): + */ +void +gi_marshalling_tests_time_t_inout (time_t *v) +{ + g_assert_cmpuint (*v, ==, 1234567890); + *v = 0; +} + +off_t +gi_marshalling_tests_off_t_return (void) +{ + return 1234567890; +} + +void +gi_marshalling_tests_off_t_in (off_t v) +{ + g_assert_cmpuint (v, ==, 1234567890); +} + +/** + * gi_marshalling_tests_off_t_out: + * @v: (out): + */ +void +gi_marshalling_tests_off_t_out (off_t *v) +{ + *v = 1234567890; +} + +/** + * gi_marshalling_tests_off_t_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_off_t_out_uninitialized (off_t *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_off_t_inout: + * @v: (inout): + */ +void +gi_marshalling_tests_off_t_inout (off_t *v) +{ + g_assert_cmpuint (*v, ==, 1234567890); + *v = 0; +} + +#ifdef G_OS_UNIX + +dev_t +gi_marshalling_tests_dev_t_return (void) +{ + return 1234567890; +} + +void +gi_marshalling_tests_dev_t_in (dev_t v) +{ + g_assert_cmpuint (v, ==, 1234567890); +} + +/** + * gi_marshalling_tests_dev_t_out: + * @v: (out): + */ +void +gi_marshalling_tests_dev_t_out (dev_t *v) +{ + *v = 1234567890; +} + +/** + * gi_marshalling_tests_dev_t_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_dev_t_out_uninitialized (dev_t *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_dev_t_inout: + * @v: (inout): + */ +void +gi_marshalling_tests_dev_t_inout (dev_t *v) +{ + g_assert_cmpuint (*v, ==, 1234567890); + *v = 0; +} + +gid_t +gi_marshalling_tests_gid_t_return (void) +{ + return 65534; +} + +void +gi_marshalling_tests_gid_t_in (gid_t v) +{ + g_assert_cmpuint (v, ==, 65534); +} + +/** + * gi_marshalling_tests_gid_t_out: + * @v: (out): + */ +void +gi_marshalling_tests_gid_t_out (gid_t *v) +{ + *v = 65534; +} + +/** + * gi_marshalling_tests_gid_t_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_gid_t_out_uninitialized (gid_t *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_gid_t_inout: + * @v: (inout): + */ +void +gi_marshalling_tests_gid_t_inout (gid_t *v) +{ + g_assert_cmpuint (*v, ==, 65534); + *v = 0; +} + +pid_t +gi_marshalling_tests_pid_t_return (void) +{ + return 12345; +} + +void +gi_marshalling_tests_pid_t_in (pid_t v) +{ + g_assert_cmpuint (v, ==, 12345); +} + +/** + * gi_marshalling_tests_pid_t_out: + * @v: (out): + */ +void +gi_marshalling_tests_pid_t_out (pid_t *v) +{ + *v = 12345; +} + +/** + * gi_marshalling_tests_pid_t_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_pid_t_out_uninitialized (pid_t *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_pid_t_inout: + * @v: (inout): + */ +void +gi_marshalling_tests_pid_t_inout (pid_t *v) +{ + g_assert_cmpuint (*v, ==, 12345); + *v = 0; +} + +socklen_t +gi_marshalling_tests_socklen_t_return (void) +{ + return 123; +} + +void +gi_marshalling_tests_socklen_t_in (socklen_t v) +{ + g_assert_cmpuint (v, ==, 123); +} + +/** + * gi_marshalling_tests_socklen_t_out: + * @v: (out): + */ +void +gi_marshalling_tests_socklen_t_out (socklen_t *v) +{ + *v = 123; +} + +/** + * gi_marshalling_tests_socklen_t_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_socklen_t_out_uninitialized (socklen_t *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_socklen_t_inout: + * @v: (inout): + */ +void +gi_marshalling_tests_socklen_t_inout (socklen_t *v) +{ + g_assert_cmpuint (*v, ==, 123); + *v = 0; +} + +uid_t +gi_marshalling_tests_uid_t_return (void) +{ + return 65534; +} + +void +gi_marshalling_tests_uid_t_in (uid_t v) +{ + g_assert_cmpuint (v, ==, 65534); +} + +/** + * gi_marshalling_tests_uid_t_out: + * @v: (out): + */ +void +gi_marshalling_tests_uid_t_out (uid_t *v) +{ + *v = 65534; +} + +/** + * gi_marshalling_tests_uid_t_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_uid_t_out_uninitialized (uid_t *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_uid_t_inout: + * @v: (inout): + */ +void +gi_marshalling_tests_uid_t_inout (uid_t *v) +{ + g_assert_cmpuint (*v, ==, 65534); + *v = 0; +} + +#endif /* G_OS_UNIX */ + +GType +gi_marshalling_tests_gtype_return (void) +{ + return G_TYPE_NONE; +} + +GType +gi_marshalling_tests_gtype_string_return (void) +{ + return G_TYPE_STRING; +} + +void +gi_marshalling_tests_gtype_in (GType gtype) +{ + g_assert (gtype == G_TYPE_NONE); +} + +void +gi_marshalling_tests_gtype_string_in (GType gtype) +{ + g_assert (gtype == G_TYPE_STRING); +} + +/** + * gi_marshalling_tests_gtype_out: + * @gtype: (out): + */ +void +gi_marshalling_tests_gtype_out (GType *gtype) +{ + *gtype = G_TYPE_NONE; +} + +/** + * gi_marshalling_tests_gtype_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_gtype_out_uninitialized (GType *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_gtype_string_out: + * @gtype: (out): + */ +void +gi_marshalling_tests_gtype_string_out (GType *gtype) +{ + *gtype = G_TYPE_STRING; +} + +/** + * gi_marshalling_tests_gtype_inout: + * @gtype: (inout): + */ +void +gi_marshalling_tests_gtype_inout (GType *gtype) +{ + g_assert (*gtype == G_TYPE_NONE); + *gtype = G_TYPE_INT; +} + +const gchar * +gi_marshalling_tests_utf8_none_return (void) +{ + return GI_MARSHALLING_TESTS_CONSTANT_UTF8; +} + +gchar * +gi_marshalling_tests_utf8_full_return (void) +{ + return g_strdup (GI_MARSHALLING_TESTS_CONSTANT_UTF8); +} + +void +gi_marshalling_tests_utf8_none_in (const gchar *utf8) +{ + g_assert_cmpstr (GI_MARSHALLING_TESTS_CONSTANT_UTF8, ==, utf8); +} + +/** + * gi_marshalling_tests_utf8_as_uint8array_in: + * @array: (array length=len) (element-type guint8): Byte data that happens to be UTF-8 + * @len: Length + * + * Takes data that happens to be UTF-8 as a byte array, to test + * binding conversion from their string type (e.g. JavaScript's + * UTF-16) to UTF-8. + */ +void +gi_marshalling_tests_utf8_as_uint8array_in (const guint8 *array, gsize len) +{ + gsize orig_len = strlen (GI_MARSHALLING_TESTS_CONSTANT_UTF8); + g_assert_cmpint (orig_len, ==, len); + g_assert (memcmp (GI_MARSHALLING_TESTS_CONSTANT_UTF8, array, len) == 0); +} + +/** + * gi_marshalling_tests_utf8_none_out: + * @utf8: (out) (transfer none): + */ +void +gi_marshalling_tests_utf8_none_out (const gchar **utf8) +{ + *utf8 = GI_MARSHALLING_TESTS_CONSTANT_UTF8; +} + +/** + * gi_marshalling_tests_utf8_none_out_uninitialized: + * @v: (out) (transfer none): + */ +gboolean +gi_marshalling_tests_utf8_none_out_uninitialized (const gchar **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_utf8_full_out: + * @utf8: (out) (transfer full): + */ +void +gi_marshalling_tests_utf8_full_out (gchar **utf8) +{ + *utf8 = g_strdup (GI_MARSHALLING_TESTS_CONSTANT_UTF8); +} + +/** + * gi_marshalling_tests_utf8_dangling_out: + * @utf8: (out) (transfer full): + */ +void +gi_marshalling_tests_utf8_dangling_out (gchar **utf8 G_GNUC_UNUSED) +{ + /* Intentionally don't touch the pointer to see how + the bindings handle this case. Bindings should be + robust against broken C functions and can initialize + even OUT vlues to NULL. + */ +} + +/** + * gi_marshalling_tests_utf8_none_inout: + * @utf8: (inout) (transfer none): + */ +void +gi_marshalling_tests_utf8_none_inout (const gchar **utf8) +{ + g_assert_cmpstr (GI_MARSHALLING_TESTS_CONSTANT_UTF8, ==, *utf8); + *utf8 = ""; +} + +/** + * gi_marshalling_tests_utf8_full_inout: + * @utf8: (inout) (transfer full): + */ +void +gi_marshalling_tests_utf8_full_inout (gchar **utf8) +{ + g_assert_cmpstr (GI_MARSHALLING_TESTS_CONSTANT_UTF8, ==, *utf8); + g_free (*utf8); + *utf8 = g_strdup (""); +} + +/** + * gi_marshalling_tests_init_function: + * @n_args: (inout) (allow-none): number of args + * @argv: (inout) (array length=n_args) (allow-none): args + * + * This is like gtk_init(). + */ +gboolean +gi_marshalling_tests_init_function (gint *n_args, char ***argv) +{ + if (n_args == NULL) + return TRUE; + + if (*n_args == 0) + return TRUE; + (*n_args)--; + g_assert (argv != NULL); + /* we have transfer ownership full, so we need to free the element ourself */ + g_free ((*argv)[*n_args]); + (*argv)[*n_args] = NULL; + return TRUE; +} + +/** + * gi_marshalling_tests_array_fixed_int_return: + * + * Returns: (array fixed-size=4): + */ +const gint * +gi_marshalling_tests_array_fixed_int_return (void) +{ + static gint ints[] = { -1, 0, 1, 2 }; + return ints; +} + +/** + * gi_marshalling_tests_array_fixed_short_return: + * + * Returns: (array fixed-size=4): + */ +const gshort * +gi_marshalling_tests_array_fixed_short_return (void) +{ + static gshort shorts[] = { -1, 0, 1, 2 }; + return shorts; +} + +/** + * gi_marshalling_tests_array_fixed_int_in: + * @ints: (array fixed-size=4): + */ +void +gi_marshalling_tests_array_fixed_int_in (const gint *ints) +{ + g_assert_cmpint (ints[0], ==, -1); + g_assert_cmpint (ints[1], ==, 0); + g_assert_cmpint (ints[2], ==, 1); + g_assert_cmpint (ints[3], ==, 2); +} + +/** + * gi_marshalling_tests_array_fixed_caller_allocated_out: + * @ints: (out caller-allocates) (array fixed-size=4): + */ +void +gi_marshalling_tests_array_fixed_caller_allocated_out (gint *ints) +{ + ints[0] = -1; + ints[1] = 0; + ints[2] = 1; + ints[3] = 2; +} + +/** + * gi_marshalling_tests_array_fixed_short_in: + * @shorts: (array fixed-size=4): + */ +void +gi_marshalling_tests_array_fixed_short_in (const gshort *shorts) +{ + g_assert_cmpint (shorts[0], ==, -1); + g_assert_cmpint (shorts[1], ==, 0); + g_assert_cmpint (shorts[2], ==, 1); + g_assert_cmpint (shorts[3], ==, 2); +} + +/** + * gi_marshalling_tests_array_fixed_out: + * @ints: (out) (array fixed-size=4) (transfer none): + */ +void +gi_marshalling_tests_array_fixed_out (gint **ints) +{ + static gint values[] = { -1, 0, 1, 2 }; + *ints = values; +} + +/** + * gi_marshalling_tests_array_fixed_out_uninitialized: + * @v: (out) (array fixed-size=4) (transfer none): + */ +gboolean +gi_marshalling_tests_array_fixed_out_uninitialized (gint **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_array_fixed_out_struct: + * @structs: (out) (array fixed-size=2) (transfer none): + */ +void +gi_marshalling_tests_array_fixed_out_struct (GIMarshallingTestsSimpleStruct **structs) +{ + static GIMarshallingTestsSimpleStruct *values; + + if (values == NULL) + { + values = g_new (GIMarshallingTestsSimpleStruct, 2); + + values[0].long_ = 7; + values[0].int8 = 6; + + values[1].long_ = 6; + values[1].int8 = 7; + } + + *structs = values; +} + +/** + * gi_marshalling_tests_array_fixed_out_struct_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_array_fixed_out_struct_uninitialized (GIMarshallingTestsSimpleStruct **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_array_fixed_caller_allocated_struct_out: + * @structs: (out caller-allocates) (array fixed-size=4): + */ +void +gi_marshalling_tests_array_fixed_caller_allocated_struct_out (GIMarshallingTestsSimpleStruct *structs) +{ + structs[0].long_ = -2; + structs[0].int8 = -1; + structs[1].long_ = 1; + structs[1].int8 = 2; + structs[2].long_ = 3; + structs[2].int8 = 4; + structs[3].long_ = 5; + structs[3].int8 = 6; +} + +/** + * gi_marshalling_tests_array_fixed_inout: + * @ints: (inout) (array fixed-size=4) (transfer none): + */ +void +gi_marshalling_tests_array_fixed_inout (gint **ints) +{ + static gint values[] = { 2, 1, 0, -1 }; + + g_assert_cmpint ((*ints)[0], ==, -1); + g_assert_cmpint ((*ints)[1], ==, 0); + g_assert_cmpint ((*ints)[2], ==, 1); + g_assert_cmpint ((*ints)[3], ==, 2); + + *ints = values; +} + +/** + * gi_marshalling_tests_array_return: + * + * Returns: (array length=length): + */ +const gint * +gi_marshalling_tests_array_return (gint *length) +{ + static gint ints[] = { -1, 0, 1, 2 }; + + *length = 4; + return ints; +} + +/** + * gi_marshalling_tests_array_return_etc: + * @first: + * @length: (out): + * @last: + * @sum: (out): + * + * Returns: (array length=length): + */ +const gint * +gi_marshalling_tests_array_return_etc (gint first, gint *length, gint last, gint *sum) +{ + static gint ints[] = { -1, 0, 1, 2 }; + + ints[0] = first; + ints[3] = last; + *sum = first + last; + *length = 4; + return ints; +} + +/** + * gi_marshalling_tests_array_in: + * @ints: (array length=length): + * @length: + */ +void +gi_marshalling_tests_array_in (const gint *ints, gint length) +{ + g_assert_cmpint (length, ==, 4); + g_assert_cmpint (ints[0], ==, -1); + g_assert_cmpint (ints[1], ==, 0); + g_assert_cmpint (ints[2], ==, 1); + g_assert_cmpint (ints[3], ==, 2); +} + +/** + * gi_marshalling_tests_array_in_len_before: + * @length: + * @ints: (array length=length): + */ +void +gi_marshalling_tests_array_in_len_before (gint length, const gint *ints) +{ + gi_marshalling_tests_array_in (ints, length); +} + +/** + * gi_marshalling_tests_array_in_len_zero_terminated: + * @ints: (array length=length zero-terminated): + * @length: + */ +void +gi_marshalling_tests_array_in_len_zero_terminated (const gint *ints, gint length) +{ + g_assert_cmpint (length, ==, 4); + + g_assert_cmpint (ints[0], ==, -1); + g_assert_cmpint (ints[1], ==, 0); + g_assert_cmpint (ints[2], ==, 1); + g_assert_cmpint (ints[3], ==, 2); + + /* One past the end, null terminator */ + g_assert_cmpint (ints[4], ==, 0); +} + +/** + * gi_marshalling_tests_array_string_in: + * @strings: (array length=length): + */ +void +gi_marshalling_tests_array_string_in (const gchar **strings, gint length) +{ + g_assert_cmpint (length, ==, 2); + g_assert_cmpstr (strings[0], ==, "foo"); + g_assert_cmpstr (strings[1], ==, "bar"); +} + +/** + * gi_marshalling_tests_array_uint8_in: + * @chars: (array length=length): + */ +void +gi_marshalling_tests_array_uint8_in (const guint8 *chars, gint length) +{ + g_assert_cmpint (length, ==, 4); + g_assert (chars[0] == 'a'); + g_assert (chars[1] == 'b'); + g_assert (chars[2] == 'c'); + g_assert (chars[3] == 'd'); +} + +/** + * gi_marshalling_tests_array_int64_in: + * @ints: (array length=length): + * @length: + */ +void +gi_marshalling_tests_array_int64_in (const gint64 *ints, gint length) +{ + g_assert_cmpint (length, ==, 4); + g_assert_cmpint (ints[0], ==, -1); + g_assert_cmpint (ints[1], ==, 0); + g_assert_cmpint (ints[2], ==, 1); + g_assert_cmpint (ints[3], ==, 2); +} + +/** + * gi_marshalling_tests_array_uint64_in: + * @ints: (array length=length): + * @length: + */ +void +gi_marshalling_tests_array_uint64_in (const guint64 *ints, gint length) +{ + g_assert_cmpint (length, ==, 4); + g_assert_cmpint (ints[0], ==, -1); + g_assert_cmpint (ints[1], ==, 0); + g_assert_cmpint (ints[2], ==, 1); + g_assert_cmpint (ints[3], ==, 2); +} + +/** + * gi_marshalling_tests_array_unichar_in: + * @chars: (array length=length): + * @length: + */ +void +gi_marshalling_tests_array_unichar_in (const gunichar *chars, gint length) +{ + int ix; + static const gunichar expected[] = GI_MARSHALLING_TESTS_CONSTANT_UCS4; + g_assert_cmpint (length, ==, 12); + for (ix = 0; ix < length; ix++) + g_assert_cmpuint (chars[ix], ==, expected[ix]); +} + +/** + * gi_marshalling_tests_array_bool_in: + * @bools: (array length=length): + * @length: + */ +void +gi_marshalling_tests_array_bool_in (const gboolean *bools, gint length) +{ + g_assert_cmpint (length, ==, 4); + g_assert_cmpint (bools[0], ==, TRUE); + g_assert_cmpint (bools[1], ==, FALSE); + g_assert_cmpint (bools[2], ==, TRUE); + g_assert_cmpint (bools[3], ==, TRUE); +} + +/** + * gi_marshalling_tests_array_struct_in: + * @structs: (array length=length): + */ +void +gi_marshalling_tests_array_struct_in (GIMarshallingTestsBoxedStruct **structs, gint length) +{ + g_assert_cmpint (length, ==, 3); + g_assert_cmpint (structs[0]->long_, ==, 1); + g_assert_cmpint (structs[1]->long_, ==, 2); + g_assert_cmpint (structs[2]->long_, ==, 3); +} + +/** + * gi_marshalling_tests_array_struct_value_in: + * @structs: (array length=length): + */ +void +gi_marshalling_tests_array_struct_value_in (GIMarshallingTestsBoxedStruct *structs, gint length) +{ + g_assert_cmpint (length, ==, 3); + g_assert_cmpint (structs[0].long_, ==, 1); + g_assert_cmpint (structs[1].long_, ==, 2); + g_assert_cmpint (structs[2].long_, ==, 3); +} + +/** + * gi_marshalling_tests_array_simple_struct_in: + * @structs: (array length=length): + */ +void +gi_marshalling_tests_array_simple_struct_in (GIMarshallingTestsSimpleStruct *structs, gint length) +{ + g_assert_cmpint (length, ==, 3); + g_assert_cmpint (structs[0].long_, ==, 1); + g_assert_cmpint (structs[1].long_, ==, 2); + g_assert_cmpint (structs[2].long_, ==, 3); +} + +/** + * gi_marshalling_tests_multi_array_key_value_in: + * @keys: (array length=length): + * @values: (array length=length): + */ +void +gi_marshalling_tests_multi_array_key_value_in (gint length, const gchar **keys, const GValue *values) +{ + g_assert_cmpint (length, ==, 3); + g_assert_cmpstr ("one", ==, keys[0]); + g_assert_cmpint (g_value_get_int (&values[0]), ==, 1); + g_assert_cmpstr ("two", ==, keys[1]); + g_assert_cmpint (g_value_get_int (&values[1]), ==, 2); + g_assert_cmpstr ("three", ==, keys[2]); + g_assert_cmpint (g_value_get_int (&values[2]), ==, 3); +} + +/** + * gi_marshalling_tests_array_struct_take_in: + * @structs: (array length=length) (transfer full): + */ +void +gi_marshalling_tests_array_struct_take_in (GIMarshallingTestsBoxedStruct **structs, gint length) +{ + gi_marshalling_tests_array_struct_in (structs, length); + + /* only really useful if run in valgrind actually */ + gi_marshalling_tests_boxed_struct_free (structs[0]); + gi_marshalling_tests_boxed_struct_free (structs[1]); + gi_marshalling_tests_boxed_struct_free (structs[2]); + g_free (structs); +} + +/** + * gi_marshalling_tests_array_enum_in: + * @_enum: (array length=length) (transfer none): + * @length: + */ +void +gi_marshalling_tests_array_enum_in (GIMarshallingTestsEnum *v, gint length) +{ + g_assert_cmpint (length, ==, 3); + g_assert_cmpint (v[0], ==, GI_MARSHALLING_TESTS_ENUM_VALUE1); + g_assert_cmpint (v[1], ==, GI_MARSHALLING_TESTS_ENUM_VALUE2); + g_assert_cmpint (v[2], ==, GI_MARSHALLING_TESTS_ENUM_VALUE3); +} + +/** + * gi_marshalling_tests_array_flags_in: + * @flags: (array length=length) (transfer none): + * @length: + */ +void +gi_marshalling_tests_array_flags_in (GIMarshallingTestsFlags *v, gint length) +{ + g_assert_cmpint (length, ==, 3); + g_assert_cmpint (v[0], ==, GI_MARSHALLING_TESTS_FLAGS_VALUE1); + g_assert_cmpint (v[1], ==, GI_MARSHALLING_TESTS_FLAGS_VALUE2); + g_assert_cmpint (v[2], ==, GI_MARSHALLING_TESTS_FLAGS_VALUE3); +} + +/** + * gi_marshalling_tests_array_in_guint64_len: + * @ints: (array length=length) (transfer none): + * @length: + */ +void +gi_marshalling_tests_array_in_guint64_len (const gint *ints, guint64 length) +{ + g_assert_cmpint (length, ==, 4); + + gi_marshalling_tests_array_in (ints, length); +} + +/** + * gi_marshalling_tests_array_in_guint8_len: + * @ints: (array length=length) (transfer none): + * @length: + */ +void +gi_marshalling_tests_array_in_guint8_len (const gint *ints, guint8 length) +{ + g_assert_cmpint (length, ==, 4); + + gi_marshalling_tests_array_in (ints, length); +} + +/** + * gi_marshalling_tests_array_out: + * @ints: (out) (array length=length) (transfer none): + */ +void +gi_marshalling_tests_array_out (gint **ints, gint *length) +{ + static gint values[] = { -1, 0, 1, 2 }; + + *length = 4; + *ints = values; +} + +/** + * gi_marshalling_tests_array_out_uninitialized: + * @v: (out) (array length=length) (transfer none): + * @length: + */ +gboolean +gi_marshalling_tests_array_out_uninitialized (gint **v G_GNUC_UNUSED, gint *length G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_array_out_etc: + * @first: + * @ints: (out) (array length=length) (transfer none): + * @length: (out): + * @last: + * @sum: (out): + */ +void +gi_marshalling_tests_array_out_etc (gint first, gint **ints, gint *length, gint last, gint *sum) +{ + static gint values[] = { -1, 0, 1, 2 }; + + values[0] = first; + values[3] = last; + *sum = first + last; + *length = 4; + *ints = values; +} + +/** + * gi_marshalling_tests_array_bool_out: + * @bools: (out) (array length=length) (transfer none): + */ +void +gi_marshalling_tests_array_bool_out (const gboolean **bools, gint *length) +{ + static const gboolean values[] = { TRUE, FALSE, TRUE, TRUE }; + + *length = 4; + *bools = values; +} + +/** + * gi_marshalling_tests_array_unichar_out: + * @chars: (out) (array length=length) (transfer none): + */ +void +gi_marshalling_tests_array_unichar_out (const gunichar **chars, gint *length) +{ + static const gunichar values[] = GI_MARSHALLING_TESTS_CONSTANT_UCS4; + *length = 12; + *chars = values; +} + +/** + * gi_marshalling_tests_array_inout: + * @ints: (inout) (array length=length) (transfer none): + * @length: (inout): + */ +void +gi_marshalling_tests_array_inout (gint **ints, gint *length) +{ + static gint values[] = { -2, -1, 0, 1, 2 }; + + g_assert_cmpint (*length, ==, 4); + g_assert_cmpint ((*ints)[0], ==, -1); + g_assert_cmpint ((*ints)[1], ==, 0); + g_assert_cmpint ((*ints)[2], ==, 1); + g_assert_cmpint ((*ints)[3], ==, 2); + + *length = 5; + *ints = values; +} + +/** + * gi_marshalling_tests_array_inout_etc: + * @first: + * @ints: (inout) (array length=length) (transfer none): + * @length: (inout): + * @last: + * @sum: (out): + */ +void +gi_marshalling_tests_array_inout_etc (gint first, gint **ints, gint *length, gint last, gint *sum) +{ + static gint values[] = { -2, -1, 0, 1, 2 }; + + g_assert_cmpint (*length, ==, 4); + g_assert_cmpint ((*ints)[0], ==, -1); + g_assert_cmpint ((*ints)[1], ==, 0); + g_assert_cmpint ((*ints)[2], ==, 1); + g_assert_cmpint ((*ints)[3], ==, 2); + + values[0] = first; + values[4] = last; + *sum = first + last; + *length = 5; + *ints = values; +} + +/** + * gi_marshalling_tests_array_in_nonzero_nonlen: + * @first: + * @chars: (array): + */ +void +gi_marshalling_tests_array_in_nonzero_nonlen (gint first G_GNUC_UNUSED, + const guint8 *chars) +{ + g_assert (chars[0] == 'a'); + g_assert (chars[1] == 'b'); + g_assert (chars[2] == 'c'); + g_assert (chars[3] == 'd'); +} + +/** + * gi_marshalling_tests_array_zero_terminated_return: + * + * Returns: (array zero-terminated) (transfer none): + */ +const gchar ** +gi_marshalling_tests_array_zero_terminated_return (void) +{ + static const gchar *values[] = { "0", "1", "2", NULL }; + return values; +} + +/** + * gi_marshalling_tests_array_zero_terminated_return_null: + * + * Returns: (array zero-terminated) (transfer none): + */ +gchar ** +gi_marshalling_tests_array_zero_terminated_return_null (void) +{ + return NULL; +} + +/** + * gi_marshalling_tests_array_zero_terminated_return_struct: + * + * Returns: (array zero-terminated) (transfer full): + */ +GIMarshallingTestsBoxedStruct ** +gi_marshalling_tests_array_zero_terminated_return_struct (void) +{ + GIMarshallingTestsBoxedStruct **ret = (GIMarshallingTestsBoxedStruct **) g_new (gpointer, 4); + + ret[0] = gi_marshalling_tests_boxed_struct_new (); + ret[0]->long_ = 42; + + ret[1] = gi_marshalling_tests_boxed_struct_new (); + ret[1]->long_ = 43; + + ret[2] = gi_marshalling_tests_boxed_struct_new (); + ret[2]->long_ = 44; + + ret[3] = NULL; + + return ret; +} + +/** + * gi_marshalling_tests_array_zero_terminated_return_unichar: + * + * Returns: (array zero-terminated) (transfer full): + */ +gunichar * +gi_marshalling_tests_array_zero_terminated_return_unichar (void) +{ + static const gunichar value[] = GI_MARSHALLING_TESTS_CONSTANT_UCS4; + gunichar *retval = g_new0 (gunichar, 13); + memcpy (retval, value, 12 * sizeof (gunichar)); + return retval; +} + +/** + * gi_marshalling_tests_array_zero_terminated_in: + * @utf8s: (array zero-terminated) (transfer none): + */ +void +gi_marshalling_tests_array_zero_terminated_in (gchar **utf8s) +{ + g_assert (g_strv_length (utf8s)); + g_assert_cmpstr (utf8s[0], ==, "0"); + g_assert_cmpstr (utf8s[1], ==, "1"); + g_assert_cmpstr (utf8s[2], ==, "2"); +} + +/** + * gi_marshalling_tests_array_zero_terminated_out: + * @utf8s: (out) (array zero-terminated) (transfer none): + */ +void +gi_marshalling_tests_array_zero_terminated_out (const gchar ***utf8s) +{ + static const gchar *values[] = { "0", "1", "2", NULL }; + *utf8s = values; +} + +/** + * gi_marshalling_tests_array_zero_terminated_out_uninitialized: + * @v: (out) (array zero-terminated) (transfer none): + */ +gboolean +gi_marshalling_tests_array_zero_terminated_out_uninitialized (const gchar ***v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_array_zero_terminated_inout: + * @utf8s: (inout) (array zero-terminated) (transfer none): + */ +void +gi_marshalling_tests_array_zero_terminated_inout (const gchar ***utf8s) +{ + static const gchar *values[] = { "-1", "0", "1", "2", NULL }; + + g_assert (g_strv_length ((gchar **) (*utf8s))); + g_assert_cmpstr ((*utf8s)[0], ==, "0"); + g_assert_cmpstr ((*utf8s)[1], ==, "1"); + g_assert_cmpstr ((*utf8s)[2], ==, "2"); + + *utf8s = values; +} + +/** + * gi_marshalling_tests_array_gvariant_none_in: + * @variants: (array zero-terminated) (transfer none): + * + * Returns: (array zero-terminated) (transfer none): + */ +GVariant ** +gi_marshalling_tests_array_gvariant_none_in (GVariant **variants) +{ + /* Use a static container to detect if someone tries to free it */ + static GVariant *private_container[3] = { NULL, NULL, NULL }; + + if (private_container[0] == NULL) + { + private_container[0] = g_variant_new_int32 (27); + private_container[1] = g_variant_new_string ("Hello"); + } + + g_assert (variants != NULL); + g_assert_cmpint (g_variant_get_int32 (variants[0]), ==, 27); + g_assert_cmpstr (g_variant_get_string (variants[1], NULL), ==, "Hello"); + g_assert (variants[2] == NULL); + + return private_container; +} + +/** + * gi_marshalling_tests_array_gvariant_container_in: + * @variants: (array zero-terminated) (transfer container): + * + * Returns: (array zero-terminated) (transfer container): + */ +GVariant ** +gi_marshalling_tests_array_gvariant_container_in (GVariant **variants) +{ + GVariant **container; + + g_assert (variants != NULL); + g_assert_cmpint (g_variant_get_int32 (variants[0]), ==, 27); + g_assert_cmpstr (g_variant_get_string (variants[1], NULL), ==, "Hello"); + g_assert (variants[2] == NULL); + + container = g_new0 (GVariant *, 3); + /* This is a floating reference, so it's fine for transfer container */ + container[0] = g_variant_new_int32 (g_variant_get_int32 (variants[0])); + container[1] = variants[1]; + g_free (variants); + + return container; +} + +/** + * gi_marshalling_tests_array_gvariant_full_in: + * @variants: (array zero-terminated) (transfer full): + * + * Returns: (array zero-terminated) (transfer full): + */ +GVariant ** +gi_marshalling_tests_array_gvariant_full_in (GVariant **variants) +{ + GVariant **container; + + g_assert (variants != NULL); + g_assert_cmpint (g_variant_get_int32 (variants[0]), ==, 27); + g_assert_cmpstr (g_variant_get_string (variants[1], NULL), ==, "Hello"); + g_assert (variants[2] == NULL); + + /* To catch different behaviors we reconstruct one variant from scratch, + * while taking the refernce of the other. Both approaches are legal with full + * transfer in and out */ + container = g_new0 (GVariant *, 3); + container[0] = g_variant_ref_sink ( + g_variant_new_int32 (g_variant_get_int32 (variants[0]))); + g_variant_unref (variants[0]); + + /* In case the variant is floating, we want to transform it into a full + * reference, so that's fully owned by the container like if the case + * above, otherwise we just steal it since it has already a strong reference. + */ + container[1] = g_variant_take_ref (variants[1]); + g_free (variants); + + return container; +} + +/** + * gi_marshalling_tests_garray_int_none_return: + * + * Returns: (element-type gint) (transfer none): + */ +GArray * +gi_marshalling_tests_garray_int_none_return (void) +{ + static GArray *v = NULL; + gint i; + + if (v == NULL) + { + v = g_array_new (TRUE, TRUE, sizeof (gint)); + for (i = -1; i < 3; i++) + g_array_append_val (v, i); + } + + return v; +} + +/** + * gi_marshalling_tests_garray_uint64_none_return: + * + * Returns: (element-type guint64) (transfer none): + */ +GArray * +gi_marshalling_tests_garray_uint64_none_return (void) +{ + static GArray *array = NULL; + guint64 i; + + if (array == NULL) + { + array = g_array_new (TRUE, TRUE, sizeof (guint64)); + i = 0; + g_array_append_val (array, i); + i = G_MAXUINT64; + g_array_append_val (array, i); + } + + return array; +} + +/** + * gi_marshalling_tests_garray_utf8_none_return: + * + * Returns: (element-type utf8) (transfer none): + */ +GArray * +gi_marshalling_tests_garray_utf8_none_return (void) +{ + static GArray *array = NULL; + static const gchar *values[] = { "0", "1", "2", NULL }; + gint i; + + if (array == NULL) + { + array = g_array_new (TRUE, TRUE, sizeof (gchar *)); + for (i = 0; values[i]; i++) + g_array_append_val (array, values[i]); + } + + return array; +} + +/** + * gi_marshalling_tests_garray_utf8_container_return: + * + * Returns: (element-type utf8) (transfer container): + */ +GArray * +gi_marshalling_tests_garray_utf8_container_return (void) +{ + GArray *array = NULL; + static const gchar *values[] = { "0", "1", "2", NULL }; + gint i; + + array = g_array_new (TRUE, TRUE, sizeof (gchar *)); + for (i = 0; values[i]; i++) + g_array_append_val (array, values[i]); + + return array; +} + +/** + * gi_marshalling_tests_garray_utf8_full_return: + * + * Returns: (element-type utf8) (transfer full): + */ +GArray * +gi_marshalling_tests_garray_utf8_full_return (void) +{ + GArray *array = NULL; + static const gchar *values[] = { "0", "1", "2", NULL }; + gint i; + + array = g_array_new (TRUE, TRUE, sizeof (gchar *)); + for (i = 0; values[i]; i++) + { + gchar *str = g_strdup (values[i]); + g_array_append_val (array, str); + } + + return array; +} + +/** + * gi_marshalling_tests_garray_boxed_struct_full_return: + * + * Returns: (element-type GIMarshallingTestsBoxedStruct) (transfer full): + */ +GArray * +gi_marshalling_tests_garray_boxed_struct_full_return (void) +{ + GArray *array = NULL; + static const glong long_values[] = { 42, 43, 44 }; + gint i; + + array = g_array_new (TRUE, TRUE, sizeof (GIMarshallingTestsBoxedStruct)); + g_array_set_size (array, 3); + for (i = 0; i < 3; i++) + { + GIMarshallingTestsBoxedStruct *new_struct; + new_struct = &g_array_index (array, GIMarshallingTestsBoxedStruct, i); + memset (new_struct, 0, sizeof (GIMarshallingTestsSimpleStruct)); + new_struct->long_ = long_values[i]; + } + + return array; +} + +/** + * gi_marshalling_tests_garray_int_none_in: + * @array_: (element-type gint) (transfer none): + */ +void +gi_marshalling_tests_garray_int_none_in (GArray *array_) +{ + g_assert_cmpint (array_->len, ==, 4); + g_assert_cmpint (g_array_index (array_, gint, 0), ==, -1); + g_assert_cmpint (g_array_index (array_, gint, 1), ==, 0); + g_assert_cmpint (g_array_index (array_, gint, 2), ==, 1); + g_assert_cmpint (g_array_index (array_, gint, 3), ==, 2); +} + +/** + * gi_marshalling_tests_garray_uint64_none_in: + * @array_: (element-type guint64) (transfer none): + */ +void +gi_marshalling_tests_garray_uint64_none_in (GArray *array_) +{ + g_assert_cmpint (array_->len, ==, 2); + g_assert_cmpint (g_array_index (array_, guint64, 0), ==, 0); + g_assert_cmpint (g_array_index (array_, guint64, 1), ==, G_MAXUINT64); +} + +/** + * gi_marshalling_tests_garray_utf8_none_in: + * @array_: (element-type utf8) (transfer none): + */ +void +gi_marshalling_tests_garray_utf8_none_in (GArray *array_) +{ + g_assert_cmpint (array_->len, ==, 3); + g_assert_cmpstr (g_array_index (array_, gchar *, 0), ==, "0"); + g_assert_cmpstr (g_array_index (array_, gchar *, 1), ==, "1"); + g_assert_cmpstr (g_array_index (array_, gchar *, 2), ==, "2"); +} + +/** + * gi_marshalling_tests_garray_utf8_none_out: + * @array_: (out) (element-type utf8) (transfer none): + */ +void +gi_marshalling_tests_garray_utf8_none_out (GArray **array_) +{ + static GArray *internal = NULL; + static const gchar *values[] = { "0", "1", "2", NULL }; + gint i; + + if (internal == NULL) + { + internal = g_array_new (TRUE, TRUE, sizeof (gchar *)); + for (i = 0; values[i]; i++) + g_array_append_val (internal, values[i]); + } + + *array_ = internal; +} + +/** + * gi_marshalling_tests_garray_utf8_none_out_uninitialized: + * @v: (out) (element-type utf8) (transfer none): + */ +gboolean +gi_marshalling_tests_garray_utf8_none_out_uninitialized (GArray **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_garray_utf8_container_out: + * @array_: (out) (element-type utf8) (transfer container): + */ +void +gi_marshalling_tests_garray_utf8_container_out (GArray **array_) +{ + static const gchar *values[] = { "0", "1", "2", NULL }; + gint i; + + *array_ = NULL; + + *array_ = g_array_new (TRUE, TRUE, sizeof (gchar *)); + for (i = 0; values[i]; i++) + g_array_append_val (*array_, values[i]); +} + +/** + * gi_marshalling_tests_garray_utf8_container_out_uninitialized: + * @v: (out) (element-type utf8) (transfer container): + */ +gboolean +gi_marshalling_tests_garray_utf8_container_out_uninitialized (GArray **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_garray_utf8_full_out: + * @array_: (out) (element-type utf8) (transfer full): + */ +void +gi_marshalling_tests_garray_utf8_full_out (GArray **array_) +{ + static const gchar *values[] = { "0", "1", "2", NULL }; + gint i; + + *array_ = NULL; + + *array_ = g_array_new (TRUE, TRUE, sizeof (gchar *)); + for (i = 0; values[i]; i++) + { + gchar *str = g_strdup (values[i]); + g_array_append_val (*array_, str); + } +} + +/** + * gi_marshalling_tests_garray_utf8_full_out_uninitialized: + * @v: (out) (element-type utf8) (transfer full): + */ +gboolean +gi_marshalling_tests_garray_utf8_full_out_uninitialized (GArray **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_garray_utf8_full_out_caller_allocated: + * @array_: (out caller-allocates) (array) (element-type utf8) (transfer full): + */ +void +gi_marshalling_tests_garray_utf8_full_out_caller_allocated (GArray *array_) +{ + static const gchar *values[] = { "0", "1", "2", NULL }; + gint i; + + g_array_set_size (array_, 0); + for (i = 0; values[i]; i++) + { + gchar *str = g_strdup (values[i]); + g_array_append_val (array_, str); + } +} + +/** + * gi_marshalling_tests_garray_utf8_none_inout: + * @array_: (inout) (element-type utf8) (transfer none): + */ +void +gi_marshalling_tests_garray_utf8_none_inout (GArray **array_) +{ + static GArray *internal = NULL; + static const gchar *values[] = { "-2", "-1", "0", "1", NULL }; + gint i; + + g_assert_cmpint ((*array_)->len, ==, 3); + g_assert_cmpstr (g_array_index (*array_, gchar *, 0), ==, "0"); + g_assert_cmpstr (g_array_index (*array_, gchar *, 1), ==, "1"); + g_assert_cmpstr (g_array_index (*array_, gchar *, 2), ==, "2"); + + if (internal == NULL) + { + internal = g_array_new (TRUE, TRUE, sizeof (gchar *)); + for (i = 0; values[i]; i++) + g_array_append_val (internal, values[i]); + } + + *array_ = internal; +} + +/** + * gi_marshalling_tests_garray_utf8_container_inout: + * @array_: (inout) (element-type utf8) (transfer container): + */ +void +gi_marshalling_tests_garray_utf8_container_inout (GArray **array_) +{ + static const gchar *val1 = "-2"; + static const gchar *val2 = "-1"; + static const gchar *val3 = "0"; + static const gchar *val4 = "1"; + GArray *result; + + g_assert_cmpint ((*array_)->len, ==, 3); + g_assert_cmpstr (g_array_index (*array_, gchar *, 0), ==, "0"); + g_assert_cmpstr (g_array_index (*array_, gchar *, 1), ==, "1"); + g_assert_cmpstr (g_array_index (*array_, gchar *, 2), ==, "2"); + + result = g_array_new (TRUE, TRUE, sizeof (gchar *)); + g_array_append_val (result, val1); + g_array_append_val (result, val2); + g_array_append_val (result, val3); + g_array_append_val (result, val4); + + g_array_unref (*array_); + *array_ = result; +} + +/** + * gi_marshalling_tests_garray_utf8_full_inout: + * @array_: (inout) (element-type utf8) (transfer full): + */ +void +gi_marshalling_tests_garray_utf8_full_inout (GArray **array_) +{ + static const gchar *val1 = "-1"; + static const gchar *val2 = "-2"; + gchar *val; + GArray *result; + + g_assert_cmpint ((*array_)->len, ==, 3); + g_assert_cmpstr (g_array_index (*array_, gchar *, 0), ==, "0"); + g_assert_cmpstr (g_array_index (*array_, gchar *, 1), ==, "1"); + g_assert_cmpstr (g_array_index (*array_, gchar *, 2), ==, "2"); + + result = g_array_new (TRUE, TRUE, sizeof (gchar *)); + val = g_strdup (val2); + g_array_append_val (result, val); + val = g_strdup (val1); + g_array_append_val (result, val); + val = g_strdup ("0"); + g_array_append_val (result, val); + val = g_strdup ("1"); + g_array_append_val (result, val); + + g_array_unref (*array_); + *array_ = result; +} + +/** + * gi_marshalling_tests_garray_bool_none_in: + * @array_: (element-type gboolean) (transfer none): + */ +void +gi_marshalling_tests_garray_bool_none_in (GArray *array_) +{ + g_assert_cmpint (array_->len, ==, 4); + g_assert_cmpint (g_array_index (array_, gboolean, 0), ==, TRUE); + g_assert_cmpint (g_array_index (array_, gboolean, 1), ==, FALSE); + g_assert_cmpint (g_array_index (array_, gboolean, 2), ==, TRUE); + g_assert_cmpint (g_array_index (array_, gboolean, 3), ==, TRUE); +} + +/** + * gi_marshalling_tests_garray_unichar_none_in: + * @array_: (element-type gunichar) (transfer none): + */ +void +gi_marshalling_tests_garray_unichar_none_in (GArray *array_) +{ + unsigned ix; + static const gunichar expected[] = GI_MARSHALLING_TESTS_CONSTANT_UCS4; + g_assert_cmpint (array_->len, ==, 12); + for (ix = 0; ix < array_->len; ix++) + g_assert_cmpuint (g_array_index (array_, gunichar, ix), ==, expected[ix]); +} + +/** + * gi_marshalling_tests_gptrarray_utf8_none_return: + * + * Returns: (element-type utf8) (transfer none): + */ +GPtrArray * +gi_marshalling_tests_gptrarray_utf8_none_return (void) +{ + static GPtrArray *parray = NULL; + static const gchar *values[] = { "0", "1", "2" }; + gint i; + + if (parray == NULL) + { + parray = g_ptr_array_new (); + for (i = 0; i < 3; i++) + g_ptr_array_add (parray, (gpointer) values[i]); + } + + return parray; +} + +/** + * gi_marshalling_tests_gptrarray_utf8_container_return: + * + * Returns: (element-type utf8) (transfer container): + */ +GPtrArray * +gi_marshalling_tests_gptrarray_utf8_container_return (void) +{ + GPtrArray *parray = NULL; + static const gchar *values[] = { "0", "1", "2", NULL }; + gint i; + + parray = g_ptr_array_new (); + for (i = 0; values[i]; i++) + g_ptr_array_add (parray, (gpointer) values[i]); + + return parray; +} + +/** + * gi_marshalling_tests_gptrarray_utf8_full_return: + * + * Returns: (element-type utf8) (transfer full): + */ +GPtrArray * +gi_marshalling_tests_gptrarray_utf8_full_return (void) +{ + GPtrArray *parray = NULL; + static const gchar *values[] = { "0", "1", "2", NULL }; + gint i; + + parray = g_ptr_array_new (); + for (i = 0; values[i]; i++) + { + gchar *str = g_strdup (values[i]); + g_ptr_array_add (parray, (gpointer) str); + } + + return parray; +} + +/** + * gi_marshalling_tests_gptrarray_boxed_struct_full_return: + * + * Returns: (element-type GIMarshallingTestsBoxedStruct) (transfer full): + */ +GPtrArray * +gi_marshalling_tests_gptrarray_boxed_struct_full_return (void) +{ + GPtrArray *parray = NULL; + static const glong long_values[] = { 42, 43, 44 }; + gint i; + + parray = g_ptr_array_new (); + for (i = 0; i < 3; i++) + { + GIMarshallingTestsBoxedStruct *new_struct = gi_marshalling_tests_boxed_struct_new (); + new_struct->long_ = long_values[i]; + g_ptr_array_add (parray, (gpointer) new_struct); + } + + return parray; +} + +/** + * gi_marshalling_tests_gptrarray_utf8_none_in: + * @parray_: (element-type utf8) (transfer none): + */ +void +gi_marshalling_tests_gptrarray_utf8_none_in (GPtrArray *parray_) +{ + g_assert_cmpint (parray_->len, ==, 3); + g_assert_cmpstr (g_ptr_array_index (parray_, 0), ==, "0"); + g_assert_cmpstr (g_ptr_array_index (parray_, 1), ==, "1"); + g_assert_cmpstr (g_ptr_array_index (parray_, 2), ==, "2"); +} + +/** + * gi_marshalling_tests_gptrarray_utf8_none_out: + * @parray_: (out) (element-type utf8) (transfer none): + */ +void +gi_marshalling_tests_gptrarray_utf8_none_out (GPtrArray **parray_) +{ + static GPtrArray *internal = NULL; + static const gchar *values[] = { "0", "1", "2", NULL }; + gint i; + + if (internal == NULL) + { + internal = g_ptr_array_new (); + for (i = 0; values[i]; i++) + g_ptr_array_add (internal, (gpointer) values[i]); + } + + *parray_ = internal; +} + +/** + * gi_marshalling_tests_gptrarray_utf8_none_out_uninitialized: + * @v: (out) (element-type utf8) (transfer none): + */ +gboolean +gi_marshalling_tests_gptrarray_utf8_none_out_uninitialized (GPtrArray **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_gptrarray_utf8_container_out: + * @parray_: (out) (element-type utf8) (transfer container): + */ +void +gi_marshalling_tests_gptrarray_utf8_container_out (GPtrArray **parray_) +{ + static const gchar *values[] = { "0", "1", "2", NULL }; + gint i; + + *parray_ = NULL; + + *parray_ = g_ptr_array_new (); + for (i = 0; values[i]; i++) + g_ptr_array_add (*parray_, (gpointer) values[i]); +} + +/** + * gi_marshalling_tests_gptrarray_utf8_container_out_uninitialized: + * @v: (out) (element-type utf8) (transfer container): + */ +gboolean +gi_marshalling_tests_gptrarray_utf8_container_out_uninitialized (GPtrArray **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_gptrarray_utf8_full_out: + * @parray_: (out) (element-type utf8) (transfer full): + */ +void +gi_marshalling_tests_gptrarray_utf8_full_out (GPtrArray **parray_) +{ + static const gchar *values[] = { "0", "1", "2", NULL }; + gint i; + + *parray_ = NULL; + + *parray_ = g_ptr_array_new (); + for (i = 0; values[i]; i++) + { + gchar *str = g_strdup (values[i]); + g_ptr_array_add (*parray_, (gpointer) str); + } +} + +/** + * gi_marshalling_tests_gptrarray_utf8_full_out_uninitialized: + * @v: (out) (element-type utf8) (transfer full): + */ +gboolean +gi_marshalling_tests_gptrarray_utf8_full_out_uninitialized (GPtrArray **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_gptrarray_utf8_none_inout: + * @parray_: (inout) (element-type utf8) (transfer none): + */ +void +gi_marshalling_tests_gptrarray_utf8_none_inout (GPtrArray **parray_) +{ + static GPtrArray *internal = NULL; + static const gchar *values[] = { "-2", "-1", "0", "1", NULL }; + gint i; + + g_assert_cmpint ((*parray_)->len, ==, 3); + g_assert_cmpstr (g_ptr_array_index (*parray_, 0), ==, "0"); + g_assert_cmpstr (g_ptr_array_index (*parray_, 1), ==, "1"); + g_assert_cmpstr (g_ptr_array_index (*parray_, 2), ==, "2"); + + if (internal == NULL) + { + internal = g_ptr_array_new (); + for (i = 0; values[i]; i++) + g_ptr_array_add (internal, (gpointer) values[i]); + } + + *parray_ = internal; +} + +/** + * gi_marshalling_tests_gptrarray_utf8_container_inout: + * @parray_: (inout) (element-type utf8) (transfer container): + */ +void +gi_marshalling_tests_gptrarray_utf8_container_inout (GPtrArray **parray_) +{ + static const gchar *val1 = "-2"; + static const gchar *val2 = "-1"; + static const gchar *val3 = "0"; + static const gchar *val4 = "1"; + GPtrArray *result; + + g_assert_cmpint ((*parray_)->len, ==, 3); + g_assert_cmpstr (g_ptr_array_index (*parray_, 0), ==, "0"); + g_assert_cmpstr (g_ptr_array_index (*parray_, 1), ==, "1"); + g_assert_cmpstr (g_ptr_array_index (*parray_, 2), ==, "2"); + + result = g_ptr_array_new (); + g_ptr_array_add (result, (gpointer) val1); + g_ptr_array_add (result, (gpointer) val2); + g_ptr_array_add (result, (gpointer) val3); + g_ptr_array_add (result, (gpointer) val4); + + g_ptr_array_unref (*parray_); + *parray_ = result; +} + +/** + * gi_marshalling_tests_gptrarray_utf8_full_inout: + * @parray_: (inout) (element-type utf8) (transfer full): + */ +void +gi_marshalling_tests_gptrarray_utf8_full_inout (GPtrArray **parray_) +{ + static const gchar *val1 = "-1"; + static const gchar *val2 = "-2"; + gchar *val; + GPtrArray *result; + + g_assert_cmpint ((*parray_)->len, ==, 3); + g_assert_cmpstr (g_ptr_array_index (*parray_, 0), ==, "0"); + g_assert_cmpstr (g_ptr_array_index (*parray_, 1), ==, "1"); + g_assert_cmpstr (g_ptr_array_index (*parray_, 2), ==, "2"); + + result = g_ptr_array_new (); + val = g_strdup (val2); + g_ptr_array_add (result, (gpointer) val); + val = g_strdup (val1); + g_ptr_array_add (result, (gpointer) val); + val = g_strdup ("0"); + g_ptr_array_add (result, (gpointer) val); + val = g_strdup ("1"); + g_ptr_array_add (result, (gpointer) val); + + g_ptr_array_unref (*parray_); + *parray_ = result; +} + +/** + * gi_marshalling_tests_bytearray_full_return: + * + * Returns: (transfer full): + */ +GByteArray * +gi_marshalling_tests_bytearray_full_return (void) +{ + GByteArray *array = NULL; + guint8 data[] = { '\0', '1', '\xFF', '3' }; + + array = g_byte_array_new (); + g_byte_array_append (array, (const guint8 *) data, G_N_ELEMENTS (data)); + + return array; +} + +/** + * gi_marshalling_tests_bytearray_none_in: + * @v: (element-type gint8) (transfer none): + */ +void +gi_marshalling_tests_bytearray_none_in (GByteArray *v) +{ + g_assert_cmpuint (v->len, ==, 4); + g_assert_cmpuint (g_array_index (v, unsigned char, 0), ==, 0); + g_assert_cmpuint (g_array_index (v, unsigned char, 1), ==, 49); + g_assert_cmpuint (g_array_index (v, unsigned char, 2), ==, 0xFF); + g_assert_cmpuint (g_array_index (v, unsigned char, 3), ==, 51); +} + +/** + * gi_marshalling_tests_gbytes_full_return: + * + * Returns: (transfer full): + */ +GBytes * +gi_marshalling_tests_gbytes_full_return (void) +{ + static guint8 data[] = { 0, 49, 0xFF, 51 }; + + return g_bytes_new_static (data, G_N_ELEMENTS (data)); +} + +/** + * gi_marshalling_tests_gbytes_none_in: + */ +void +gi_marshalling_tests_gbytes_none_in (GBytes *v) +{ + const guint8 *data; + gsize len; + data = g_bytes_get_data (v, &len); + + g_assert_cmpuint (len, ==, 4); + g_assert_cmpuint (data[0], ==, 0); + g_assert_cmpuint (data[1], ==, 49); + g_assert_cmpuint (data[2], ==, 0xFF); + g_assert_cmpuint (data[3], ==, 51); +} + +/** + * gi_marshalling_tests_gstrv_return: + * + * Returns: (transfer full): an array of strings + */ +GStrv +gi_marshalling_tests_gstrv_return (void) +{ + GStrv values = g_new0 (gchar *, 4); + values[0] = g_strdup ("0"); + values[1] = g_strdup ("1"); + values[2] = g_strdup ("2"); + values[3] = NULL; + return values; +} + +/** + * gi_marshalling_tests_gstrv_in: + * @g_strv: + */ +void +gi_marshalling_tests_gstrv_in (GStrv g_strv) +{ + g_assert_cmpint (g_strv_length (g_strv), ==, 3); + g_assert_cmpstr (g_strv[0], ==, "0"); + g_assert_cmpstr (g_strv[1], ==, "1"); + g_assert_cmpstr (g_strv[2], ==, "2"); +} + +/** + * gi_marshalling_tests_gstrv_out: + * @g_strv: (out) (transfer none): + */ +void +gi_marshalling_tests_gstrv_out (GStrv *g_strv) +{ + static const gchar *values[] = { "0", "1", "2", NULL }; + *g_strv = (gchar **) values; +} + +/** + * gi_marshalling_tests_gstrv_out_uninitialized: + * @v: (out) (transfer none): + */ +gboolean +gi_marshalling_tests_gstrv_out_uninitialized (GStrv *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_gstrv_inout: + * @g_strv: (inout) (transfer none): + */ +void +gi_marshalling_tests_gstrv_inout (GStrv *g_strv) +{ + static const gchar *values[] = { "-1", "0", "1", "2", NULL }; + + g_assert (g_strv_length (*g_strv) == 3); + g_assert (strcmp ((*g_strv)[0], "0") == 0); + g_assert (strcmp ((*g_strv)[1], "1") == 0); + g_assert (strcmp ((*g_strv)[2], "2") == 0); + + *g_strv = (gchar **) values; +} + +/** + * gi_marshalling_tests_glist_int_none_return: + * + * Returns: (element-type gint) (transfer none): + */ +GList * +gi_marshalling_tests_glist_int_none_return (void) +{ + static GList *list = NULL; + + if (list == NULL) + { + list = g_list_append (list, GINT_TO_POINTER (-1)); + list = g_list_append (list, GINT_TO_POINTER (0)); + list = g_list_append (list, GINT_TO_POINTER (1)); + list = g_list_append (list, GINT_TO_POINTER (2)); + } + + return list; +} + +/** + * gi_marshalling_tests_glist_uint32_none_return: + * + * Returns: (element-type guint32) (transfer none): + */ +GList * +gi_marshalling_tests_glist_uint32_none_return (void) +{ + static GList *list = NULL; + + if (list == NULL) + { + list = g_list_append (list, GUINT_TO_POINTER (0)); + list = g_list_append (list, GUINT_TO_POINTER (G_MAXUINT32)); + } + + return list; +} + +/** + * gi_marshalling_tests_glist_utf8_none_return: + * + * Returns: (element-type utf8) (transfer none): + */ +GList * +gi_marshalling_tests_glist_utf8_none_return (void) +{ + static GList *list = NULL; + + if (list == NULL) + { + list = g_list_append (list, (gpointer) "0"); + list = g_list_append (list, (gpointer) "1"); + list = g_list_append (list, (gpointer) "2"); + } + + return list; +} + +/** + * gi_marshalling_tests_glist_utf8_container_return: + * + * Returns: (element-type utf8) (transfer container): + */ +GList * +gi_marshalling_tests_glist_utf8_container_return (void) +{ + GList *list = NULL; + + list = g_list_append (list, (gpointer) "0"); + list = g_list_append (list, (gpointer) "1"); + list = g_list_append (list, (gpointer) "2"); + + return list; +} + +/** + * gi_marshalling_tests_glist_utf8_full_return: + * + * Returns: (element-type utf8) (transfer full): + */ +GList * +gi_marshalling_tests_glist_utf8_full_return (void) +{ + GList *list = NULL; + + list = g_list_append (list, g_strdup ("0")); + list = g_list_append (list, g_strdup ("1")); + list = g_list_append (list, g_strdup ("2")); + + return list; +} + +/** + * gi_marshalling_tests_glist_int_none_in: + * @list: (element-type gint) (transfer none): + */ +void +gi_marshalling_tests_glist_int_none_in (GList *list) +{ + g_assert_cmpint (g_list_length (list), ==, 4); + g_assert_cmpint (GPOINTER_TO_INT (g_list_nth_data (list, 0)), ==, -1); + g_assert_cmpint (GPOINTER_TO_INT (g_list_nth_data (list, 1)), ==, 0); + g_assert_cmpint (GPOINTER_TO_INT (g_list_nth_data (list, 2)), ==, 1); + g_assert_cmpint (GPOINTER_TO_INT (g_list_nth_data (list, 3)), ==, 2); +} + +/** + * gi_marshalling_tests_glist_uint32_none_in: + * @list: (element-type guint32) (transfer none): + */ +void +gi_marshalling_tests_glist_uint32_none_in (GList *list) +{ + g_assert_cmpint (g_list_length (list), ==, 2); + g_assert_cmpint (GPOINTER_TO_UINT (g_list_nth_data (list, 0)), ==, 0); + g_assert_cmpint (GPOINTER_TO_UINT (g_list_nth_data (list, 1)), ==, G_MAXUINT32); +} + +/** + * gi_marshalling_tests_glist_utf8_none_in: + * @list: (element-type utf8) (transfer none): + */ +void +gi_marshalling_tests_glist_utf8_none_in (GList *list) +{ + g_assert_cmpint (g_list_length (list), ==, 3); + g_assert_cmpint (strcmp (g_list_nth_data (list, 0), "0"), ==, 0); + g_assert_cmpint (strcmp (g_list_nth_data (list, 1), "1"), ==, 0); + g_assert_cmpint (strcmp (g_list_nth_data (list, 2), "2"), ==, 0); +} + +/** + * gi_marshalling_tests_glist_utf8_none_out: + * @list: (out) (element-type utf8) (transfer none): + */ +void +gi_marshalling_tests_glist_utf8_none_out (GList **list) +{ + static GList *values = NULL; + + if (values == NULL) + { + values = g_list_append (values, (gpointer) "0"); + values = g_list_append (values, (gpointer) "1"); + values = g_list_append (values, (gpointer) "2"); + } + + *list = values; +} + +/** + * gi_marshalling_tests_glist_utf8_none_out_uninitialized: + * @v: (out) (element-type utf8) (transfer none): + */ +gboolean +gi_marshalling_tests_glist_utf8_none_out_uninitialized (GList **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_glist_utf8_container_out: + * @list: (out) (element-type utf8) (transfer container): + */ +void +gi_marshalling_tests_glist_utf8_container_out (GList **list) +{ + *list = NULL; + + *list = g_list_append (*list, (gpointer) "0"); + *list = g_list_append (*list, (gpointer) "1"); + *list = g_list_append (*list, (gpointer) "2"); +} + +/** + * gi_marshalling_tests_glist_utf8_container_out_uninitialized: + * @v: (out) (element-type utf8) (transfer container): + */ +gboolean +gi_marshalling_tests_glist_utf8_container_out_uninitialized (GList **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_glist_utf8_full_out: + * @list: (out) (element-type utf8) (transfer full): + */ +void +gi_marshalling_tests_glist_utf8_full_out (GList **list) +{ + *list = NULL; + + *list = g_list_append (*list, g_strdup ("0")); + *list = g_list_append (*list, g_strdup ("1")); + *list = g_list_append (*list, g_strdup ("2")); +} + +/** + * gi_marshalling_tests_glist_utf8_full_out_uninitialized: + * @v: (out) (element-type utf8) (transfer full): + */ +gboolean +gi_marshalling_tests_glist_utf8_full_out_uninitialized (GList **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_glist_utf8_none_inout: + * @list: (inout) (element-type utf8) (transfer none): + */ +void +gi_marshalling_tests_glist_utf8_none_inout (GList **list) +{ + static GList *values = NULL; + + g_assert_cmpint (g_list_length (*list), ==, 3); + g_assert_cmpstr (g_list_nth_data (*list, 0), ==, "0"); + g_assert_cmpstr (g_list_nth_data (*list, 1), ==, "1"); + g_assert_cmpstr (g_list_nth_data (*list, 2), ==, "2"); + + if (values == NULL) + { + values = g_list_append (values, (gpointer) "-2"); + values = g_list_append (values, (gpointer) "-1"); + values = g_list_append (values, (gpointer) "0"); + values = g_list_append (values, (gpointer) "1"); + } + + *list = values; +} + +/** + * gi_marshalling_tests_glist_utf8_container_inout: + * @list: (inout) (element-type utf8) (transfer container): + */ +void +gi_marshalling_tests_glist_utf8_container_inout (GList **list) +{ + GList *result = NULL; + + g_assert_cmpint (g_list_length (*list), ==, 3); + g_assert_cmpstr (g_list_nth_data (*list, 0), ==, "0"); + g_assert_cmpstr (g_list_nth_data (*list, 1), ==, "1"); + g_assert_cmpstr (g_list_nth_data (*list, 2), ==, "2"); + + result = g_list_prepend (result, (gpointer) "1"); + result = g_list_prepend (result, (gpointer) "0"); + result = g_list_prepend (result, (gpointer) "-1"); + result = g_list_prepend (result, (gpointer) "-2"); + + g_list_free (*list); + *list = result; +} + +/** + * gi_marshalling_tests_glist_utf8_full_inout: + * @list: (inout) (element-type utf8) (transfer full): + */ +void +gi_marshalling_tests_glist_utf8_full_inout (GList **list) +{ + GList *result = NULL; + + g_assert_cmpint (g_list_length (*list), ==, 3); + g_assert_cmpstr (g_list_nth_data (*list, 0), ==, "0"); + g_assert_cmpstr (g_list_nth_data (*list, 1), ==, "1"); + g_assert_cmpstr (g_list_nth_data (*list, 2), ==, "2"); + + result = g_list_prepend (result, g_strdup ("1")); + result = g_list_prepend (result, g_strdup ("0")); + result = g_list_prepend (result, g_strdup ("-1")); + result = g_list_prepend (result, g_strdup ("-2")); + + g_list_free_full (*list, g_free); + *list = result; +} + +/** + * gi_marshalling_tests_gslist_int_none_return: + * + * Returns: (element-type gint) (transfer none): + */ +GSList * +gi_marshalling_tests_gslist_int_none_return (void) +{ + static GSList *list = NULL; + + if (list == NULL) + { + list = g_slist_prepend (list, GINT_TO_POINTER (-1)); + list = g_slist_prepend (list, GINT_TO_POINTER (0)); + list = g_slist_prepend (list, GINT_TO_POINTER (1)); + list = g_slist_prepend (list, GINT_TO_POINTER (2)); + list = g_slist_reverse (list); + } + + return list; +} + +/** + * gi_marshalling_tests_gslist_utf8_none_return: + * + * Returns: (element-type utf8) (transfer none): + */ +GSList * +gi_marshalling_tests_gslist_utf8_none_return (void) +{ + static GSList *list = NULL; + + if (list == NULL) + { + list = g_slist_prepend (list, (gpointer) "0"); + list = g_slist_prepend (list, (gpointer) "1"); + list = g_slist_prepend (list, (gpointer) "2"); + list = g_slist_reverse (list); + } + + return list; +} + +/** + * gi_marshalling_tests_gslist_utf8_container_return: + * + * Returns: (element-type utf8) (transfer container): + */ +GSList * +gi_marshalling_tests_gslist_utf8_container_return (void) +{ + GSList *list = NULL; + + list = g_slist_prepend (list, (gpointer) "0"); + list = g_slist_prepend (list, (gpointer) "1"); + list = g_slist_prepend (list, (gpointer) "2"); + list = g_slist_reverse (list); + + return list; +} + +/** + * gi_marshalling_tests_gslist_utf8_full_return: + * + * Returns: (element-type utf8) (transfer full): + */ +GSList * +gi_marshalling_tests_gslist_utf8_full_return (void) +{ + GSList *list = NULL; + + list = g_slist_prepend (list, g_strdup ("0")); + list = g_slist_prepend (list, g_strdup ("1")); + list = g_slist_prepend (list, g_strdup ("2")); + list = g_slist_reverse (list); + + return list; +} + +/** + * gi_marshalling_tests_gslist_int_none_in: + * @list: (element-type gint) (transfer none): + */ +void +gi_marshalling_tests_gslist_int_none_in (GSList *list) +{ + g_assert_cmpint (g_slist_length (list), ==, 4); + g_assert_cmpint (GPOINTER_TO_INT (g_slist_nth_data (list, 0)), ==, -1); + g_assert_cmpint (GPOINTER_TO_INT (g_slist_nth_data (list, 1)), ==, 0); + g_assert_cmpint (GPOINTER_TO_INT (g_slist_nth_data (list, 2)), ==, 1); + g_assert_cmpint (GPOINTER_TO_INT (g_slist_nth_data (list, 3)), ==, 2); +} + +/** + * gi_marshalling_tests_gslist_utf8_none_in: + * @list: (element-type utf8) (transfer none): + */ +void +gi_marshalling_tests_gslist_utf8_none_in (GSList *list) +{ + g_assert_cmpint (g_slist_length (list), ==, 3); + g_assert_cmpstr (g_slist_nth_data (list, 0), ==, "0"); + g_assert_cmpstr (g_slist_nth_data (list, 1), ==, "1"); + g_assert_cmpstr (g_slist_nth_data (list, 2), ==, "2"); +} + +/** + * gi_marshalling_tests_gslist_utf8_none_out: + * @list: (out) (element-type utf8) (transfer none): + */ +void +gi_marshalling_tests_gslist_utf8_none_out (GSList **list) +{ + static GSList *values = NULL; + + if (values == NULL) + { + values = g_slist_prepend (values, (gpointer) "0"); + values = g_slist_prepend (values, (gpointer) "1"); + values = g_slist_prepend (values, (gpointer) "2"); + values = g_slist_reverse (values); + } + + *list = values; +} + +/** + * gi_marshalling_tests_gslist_utf8_none_out_uninitialized: + * @v: (out) (element-type utf8) (transfer none): + */ +gboolean +gi_marshalling_tests_gslist_utf8_none_out_uninitialized (GSList **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_gslist_utf8_container_out: + * @list: (out) (element-type utf8) (transfer container): + */ +void +gi_marshalling_tests_gslist_utf8_container_out (GSList **list) +{ + *list = NULL; + + *list = g_slist_prepend (*list, (gpointer) "0"); + *list = g_slist_prepend (*list, (gpointer) "1"); + *list = g_slist_prepend (*list, (gpointer) "2"); + *list = g_slist_reverse (*list); +} + +/** + * gi_marshalling_tests_gslist_utf8_container_out_uninitialized: + * @v: (out) (element-type utf8) (transfer container): + */ +gboolean +gi_marshalling_tests_gslist_utf8_container_out_uninitialized (GSList **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_gslist_utf8_full_out: + * @list: (out) (element-type utf8) (transfer full): + */ +void +gi_marshalling_tests_gslist_utf8_full_out (GSList **list) +{ + *list = NULL; + + *list = g_slist_prepend (*list, g_strdup ("0")); + *list = g_slist_prepend (*list, g_strdup ("1")); + *list = g_slist_prepend (*list, g_strdup ("2")); + *list = g_slist_reverse (*list); +} + +/** + * gi_marshalling_tests_gslist_utf8_full_out_uninitialized: + * @v: (out) (element-type utf8) (transfer full): + */ +gboolean +gi_marshalling_tests_gslist_utf8_full_out_uninitialized (GSList **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_gslist_utf8_none_inout: + * @list: (inout) (element-type utf8) (transfer none): + */ +void +gi_marshalling_tests_gslist_utf8_none_inout (GSList **list) +{ + static GSList *values = NULL; + + g_assert_cmpint (g_slist_length (*list), ==, 3); + g_assert_cmpstr (g_slist_nth_data (*list, 0), ==, "0"); + g_assert_cmpstr (g_slist_nth_data (*list, 1), ==, "1"); + g_assert_cmpstr (g_slist_nth_data (*list, 2), ==, "2"); + + if (values == NULL) + { + values = g_slist_prepend (values, (gpointer) "-2"); + values = g_slist_prepend (values, (gpointer) "-1"); + values = g_slist_prepend (values, (gpointer) "0"); + values = g_slist_prepend (values, (gpointer) "1"); + values = g_slist_reverse (values); + } + + *list = values; +} + +/** + * gi_marshalling_tests_gslist_utf8_container_inout: + * @list: (inout) (element-type utf8) (transfer container): + */ +void +gi_marshalling_tests_gslist_utf8_container_inout (GSList **list) +{ + GSList *result = NULL; + + g_assert_cmpint (g_slist_length (*list), ==, 3); + g_assert_cmpstr (g_slist_nth_data (*list, 0), ==, "0"); + g_assert_cmpstr (g_slist_nth_data (*list, 1), ==, "1"); + g_assert_cmpstr (g_slist_nth_data (*list, 2), ==, "2"); + + result = g_slist_prepend (result, (gpointer) "1"); + result = g_slist_prepend (result, (gpointer) "0"); + result = g_slist_prepend (result, (gpointer) "-1"); + result = g_slist_prepend (result, (gpointer) "-2"); + + g_slist_free (*list); + *list = result; +} + +/** + * gi_marshalling_tests_gslist_utf8_full_inout: + * @list: (inout) (element-type utf8) (transfer full): + */ +void +gi_marshalling_tests_gslist_utf8_full_inout (GSList **list) +{ + GSList *result = NULL; + + g_assert_cmpint (g_slist_length (*list), ==, 3); + g_assert_cmpstr (g_slist_nth_data (*list, 0), ==, "0"); + g_assert_cmpstr (g_slist_nth_data (*list, 1), ==, "1"); + g_assert_cmpstr (g_slist_nth_data (*list, 2), ==, "2"); + + result = g_slist_prepend (result, g_strdup ("1")); + result = g_slist_prepend (result, g_strdup ("0")); + result = g_slist_prepend (result, g_strdup ("-1")); + result = g_slist_prepend (result, g_strdup ("-2")); + + g_slist_free_full (*list, g_free); + *list = result; +} + +/** + * gi_marshalling_tests_ghashtable_int_none_return: + * + * Returns: (element-type gint gint) (transfer none): + */ +GHashTable * +gi_marshalling_tests_ghashtable_int_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 (1)); + g_hash_table_insert (hash_table, GINT_TO_POINTER (0), GINT_TO_POINTER (0)); + g_hash_table_insert (hash_table, GINT_TO_POINTER (1), GINT_TO_POINTER (-1)); + g_hash_table_insert (hash_table, GINT_TO_POINTER (2), GINT_TO_POINTER (-2)); + } + + return hash_table; +} + +/** + * gi_marshalling_tests_ghashtable_utf8_none_return: + * + * Returns: (element-type utf8 utf8) (transfer none): + */ +GHashTable * +gi_marshalling_tests_ghashtable_utf8_none_return (void) +{ + static GHashTable *hash_table = NULL; + + if (hash_table == NULL) + { + hash_table = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (hash_table, (gpointer) "-1", (gpointer) "1"); + g_hash_table_insert (hash_table, (gpointer) "0", (gpointer) "0"); + g_hash_table_insert (hash_table, (gpointer) "1", (gpointer) "-1"); + g_hash_table_insert (hash_table, (gpointer) "2", (gpointer) "-2"); + } + + return hash_table; +} + +/** + * gi_marshalling_tests_ghashtable_utf8_container_return: + * + * Returns: (element-type utf8 utf8) (transfer container): + */ +GHashTable * +gi_marshalling_tests_ghashtable_utf8_container_return (void) +{ + GHashTable *hash_table = NULL; + + hash_table = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (hash_table, (gpointer) "-1", (gpointer) "1"); + g_hash_table_insert (hash_table, (gpointer) "0", (gpointer) "0"); + g_hash_table_insert (hash_table, (gpointer) "1", (gpointer) "-1"); + g_hash_table_insert (hash_table, (gpointer) "2", (gpointer) "-2"); + + return hash_table; +} + +/** + * gi_marshalling_tests_ghashtable_utf8_full_return: + * + * Returns: (element-type utf8 utf8) (transfer full): + */ +GHashTable * +gi_marshalling_tests_ghashtable_utf8_full_return (void) +{ + GHashTable *hash_table = NULL; + + hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + g_hash_table_insert (hash_table, g_strdup ("-1"), g_strdup ("1")); + g_hash_table_insert (hash_table, g_strdup ("0"), g_strdup ("0")); + g_hash_table_insert (hash_table, g_strdup ("1"), g_strdup ("-1")); + g_hash_table_insert (hash_table, g_strdup ("2"), g_strdup ("-2")); + + return hash_table; +} + +/** + * gi_marshalling_tests_ghashtable_int_none_in: + * @hash_table: (element-type gint gint) (transfer none): + */ +void +gi_marshalling_tests_ghashtable_int_none_in (GHashTable *hash_table) +{ + g_assert_cmpint (GPOINTER_TO_INT (g_hash_table_lookup (hash_table, GINT_TO_POINTER (-1))), ==, 1); + g_assert_cmpint (GPOINTER_TO_INT (g_hash_table_lookup (hash_table, GINT_TO_POINTER (0))), ==, 0); + g_assert_cmpint (GPOINTER_TO_INT (g_hash_table_lookup (hash_table, GINT_TO_POINTER (1))), ==, -1); + g_assert_cmpint (GPOINTER_TO_INT (g_hash_table_lookup (hash_table, GINT_TO_POINTER (2))), ==, -2); +} + +/** + * gi_marshalling_tests_ghashtable_utf8_none_in: + * @hash_table: (element-type utf8 utf8) (transfer none): + */ +void +gi_marshalling_tests_ghashtable_utf8_none_in (GHashTable *hash_table) +{ + g_assert_cmpstr (g_hash_table_lookup (hash_table, "-1"), ==, "1"); + g_assert_cmpstr (g_hash_table_lookup (hash_table, "0"), ==, "0"); + g_assert_cmpstr (g_hash_table_lookup (hash_table, "1"), ==, "-1"); + g_assert_cmpstr (g_hash_table_lookup (hash_table, "2"), ==, "-2"); +} + +/** + * gi_marshalling_tests_ghashtable_double_in: + * @hash_table: (element-type utf8 double) (transfer none): + * + * Meant to test a value type that doesn't fit inside a pointer. + */ +void +gi_marshalling_tests_ghashtable_double_in (GHashTable *hash_table) +{ + double *value; + + value = g_hash_table_lookup (hash_table, "-1"); + g_assert_cmpfloat_with_epsilon (*value, -0.1, 0.01); + value = g_hash_table_lookup (hash_table, "0"); + g_assert_cmpfloat (*value, ==, 0.0); + value = g_hash_table_lookup (hash_table, "1"); + g_assert_cmpfloat_with_epsilon (*value, 0.1, 0.01); + value = g_hash_table_lookup (hash_table, "2"); + g_assert_cmpfloat_with_epsilon (*value, 0.2, 0.01); +} + +/** + * gi_marshalling_tests_ghashtable_float_in: + * @hash_table: (element-type utf8 float) (transfer none): + * + * Meant to test a value type that doesn't fit inside a pointer. + */ +void +gi_marshalling_tests_ghashtable_float_in (GHashTable *hash_table) +{ + float *value; + + value = g_hash_table_lookup (hash_table, "-1"); + g_assert_cmpfloat_with_epsilon (*value, -0.1f, 0.01f); + value = g_hash_table_lookup (hash_table, "0"); + g_assert_cmpfloat (*value, ==, 0.0f); + value = g_hash_table_lookup (hash_table, "1"); + g_assert_cmpfloat_with_epsilon (*value, 0.1f, 0.01f); + value = g_hash_table_lookup (hash_table, "2"); + g_assert_cmpfloat_with_epsilon (*value, 0.2f, 0.01f); +} + +/** + * gi_marshalling_tests_ghashtable_int64_in: + * @hash_table: (element-type utf8 gint64) (transfer none): + * + * Meant to test a value type that doesn't fit inside a pointer. + */ +void +gi_marshalling_tests_ghashtable_int64_in (GHashTable *hash_table) +{ + gint64 *value; + + value = g_hash_table_lookup (hash_table, "-1"); + g_assert_cmpint (*value, ==, -1); + value = g_hash_table_lookup (hash_table, "0"); + g_assert_cmpint (*value, ==, 0); + value = g_hash_table_lookup (hash_table, "1"); + g_assert_cmpint (*value, ==, 1); + value = g_hash_table_lookup (hash_table, "2"); + g_assert_cmpint (*value, ==, (gint64) G_MAXUINT32 + 1); +} + +/** + * gi_marshalling_tests_ghashtable_uint64_in: + * @hash_table: (element-type utf8 guint64) (transfer none): + * + * Meant to test a value type that doesn't fit inside a pointer. + */ +void +gi_marshalling_tests_ghashtable_uint64_in (GHashTable *hash_table) +{ + guint64 *value; + + value = g_hash_table_lookup (hash_table, "-1"); + g_assert_cmpuint (*value, ==, (guint64) G_MAXUINT32 + 1); + value = g_hash_table_lookup (hash_table, "0"); + g_assert_cmpuint (*value, ==, 0); + value = g_hash_table_lookup (hash_table, "1"); + g_assert_cmpuint (*value, ==, 1); + value = g_hash_table_lookup (hash_table, "2"); + g_assert_cmpuint (*value, ==, 2); +} + +/** + * gi_marshalling_tests_ghashtable_utf8_none_out: + * @hash_table: (out) (element-type utf8 utf8) (transfer none): + */ +void +gi_marshalling_tests_ghashtable_utf8_none_out (GHashTable **hash_table) +{ + static GHashTable *new_hash_table = NULL; + + if (new_hash_table == NULL) + { + new_hash_table = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (new_hash_table, (gpointer) "-1", (gpointer) "1"); + g_hash_table_insert (new_hash_table, (gpointer) "0", (gpointer) "0"); + g_hash_table_insert (new_hash_table, (gpointer) "1", (gpointer) "-1"); + g_hash_table_insert (new_hash_table, (gpointer) "2", (gpointer) "-2"); + } + + *hash_table = new_hash_table; +} + +/** + * gi_marshalling_tests_ghashtable_utf8_none_out_uninitialized: + * @v: (out) (element-type utf8 utf8) (transfer none): + */ +gboolean +gi_marshalling_tests_ghashtable_utf8_none_out_uninitialized (GHashTable **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_ghashtable_utf8_container_out: + * @hash_table: (out) (element-type utf8 utf8) (transfer container): + */ +void +gi_marshalling_tests_ghashtable_utf8_container_out (GHashTable **hash_table) +{ + *hash_table = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (*hash_table, (gpointer) "-1", (gpointer) "1"); + g_hash_table_insert (*hash_table, (gpointer) "0", (gpointer) "0"); + g_hash_table_insert (*hash_table, (gpointer) "1", (gpointer) "-1"); + g_hash_table_insert (*hash_table, (gpointer) "2", (gpointer) "-2"); +} + +/** + * gi_marshalling_tests_ghashtable_utf8_container_out_uninitialized: + * @v: (out) (element-type utf8 utf8) (transfer container): + */ +gboolean +gi_marshalling_tests_ghashtable_utf8_container_out_uninitialized (GHashTable **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_ghashtable_utf8_full_out: + * @hash_table: (out) (element-type utf8 utf8) (transfer full): + */ +void +gi_marshalling_tests_ghashtable_utf8_full_out (GHashTable **hash_table) +{ + *hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + g_hash_table_insert (*hash_table, g_strdup ("-1"), g_strdup ("1")); + g_hash_table_insert (*hash_table, g_strdup ("0"), g_strdup ("0")); + g_hash_table_insert (*hash_table, g_strdup ("1"), g_strdup ("-1")); + g_hash_table_insert (*hash_table, g_strdup ("2"), g_strdup ("-2")); +} + +/** + * gi_marshalling_tests_ghashtable_utf8_full_out_uninitialized: + * @v: (out) (element-type utf8 utf8) (transfer full): + */ +gboolean +gi_marshalling_tests_ghashtable_utf8_full_out_uninitialized (GHashTable **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_ghashtable_utf8_none_inout: + * @hash_table: (inout) (element-type utf8 utf8) (transfer none): + */ +void +gi_marshalling_tests_ghashtable_utf8_none_inout (GHashTable **hash_table) +{ + static GHashTable *new_hash_table = NULL; + + g_assert_cmpstr (g_hash_table_lookup (*hash_table, "-1"), ==, "1"); + g_assert_cmpstr (g_hash_table_lookup (*hash_table, "0"), ==, "0"); + g_assert_cmpstr (g_hash_table_lookup (*hash_table, "1"), ==, "-1"); + g_assert_cmpstr (g_hash_table_lookup (*hash_table, "2"), ==, "-2"); + + if (new_hash_table == NULL) + { + new_hash_table = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (new_hash_table, (gpointer) "-1", (gpointer) "1"); + g_hash_table_insert (new_hash_table, (gpointer) "0", (gpointer) "0"); + g_hash_table_insert (new_hash_table, (gpointer) "1", (gpointer) "1"); + } + + *hash_table = new_hash_table; +} + +/** + * gi_marshalling_tests_ghashtable_utf8_container_inout: + * @hash_table: (inout) (element-type utf8 utf8) (transfer container): + */ +void +gi_marshalling_tests_ghashtable_utf8_container_inout (GHashTable **hash_table) +{ + GHashTable *result = g_hash_table_new (g_str_hash, g_str_equal); + + g_assert_cmpstr (g_hash_table_lookup (*hash_table, "-1"), ==, "1"); + g_assert_cmpstr (g_hash_table_lookup (*hash_table, "0"), ==, "0"); + g_assert_cmpstr (g_hash_table_lookup (*hash_table, "1"), ==, "-1"); + g_assert_cmpstr (g_hash_table_lookup (*hash_table, "2"), ==, "-2"); + + g_hash_table_insert (result, (gpointer) "-1", (gpointer) "1"); + g_hash_table_insert (result, (gpointer) "0", (gpointer) "0"); + g_hash_table_insert (result, (gpointer) "1", (gpointer) "1"); + + g_hash_table_unref (*hash_table); + *hash_table = result; +} + +/** + * gi_marshalling_tests_ghashtable_utf8_full_inout: + * @hash_table: (inout) (element-type utf8 utf8) (transfer full): + */ +void +gi_marshalling_tests_ghashtable_utf8_full_inout (GHashTable **hash_table) +{ + GHashTable *result = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + + g_assert_cmpstr (g_hash_table_lookup (*hash_table, "-1"), ==, "1"); + g_assert_cmpstr (g_hash_table_lookup (*hash_table, "0"), ==, "0"); + g_assert_cmpstr (g_hash_table_lookup (*hash_table, "1"), ==, "-1"); + g_assert_cmpstr (g_hash_table_lookup (*hash_table, "2"), ==, "-2"); + + g_hash_table_insert (result, g_strdup ("-1"), g_strdup ("1")); + g_hash_table_insert (result, g_strdup ("0"), g_strdup ("0")); + g_hash_table_insert (result, g_strdup ("1"), g_strdup ("1")); + + g_hash_table_unref (*hash_table); + *hash_table = result; +} + +/** + * gi_marshalling_tests_gvalue_return: + * + * Returns: (transfer none): + */ +GValue * +gi_marshalling_tests_gvalue_return (void) +{ + static GValue *value = NULL; + + if (value == NULL) + { + value = g_new0 (GValue, 1); + g_value_init (value, G_TYPE_INT); + g_value_set_int (value, 42); + } + + return value; +} + +/** + * gi_marshalling_tests_gvalue_noncanonical_nan_float: + * + * Returns: (transfer none): + */ +GValue * +gi_marshalling_tests_gvalue_noncanonical_nan_float (void) +{ + static GValue *value = NULL; + + if (value == NULL) + { + value = g_new0 (GValue, 1); + g_value_init (value, G_TYPE_FLOAT); + g_value_set_float (value, noncanonical_nan_float ()); + } + + return value; +} + +/** + * gi_marshalling_tests_gvalue_noncanonical_nan_double: + * + * Returns: (transfer none): + */ +GValue * +gi_marshalling_tests_gvalue_noncanonical_nan_double (void) +{ + static GValue *value = NULL; + + if (value == NULL) + { + value = g_new0 (GValue, 1); + g_value_init (value, G_TYPE_DOUBLE); + g_value_set_double (value, noncanonical_nan_double ()); + } + + return value; +} + +/** + * gi_marshalling_tests_gvalue_in: + * @value: (transfer none): + */ +void +gi_marshalling_tests_gvalue_in (GValue *value) +{ + g_assert_cmpint (g_value_get_int (value), ==, 42); +} + +/** + * gi_marshalling_tests_gvalue_int64_in: + * @value: (transfer none): + */ +void +gi_marshalling_tests_gvalue_int64_in (GValue *value) +{ + g_assert_cmpint (g_value_get_int64 (value), ==, G_MAXINT64); +} + +/** + * gi_marshalling_tests_gvalue_in_with_type: + * @value: (transfer none): + * @type: + */ +void +gi_marshalling_tests_gvalue_in_with_type (GValue *value, GType type) +{ + g_assert (g_type_is_a (G_VALUE_TYPE (value), type)); +} + +/** + * gi_marshalling_tests_gvalue_in_with_modification: + * @value: (transfer none): + * + * Expects a GValue passed by reference which is then modified by + * this function. + */ +void +gi_marshalling_tests_gvalue_in_with_modification (GValue *value) +{ + g_assert_cmpint (g_value_get_int (value), ==, 42); + g_value_set_int (value, 24); +} + +/** + * gi_marshalling_tests_gvalue_in_enum: + * @value: (transfer none): + */ +void +gi_marshalling_tests_gvalue_in_enum (GValue *value) +{ + if (!G_VALUE_HOLDS_ENUM (value)) + g_critical ("Expected enum, got %s", G_VALUE_TYPE_NAME (value)); + g_assert (g_value_get_enum (value) == GI_MARSHALLING_TESTS_ENUM_VALUE3); +} + +/** + * gi_marshalling_tests_gvalue_in_flags: + * @value: (transfer none): + */ +void +gi_marshalling_tests_gvalue_in_flags (GValue *value) +{ + if (!G_VALUE_HOLDS_FLAGS (value)) + g_critical ("Expected flags, got %s", G_VALUE_TYPE_NAME (value)); + g_assert_cmpint (g_value_get_flags (value), ==, GI_MARSHALLING_TESTS_FLAGS_VALUE3); +} + +/** + * gi_marshalling_tests_gvalue_out: + * @value: (out) (transfer none): + */ +void +gi_marshalling_tests_gvalue_out (GValue **value) +{ + static GValue *new_value = NULL; + + if (new_value == NULL) + { + new_value = g_new0 (GValue, 1); + g_value_init (new_value, G_TYPE_INT); + g_value_set_int (new_value, 42); + } + + *value = new_value; +} + +/** + * gi_marshalling_tests_gvalue_out_uninitialized: + * @v: (out) (transfer none): + */ +gboolean +gi_marshalling_tests_gvalue_out_uninitialized (GValue **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_gvalue_int64_out: + * @value: (out) (transfer none): + */ +void +gi_marshalling_tests_gvalue_int64_out (GValue **value) +{ + static GValue *new_value = NULL; + + if (new_value == NULL) + { + new_value = g_new0 (GValue, 1); + g_value_init (new_value, G_TYPE_INT64); + g_value_set_int64 (new_value, G_MAXINT64); + } + + *value = new_value; +} + +/** + * gi_marshalling_tests_gvalue_out_caller_allocates: + * @value: (out) (transfer none): + */ +void +gi_marshalling_tests_gvalue_out_caller_allocates (GValue *value) +{ + g_value_init (value, G_TYPE_INT); + g_value_set_int (value, 42); +} + +/** + * gi_marshalling_tests_gvalue_inout: + * @value: (inout) (transfer none): + */ +void +gi_marshalling_tests_gvalue_inout (GValue **value) +{ + g_assert_cmpint (g_value_get_int (*value), ==, 42); + g_value_unset (*value); + g_value_init (*value, G_TYPE_STRING); + g_value_set_string (*value, "42"); +} + +/** + * gi_marshalling_tests_gvalue_flat_array: + * @n_values: number of values + * @values: (array length=n_values): an array containing values + */ +void +gi_marshalling_tests_gvalue_flat_array (guint n_values, const GValue *values) +{ + g_assert (n_values == 3); + + g_assert_cmpint (g_value_get_int (&values[0]), ==, 42); + g_assert_cmpstr (g_value_get_string (&values[1]), ==, "42"); + g_assert_cmpint (g_value_get_boolean (&values[2]), ==, TRUE); +} + +/** + * gi_marshalling_tests_return_gvalue_flat_array: + * + * Returns: (array fixed-size=3) (transfer full): a flat GValue array + */ +GValue * +gi_marshalling_tests_return_gvalue_flat_array (void) +{ + GValue *array = g_new0 (GValue, 3); + + g_value_init (&array[0], G_TYPE_INT); + g_value_set_int (&array[0], 42); + + g_value_init (&array[1], G_TYPE_STRING); + g_value_set_static_string (&array[1], "42"); + + g_value_init (&array[2], G_TYPE_BOOLEAN); + g_value_set_boolean (&array[2], TRUE); + + return array; +} + +/** + * gi_marshalling_tests_return_gvalue_zero_terminated_array: + * + * Returns: (array zero-terminated) (transfer full): a flat GValue array + */ +GValue * +gi_marshalling_tests_return_gvalue_zero_terminated_array (void) +{ + GValue *array = g_new0 (GValue, 4); + + g_value_init (&array[0], G_TYPE_INT); + g_value_set_int (&array[0], 42); + + g_value_init (&array[1], G_TYPE_STRING); + g_value_set_static_string (&array[1], "42"); + + g_value_init (&array[2], G_TYPE_BOOLEAN); + g_value_set_boolean (&array[2], TRUE); + + return array; +} + +/** + * gi_marshalling_tests_gvalue_round_trip: + * @value: The first GValue + * + * Returns: (transfer none): + */ +GValue * +gi_marshalling_tests_gvalue_round_trip (GValue *value) +{ + return value; +} + +/** + * gi_marshalling_tests_gvalue_copy: + * @value: The first GValue + * + * Returns: (transfer full): + */ +GValue * +gi_marshalling_tests_gvalue_copy (GValue *value) +{ + GValue *return_value = g_new0 (GValue, 1); + + g_value_init (return_value, G_VALUE_TYPE (value)); + g_value_copy (value, return_value); + + return return_value; +} + +/** + * gi_marshalling_tests_gvalue_flat_array_round_trip: + * @one: The first GValue + * @two: The second GValue + * @three: The third GValue + * + * Returns: (array fixed-size=3) (transfer full): a flat array of [@one, @two, @three] + */ +GValue * +gi_marshalling_tests_gvalue_flat_array_round_trip (const GValue one, const GValue two, const GValue three) +{ + GValue *array = g_new (GValue, 3); + array[0] = one; + array[1] = two; + array[2] = three; + + return array; +} + +/** + * gi_marshalling_tests_gclosure_in: + * @closure: (transfer none): + */ +void +gi_marshalling_tests_gclosure_in (GClosure *closure) +{ + GValue return_value = { + 0, + }; + + g_value_init (&return_value, G_TYPE_INT); + + g_closure_invoke (closure, &return_value, 0, NULL, NULL); + + g_assert_cmpint (g_value_get_int (&return_value), ==, 42); + + g_value_unset (&return_value); +} + +static gint +_closure_return_42 (void) +{ + return 42; +} + +static void +_marshal_INT__VOID (GClosure *closure, + GValue *return_value, + guint n_param_values G_GNUC_UNUSED, + const GValue *param_values G_GNUC_UNUSED, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data G_GNUC_UNUSED) +{ + typedef gint (*GMarshalFunc_INT__VOID) (void); + register GMarshalFunc_INT__VOID callback; + register GCClosure *cc = (GCClosure *) closure; + + callback = (GMarshalFunc_INT__VOID) cc->callback; + g_value_set_int (return_value, callback ()); +} + +/** + * gi_marshalling_tests_gclosure_return: + * + * Return: a #GClosure + */ +GClosure * +gi_marshalling_tests_gclosure_return (void) +{ + GClosure *closure = g_cclosure_new ((GCallback) _closure_return_42, + NULL, NULL); + g_closure_set_marshal (closure, _marshal_INT__VOID); + + return closure; +} + +/** + * gi_marshalling_tests_callback_return_value_only: + * @callback: (scope call): + */ +glong +gi_marshalling_tests_callback_return_value_only (GIMarshallingTestsCallbackReturnValueOnly callback) +{ + return callback (); +} + +/** + * gi_marshalling_tests_callback_one_out_parameter: + * @callback: (scope call): + * @a: (out): + */ +void +gi_marshalling_tests_callback_one_out_parameter (GIMarshallingTestsCallbackOneOutParameter callback, gfloat *a) +{ + callback (a); +} + +/** + * gi_marshalling_tests_callback_multiple_out_parameters: + * @callback: (scope call): + * @a: (out): + * @b: (out): + */ +void +gi_marshalling_tests_callback_multiple_out_parameters (GIMarshallingTestsCallbackMultipleOutParameters callback, gfloat *a, gfloat *b) +{ + callback (a, b); +} + +/** + * gi_marshalling_tests_callback_return_value_and_one_out_parameter: + * @callback: (scope call): + * @a: (out): + */ +glong +gi_marshalling_tests_callback_return_value_and_one_out_parameter (GIMarshallingTestsCallbackReturnValueAndOneOutParameter callback, glong *a) +{ + return callback (a); +} + +/** + * gi_marshalling_tests_callback_return_value_and_multiple_out_parameters: + * @callback: (scope call): + * @a: (out): + * @b: (out): + */ +glong +gi_marshalling_tests_callback_return_value_and_multiple_out_parameters (GIMarshallingTestsCallbackReturnValueAndMultipleOutParameters callback, glong *a, glong *b) +{ + return callback (a, b); +} + +/** + * gi_marshalling_tests_pointer_in_return: + * + * Returns: The same pointer + */ +gpointer +gi_marshalling_tests_pointer_in_return (gpointer pointer) +{ + return pointer; +} + +GType +gi_marshalling_tests_genum_get_type (void) +{ + static GType type = 0; + if (G_UNLIKELY (type == 0)) + { + static const GEnumValue values[] = { + { GI_MARSHALLING_TESTS_GENUM_VALUE1, + "GI_MARSHALLING_TESTS_GENUM_VALUE1", "value1" }, + { GI_MARSHALLING_TESTS_GENUM_VALUE2, + "GI_MARSHALLING_TESTS_GENUM_VALUE2", "value2" }, + { GI_MARSHALLING_TESTS_GENUM_VALUE3, + "GI_MARSHALLING_TESTS_GENUM_VALUE3", "value3" }, + { 0, NULL, NULL } + }; + type = g_enum_register_static (g_intern_static_string ("GIMarshallingTestsGEnum"), values); + } + + return type; +} + +GIMarshallingTestsGEnum +gi_marshalling_tests_genum_returnv (void) +{ + return GI_MARSHALLING_TESTS_GENUM_VALUE3; +} + +void +gi_marshalling_tests_genum_in (GIMarshallingTestsGEnum v) +{ + g_assert_cmpint (v, ==, GI_MARSHALLING_TESTS_GENUM_VALUE3); +} + +/** + * gi_marshalling_tests_genum_out: + * @v: (out): + */ +void +gi_marshalling_tests_genum_out (GIMarshallingTestsGEnum *v) +{ + *v = GI_MARSHALLING_TESTS_GENUM_VALUE3; +} + +/** + * gi_marshalling_tests_genum_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_genum_out_uninitialized (GIMarshallingTestsGEnum *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_genum_inout: + * @v: (inout): + */ +void +gi_marshalling_tests_genum_inout (GIMarshallingTestsGEnum *v) +{ + g_assert_cmpint (*v, ==, GI_MARSHALLING_TESTS_GENUM_VALUE3); + *v = GI_MARSHALLING_TESTS_GENUM_VALUE1; +} + +GIMarshallingTestsEnum +gi_marshalling_tests_enum_returnv (void) +{ + return GI_MARSHALLING_TESTS_ENUM_VALUE3; +} + +void +gi_marshalling_tests_enum_in (GIMarshallingTestsEnum v) +{ + g_assert_cmpint (v, ==, GI_MARSHALLING_TESTS_ENUM_VALUE3); +} + +/** + * gi_marshalling_tests_enum_out: + * @v: (out): + */ +void +gi_marshalling_tests_enum_out (GIMarshallingTestsEnum *v) +{ + *v = GI_MARSHALLING_TESTS_ENUM_VALUE3; +} + +/** + * gi_marshalling_tests_enum_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_enum_out_uninitialized (GIMarshallingTestsEnum **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_enum_inout: + * @v: (inout): + */ +void +gi_marshalling_tests_enum_inout (GIMarshallingTestsEnum *v) +{ + g_assert_cmpint (*v, ==, GI_MARSHALLING_TESTS_ENUM_VALUE3); + *v = GI_MARSHALLING_TESTS_ENUM_VALUE1; +} + +GType +gi_marshalling_tests_flags_get_type (void) +{ + static GType type = 0; + if (G_UNLIKELY (type == 0)) + { + static const GFlagsValue values[] = { + { GI_MARSHALLING_TESTS_FLAGS_VALUE1, + "GI_MARSHALLING_TESTS_FLAGS_VALUE1", "value1" }, + { GI_MARSHALLING_TESTS_FLAGS_VALUE2, + "GI_MARSHALLING_TESTS_FLAGS_VALUE2", "value2" }, + { GI_MARSHALLING_TESTS_FLAGS_VALUE3, + "GI_MARSHALLING_TESTS_FLAGS_VALUE3", "value3" }, + { GI_MARSHALLING_TESTS_FLAGS_MASK, "GI_MARSHALLING_TESTS_FLAGS_MASK", + "mask" }, + { GI_MARSHALLING_TESTS_FLAGS_MASK2, "GI_MARSHALLING_TESTS_FLAGS_MASK2", + "mask2" }, + { 0, NULL, NULL } + }; + type = g_flags_register_static (g_intern_static_string ("GIMarshallingTestsFlags"), values); + } + + return type; +} + +GIMarshallingTestsFlags +gi_marshalling_tests_flags_returnv (void) +{ + return GI_MARSHALLING_TESTS_FLAGS_VALUE2; +} + +void +gi_marshalling_tests_flags_in (GIMarshallingTestsFlags v) +{ + g_assert (v == GI_MARSHALLING_TESTS_FLAGS_VALUE2); +} + +void +gi_marshalling_tests_flags_in_zero (GIMarshallingTestsFlags v) +{ + g_assert (v == 0); +} + +/** + * gi_marshalling_tests_flags_out: + * @v: (out): + */ +void +gi_marshalling_tests_flags_out (GIMarshallingTestsFlags *v) +{ + *v = GI_MARSHALLING_TESTS_FLAGS_VALUE2; +} + +/** + * gi_marshalling_tests_flags_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_flags_out_uninitialized (GIMarshallingTestsFlags *v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_flags_inout: + * @v: (inout): + */ +void +gi_marshalling_tests_flags_inout (GIMarshallingTestsFlags *v) +{ + g_assert (*v == GI_MARSHALLING_TESTS_FLAGS_VALUE2); + *v = GI_MARSHALLING_TESTS_FLAGS_VALUE1; +} + +GIMarshallingTestsNoTypeFlags +gi_marshalling_tests_no_type_flags_returnv (void) +{ + return GI_MARSHALLING_TESTS_NO_TYPE_FLAGS_VALUE2; +} + +void +gi_marshalling_tests_no_type_flags_in (GIMarshallingTestsNoTypeFlags v) +{ + g_assert (v == GI_MARSHALLING_TESTS_NO_TYPE_FLAGS_VALUE2); +} + +void +gi_marshalling_tests_no_type_flags_in_zero (GIMarshallingTestsNoTypeFlags v) +{ + g_assert (v == 0); +} + +/** + * gi_marshalling_tests_no_type_flags_out: + * @v: (out): + */ +void +gi_marshalling_tests_no_type_flags_out (GIMarshallingTestsNoTypeFlags *v) +{ + *v = GI_MARSHALLING_TESTS_NO_TYPE_FLAGS_VALUE2; +} + +/** + * gi_marshalling_tests_no_type_flags_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_no_type_flags_out_uninitialized (GIMarshallingTestsNoTypeFlags **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_no_type_flags_inout: + * @v: (inout): + */ +void +gi_marshalling_tests_no_type_flags_inout (GIMarshallingTestsNoTypeFlags *v) +{ + g_assert (*v == GI_MARSHALLING_TESTS_NO_TYPE_FLAGS_VALUE2); + *v = GI_MARSHALLING_TESTS_NO_TYPE_FLAGS_VALUE1; +} + +/** + * gi_marshalling_tests_simple_struct_returnv: + * + * Returns: (transfer none): + */ +GIMarshallingTestsSimpleStruct * +gi_marshalling_tests_simple_struct_returnv (void) +{ + static GIMarshallingTestsSimpleStruct *struct_ = NULL; + + if (struct_ == NULL) + { + struct_ = g_new (GIMarshallingTestsSimpleStruct, 1); + + struct_->long_ = 6; + struct_->int8 = 7; + } + + return struct_; +} + +/** + * gi_marshalling_tests_simple_struct_inv: + * @struct_: (transfer none): + */ +void +gi_marshalling_tests_simple_struct_inv (GIMarshallingTestsSimpleStruct *struct_) +{ + g_assert_cmpint (struct_->long_, ==, 6); + g_assert_cmpint (struct_->int8, ==, 7); +} + +void +gi_marshalling_tests_simple_struct_method (GIMarshallingTestsSimpleStruct *struct_) +{ + g_assert_cmpint (struct_->long_, ==, 6); + g_assert_cmpint (struct_->int8, ==, 7); +} + +GType +gi_marshalling_tests_pointer_struct_get_type (void) +{ + static GType type = 0; + + if (type == 0) + { + type = g_pointer_type_register_static ("GIMarshallingTestsPointerStruct"); + } + + return type; +} + +/** + * gi_marshalling_tests_pointer_struct_returnv: + * + * Returns: (transfer none): + */ +GIMarshallingTestsPointerStruct * +gi_marshalling_tests_pointer_struct_returnv (void) +{ + static GIMarshallingTestsPointerStruct *struct_ = NULL; + + if (struct_ == NULL) + { + struct_ = g_new (GIMarshallingTestsPointerStruct, 1); + + struct_->long_ = 42; + } + + return struct_; +} + +/** + * gi_marshalling_tests_pointer_struct_inv: + * @struct_: (transfer none): + */ +void +gi_marshalling_tests_pointer_struct_inv (GIMarshallingTestsPointerStruct *struct_) +{ + g_assert_cmpint (struct_->long_, ==, 42); +} + +static GIMarshallingTestsBoxedStruct * +gi_marshalling_tests_boxed_struct_copy (GIMarshallingTestsBoxedStruct *struct_) +{ + GIMarshallingTestsBoxedStruct *new_struct; + + if (struct_ == NULL) + return NULL; + + new_struct = g_slice_new (GIMarshallingTestsBoxedStruct); + + *new_struct = *struct_; + new_struct->string_ = g_strdup (struct_->string_); + new_struct->g_strv = g_strdupv (struct_->g_strv); + + return new_struct; +} + +static void +gi_marshalling_tests_boxed_struct_free (GIMarshallingTestsBoxedStruct *struct_) +{ + if (struct_ != NULL) + { + g_free (struct_->string_); + g_clear_pointer (&struct_->g_strv, g_strfreev); + g_slice_free (GIMarshallingTestsBoxedStruct, struct_); + } +} + +GType +gi_marshalling_tests_boxed_struct_get_type (void) +{ + static GType type = 0; + + if (type == 0) + { + type = g_boxed_type_register_static ("GIMarshallingTestsBoxedStruct", + (GBoxedCopyFunc) + gi_marshalling_tests_boxed_struct_copy, + (GBoxedFreeFunc) gi_marshalling_tests_boxed_struct_free); + } + + return type; +} + +static GType +gi_marshalling_tests_boxed_glist_get_type (void) +{ + static GType type = 0; + + if (type == 0) + { + type = g_boxed_type_register_static ("GIMarshallingTestsBoxedGList", + (GBoxedCopyFunc) g_list_copy, (GBoxedFreeFunc) g_list_free); + } + + return type; +} + +GIMarshallingTestsBoxedStruct * +gi_marshalling_tests_boxed_struct_new (void) +{ + return g_slice_new0 (GIMarshallingTestsBoxedStruct); +} + +/** + * gi_marshalling_tests_boxed_struct_returnv: + * + * Returns: (transfer none): + */ +GIMarshallingTestsBoxedStruct * +gi_marshalling_tests_boxed_struct_returnv (void) +{ + static GIMarshallingTestsBoxedStruct *struct_ = NULL; + + if (struct_ == NULL) + { + struct_ = g_new (GIMarshallingTestsBoxedStruct, 1); + + struct_->long_ = 42; + struct_->string_ = g_strdup ("hello"); + struct_->g_strv = g_new0 (gchar *, 4); + struct_->g_strv[0] = g_strdup ("0"); + struct_->g_strv[1] = g_strdup ("1"); + struct_->g_strv[2] = g_strdup ("2"); + struct_->g_strv[3] = NULL; + } + + return struct_; +} + +/** + * gi_marshalling_tests_boxed_struct_inv: + * @struct_: (transfer none): + */ +void +gi_marshalling_tests_boxed_struct_inv (GIMarshallingTestsBoxedStruct *struct_) +{ + g_assert_cmpint (struct_->long_, ==, 42); +} + +/** + * gi_marshalling_tests_boxed_struct_out: + * @struct_: (out) (transfer none): + */ +void +gi_marshalling_tests_boxed_struct_out (GIMarshallingTestsBoxedStruct **struct_) +{ + static GIMarshallingTestsBoxedStruct *new_struct = NULL; + + if (new_struct == NULL) + { + new_struct = g_new0 (GIMarshallingTestsBoxedStruct, 1); + + new_struct->long_ = 42; + } + + *struct_ = new_struct; +} + +/** + * gi_marshalling_tests_boxed_struct_out_uninitialized: + * @v: (out) (transfer none): + */ +gboolean +gi_marshalling_tests_boxed_struct_out_uninitialized (GIMarshallingTestsBoxedStruct **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_boxed_struct_inout: + * @struct_: (inout) (transfer full): + */ +void +gi_marshalling_tests_boxed_struct_inout (GIMarshallingTestsBoxedStruct **struct_) +{ + g_assert_cmpint ((*struct_)->long_, ==, 42); + + g_boxed_free (gi_marshalling_tests_boxed_struct_get_type (), *struct_); + (*struct_) = g_slice_new0 (GIMarshallingTestsBoxedStruct); + (*struct_)->long_ = 0; +} + +static GIMarshallingTestsUnion * +gi_marshalling_tests_union_copy (GIMarshallingTestsUnion *union_) +{ + GIMarshallingTestsUnion *new_union; + + new_union = g_slice_new (GIMarshallingTestsUnion); + + *new_union = *union_; + + return new_union; +} + +static void +gi_marshalling_tests_union_free (GIMarshallingTestsUnion *union_) +{ + g_slice_free (GIMarshallingTestsUnion, union_); +} + +GType +gi_marshalling_tests_union_get_type (void) +{ + static GType type = 0; + + if (type == 0) + { + type = g_boxed_type_register_static ("GIMarshallingTestsUnion", + (GBoxedCopyFunc) + gi_marshalling_tests_union_copy, + (GBoxedFreeFunc) gi_marshalling_tests_union_free); + } + + return type; +} + +/** + * gi_marshalling_tests_union_returnv: + * + * Returns: (transfer none): + */ +GIMarshallingTestsUnion * +gi_marshalling_tests_union_returnv (void) +{ + static GIMarshallingTestsUnion *union_ = NULL; + + if (union_ == NULL) + { + union_ = g_new (GIMarshallingTestsUnion, 1); + + union_->long_ = 42; + } + + return union_; +} + +/** + * gi_marshalling_tests_union_inv: + * @union_: (transfer none): + */ +void +gi_marshalling_tests_union_inv (GIMarshallingTestsUnion *union_) +{ + g_assert_cmpint (union_->long_, ==, 42); +} + +void +gi_marshalling_tests_union_method (GIMarshallingTestsUnion *union_) +{ + g_assert_cmpint (union_->long_, ==, 42); +} + +/** + * gi_marshalling_tests_structured_union_new: + * @type: Type of #GIMarshallingTestsStructuredUnion to create + */ +GIMarshallingTestsStructuredUnion * +gi_marshalling_tests_structured_union_new (GIMarshallingTestsStructuredUnionType type) +{ + GIMarshallingTestsStructuredUnion *new_union; + + new_union = g_new0 (GIMarshallingTestsStructuredUnion, 1); + new_union->type = type; + + switch (type) + { + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_NONE: + break; + + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_SIMPLE_STRUCT: + new_union->simple_struct.parent.long_ = 6; + new_union->simple_struct.parent.int8 = 7; + break; + + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_NESTED_STRUCT: + new_union->nested_struct.parent.simple_struct.long_ = 6; + new_union->nested_struct.parent.simple_struct.int8 = 7; + break; + + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_BOXED_STRUCT: + new_union->boxed_struct.parent.long_ = 42; + new_union->boxed_struct.parent.string_ = g_strdup ("hello"); + new_union->boxed_struct.parent.g_strv = g_new0 (gchar *, 4); + new_union->boxed_struct.parent.g_strv[0] = g_strdup ("0"); + new_union->boxed_struct.parent.g_strv[1] = g_strdup ("1"); + new_union->boxed_struct.parent.g_strv[2] = g_strdup ("2"); + new_union->boxed_struct.parent.g_strv[3] = NULL; + break; + + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_BOXED_STRUCT_PTR: + new_union->boxed_struct_ptr.parent = g_boxed_copy ( + gi_marshalling_tests_boxed_struct_get_type (), + gi_marshalling_tests_boxed_struct_returnv ()); + break; + + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_POINTER_STRUCT: + new_union->pointer_struct.parent.long_ = 42; + break; + + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_SINGLE_UNION: + new_union->single_union.parent.union_.long_ = 42; + break; + + default: + g_free (new_union); + g_return_val_if_reached (NULL); + } + + return new_union; +} + +static GIMarshallingTestsStructuredUnion * +gi_marshalling_tests_structured_union_copy (GIMarshallingTestsStructuredUnion *union_) +{ + GIMarshallingTestsStructuredUnion *new_union; + + new_union = g_new (GIMarshallingTestsStructuredUnion, 1); + *new_union = *union_; + + switch (union_->type) + { + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_BOXED_STRUCT: + new_union->boxed_struct.parent.string_ = g_strdup (union_->boxed_struct.parent.string_); + if (union_->boxed_struct.parent.g_strv) + { + guint length = g_strv_length (union_->boxed_struct.parent.g_strv); + guint i; + + new_union->boxed_struct.parent.g_strv = g_new0 (gchar *, length + 1); + for (i = 0; i < length; i++) + new_union->boxed_struct.parent.g_strv[i] = g_strdup (union_->boxed_struct.parent.g_strv[i]); + new_union->boxed_struct.parent.g_strv[i] = NULL; + } + break; + + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_BOXED_STRUCT_PTR: + new_union->boxed_struct_ptr.parent = g_boxed_copy ( + gi_marshalling_tests_boxed_struct_get_type (), union_->boxed_struct_ptr.parent); + break; + + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_NONE: + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_SINGLE_UNION: + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_POINTER_STRUCT: + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_SIMPLE_STRUCT: + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_NESTED_STRUCT: + break; + + default: + g_return_val_if_reached (new_union); + } + + return new_union; +} + +static void +gi_marshalling_tests_structured_union_free (GIMarshallingTestsStructuredUnion *union_) +{ + switch (union_->type) + { + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_BOXED_STRUCT: + g_free (union_->boxed_struct.parent.string_); + g_strfreev (union_->boxed_struct.parent.g_strv); + break; + + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_BOXED_STRUCT_PTR: + g_boxed_free (gi_marshalling_tests_boxed_struct_get_type (), union_->boxed_struct_ptr.parent); + break; + + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_NONE: + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_SINGLE_UNION: + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_POINTER_STRUCT: + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_SIMPLE_STRUCT: + case GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_NESTED_STRUCT: + break; + + default: + g_assert_not_reached (); + } + + g_free (union_); +} + +GType +gi_marshalling_tests_structured_union_get_type (void) +{ + static GType type = 0; + + if (type == 0) + { + type = g_boxed_type_register_static ("GIMarshallingTestsStructuredUnion", + (GBoxedCopyFunc) + gi_marshalling_tests_structured_union_copy, + (GBoxedFreeFunc) gi_marshalling_tests_structured_union_free); + } + + return type; +} + +GIMarshallingTestsStructuredUnionType +gi_marshalling_tests_structured_union_type (GIMarshallingTestsStructuredUnion *structured_union) +{ + return structured_union->type; +} + +enum +{ + PROP_0, + PROP_INT_ +}; + +static void +gi_marshalling_tests_object_real_method_with_default_implementation (GIMarshallingTestsObject *self, gint8 in); + +G_DEFINE_TYPE (GIMarshallingTestsObject, gi_marshalling_tests_object, G_TYPE_OBJECT); + +static void +gi_marshalling_tests_object_init (GIMarshallingTestsObject *self G_GNUC_UNUSED) +{ +} + +static void +gi_marshalling_tests_object_finalize (GObject *object) +{ + G_OBJECT_CLASS (gi_marshalling_tests_object_parent_class)->finalize (object); +} + +static void +gi_marshalling_tests_object_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + g_return_if_fail (GI_MARSHALLING_TESTS_IS_OBJECT (object)); + + switch (prop_id) + { + case PROP_INT_: + GI_MARSHALLING_TESTS_OBJECT (object)->int_ = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gi_marshalling_tests_object_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + g_return_if_fail (GI_MARSHALLING_TESTS_IS_OBJECT (object)); + + switch (prop_id) + { + case PROP_INT_: + g_value_set_int (value, GI_MARSHALLING_TESTS_OBJECT (object)->int_); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gi_marshalling_tests_object_class_init (GIMarshallingTestsObjectClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); +#if 0 + GObjectClass *parent_class = G_OBJECT_CLASS (klass); +#endif + + object_class->finalize = gi_marshalling_tests_object_finalize; + object_class->set_property = gi_marshalling_tests_object_set_property; + object_class->get_property = gi_marshalling_tests_object_get_property; + + g_object_class_install_property (object_class, PROP_INT_, + g_param_spec_int ("int", "Integer", + "An integer", G_MININT, + G_MAXINT, 0, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + klass->method_with_default_implementation = gi_marshalling_tests_object_real_method_with_default_implementation; +} + +void +gi_marshalling_tests_object_static_method (void) +{ +} + +void +gi_marshalling_tests_object_method (GIMarshallingTestsObject *object) +{ + g_return_if_fail (GI_MARSHALLING_TESTS_IS_OBJECT (object)); + g_assert_cmpint (object->int_, ==, 42); +} + +void +gi_marshalling_tests_object_overridden_method (GIMarshallingTestsObject *object) +{ + g_return_if_fail (GI_MARSHALLING_TESTS_IS_OBJECT (object)); + g_assert_cmpint (object->int_, ==, 0); +} + +GIMarshallingTestsObject * +gi_marshalling_tests_object_new (gint int_) +{ + return g_object_new (GI_MARSHALLING_TESTS_TYPE_OBJECT, "int", int_, NULL); +} + +GIMarshallingTestsObject * +gi_marshalling_tests_object_new_fail (gint int_ G_GNUC_UNUSED, + GError **error) +{ + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + g_set_error_literal (error, + g_quark_from_static_string (GI_MARSHALLING_TESTS_CONSTANT_GERROR_DOMAIN), + GI_MARSHALLING_TESTS_CONSTANT_GERROR_CODE, + GI_MARSHALLING_TESTS_CONSTANT_GERROR_MESSAGE); + + return NULL; +} + +/** + * gi_marshalling_tests_object_method_array_in: + * @ints: (array length=length): + */ +void +gi_marshalling_tests_object_method_array_in (GIMarshallingTestsObject *self G_GNUC_UNUSED, + const gint *ints, + gint length) +{ + g_assert_cmpint (length, ==, 4); + g_assert_cmpint (ints[0], ==, -1); + g_assert_cmpint (ints[1], ==, 0); + g_assert_cmpint (ints[2], ==, 1); + g_assert_cmpint (ints[3], ==, 2); +} + +/** + * gi_marshalling_tests_object_method_array_out: + * @ints: (out) (array length=length) (transfer none): + */ +void +gi_marshalling_tests_object_method_array_out (GIMarshallingTestsObject *self G_GNUC_UNUSED, + gint **ints, + gint *length) +{ + static gint values[] = { -1, 0, 1, 2 }; + + *length = 4; + *ints = values; +} + +/** + * gi_marshalling_tests_object_method_array_inout: + * @ints: (inout) (array length=length) (transfer none): + * @length: (inout): + */ +void +gi_marshalling_tests_object_method_array_inout (GIMarshallingTestsObject *self G_GNUC_UNUSED, + gint **ints, + gint *length) +{ + static gint values[] = { -2, -1, 0, 1, 2 }; + + g_assert_cmpint (*length, ==, 4); + g_assert_cmpint ((*ints)[0], ==, -1); + g_assert_cmpint ((*ints)[1], ==, 0); + g_assert_cmpint ((*ints)[2], ==, 1); + g_assert_cmpint ((*ints)[3], ==, 2); + + *length = 5; + *ints = values; +} + +/** + * gi_marshalling_tests_object_method_array_return: + * + * Returns: (array length=length): + */ +const gint * +gi_marshalling_tests_object_method_array_return (GIMarshallingTestsObject *self G_GNUC_UNUSED, + gint *length) +{ + static gint ints[] = { -1, 0, 1, 2 }; + + *length = 4; + return ints; +} + +/** + * gi_marshalling_tests_object_method_int8_in: + * @in: (in): + */ +void +gi_marshalling_tests_object_method_int8_in (GIMarshallingTestsObject *self, gint8 in) +{ + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->method_int8_in (self, in); +} + +/** + * gi_marshalling_tests_object_method_int8_out: + * @out: (out): + */ +void +gi_marshalling_tests_object_method_int8_out (GIMarshallingTestsObject *self, gint8 *out) +{ + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->method_int8_out (self, out); +} + +/** + * gi_marshalling_tests_object_method_int8_arg_and_out_caller: + * @out: (out): + */ +void +gi_marshalling_tests_object_method_int8_arg_and_out_caller (GIMarshallingTestsObject *self, gint8 arg, gint8 *out) +{ + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->method_int8_arg_and_out_caller (self, arg, out); +} + +/** + * gi_marshalling_tests_object_method_int8_arg_and_out_callee: + * @out: (out): + */ +void +gi_marshalling_tests_object_method_int8_arg_and_out_callee (GIMarshallingTestsObject *self, gint8 arg, gint8 **out) +{ + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->method_int8_arg_and_out_callee (self, arg, out); +} + +/** + * gi_marshalling_tests_object_method_str_arg_out_ret: + * @out: (out): + * + * Returns: (transfer none) + */ +const gchar * +gi_marshalling_tests_object_method_str_arg_out_ret (GIMarshallingTestsObject *self, const gchar *arg, guint *out) +{ + return GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->method_str_arg_out_ret (self, arg, out); +} + +/** + * gi_marshalling_tests_object_method_with_default_implementation: + * @in: (in): + */ +void +gi_marshalling_tests_object_method_with_default_implementation (GIMarshallingTestsObject *self, gint8 in) +{ + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->method_with_default_implementation (self, in); +} + +static void +gi_marshalling_tests_object_real_method_with_default_implementation (GIMarshallingTestsObject *self, gint8 in) +{ + GValue val = { + 0, + }; + g_value_init (&val, G_TYPE_INT); + g_value_set_int (&val, in); + g_object_set_property (G_OBJECT (self), "int", &val); +} + +/** + * gi_marshalling_tests_object_vfunc_with_callback: (virtual vfunc_with_callback) + * @callback: (scope call) (closure callback_data): + * @callback_data: (allow-none): + */ +void +gi_marshalling_tests_object_vfunc_with_callback (GIMarshallingTestsObject *self G_GNUC_UNUSED, + GIMarshallingTestsCallbackIntInt callback G_GNUC_UNUSED, + void *callback_data G_GNUC_UNUSED) +{ +} + +static int +_callback (int val, void *user_data) +{ + g_assert (user_data == (gpointer) 0xdeadbeef); + return val; +} + +void +gi_marshalling_tests_object_call_vfunc_with_callback (GIMarshallingTestsObject *object) +{ + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (object)->vfunc_with_callback (object, _callback, (void *) 0xdeadbeef); +} + +/** + * gi_marshalling_tests_object_none_return: + * + * Returns: (transfer none): + */ +GIMarshallingTestsObject * +gi_marshalling_tests_object_none_return (void) +{ + static GIMarshallingTestsObject *object = NULL; + + if (object == NULL) + { + object = g_object_new (GI_MARSHALLING_TESTS_TYPE_OBJECT, NULL); + } + + return object; +} + +/** + * gi_marshalling_tests_object_full_return: + * + * Returns: (transfer full): + */ +GIMarshallingTestsObject * +gi_marshalling_tests_object_full_return (void) +{ + return g_object_new (GI_MARSHALLING_TESTS_TYPE_OBJECT, NULL); +} + +/** + * gi_marshalling_tests_object_none_in: + * @object: (transfer none): + */ +void +gi_marshalling_tests_object_none_in (GIMarshallingTestsObject *object) +{ + g_assert_cmpint (object->int_, ==, 42); +} + +/** + * gi_marshalling_tests_object_none_out: + * @object: (out) (transfer none): + */ +void +gi_marshalling_tests_object_none_out (GIMarshallingTestsObject **object) +{ + static GIMarshallingTestsObject *new_object = NULL; + + if (new_object == NULL) + { + new_object = g_object_new (GI_MARSHALLING_TESTS_TYPE_OBJECT, NULL); + } + + *object = new_object; +} + +/** + * gi_marshalling_tests_object_none_out_uninitialized: + * @v: (out) (transfer none): + */ +gboolean +gi_marshalling_tests_object_none_out_uninitialized (GIMarshallingTestsObject **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_object_full_out: + * @object: (out) (transfer full): + */ +void +gi_marshalling_tests_object_full_out (GIMarshallingTestsObject **object) +{ + *object = g_object_new (GI_MARSHALLING_TESTS_TYPE_OBJECT, NULL); +} + +/** + * gi_marshalling_tests_object_full_out_uninitialized: + * @v: (out) (transfer full): + */ +gboolean +gi_marshalling_tests_object_full_out_uninitialized (GIMarshallingTestsObject **v G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_object_none_inout: + * @object: (inout) (transfer none): + */ +void +gi_marshalling_tests_object_none_inout (GIMarshallingTestsObject **object) +{ + static GIMarshallingTestsObject *new_object = NULL; + + g_assert_cmpint ((*object)->int_, ==, 42); + + if (new_object == NULL) + { + new_object = g_object_new (GI_MARSHALLING_TESTS_TYPE_OBJECT, NULL); + new_object->int_ = 0; + } + + *object = new_object; +} + +/** + * gi_marshalling_tests_object_full_inout: + * @object: (inout) (transfer full): + */ +void +gi_marshalling_tests_object_full_inout (GIMarshallingTestsObject **object) +{ + g_assert_cmpint ((*object)->int_, ==, 42); + + g_object_unref (*object); + *object = g_object_new (GI_MARSHALLING_TESTS_TYPE_OBJECT, NULL); +} + +/** + * gi_marshalling_tests_object_int8_in: + * @in: (in): + */ +void +gi_marshalling_tests_object_int8_in (GIMarshallingTestsObject *object, gint8 in) +{ + gi_marshalling_tests_object_method_int8_in (object, in); +} + +/** + * gi_marshalling_tests_object_int8_out: + * @out: (out): + */ +void +gi_marshalling_tests_object_int8_out (GIMarshallingTestsObject *object, gint8 *out) +{ + gi_marshalling_tests_object_method_int8_out (object, out); +} + +/** + * gi_marshalling_tests_object_vfunc_return_value_only: + */ +glong +gi_marshalling_tests_object_vfunc_return_value_only (GIMarshallingTestsObject *self) +{ + /* make sure that local variables don't get smashed */ + glong return_value; + gulong local = 0x12345678; + return_value = GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_return_value_only (self); + g_assert_cmpint (local, ==, 0x12345678); + return return_value; +} + +/** + * gi_marshalling_tests_object_vfunc_one_out_parameter: + * @a: (out): + */ +void +gi_marshalling_tests_object_vfunc_one_out_parameter (GIMarshallingTestsObject *self, gfloat *a) +{ + /* make sure that local variables don't get smashed */ + gulong local = 0x12345678; + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_one_out_parameter (self, a); + g_assert_cmpint (local, ==, 0x12345678); +} + +/** + * gi_marshalling_tests_object_vfunc_one_inout_parameter: + * @a: (inout): + */ +void +gi_marshalling_tests_object_vfunc_one_inout_parameter (GIMarshallingTestsObject *self, gfloat *a) +{ + /* make sure that local variables don't get smashed */ + gulong local = 0x12345678; + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_one_inout_parameter (self, a); + g_assert_cmpint (local, ==, 0x12345678); +} + +/** + * gi_marshalling_tests_object_vfunc_multiple_inout_parameters: + * @a: (inout): + * @b: (inout): + */ +void +gi_marshalling_tests_object_vfunc_multiple_inout_parameters (GIMarshallingTestsObject *self, gfloat *a, gfloat *b) +{ + /* make sure that local variables don't get smashed */ + gulong local = 0x12345678; + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_multiple_inout_parameters (self, a, b); + g_assert_cmpint (local, ==, 0x12345678); +} + +/** + * gi_marshalling_tests_object_vfunc_multiple_out_parameters: + * @a: (out): + * @b: (out): + */ +void +gi_marshalling_tests_object_vfunc_multiple_out_parameters (GIMarshallingTestsObject *self, gfloat *a, gfloat *b) +{ + /* make sure that local variables don't get smashed */ + gulong local = 0x12345678; + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_multiple_out_parameters (self, a, b); + g_assert_cmpint (local, ==, 0x12345678); +} + +/** + * gi_marshalling_tests_object_vfunc_caller_allocated_out_parameter: + * @a: (out): + */ +void +gi_marshalling_tests_object_vfunc_caller_allocated_out_parameter (GIMarshallingTestsObject *self, GValue *a) +{ + /* make sure that local variables don't get smashed */ + gulong local = 0x12345678; + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_caller_allocated_out_parameter (self, a); + g_assert_cmpint (local, ==, 0x12345678); +} + +/** + * gi_marshalling_tests_object_vfunc_array_out_parameter: + * @a: (out) (array zero-terminated): + */ +void +gi_marshalling_tests_object_vfunc_array_out_parameter (GIMarshallingTestsObject *self, gfloat **a) +{ + /* make sure that local variables don't get smashed */ + gulong local = 0x12345678; + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_array_out_parameter (self, a); + g_assert_cmpint (local, ==, 0x12345678); +} + +/** + * gi_marshalling_tests_object_vfunc_return_value_and_one_out_parameter: + * @a: (out): + */ +glong +gi_marshalling_tests_object_vfunc_return_value_and_one_out_parameter (GIMarshallingTestsObject *self, glong *a) +{ + /* make sure that local variables don't get smashed */ + gulong return_value; + gulong local = 0x12345678; + return_value = GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_return_value_and_one_out_parameter (self, a); + g_assert_cmpint (local, ==, 0x12345678); + return return_value; +} + +/** + * gi_marshalling_tests_object_vfunc_return_value_and_multiple_out_parameters: + * @a: (out): + * @b: (out): + */ +glong +gi_marshalling_tests_object_vfunc_return_value_and_multiple_out_parameters (GIMarshallingTestsObject *self, glong *a, glong *b) +{ + gulong return_value; + gulong local = 0x12345678; + return_value = + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_return_value_and_multiple_out_parameters (self, a, b); + g_assert_cmpint (local, ==, 0x12345678); + return return_value; +} + +/** + * gi_marshalling_tests_object_vfunc_return_value_and_one_inout_parameter: + * @a: (inout): + */ +glong +gi_marshalling_tests_object_vfunc_return_value_and_one_inout_parameter (GIMarshallingTestsObject *self, glong *a) +{ + /* make sure that local variables don't get smashed */ + gulong return_value; + gulong local = 0x12345678; + return_value = GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_return_value_and_one_inout_parameter (self, a); + g_assert_cmpint (local, ==, 0x12345678); + return return_value; +} + +/** + * gi_marshalling_tests_object_vfunc_return_value_and_multiple_inout_parameters: + * @a: (inout): + * @b: (inout): + */ +glong +gi_marshalling_tests_object_vfunc_return_value_and_multiple_inout_parameters (GIMarshallingTestsObject *self, glong *a, glong *b) +{ + gulong return_value; + gulong local = 0x12345678; + return_value = + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_return_value_and_multiple_inout_parameters (self, a, b); + g_assert_cmpint (local, ==, 0x12345678); + return return_value; +} + +/** + * gi_marshalling_tests_callback_owned_boxed: + * @callback: (scope call) (closure callback_data): + * @callback_data: (allow-none): + */ +glong +gi_marshalling_tests_callback_owned_boxed (GIMarshallingTestsCallbackOwnedBoxed callback, + void *callback_data) +{ + static GIMarshallingTestsBoxedStruct *box = NULL; + glong ret; + + if (!box) + box = gi_marshalling_tests_boxed_struct_new (); + box->long_++; + callback (box, callback_data); + ret = box->long_; + return ret; +} + +gboolean +gi_marshalling_tests_object_vfunc_meth_with_error (GIMarshallingTestsObject *self, gint x, GError **error) +{ + gulong local = 0x12345678; + gboolean ret = GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_meth_with_err (self, + x, + error); + g_assert_cmpint (local, ==, 0x12345678); + return ret; +} + +/** + * gi_marshalling_tests_object_vfunc_return_enum: + */ +GIMarshallingTestsEnum +gi_marshalling_tests_object_vfunc_return_enum (GIMarshallingTestsObject *self) +{ + /* make sure that local variables don't get smashed */ + GIMarshallingTestsEnum return_value; + glong local = 0x12345678; + return_value = GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_return_enum (self); + g_assert_cmpint (local, ==, 0x12345678); + return return_value; +} + +/** + * gi_marshalling_tests_object_vfunc_out_enum: + * @_enum: (out): + */ +void +gi_marshalling_tests_object_vfunc_out_enum (GIMarshallingTestsObject *self, GIMarshallingTestsEnum *_enum) +{ + /* make sure that local variables don't get smashed */ + gulong local = 0x12345678; + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_out_enum (self, _enum); + g_assert_cmpint (local, ==, 0x12345678); +} + +/** + * gi_marshalling_tests_object_vfunc_return_flags: + */ +GIMarshallingTestsFlags +gi_marshalling_tests_object_vfunc_return_flags (GIMarshallingTestsObject *self) +{ + /* make sure that local variables don't get smashed */ + GIMarshallingTestsFlags return_value; + glong local = 0x12345678; + return_value = GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_return_flags (self); + g_assert_cmpint (local, ==, 0x12345678); + return return_value; +} + +/** + * gi_marshalling_tests_object_vfunc_out_flags: + * @flags: (out): + */ +void +gi_marshalling_tests_object_vfunc_out_flags (GIMarshallingTestsObject *self, GIMarshallingTestsFlags *flags) +{ + /* make sure that local variables don't get smashed */ + gulong local = 0x12345678; + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_out_flags (self, flags); + g_assert_cmpuint (local, ==, 0x12345678); +} + +/* NOTE: + * + * The following (get_ref_info_for_*) methods are designed to call vfuncs related + * to object argument marshaling. They do not pass the resulting objects through them + * as regular vfunc wrapper method do, but rather return reference count and floating + * information back to the callers. This is useful because callers can do testing of + * expected reference counts in isolation and from the perspective of C. This is important + * because if there are bugs in the reverse marshaling, they can obfuscate or compound + * bugs in marshaling from the vfuncs. + */ + +/** + * gi_marshalling_tests_object_get_ref_info_for_vfunc_return_object_transfer_none: + * @ref_count: (out): Ref count of the object returned from the vfunc directly after vfunc call. + * @is_floating: (out): Floating state object returned from the vfunc directly after vfunc call. + */ +void +gi_marshalling_tests_object_get_ref_info_for_vfunc_return_object_transfer_none (GIMarshallingTestsObject *self, guint *ref_count, gboolean *is_floating) +{ + GObject *object = GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_return_object_transfer_none (self); + *ref_count = object->ref_count; + *is_floating = g_object_is_floating (object); + + /* Attempt to sink and unref the returned object and avoid any potential leaks */ + g_object_ref_sink (object); + g_object_unref (object); +} + +/** + * gi_marshalling_tests_object_get_ref_info_for_vfunc_return_object_transfer_full: + * @ref_count: (out): Ref count of the object returned from the vfunc directly after vfunc call. + * @is_floating: (out): Floating state object returned from the vfunc directly after vfunc call. + */ +void +gi_marshalling_tests_object_get_ref_info_for_vfunc_return_object_transfer_full (GIMarshallingTestsObject *self, guint *ref_count, gboolean *is_floating) +{ + GObject *object = GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_return_object_transfer_full (self); + *ref_count = object->ref_count; + *is_floating = g_object_is_floating (object); + g_object_unref (object); +} + +/** + * gi_marshalling_tests_object_get_ref_info_for_vfunc_out_object_transfer_none: + * @ref_count: (out): Ref count of the object returned from the vfunc directly after vfunc call. + * @is_floating: (out): Floating state object returned from the vfunc directly after vfunc call. + */ +void +gi_marshalling_tests_object_get_ref_info_for_vfunc_out_object_transfer_none (GIMarshallingTestsObject *self, guint *ref_count, gboolean *is_floating) +{ + GObject *object = NULL; + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_out_object_transfer_none (self, &object); + *ref_count = object->ref_count; + *is_floating = g_object_is_floating (object); + + /* Attempt to sink and unref the returned object and avoid any potential leaks */ + g_object_ref_sink (object); + g_object_unref (object); +} + +/** + * gi_marshalling_tests_object_get_ref_info_for_vfunc_out_object_transfer_full: + * @ref_count: (out): Ref count of the object returned from the vfunc directly after vfunc call. + * @is_floating: (out): Floating state object returned from the vfunc directly after vfunc call. + */ +void +gi_marshalling_tests_object_get_ref_info_for_vfunc_out_object_transfer_full (GIMarshallingTestsObject *self, guint *ref_count, gboolean *is_floating) +{ + GObject *object = NULL; + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_out_object_transfer_full (self, &object); + *ref_count = object->ref_count; + *is_floating = g_object_is_floating (object); + g_object_unref (object); +} + +static void +_vfunc_in_object_destroy_callback (gboolean *destroy_called, + GObject *where_the_object_was G_GNUC_UNUSED) +{ + *destroy_called = TRUE; +} + +/** + * gi_marshalling_tests_object_get_ref_info_for_vfunc_in_object_transfer_none: + * @type: GType of object to create and pass as in argument to the vfunc + * @ref_count: (out): Ref count of the in object directly after vfunc call. + * @is_floating: (out): Floating state of in object directly after vfunc call. + * + * Calls vfunc_in_object_transfer_none with a new object of the given type. + */ +void +gi_marshalling_tests_object_get_ref_info_for_vfunc_in_object_transfer_none (GIMarshallingTestsObject *self, GType type, guint *ref_count, gboolean *is_floating) +{ + static gboolean destroy_called; + GObject *object; + destroy_called = FALSE; + + object = g_object_new (type, NULL); + g_object_weak_ref (object, (GWeakNotify) _vfunc_in_object_destroy_callback, &destroy_called); + + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_in_object_transfer_none (self, object); + if (destroy_called) + { + *ref_count = 0; + *is_floating = FALSE; + } + else + { + *ref_count = object->ref_count; + *is_floating = g_object_is_floating (object); + g_object_unref (object); + } +} + +/** + * gi_marshalling_tests_object_get_ref_info_for_vfunc_in_object_transfer_full: + * @type: GType of object to create and pass as in argument to the vfunc + * @ref_count: (out): Ref count of the in object directly after vfunc call. + * @is_floating: (out): Floating state of in object directly after vfunc call. + */ +void +gi_marshalling_tests_object_get_ref_info_for_vfunc_in_object_transfer_full (GIMarshallingTestsObject *self, GType type, guint *ref_count, gboolean *is_floating) +{ + static gboolean destroy_called; + GObject *object; + destroy_called = FALSE; + + object = g_object_new (type, NULL); + g_object_weak_ref (object, (GWeakNotify) _vfunc_in_object_destroy_callback, &destroy_called); + + /* Calling the vfunc takes ownership of the object, so we use a weak_ref to determine + * if the object gets destroyed after the call and appropriately return 0 as the ref count. + */ + GI_MARSHALLING_TESTS_OBJECT_GET_CLASS (self)->vfunc_in_object_transfer_full (self, object); + if (destroy_called) + { + *ref_count = 0; + *is_floating = FALSE; + } + else + { + *ref_count = object->ref_count; + *is_floating = g_object_is_floating (object); + } +} + +G_DEFINE_TYPE (GIMarshallingTestsSubObject, gi_marshalling_tests_sub_object, GI_MARSHALLING_TESTS_TYPE_OBJECT); + +static void +gi_marshalling_tests_sub_object_init (GIMarshallingTestsSubObject *self G_GNUC_UNUSED) +{ +} + +static void +gi_marshalling_tests_sub_object_finalize (GObject *object) +{ + G_OBJECT_CLASS (gi_marshalling_tests_sub_object_parent_class)->finalize (object); +} + +static void +method_deep_hierarchy (GIMarshallingTestsObject *self, gint8 in) +{ + GValue val = { + 0, + }; + g_value_init (&val, G_TYPE_INT); + g_value_set_int (&val, in); + g_object_set_property (G_OBJECT (self), "int", &val); +} + +static void +gi_marshalling_tests_sub_object_class_init (GIMarshallingTestsSubObjectClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = gi_marshalling_tests_sub_object_finalize; + GI_MARSHALLING_TESTS_OBJECT_CLASS (klass)->method_deep_hierarchy = method_deep_hierarchy; +} + +void +gi_marshalling_tests_sub_object_sub_method (GIMarshallingTestsSubObject *object) +{ + g_assert_cmpint (GI_MARSHALLING_TESTS_OBJECT (object)->int_, ==, 0); +} + +void +gi_marshalling_tests_sub_object_overwritten_method (GIMarshallingTestsSubObject *object) +{ + g_assert_cmpint (GI_MARSHALLING_TESTS_OBJECT (object)->int_, ==, 0); +} + +G_DEFINE_TYPE (GIMarshallingTestsSubSubObject, + gi_marshalling_tests_sub_sub_object, + GI_MARSHALLING_TESTS_TYPE_SUB_OBJECT); + +static void +gi_marshalling_tests_sub_sub_object_init (GIMarshallingTestsSubSubObject *self G_GNUC_UNUSED) +{ +} + +static void +gi_marshalling_tests_sub_sub_object_class_init (GIMarshallingTestsSubSubObjectClass *klass G_GNUC_UNUSED) +{ +} + +/* Interfaces */ + +static void +gi_marshalling_tests_interface_class_init (void *g_iface G_GNUC_UNUSED, + void *data G_GNUC_UNUSED) +{ +} + +GType +gi_marshalling_tests_interface_get_type (void) +{ + static GType type = 0; + if (type == 0) + { + /* Not adding prerequisite here for test purposes */ + type = g_type_register_static_simple (G_TYPE_INTERFACE, + "GIMarshallingTestsInterface", + sizeof (GIMarshallingTestsInterfaceIface), + (GClassInitFunc) gi_marshalling_tests_interface_class_init, 0, NULL, 0); + } + + return type; +} + +/** + * gi_marshalling_tests_interface_test_int8_in: + * @in: (in): + */ +void +gi_marshalling_tests_interface_test_int8_in (GIMarshallingTestsInterface *self, gint8 in) +{ + GI_MARSHALLING_TESTS_INTERFACE_GET_IFACE (self)->test_int8_in (self, in); +} + +/** + * gi_marshalling_tests_test_interface_test_int8_in: + * @in: (in): + */ +void +gi_marshalling_tests_test_interface_test_int8_in (GIMarshallingTestsInterface *test_iface, gint8 in) +{ + gi_marshalling_tests_interface_test_int8_in (test_iface, in); +} + +static void test_interface_init (GIMarshallingTestsInterfaceIface *iface); + +G_DEFINE_TYPE_WITH_CODE (GIMarshallingTestsInterfaceImpl, gi_marshalling_tests_interface_impl, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GI_MARSHALLING_TESTS_TYPE_INTERFACE, test_interface_init)) + +static void +gi_marshalling_tests_interface_impl_test_int8_in (GIMarshallingTestsInterface *self G_GNUC_UNUSED, + gint8 in G_GNUC_UNUSED) +{ +} + +static void +test_interface_init (GIMarshallingTestsInterfaceIface *iface) +{ + iface->test_int8_in = gi_marshalling_tests_interface_impl_test_int8_in; +} + +static void +gi_marshalling_tests_interface_impl_init (GIMarshallingTestsInterfaceImpl *self G_GNUC_UNUSED) +{ +} + +static void +gi_marshalling_tests_interface_impl_class_init (GIMarshallingTestsInterfaceImplClass *klass G_GNUC_UNUSED) +{ +} + +/** + * gi_marshalling_tests_interface_impl_get_as_interface: + * + * Returns: (transfer none): + */ +GIMarshallingTestsInterface * +gi_marshalling_tests_interface_impl_get_as_interface (GIMarshallingTestsInterfaceImpl *self) +{ + return (GIMarshallingTestsInterface *) self; +} + +static void +gi_marshalling_tests_interface2_class_init (void *g_iface G_GNUC_UNUSED, + void *data G_GNUC_UNUSED) +{ +} + +GType +gi_marshalling_tests_interface2_get_type (void) +{ + static GType type = 0; + if (type == 0) + { + type = g_type_register_static_simple (G_TYPE_INTERFACE, + "GIMarshallingTestsInterface2", + sizeof (GIMarshallingTestsInterface2Iface), + (GClassInitFunc) gi_marshalling_tests_interface2_class_init, 0, NULL, 0); + } + + return type; +} + +static void +gi_marshalling_tests_interface3_class_init (void *g_iface G_GNUC_UNUSED, + void *data G_GNUC_UNUSED) +{ +} + +GType +gi_marshalling_tests_interface3_get_type (void) +{ + static GType type = 0; + if (type == 0) + { + type = g_type_register_static_simple (G_TYPE_INTERFACE, + "GIMarshallingTestsInterface3", + sizeof (GIMarshallingTestsInterface3Iface), + (GClassInitFunc) gi_marshalling_tests_interface3_class_init, 0, NULL, 0); + } + + return type; +} + +/** + * gi_marshalling_tests_interface3_test_variant_array_in: + * @in: (array length=n_in): + * @n_in: + */ +void +gi_marshalling_tests_interface3_test_variant_array_in (GIMarshallingTestsInterface3 *self, GVariant **in, gsize n_in) +{ + GI_MARSHALLING_TESTS_INTERFACE3_GET_IFACE (self)->test_variant_array_in (self, in, n_in); +} + +/** + * gi_marshalling_tests_int_out_out: + * @int0: (out): + * @int1: (out): + */ +void +gi_marshalling_tests_int_out_out (gint *int0, gint *int1) +{ + *int0 = 6; + *int1 = 7; +} + +/** + * gi_marshalling_tests_int_three_in_three_out: + * @a: (in): + * @b: (in): + * @c: (in): + * @out0: (out): + * @out1: (out): + * @out2: (out): + */ +void +gi_marshalling_tests_int_three_in_three_out (gint a, gint b, gint c, gint *out0, gint *out1, gint *out2) +{ + *out0 = a; + *out1 = b; + *out2 = c; +} + +/** + * gi_marshalling_tests_int_return_out: + * @int_: (out): + */ +gint +gi_marshalling_tests_int_return_out (gint *int_) +{ + *int_ = 7; + return 6; +} + +/** + * gi_marshalling_tests_int_two_in_utf8_two_in_with_allow_none: + * @a: (in): Must be 1 + * @b: (in): Must be 2 + * @c: (in) (allow-none): Must be "3" or NULL + * @d: (in) (allow-none): Must be "4" or NULL + */ +void +gi_marshalling_tests_int_two_in_utf8_two_in_with_allow_none (gint a, gint b, const gchar *c, const gchar *d) +{ + g_assert_cmpint (a, ==, 1); + g_assert_cmpint (b, ==, 2); + if (c != NULL) + g_assert_cmpstr (c, ==, "3"); + if (d != NULL) + g_assert_cmpstr (d, ==, "4"); +} + +/** + * gi_marshalling_tests_int_one_in_utf8_two_in_one_allows_none: + * @a: (in): Must be 1 + * @b: (in) (allow-none): Must be "2" or NULL + * @c: (in): Must be "3" + */ +void +gi_marshalling_tests_int_one_in_utf8_two_in_one_allows_none (gint a, const gchar *b, const gchar *c) +{ + g_assert_cmpint (a, ==, 1); + if (b != NULL) + g_assert_cmpstr (b, ==, "2"); + g_assert_cmpstr (c, ==, "3"); +} + +/** + * gi_marshalling_tests_array_in_utf8_two_in: + * @ints: (array length=length): + * @length: + * @a: (in) (allow-none): Must be "1" or NULL + * @b: (in) (allow-none): Must be "2" or NULL + */ +void +gi_marshalling_tests_array_in_utf8_two_in (const gint *ints, gint length, const gchar *a, const gchar *b) +{ + g_assert_cmpint (length, ==, 4); + g_assert_cmpint (ints[0], ==, -1); + g_assert_cmpint (ints[1], ==, 0); + g_assert_cmpint (ints[2], ==, 1); + g_assert_cmpint (ints[3], ==, 2); + + if (a != NULL) + g_assert_cmpstr (a, ==, "1"); + if (b != NULL) + g_assert_cmpstr (b, ==, "2"); +} + +/** + * gi_marshalling_tests_array_in_utf8_two_in_out_of_order: + * @length: + * @a: (in) (allow-none): Must be "1" or NULL + * @ints: (array length=length): + * @b: (in) (allow-none): Must be "2" or NULL + */ +void +gi_marshalling_tests_array_in_utf8_two_in_out_of_order (gint length, const gchar *a, const gint *ints, const gchar *b) +{ + g_assert_cmpint (length, ==, 4); + g_assert_cmpint (ints[0], ==, -1); + g_assert_cmpint (ints[1], ==, 0); + g_assert_cmpint (ints[2], ==, 1); + g_assert_cmpint (ints[3], ==, 2); + + if (a != NULL) + g_assert_cmpstr (a, ==, "1"); + if (b != NULL) + g_assert_cmpstr (b, ==, "2"); +} + +/* GError */ + +void +gi_marshalling_tests_gerror (GError **error) +{ + GQuark quark = g_quark_from_static_string (GI_MARSHALLING_TESTS_CONSTANT_GERROR_DOMAIN); + g_set_error_literal (error, quark, + GI_MARSHALLING_TESTS_CONSTANT_GERROR_CODE, GI_MARSHALLING_TESTS_CONSTANT_GERROR_MESSAGE); +} + +/** + * gi_marshalling_tests_gerror_array_in: + * @in_ints: (array zero-terminated): + */ +void +gi_marshalling_tests_gerror_array_in (gint *in_ints G_GNUC_UNUSED, + GError **error) +{ + GQuark quark = g_quark_from_static_string (GI_MARSHALLING_TESTS_CONSTANT_GERROR_DOMAIN); + g_set_error_literal (error, quark, + GI_MARSHALLING_TESTS_CONSTANT_GERROR_CODE, GI_MARSHALLING_TESTS_CONSTANT_GERROR_MESSAGE); +} + +/** + * gi_marshalling_tests_gerror_out: + * @error: (out) (allow-none) (transfer full): location for the GError. + * @debug: (out) (allow-none) (transfer full): location for the debug message + * + * Inspired by gst_message_parse_error. + */ +void +gi_marshalling_tests_gerror_out (GError **error, gchar **debug) +{ + GQuark quark = g_quark_from_static_string (GI_MARSHALLING_TESTS_CONSTANT_GERROR_DOMAIN); + g_set_error_literal (error, quark, + GI_MARSHALLING_TESTS_CONSTANT_GERROR_CODE, GI_MARSHALLING_TESTS_CONSTANT_GERROR_MESSAGE); + + if (debug != NULL) + { + *debug = g_strdup (GI_MARSHALLING_TESTS_CONSTANT_GERROR_DEBUG_MESSAGE); + } +} + +/** + * gi_marshalling_tests_gerror_out_uninitialized: + * @v: (out) (allow-none) (transfer full): + * @v2: (out) (allow-none) (transfer full): + */ +gboolean +gi_marshalling_tests_gerror_out_uninitialized (GError **v G_GNUC_UNUSED, gchar **v2 G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_gerror_out_transfer_none: + * @err: (out) (allow-none) (transfer none): location for the GError. + * @debug: (out) (allow-none) (transfer none): location for the debug message + * + * A variant of gi_marshalling_tests_gerror_out() which returns data the caller + * must not free. + */ +void +gi_marshalling_tests_gerror_out_transfer_none (GError **err, const gchar **debug) +{ + static GError error = { 0, + GI_MARSHALLING_TESTS_CONSTANT_GERROR_CODE, + (gchar *) GI_MARSHALLING_TESTS_CONSTANT_GERROR_MESSAGE }; + error.domain = g_quark_from_static_string (GI_MARSHALLING_TESTS_CONSTANT_GERROR_DOMAIN); + *err = &error; + *debug = GI_MARSHALLING_TESTS_CONSTANT_GERROR_DEBUG_MESSAGE; +} + +/** + * gi_marshalling_tests_gerror_out_transfer_none_uninitialized: + * @v: (out) (allow-none) (transfer none): + * @v2: (out) (allow-none) (transfer none): + */ +gboolean +gi_marshalling_tests_gerror_out_transfer_none_uninitialized (GError **v G_GNUC_UNUSED, const gchar **v2 G_GNUC_UNUSED) +{ + return FALSE; +} + +/** + * gi_marshalling_tests_gerror_return: + * + * Yet another variant of gi_marshalling_tests_gerror_out(). + * + * Returns: (transfer full): a GError + */ +GError * +gi_marshalling_tests_gerror_return (void) +{ + GQuark quark = g_quark_from_static_string (GI_MARSHALLING_TESTS_CONSTANT_GERROR_DOMAIN); + + return g_error_new_literal (quark, GI_MARSHALLING_TESTS_CONSTANT_GERROR_CODE, GI_MARSHALLING_TESTS_CONSTANT_GERROR_MESSAGE); +} + +static GIMarshallingTestsOverridesStruct * +gi_marshalling_tests_overrides_struct_copy (GIMarshallingTestsOverridesStruct *struct_) +{ + GIMarshallingTestsOverridesStruct *new_struct; + + new_struct = g_slice_new (GIMarshallingTestsOverridesStruct); + + *new_struct = *struct_; + + return new_struct; +} + +static void +gi_marshalling_tests_overrides_struct_free (GIMarshallingTestsOverridesStruct *struct_) +{ + g_slice_free (GIMarshallingTestsOverridesStruct, struct_); +} + +GType +gi_marshalling_tests_overrides_struct_get_type (void) +{ + static GType type = 0; + + if (type == 0) + { + type = + g_boxed_type_register_static ("GIMarshallingTestsOverridesStruct", + (GBoxedCopyFunc) + gi_marshalling_tests_overrides_struct_copy, + (GBoxedFreeFunc) gi_marshalling_tests_overrides_struct_free); + } + + return type; +} + +GIMarshallingTestsOverridesStruct * +gi_marshalling_tests_overrides_struct_new (void) +{ + return g_slice_new (GIMarshallingTestsOverridesStruct); +} + +glong +gi_marshalling_tests_overrides_struct_method (GIMarshallingTestsOverridesStruct *self G_GNUC_UNUSED) +{ + return 42; +} + +/** + * gi_marshalling_tests_overrides_struct_returnv: + * + * Returns: (transfer full): + */ +GIMarshallingTestsOverridesStruct * +gi_marshalling_tests_overrides_struct_returnv (void) +{ + return gi_marshalling_tests_overrides_struct_new (); +} + +G_DEFINE_TYPE (GIMarshallingTestsOverridesObject, gi_marshalling_tests_overrides_object, G_TYPE_OBJECT); + +static void +gi_marshalling_tests_overrides_object_init (GIMarshallingTestsOverridesObject *self G_GNUC_UNUSED) +{ +} + +static void +gi_marshalling_tests_overrides_object_finalize (GObject *object) +{ + G_OBJECT_CLASS (gi_marshalling_tests_overrides_object_parent_class)->finalize (object); +} + +static void +gi_marshalling_tests_overrides_object_class_init (GIMarshallingTestsOverridesObjectClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); +#if 0 + GObjectClass *parent_class = G_OBJECT_CLASS (klass); +#endif + + object_class->finalize = gi_marshalling_tests_overrides_object_finalize; +} + +GIMarshallingTestsOverridesObject * +gi_marshalling_tests_overrides_object_new (void) +{ + return g_object_new (GI_MARSHALLING_TESTS_TYPE_OVERRIDES_OBJECT, NULL); +} + +glong +gi_marshalling_tests_overrides_object_method (GIMarshallingTestsOverridesObject *self G_GNUC_UNUSED) +{ + return 42; +} + +/** + * gi_marshalling_tests_overrides_object_returnv: + * + * Returns: (transfer full): + */ +GIMarshallingTestsOverridesObject * +gi_marshalling_tests_overrides_object_returnv (void) +{ + return g_object_new (GI_MARSHALLING_TESTS_TYPE_OVERRIDES_OBJECT, NULL); +} + +/** + * gi_marshalling_tests_filename_list_return: + * + * Returns: (transfer none) (element-type filename): List of filenames + */ +GSList * +gi_marshalling_tests_filename_list_return (void) +{ + return NULL; +} + +/** + * gi_marshalling_tests_param_spec_in_bool: + */ +void +gi_marshalling_tests_param_spec_in_bool (const GParamSpec *param) +{ + g_assert (G_IS_PARAM_SPEC (param)); + g_assert_cmpint (G_PARAM_SPEC_VALUE_TYPE (param), ==, G_TYPE_BOOLEAN); + g_assert_cmpstr (g_param_spec_get_name ((GParamSpec *) param), ==, "mybool"); +} + +/** + * gi_marshalling_tests_param_spec_return: + * + * Returns: (transfer full): a #GParamSpec + */ +GParamSpec * +gi_marshalling_tests_param_spec_return (void) +{ + return g_param_spec_string ("test-param", "test", "This is a test", "42", G_PARAM_READABLE); +} + +/** + * gi_marshalling_tests_param_spec_out: + * @param: (out): + */ +void +gi_marshalling_tests_param_spec_out (GParamSpec **param) +{ + *param = g_param_spec_string ("test-param", "test", "This is a test", "42", G_PARAM_READABLE); +} + +/** + * gi_marshalling_tests_param_spec_out_uninitialized: + * @v: (out): + */ +gboolean +gi_marshalling_tests_param_spec_out_uninitialized (GParamSpec **v G_GNUC_UNUSED) +{ + return FALSE; +} + +enum +{ + DUMMY_PROPERTY, + SOME_BOOLEAN_PROPERTY, + SOME_CHAR_PROPERTY, + SOME_UCHAR_PROPERTY, + SOME_INT_PROPERTY, + SOME_UINT_PROPERTY, + SOME_LONG_PROPERTY, + SOME_ULONG_PROPERTY, + SOME_INT64_PROPERTY, + SOME_UINT64_PROPERTY, + SOME_FLOAT_PROPERTY, + SOME_STRING_PROPERTY, + SOME_DOUBLE_PROPERTY, + SOME_STRV_PROPERTY, + SOME_BOXED_STRUCT_PROPERTY, + SOME_VARIANT_PROPERTY, + SOME_BOXED_GLIST_PROPERTY, + SOME_GVALUE_PROPERTY, + SOME_OBJECT_PROPERTY, + SOME_FLAGS_PROPERTY, + SOME_ENUM_PROPERTY, + SOME_BYTE_ARRAY_PROPERTY, + SOME_READONLY_PROPERTY, +}; + +G_DEFINE_TYPE (GIMarshallingTestsPropertiesObject, gi_marshalling_tests_properties_object, G_TYPE_OBJECT); + +static void +gi_marshalling_tests_properties_object_init (GIMarshallingTestsPropertiesObject *self G_GNUC_UNUSED) +{ +} + +static void +gi_marshalling_tests_properties_object_finalize (GObject *obj) +{ + GIMarshallingTestsPropertiesObject *self; + self = GI_MARSHALLING_TESTS_PROPERTIES_OBJECT (obj); + + if (self->some_gvalue) + { + g_boxed_free (G_TYPE_VALUE, self->some_gvalue); + self->some_gvalue = NULL; + } + + g_clear_pointer (&self->some_string, g_free); + g_clear_pointer (&self->some_strv, g_strfreev); + g_clear_pointer (&self->some_boxed_struct, gi_marshalling_tests_boxed_struct_free); + g_clear_pointer (&self->some_byte_array, g_byte_array_unref); + g_clear_pointer (&self->some_variant, g_variant_unref); + g_clear_pointer (&self->some_boxed_glist, g_list_free); + g_clear_object (&self->some_object); + + G_OBJECT_CLASS (gi_marshalling_tests_properties_object_parent_class)->finalize (obj); +} + +static void +gi_marshalling_tests_properties_object_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GIMarshallingTestsPropertiesObject *self; + self = GI_MARSHALLING_TESTS_PROPERTIES_OBJECT (object); + switch (property_id) + { + case SOME_BOOLEAN_PROPERTY: + g_value_set_boolean (value, self->some_boolean); + break; + case SOME_CHAR_PROPERTY: + g_value_set_schar (value, self->some_char); + break; + case SOME_UCHAR_PROPERTY: + g_value_set_uchar (value, self->some_uchar); + break; + case SOME_INT_PROPERTY: + g_value_set_int (value, self->some_int); + break; + case SOME_UINT_PROPERTY: + g_value_set_uint (value, self->some_uint); + break; + case SOME_LONG_PROPERTY: + g_value_set_long (value, self->some_long); + break; + case SOME_ULONG_PROPERTY: + g_value_set_ulong (value, self->some_ulong); + break; + case SOME_INT64_PROPERTY: + g_value_set_int64 (value, self->some_int64); + break; + case SOME_UINT64_PROPERTY: + g_value_set_uint64 (value, self->some_uint64); + break; + case SOME_FLOAT_PROPERTY: + g_value_set_float (value, self->some_float); + break; + case SOME_DOUBLE_PROPERTY: + g_value_set_double (value, self->some_double); + break; + case SOME_STRING_PROPERTY: + g_value_set_string (value, self->some_string); + break; + case SOME_STRV_PROPERTY: + g_value_set_boxed (value, self->some_strv); + break; + case SOME_BOXED_STRUCT_PROPERTY: + g_value_set_boxed (value, self->some_boxed_struct); + break; + case SOME_BOXED_GLIST_PROPERTY: + g_value_set_boxed (value, self->some_boxed_glist); + break; + case SOME_GVALUE_PROPERTY: + g_value_set_boxed (value, self->some_gvalue); + break; + case SOME_VARIANT_PROPERTY: + g_value_set_variant (value, self->some_variant); + break; + case SOME_OBJECT_PROPERTY: + g_value_set_object (value, self->some_object); + break; + case SOME_FLAGS_PROPERTY: + g_value_set_flags (value, self->some_flags); + break; + case SOME_ENUM_PROPERTY: + g_value_set_enum (value, self->some_enum); + break; + case SOME_BYTE_ARRAY_PROPERTY: + g_value_set_boxed (value, self->some_byte_array); + break; + case SOME_READONLY_PROPERTY: + g_value_set_int (value, 42); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gi_marshalling_tests_properties_object_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GIMarshallingTestsPropertiesObject *self; + self = GI_MARSHALLING_TESTS_PROPERTIES_OBJECT (object); + switch (property_id) + { + case SOME_BOOLEAN_PROPERTY: + self->some_boolean = g_value_get_boolean (value); + break; + case SOME_CHAR_PROPERTY: + self->some_char = g_value_get_schar (value); + break; + case SOME_UCHAR_PROPERTY: + self->some_uchar = g_value_get_uchar (value); + break; + case SOME_INT_PROPERTY: + self->some_int = g_value_get_int (value); + break; + case SOME_UINT_PROPERTY: + self->some_uint = g_value_get_uint (value); + break; + case SOME_LONG_PROPERTY: + self->some_long = g_value_get_long (value); + break; + case SOME_ULONG_PROPERTY: + self->some_ulong = g_value_get_ulong (value); + break; + case SOME_INT64_PROPERTY: + self->some_int64 = g_value_get_int64 (value); + break; + case SOME_UINT64_PROPERTY: + self->some_uint64 = g_value_get_uint64 (value); + break; + case SOME_FLOAT_PROPERTY: + self->some_float = g_value_get_float (value); + break; + case SOME_DOUBLE_PROPERTY: + self->some_double = g_value_get_double (value); + break; + case SOME_STRING_PROPERTY: + g_clear_pointer (&self->some_string, g_free); + self->some_string = g_value_dup_string (value); + break; + case SOME_STRV_PROPERTY: + g_strfreev (self->some_strv); + self->some_strv = g_strdupv (g_value_get_boxed (value)); + break; + case SOME_BOXED_STRUCT_PROPERTY: + gi_marshalling_tests_boxed_struct_free (self->some_boxed_struct); + self->some_boxed_struct = gi_marshalling_tests_boxed_struct_copy (g_value_get_boxed (value)); + break; + case SOME_BOXED_GLIST_PROPERTY: + g_list_free (self->some_boxed_glist); + self->some_boxed_glist = g_list_copy (g_value_get_boxed (value)); + break; + case SOME_GVALUE_PROPERTY: + if (self->some_gvalue) + g_boxed_free (G_TYPE_VALUE, self->some_gvalue); + self->some_gvalue = g_value_dup_boxed (value); + break; + case SOME_VARIANT_PROPERTY: + if (self->some_variant != NULL) + g_variant_unref (self->some_variant); + self->some_variant = g_value_get_variant (value); + if (self->some_variant != NULL) + g_variant_ref (self->some_variant); + break; + case SOME_OBJECT_PROPERTY: + if (self->some_object != NULL) + g_object_unref (self->some_object); + self->some_object = g_value_dup_object (value); + break; + case SOME_FLAGS_PROPERTY: + self->some_flags = g_value_get_flags (value); + break; + case SOME_ENUM_PROPERTY: + self->some_enum = g_value_get_enum (value); + break; + case SOME_BYTE_ARRAY_PROPERTY: + if (self->some_byte_array != NULL) + g_byte_array_unref (self->some_byte_array); + self->some_byte_array = g_value_dup_boxed (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gi_marshalling_tests_properties_object_class_init (GIMarshallingTestsPropertiesObjectClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gi_marshalling_tests_properties_object_finalize; + object_class->get_property = gi_marshalling_tests_properties_object_get_property; + object_class->set_property = gi_marshalling_tests_properties_object_set_property; + + g_object_class_install_property (object_class, SOME_BOOLEAN_PROPERTY, + g_param_spec_boolean ("some-boolean", + "some-boolean", + "some-boolean", + FALSE, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_CHAR_PROPERTY, + g_param_spec_char ("some-char", + "some-char", + "some-char", G_MININT8, + G_MAXINT8, 0, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_UCHAR_PROPERTY, + g_param_spec_uchar ("some-uchar", + "some-uchar", + "some-uchar", 0, + G_MAXUINT8, 0, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_INT_PROPERTY, + g_param_spec_int ("some-int", "some-int", + "some-int", G_MININT, + G_MAXINT, 0, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_UINT_PROPERTY, + g_param_spec_uint ("some-uint", + "some-uint", + "some-uint", 0, + G_MAXUINT, 0, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_LONG_PROPERTY, + g_param_spec_long ("some-long", + "some-long", + "some-long", G_MINLONG, + G_MAXLONG, 0, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_ULONG_PROPERTY, + g_param_spec_ulong ("some-ulong", + "some-ulong", + "some-ulong", 0, + G_MAXULONG, 0, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_INT64_PROPERTY, + g_param_spec_int64 ("some-int64", + "some-int64", + "some-int64", + G_MININT64, G_MAXINT64, + 0, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_UINT64_PROPERTY, + g_param_spec_uint64 ("some-uint64", + "some-uint64", + "some-uint64", 0, + G_MAXUINT64, 0, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_FLOAT_PROPERTY, + g_param_spec_float ("some-float", + "some-float", + "some-float", + -1 * G_MAXFLOAT, + G_MAXFLOAT, 0, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_DOUBLE_PROPERTY, + g_param_spec_double ("some-double", + "some-double", + "some-double", + -1 * G_MAXDOUBLE, + G_MAXDOUBLE, 0, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_STRING_PROPERTY, + g_param_spec_string ("some-string", + "some-string", + "some-string", + NULL, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_STRV_PROPERTY, + g_param_spec_boxed ("some-strv", + "some-strv", + "some-strv", + G_TYPE_STRV, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_BOXED_STRUCT_PROPERTY, + g_param_spec_boxed ("some-boxed-struct", + "some-boxed-struct", + "some-boxed-struct", + gi_marshalling_tests_boxed_struct_get_type (), G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + /** + * GIMarshallingTestsPropertiesObject:some-boxed-glist: (type GLib.List(gint)) (transfer none): + */ + g_object_class_install_property (object_class, SOME_BOXED_GLIST_PROPERTY, + g_param_spec_boxed ("some-boxed-glist", + "some-boxed-glist", + "some-boxed-glist", + gi_marshalling_tests_boxed_glist_get_type (), G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_GVALUE_PROPERTY, + g_param_spec_boxed ("some-gvalue", + "some-gvalue", + "some-gvalue", + G_TYPE_VALUE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_VARIANT_PROPERTY, + g_param_spec_variant ("some-variant", + "some-variant", + "some-variant", + G_VARIANT_TYPE_ANY, + NULL, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_OBJECT_PROPERTY, + g_param_spec_object ("some-object", + "some-object", + "some-object", + G_TYPE_OBJECT, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_FLAGS_PROPERTY, + g_param_spec_flags ("some-flags", + "some-flags", + "some-flags", + GI_MARSHALLING_TESTS_TYPE_FLAGS, + GI_MARSHALLING_TESTS_FLAGS_VALUE1, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_ENUM_PROPERTY, + g_param_spec_enum ("some-enum", + "some-enum", + "some-enum", + GI_MARSHALLING_TESTS_TYPE_GENUM, + GI_MARSHALLING_TESTS_GENUM_VALUE1, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_BYTE_ARRAY_PROPERTY, + g_param_spec_boxed ("some-byte-array", + "some-byte-array", + "some-byte-array", + G_TYPE_BYTE_ARRAY, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, SOME_READONLY_PROPERTY, + g_param_spec_int ("some-readonly", + "some-readonly", + "some-readonly", + G_MININT, G_MAXINT, 0, + G_PARAM_READABLE)); +} + +GIMarshallingTestsPropertiesObject * +gi_marshalling_tests_properties_object_new (void) +{ + return g_object_new (GI_MARSHALLING_TESTS_TYPE_PROPERTIES_OBJECT, NULL); +} + +G_DEFINE_TYPE (GIMarshallingTestsSignalsObject, gi_marshalling_tests_signals_object, G_TYPE_OBJECT); + +static void +gi_marshalling_tests_signals_object_init (GIMarshallingTestsSignalsObject *object G_GNUC_UNUSED) +{ +} + +static void +gi_marshalling_tests_signals_object_finalize (GObject *object) +{ + G_OBJECT_CLASS (gi_marshalling_tests_signals_object_parent_class)->finalize (object); +} + +static void +gi_marshalling_tests_signals_object_class_init (GIMarshallingTestsSignalsObjectClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gi_marshalling_tests_signals_object_finalize; + + /** + * GIMarshallingTestsSignalsObject::some-boxed-gptrarray-utf8: + * @self: + * @arg: (element-type utf8): + */ + g_signal_new ("some-boxed-gptrarray-utf8", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, + G_TYPE_PTR_ARRAY); + + /** + * GIMarshallingTestsSignalsObject::some-boxed-gptrarray-utf8-container: + * @self: + * @arg: (element-type utf8) (transfer container): + */ + g_signal_new ("some-boxed-gptrarray-utf8-container", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, + G_TYPE_PTR_ARRAY); + + /** + * GIMarshallingTestsSignalsObject::some-boxed-gptrarray-utf8-full: + * @self: + * @arg: (element-type utf8) (transfer full): + */ + g_signal_new ("some-boxed-gptrarray-utf8-full", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, + G_TYPE_PTR_ARRAY); + + /** + * GIMarshallingTestsSignalsObject::some-boxed-gptrarray-boxed-struct: + * @self: + * @arg: (element-type GIMarshallingTestsBoxedStruct): + */ + g_signal_new ("some-boxed-gptrarray-boxed-struct", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, + G_TYPE_PTR_ARRAY); + + /** + * GIMarshallingTestsSignalsObject::some-boxed-gptrarray-boxed-struct-container: + * @self: + * @arg: (element-type GIMarshallingTestsBoxedStruct) (transfer container): + */ + g_signal_new ("some-boxed-gptrarray-boxed-struct-container", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, + G_TYPE_PTR_ARRAY); + /** + * GIMarshallingTestsSignalsObject::some-boxed-gptrarray-boxed-struct-full: + * @self: + * @arg: (element-type GIMarshallingTestsBoxedStruct) (transfer full): + */ + g_signal_new ("some-boxed-gptrarray-boxed-struct-full", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, + G_TYPE_PTR_ARRAY); + + /** + * GIMarshallingTestsSignalsObject::some-hash-table-utf8-int: + * @self: + * @arg: (type GHashTable) (element-type utf8 int): + */ + g_signal_new ("some-hash-table-utf8-int", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, + G_TYPE_HASH_TABLE); + + /** + * GIMarshallingTestsSignalsObject::some-hash-table-utf8-int-container: + * @self: + * @arg: (type GHashTable) (element-type utf8 int) (transfer container): + */ + g_signal_new ("some-hash-table-utf8-int-container", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, + G_TYPE_HASH_TABLE); + + /** + * GIMarshallingTestsSignalsObject::some-hash-table-utf8-int-full: + * @self: + * @arg: (type GHashTable) (element-type utf8 int) (transfer full): + */ + g_signal_new ("some-hash-table-utf8-int-full", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, + G_TYPE_HASH_TABLE); + + /** + * GIMarshallingTestsSignalsObject::some-boxed-struct: + * @self: + * @arg: + */ + g_signal_new ("some-boxed-struct", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, + gi_marshalling_tests_boxed_struct_get_type ()); + + /** + * GIMarshallingTestsSignalsObject::some-boxed-struct-full: + * @self: + * @arg: (transfer full): + */ + g_signal_new ("some-boxed-struct-full", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, + gi_marshalling_tests_boxed_struct_get_type ()); +} + +GIMarshallingTestsSignalsObject * +gi_marshalling_tests_signals_object_new (void) +{ + return g_object_new (GI_MARSHALLING_TESTS_TYPE_SIGNALS_OBJECT, NULL); +} + +void +gi_marshalling_tests_signals_object_emit_boxed_gptrarray_utf8 (GIMarshallingTestsSignalsObject *object) +{ + GPtrArray *ptrarray; + + ptrarray = gi_marshalling_tests_gptrarray_utf8_container_return (); + g_signal_emit_by_name (object, "some-boxed-gptrarray-utf8", + ptrarray); + g_ptr_array_unref (ptrarray); +} + +void +gi_marshalling_tests_signals_object_emit_boxed_gptrarray_utf8_container (GIMarshallingTestsSignalsObject *object) +{ + g_signal_emit_by_name (object, "some-boxed-gptrarray-utf8-container", + gi_marshalling_tests_gptrarray_utf8_container_return ()); +} + +void +gi_marshalling_tests_signals_object_emit_boxed_gptrarray_utf8_full (GIMarshallingTestsSignalsObject *object) +{ + g_signal_emit_by_name (object, "some-boxed-gptrarray-utf8-full", + gi_marshalling_tests_gptrarray_utf8_full_return ()); +} + +void +gi_marshalling_tests_signals_object_emit_boxed_gptrarray_boxed_struct (GIMarshallingTestsSignalsObject *object) +{ + GPtrArray *ptrarray; + + ptrarray = gi_marshalling_tests_gptrarray_boxed_struct_full_return (); + g_signal_emit_by_name (object, "some-boxed-gptrarray-boxed-struct", + ptrarray); + g_ptr_array_set_free_func (ptrarray, (GDestroyNotify) gi_marshalling_tests_boxed_struct_free); + g_ptr_array_unref (ptrarray); +} + +void +gi_marshalling_tests_signals_object_emit_boxed_gptrarray_boxed_struct_container (GIMarshallingTestsSignalsObject *object) +{ + GPtrArray *ptrarray; + + ptrarray = gi_marshalling_tests_gptrarray_boxed_struct_full_return (); + g_ptr_array_set_free_func (ptrarray, (GDestroyNotify) gi_marshalling_tests_boxed_struct_free); + g_signal_emit_by_name (object, "some-boxed-gptrarray-boxed-struct-container", + g_steal_pointer (&ptrarray)); +} + +void +gi_marshalling_tests_signals_object_emit_boxed_gptrarray_boxed_struct_full (GIMarshallingTestsSignalsObject *object) +{ + g_signal_emit_by_name (object, "some-boxed-gptrarray-boxed-struct-full", + gi_marshalling_tests_gptrarray_boxed_struct_full_return ()); +} + +void +gi_marshalling_tests_signals_object_emit_hash_table_utf8_int (GIMarshallingTestsSignalsObject *object) +{ + GHashTable *hash_table; + + hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + g_hash_table_insert (hash_table, g_strdup ("-1"), GINT_TO_POINTER (1)); + g_hash_table_insert (hash_table, g_strdup ("0"), GINT_TO_POINTER (0)); + g_hash_table_insert (hash_table, g_strdup ("1"), GINT_TO_POINTER (-1)); + g_hash_table_insert (hash_table, g_strdup ("2"), GINT_TO_POINTER (-2)); + + g_signal_emit_by_name (object, "some-hash-table-utf8-int", hash_table); + g_hash_table_unref (hash_table); +} + +void +gi_marshalling_tests_signals_object_emit_hash_table_utf8_int_container (GIMarshallingTestsSignalsObject *object) +{ + GHashTable *hash_table; + + hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + g_hash_table_insert (hash_table, g_strdup ("-1"), GINT_TO_POINTER (1)); + g_hash_table_insert (hash_table, g_strdup ("0"), GINT_TO_POINTER (0)); + g_hash_table_insert (hash_table, g_strdup ("1"), GINT_TO_POINTER (-1)); + g_hash_table_insert (hash_table, g_strdup ("2"), GINT_TO_POINTER (-2)); + + g_signal_emit_by_name (object, "some-hash-table-utf8-int-container", + g_steal_pointer (&hash_table)); +} + +void +gi_marshalling_tests_signals_object_emit_hash_table_utf8_int_full (GIMarshallingTestsSignalsObject *object) +{ + GHashTable *hash_table; + + hash_table = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (hash_table, g_strdup ("-1"), GINT_TO_POINTER (1)); + g_hash_table_insert (hash_table, g_strdup ("0"), GINT_TO_POINTER (0)); + g_hash_table_insert (hash_table, g_strdup ("1"), GINT_TO_POINTER (-1)); + g_hash_table_insert (hash_table, g_strdup ("2"), GINT_TO_POINTER (-2)); + + g_signal_emit_by_name (object, "some-hash-table-utf8-int-full", + g_steal_pointer (&hash_table)); +} + +void +gi_marshalling_tests_signals_object_emit_boxed_struct (GIMarshallingTestsSignalsObject *object) +{ + GIMarshallingTestsBoxedStruct *boxed = gi_marshalling_tests_boxed_struct_new (); + boxed->long_ = 99; + boxed->string_ = g_strdup ("a string"); + boxed->g_strv = g_strdupv ((GStrv) (const char *[]){ "foo", "bar", "baz", NULL }); + + g_signal_emit_by_name (object, "some-boxed-struct", boxed); + g_clear_pointer (&boxed, gi_marshalling_tests_boxed_struct_free); +} + +void +gi_marshalling_tests_signals_object_emit_boxed_struct_full (GIMarshallingTestsSignalsObject *object) +{ + GIMarshallingTestsBoxedStruct *boxed = gi_marshalling_tests_boxed_struct_new (); + + boxed->long_ = 99; + boxed->string_ = g_strdup ("a string"); + boxed->g_strv = g_strdupv ((GStrv) (const char *[]){ "foo", "bar", "baz", NULL }); + g_signal_emit_by_name (object, "some-boxed-struct-full", g_steal_pointer (&boxed)); +} diff --git a/subprojects/gobject-introspection-tests/gimarshallingtests.h b/subprojects/gobject-introspection-tests/gimarshallingtests.h new file mode 100644 index 000000000..6640ca24c --- /dev/null +++ b/subprojects/gobject-introspection-tests/gimarshallingtests.h @@ -0,0 +1,2325 @@ +/* +SPDX-FileCopyrightText: 2010-2012 Collabora, Ltd. +SPDX-FileCopyrightText: 2010 Johan Dahlin +SPDX-FileCopyrightText: 2010 Sugar Labs +SPDX-FileCopyrightText: 2010 Zach Goldberg +SPDX-FileCopyrightText: 2011 Alex Eftimie +SPDX-FileCopyrightText: 2011-2012 Canonical Ltd. +SPDX-FileCopyrightText: 2011-2012 Colin Walters +SPDX-FileCopyrightText: 2011 Dan Winship +SPDX-FileCopyrightText: 2011-2012 Giovanni Campagna +SPDX-FileCopyrightText: 2011 Ignacio Casal Quinteiro +SPDX-FileCopyrightText: 2011-2012 Jasper St. Pierre +SPDX-FileCopyrightText: 2011 Laszlo Pandy +SPDX-FileCopyrightText: 2011, 2013 Red Hat, Inc. +SPDX-FileCopyrightText: 2012 Bastian Winkler +SPDX-FileCopyrightText: 2012 Epitech +SPDX-FileCopyrightText: 2012 Gonzalo Odiard +SPDX-FileCopyrightText: 2012-2013 Martin Pitt +SPDX-FileCopyrightText: 2012-2013 Paolo Borelli +SPDX-FileCopyrightText: 2012 Sebastian Pölsterl +SPDX-FileCopyrightText: 2013 Simon Feltman +SPDX-FileCopyrightText: 2014 Lionel Landwerlin +SPDX-FileCopyrightText: 2014 RIFT.io, Inc. +SPDX-FileCopyrightText: 2014 SuSE +SPDX-FileCopyrightText: 2016 Endless Mobile, Inc. +SPDX-FileCopyrightText: 2017 Christoph Reiter +SPDX-FileCopyrightText: 2016-2017, 2023 Philip Chimento +SPDX-FileCopyrightText: 2018 Tomasz Miąsko +SPDX-FileCopyrightText: 2019 Stéphane Seng +SPDX-FileCopyrightText: 2020-2023 Marco Trevisan +SPDX-FileCopyrightText: 2020, 2024 Simon McVittie +SPDX-FileCopyrightText: 2021 Carlos Garnacho +*/ + +#pragma once + +#include /* off_t, time_t */ + +#include +#include + +#ifdef G_OS_UNIX +#include +#endif + +#include "gitestmacros.h" + +typedef struct _GIMarshallingTestsSimpleStruct GIMarshallingTestsSimpleStruct; +typedef struct _GIMarshallingTestsBoxedStruct GIMarshallingTestsBoxedStruct; + +/* Constants */ + +#define GI_MARSHALLING_TESTS_CONSTANT_NUMBER 42 +#define GI_MARSHALLING_TESTS_CONSTANT_UTF8 "const \xe2\x99\xa5 utf8" +#define GI_MARSHALLING_TESTS_CONSTANT_UCS4 { 0x63, 0x6f, 0x6e, 0x73, 0x74, \ + 0x20, 0x2665, 0x20, 0x75, 0x74, \ + 0x66, 0x38 } + +/* Booleans */ + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_boolean_return_true (void); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_boolean_return_false (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_boolean_in_true (gboolean v); + +GI_TEST_EXTERN +void gi_marshalling_tests_boolean_in_false (gboolean v); + +GI_TEST_EXTERN +void gi_marshalling_tests_boolean_out_true (gboolean *v); + +GI_TEST_EXTERN +void gi_marshalling_tests_boolean_out_false (gboolean *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_boolean_out_uninitialized (gboolean *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_boolean_inout_true_false (gboolean *v); + +GI_TEST_EXTERN +void gi_marshalling_tests_boolean_inout_false_true (gboolean *v); + +/* Integers */ + +GI_TEST_EXTERN +gint8 gi_marshalling_tests_int8_return_max (void); + +GI_TEST_EXTERN +gint8 gi_marshalling_tests_int8_return_min (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_int8_in_max (gint8 v); + +GI_TEST_EXTERN +void gi_marshalling_tests_int8_in_min (gint8 v); + +GI_TEST_EXTERN +void gi_marshalling_tests_int8_out_max (gint8 *v); + +GI_TEST_EXTERN +void gi_marshalling_tests_int8_out_min (gint8 *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_int8_out_uninitialized (gint8 *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_int8_inout_max_min (gint8 *v); + +GI_TEST_EXTERN +void gi_marshalling_tests_int8_inout_min_max (gint8 *v); + +GI_TEST_EXTERN +guint8 gi_marshalling_tests_uint8_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_uint8_in (guint8 v); + +GI_TEST_EXTERN +void gi_marshalling_tests_uint8_out (guint8 *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_uint8_out_uninitialized (guint8 *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_uint8_inout (guint8 *v); + +GI_TEST_EXTERN +gint16 gi_marshalling_tests_int16_return_max (void); + +GI_TEST_EXTERN +gint16 gi_marshalling_tests_int16_return_min (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_int16_in_max (gint16 v); + +GI_TEST_EXTERN +void gi_marshalling_tests_int16_in_min (gint16 v); + +GI_TEST_EXTERN +void gi_marshalling_tests_int16_out_max (gint16 *v); + +GI_TEST_EXTERN +void gi_marshalling_tests_int16_out_min (gint16 *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_int16_out_uninitialized (gint16 *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_int16_inout_max_min (gint16 *v); + +GI_TEST_EXTERN +void gi_marshalling_tests_int16_inout_min_max (gint16 *v); + +GI_TEST_EXTERN +guint16 gi_marshalling_tests_uint16_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_uint16_in (guint16 v); + +GI_TEST_EXTERN +void gi_marshalling_tests_uint16_out (guint16 *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_uint16_out_uninitialized (guint16 *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_uint16_inout (guint16 *v); + +GI_TEST_EXTERN +gint32 gi_marshalling_tests_int32_return_max (void); + +GI_TEST_EXTERN +gint32 gi_marshalling_tests_int32_return_min (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_int32_in_max (gint32 v); + +GI_TEST_EXTERN +void gi_marshalling_tests_int32_in_min (gint32 v); + +GI_TEST_EXTERN +void gi_marshalling_tests_int32_out_max (gint32 *v); + +GI_TEST_EXTERN +void gi_marshalling_tests_int32_out_min (gint32 *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_int32_out_uninitialized (gint32 *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_int32_inout_max_min (gint32 *v); + +GI_TEST_EXTERN +void gi_marshalling_tests_int32_inout_min_max (gint32 *v); + +GI_TEST_EXTERN +guint32 gi_marshalling_tests_uint32_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_uint32_in (guint32 v); + +GI_TEST_EXTERN +void gi_marshalling_tests_uint32_out (guint32 *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_uint32_out_uninitialized (guint32 *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_uint32_inout (guint32 *v); + +GI_TEST_EXTERN +gint64 gi_marshalling_tests_int64_return_max (void); + +GI_TEST_EXTERN +gint64 gi_marshalling_tests_int64_return_min (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_int64_in_max (gint64 v); + +GI_TEST_EXTERN +void gi_marshalling_tests_int64_in_min (gint64 v); + +GI_TEST_EXTERN +void gi_marshalling_tests_int64_out_max (gint64 *v); + +GI_TEST_EXTERN +void gi_marshalling_tests_int64_out_min (gint64 *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_int64_out_uninitialized (gint64 *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_int64_inout_max_min (gint64 *v); + +GI_TEST_EXTERN +void gi_marshalling_tests_int64_inout_min_max (gint64 *v); + +GI_TEST_EXTERN +guint64 gi_marshalling_tests_uint64_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_uint64_in (guint64 v); + +GI_TEST_EXTERN +void gi_marshalling_tests_uint64_out (guint64 *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_uint64_out_uninitialized (guint64 *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_uint64_inout (guint64 *v); + +GI_TEST_EXTERN +gshort gi_marshalling_tests_short_return_max (void); + +GI_TEST_EXTERN +gshort gi_marshalling_tests_short_return_min (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_short_in_max (gshort short_); + +GI_TEST_EXTERN +void gi_marshalling_tests_short_in_min (gshort short_); + +GI_TEST_EXTERN +void gi_marshalling_tests_short_out_max (gshort *short_); + +GI_TEST_EXTERN +void gi_marshalling_tests_short_out_min (gshort *short_); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_short_out_uninitialized (gshort *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_short_inout_max_min (gshort *short_); + +GI_TEST_EXTERN +void gi_marshalling_tests_short_inout_min_max (gshort *short_); + +GI_TEST_EXTERN +gushort gi_marshalling_tests_ushort_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_ushort_in (gushort ushort_); + +GI_TEST_EXTERN +void gi_marshalling_tests_ushort_out (gushort *ushort_); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_ushort_out_uninitialized (gushort *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_ushort_inout (gushort *ushort_); + +GI_TEST_EXTERN +gint gi_marshalling_tests_int_return_max (void); + +GI_TEST_EXTERN +gint gi_marshalling_tests_int_return_min (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_int_in_max (gint int_); + +GI_TEST_EXTERN +void gi_marshalling_tests_int_in_min (gint int_); + +GI_TEST_EXTERN +void gi_marshalling_tests_int_out_max (gint *int_); + +GI_TEST_EXTERN +void gi_marshalling_tests_int_out_min (gint *int_); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_int_out_uninitialized (gint *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_int_inout_max_min (gint *int_); + +GI_TEST_EXTERN +void gi_marshalling_tests_int_inout_min_max (gint *int_); + +GI_TEST_EXTERN +guint gi_marshalling_tests_uint_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_uint_in (guint uint_); + +GI_TEST_EXTERN +void gi_marshalling_tests_uint_out (guint *uint_); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_uint_out_uninitialized (guint *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_uint_inout (guint *uint_); + +GI_TEST_EXTERN +glong gi_marshalling_tests_long_return_max (void); + +GI_TEST_EXTERN +glong gi_marshalling_tests_long_return_min (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_long_in_max (glong long_); + +GI_TEST_EXTERN +void gi_marshalling_tests_long_in_min (glong long_); + +GI_TEST_EXTERN +void gi_marshalling_tests_long_out_max (glong *long_); + +GI_TEST_EXTERN +void gi_marshalling_tests_long_out_min (glong *long_); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_long_out_uninitialized (glong *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_long_inout_max_min (glong *long_); + +GI_TEST_EXTERN +void gi_marshalling_tests_long_inout_min_max (glong *long_); + +GI_TEST_EXTERN +gulong gi_marshalling_tests_ulong_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_ulong_in (gulong ulong_); + +GI_TEST_EXTERN +void gi_marshalling_tests_ulong_out (gulong *ulong_); + +GI_TEST_EXTERN +void gi_marshalling_tests_ulong_inout (gulong *ulong_); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_ulong_out_uninitialized (gulong *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +gssize gi_marshalling_tests_ssize_return_max (void); + +GI_TEST_EXTERN +gssize gi_marshalling_tests_ssize_return_min (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_ssize_in_max (gssize ssize); + +GI_TEST_EXTERN +void gi_marshalling_tests_ssize_in_min (gssize ssize); + +GI_TEST_EXTERN +void gi_marshalling_tests_ssize_out_max (gssize *ssize); + +GI_TEST_EXTERN +void gi_marshalling_tests_ssize_out_min (gssize *ssize); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_ssize_out_uninitialized (gssize *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_ssize_inout_max_min (gssize *ssize); + +GI_TEST_EXTERN +void gi_marshalling_tests_ssize_inout_min_max (gssize *ssize); + +GI_TEST_EXTERN +gsize gi_marshalling_tests_size_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_size_in (gsize size); + +GI_TEST_EXTERN +void gi_marshalling_tests_size_out (gsize *size); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_size_out_uninitialized (gsize *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_size_inout (gsize *size); + +/* Floating-point */ + +GI_TEST_EXTERN +gfloat gi_marshalling_tests_float_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_float_in (gfloat v); + +GI_TEST_EXTERN +void gi_marshalling_tests_float_out (gfloat *v); + +GI_TEST_EXTERN +void gi_marshalling_tests_float_noncanonical_nan_out (gfloat *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_float_out_uninitialized (gfloat *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_float_inout (gfloat *v); + +GI_TEST_EXTERN +gdouble gi_marshalling_tests_double_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_double_in (gdouble v); + +GI_TEST_EXTERN +void gi_marshalling_tests_double_out (gdouble *v); + +GI_TEST_EXTERN +void gi_marshalling_tests_double_noncanonical_nan_out (gdouble *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_double_out_uninitialized (gdouble *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_double_inout (gdouble *v); + +/* Timestamps */ + +GI_TEST_EXTERN +time_t gi_marshalling_tests_time_t_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_time_t_in (time_t v); + +GI_TEST_EXTERN +void gi_marshalling_tests_time_t_out (time_t *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_time_t_out_uninitialized (time_t *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_time_t_inout (time_t *v); + +/* Platform file offset (avoid this, use goffset instead) */ + +GI_TEST_EXTERN +off_t gi_marshalling_tests_off_t_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_off_t_in (off_t v); + +GI_TEST_EXTERN +void gi_marshalling_tests_off_t_out (off_t *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_off_t_out_uninitialized (off_t *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_off_t_inout (off_t *v); + +#ifdef G_OS_UNIX + +/* Unix device number */ + +GI_TEST_EXTERN +dev_t gi_marshalling_tests_dev_t_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_dev_t_in (dev_t v); + +GI_TEST_EXTERN +void gi_marshalling_tests_dev_t_out (dev_t *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_dev_t_out_uninitialized (dev_t *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_dev_t_inout (dev_t *v); + +/* Unix group */ + +GI_TEST_EXTERN +gid_t gi_marshalling_tests_gid_t_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_gid_t_in (gid_t v); + +GI_TEST_EXTERN +void gi_marshalling_tests_gid_t_out (gid_t *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_gid_t_out_uninitialized (gid_t *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_gid_t_inout (gid_t *v); + +/* Unix process */ + +GI_TEST_EXTERN +pid_t gi_marshalling_tests_pid_t_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_pid_t_in (pid_t v); + +GI_TEST_EXTERN +void gi_marshalling_tests_pid_t_out (pid_t *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_pid_t_out_uninitialized (pid_t *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_pid_t_inout (pid_t *v); + +/* Unix socket address length */ + +GI_TEST_EXTERN +socklen_t gi_marshalling_tests_socklen_t_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_socklen_t_in (socklen_t v); + +GI_TEST_EXTERN +void gi_marshalling_tests_socklen_t_out (socklen_t *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_socklen_t_out_uninitialized (socklen_t *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_socklen_t_inout (socklen_t *v); + +/* Unix user */ + +GI_TEST_EXTERN +uid_t gi_marshalling_tests_uid_t_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_uid_t_in (uid_t v); + +GI_TEST_EXTERN +void gi_marshalling_tests_uid_t_out (uid_t *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_uid_t_out_uninitialized (uid_t *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_uid_t_inout (uid_t *v); + +#endif /* G_OS_UNIX */ + +/* GType */ + +GI_TEST_EXTERN +GType gi_marshalling_tests_gtype_return (void); + +GI_TEST_EXTERN +GType gi_marshalling_tests_gtype_string_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_gtype_in (GType gtype); + +GI_TEST_EXTERN +void gi_marshalling_tests_gtype_string_in (GType gtype); + +GI_TEST_EXTERN +void gi_marshalling_tests_gtype_out (GType *gtype); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_gtype_out_uninitialized (GType *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_gtype_string_out (GType *gtype); + +GI_TEST_EXTERN +void gi_marshalling_tests_gtype_inout (GType *gtype); + +/* UTF-8 */ + +GI_TEST_EXTERN +const gchar *gi_marshalling_tests_utf8_none_return (void); + +GI_TEST_EXTERN +gchar *gi_marshalling_tests_utf8_full_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_utf8_none_in (const gchar *utf8); + +GI_TEST_EXTERN +void gi_marshalling_tests_utf8_full_in (gchar *utf8); + +GI_TEST_EXTERN +void gi_marshalling_tests_utf8_none_out (const gchar **utf8); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_utf8_none_out_uninitialized (const gchar **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_utf8_full_out (gchar **utf8); + +GI_TEST_EXTERN +void gi_marshalling_tests_utf8_dangling_out (gchar **utf8); + +GI_TEST_EXTERN +void gi_marshalling_tests_utf8_none_inout (const gchar **utf8); + +GI_TEST_EXTERN +void gi_marshalling_tests_utf8_full_inout (gchar **utf8); + +GI_TEST_EXTERN +GSList *gi_marshalling_tests_filename_list_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_utf8_as_uint8array_in (const guint8 *array, + gsize len); + +/* Enum */ + +typedef enum +{ + GI_MARSHALLING_TESTS_ENUM_VALUE1, + GI_MARSHALLING_TESTS_ENUM_VALUE2, + GI_MARSHALLING_TESTS_ENUM_VALUE3 = 42 +} GIMarshallingTestsEnum; + +typedef enum +{ + GI_MARSHALLING_TESTS_SECOND_ENUM_SECONDVALUE1, + GI_MARSHALLING_TESTS_SECOND_ENUM_SECONDVALUE2, +} GIMarshallingTestsSecondEnum; + +GI_TEST_EXTERN +GIMarshallingTestsEnum gi_marshalling_tests_enum_returnv (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_enum_in (GIMarshallingTestsEnum v); + +GI_TEST_EXTERN +void gi_marshalling_tests_enum_out (GIMarshallingTestsEnum *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_enum_out_uninitialized (GIMarshallingTestsEnum **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_enum_inout (GIMarshallingTestsEnum *v); + +/* GEnum */ + +typedef enum +{ + GI_MARSHALLING_TESTS_GENUM_VALUE1, + GI_MARSHALLING_TESTS_GENUM_VALUE2, + GI_MARSHALLING_TESTS_GENUM_VALUE3 = 42 +} GIMarshallingTestsGEnum; + +GI_TEST_EXTERN +GType gi_marshalling_tests_genum_get_type (void) G_GNUC_CONST; +#define GI_MARSHALLING_TESTS_TYPE_GENUM (gi_marshalling_tests_genum_get_type ()) + +GI_TEST_EXTERN +GIMarshallingTestsGEnum gi_marshalling_tests_genum_returnv (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_genum_in (GIMarshallingTestsGEnum v); + +GI_TEST_EXTERN +void gi_marshalling_tests_genum_out (GIMarshallingTestsGEnum *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_genum_out_uninitialized (GIMarshallingTestsGEnum *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_genum_inout (GIMarshallingTestsGEnum *v); + +/* GFlags */ + +typedef enum +{ + GI_MARSHALLING_TESTS_FLAGS_VALUE1 = 1 << 0, + GI_MARSHALLING_TESTS_FLAGS_VALUE2 = 1 << 1, + GI_MARSHALLING_TESTS_FLAGS_VALUE3 = 1 << 2, + GI_MARSHALLING_TESTS_FLAGS_MASK = GI_MARSHALLING_TESTS_FLAGS_VALUE1 | + GI_MARSHALLING_TESTS_FLAGS_VALUE2, + GI_MARSHALLING_TESTS_FLAGS_MASK2 = GI_MARSHALLING_TESTS_FLAGS_MASK +} GIMarshallingTestsFlags; + +GI_TEST_EXTERN +GType gi_marshalling_tests_flags_get_type (void) G_GNUC_CONST; +#define GI_MARSHALLING_TESTS_TYPE_FLAGS (gi_marshalling_tests_flags_get_type ()) + +GI_TEST_EXTERN +GIMarshallingTestsFlags gi_marshalling_tests_flags_returnv (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_flags_in (GIMarshallingTestsFlags v); + +GI_TEST_EXTERN +void gi_marshalling_tests_flags_in_zero (GIMarshallingTestsFlags v); + +GI_TEST_EXTERN +void gi_marshalling_tests_flags_out (GIMarshallingTestsFlags *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_flags_out_uninitialized (GIMarshallingTestsFlags *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_flags_inout (GIMarshallingTestsFlags *v); + +/* Flags with no GType */ + +typedef enum +{ + GI_MARSHALLING_TESTS_NO_TYPE_FLAGS_VALUE1 = 1 << 0, + GI_MARSHALLING_TESTS_NO_TYPE_FLAGS_VALUE2 = 1 << 1, + GI_MARSHALLING_TESTS_NO_TYPE_FLAGS_VALUE3 = 1 << 2, + GI_MARSHALLING_TESTS_NO_TYPE_FLAGS_MASK = GI_MARSHALLING_TESTS_NO_TYPE_FLAGS_VALUE1 | + GI_MARSHALLING_TESTS_NO_TYPE_FLAGS_VALUE2, + GI_MARSHALLING_TESTS_NO_TYPE_FLAGS_MASK2 = GI_MARSHALLING_TESTS_FLAGS_MASK +} GIMarshallingTestsNoTypeFlags; + +GI_TEST_EXTERN +GIMarshallingTestsNoTypeFlags gi_marshalling_tests_no_type_flags_returnv (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_no_type_flags_in (GIMarshallingTestsNoTypeFlags v); + +GI_TEST_EXTERN +void gi_marshalling_tests_no_type_flags_in_zero (GIMarshallingTestsNoTypeFlags v); + +GI_TEST_EXTERN +void gi_marshalling_tests_no_type_flags_out (GIMarshallingTestsNoTypeFlags *v); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_no_type_flags_out_uninitialized (GIMarshallingTestsNoTypeFlags **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_no_type_flags_inout (GIMarshallingTestsNoTypeFlags *v); + +/* Arrays */ + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_init_function (gint *n_args, char ***argv); + +/* Fixed-size */ + +GI_TEST_EXTERN +const gint *gi_marshalling_tests_array_fixed_int_return (void); + +GI_TEST_EXTERN +const gshort *gi_marshalling_tests_array_fixed_short_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_fixed_int_in (const gint *ints); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_fixed_caller_allocated_out (gint *ints); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_fixed_short_in (const gshort *shorts); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_fixed_out (gint **ints); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_array_fixed_out_uninitialized (gint **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_fixed_out_struct (GIMarshallingTestsSimpleStruct **structs); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_array_fixed_out_struct_uninitialized (GIMarshallingTestsSimpleStruct **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_fixed_caller_allocated_struct_out (GIMarshallingTestsSimpleStruct *structs); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_fixed_inout (gint **ints); + +/* Variable-size */ + +GI_TEST_EXTERN +const gint *gi_marshalling_tests_array_return (gint *length); + +GI_TEST_EXTERN +const gint *gi_marshalling_tests_array_return_etc (gint first, gint *length, gint last, gint *sum); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_in (const gint *ints, gint length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_in_len_before (gint length, const gint *ints); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_in_len_zero_terminated (const gint *ints, gint length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_string_in (const gchar **strings, gint length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_uint8_in (const guint8 *chars, gint length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_int64_in (const gint64 *ints, gint length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_uint64_in (const guint64 *ints, gint length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_unichar_in (const gunichar *chars, gint length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_bool_in (const gboolean *bools, gint length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_struct_in (GIMarshallingTestsBoxedStruct **structs, gint length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_struct_value_in (GIMarshallingTestsBoxedStruct *structs, gint length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_struct_take_in (GIMarshallingTestsBoxedStruct **structs, gint length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_simple_struct_in (GIMarshallingTestsSimpleStruct *structs, gint length); + +GI_TEST_EXTERN +void gi_marshalling_tests_multi_array_key_value_in (gint length, const gchar **keys, const GValue *values); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_enum_in (GIMarshallingTestsEnum *_enum, gint length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_flags_in (GIMarshallingTestsFlags *flags, gint length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_in_guint64_len (const gint *ints, guint64 length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_in_guint8_len (const gint *ints, guint8 length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_out (gint **ints, gint *length); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_array_out_uninitialized (gint **v G_GNUC_UNUSED, gint *length G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_out_etc (gint first, gint **ints, gint *length, gint last, gint *sum); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_bool_out (const gboolean **bools, gint *length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_unichar_out (const gunichar **chars, gint *length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_inout (gint **ints, gint *length); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_inout_etc (gint first, gint **ints, gint *length, gint last, gint *sum); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_in_nonzero_nonlen (gint first, const guint8 *chars); + +/* Zero-terminated */ + +GI_TEST_EXTERN +const gchar **gi_marshalling_tests_array_zero_terminated_return (void); + +GI_TEST_EXTERN +gchar **gi_marshalling_tests_array_zero_terminated_return_null (void); + +GI_TEST_EXTERN +GIMarshallingTestsBoxedStruct **gi_marshalling_tests_array_zero_terminated_return_struct (void); + +GI_TEST_EXTERN +gunichar *gi_marshalling_tests_array_zero_terminated_return_unichar (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_zero_terminated_in (gchar **utf8s); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_zero_terminated_out (const gchar ***utf8s); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_array_zero_terminated_out_uninitialized (const gchar ***v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_zero_terminated_inout (const gchar ***utf8s); + +GI_TEST_EXTERN +GVariant **gi_marshalling_tests_array_gvariant_none_in (GVariant **variants); + +GI_TEST_EXTERN +GVariant **gi_marshalling_tests_array_gvariant_container_in (GVariant **variants); + +GI_TEST_EXTERN +GVariant **gi_marshalling_tests_array_gvariant_full_in (GVariant **variants); + +/* GArray */ + +GI_TEST_EXTERN +GArray *gi_marshalling_tests_garray_int_none_return (void); + +GI_TEST_EXTERN +GArray *gi_marshalling_tests_garray_uint64_none_return (void); + +GI_TEST_EXTERN +GArray *gi_marshalling_tests_garray_utf8_none_return (void); + +GI_TEST_EXTERN +GArray *gi_marshalling_tests_garray_utf8_container_return (void); + +GI_TEST_EXTERN +GArray *gi_marshalling_tests_garray_utf8_full_return (void); + +GI_TEST_EXTERN +GArray *gi_marshalling_tests_garray_boxed_struct_full_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_garray_int_none_in (GArray *array_); + +GI_TEST_EXTERN +void gi_marshalling_tests_garray_uint64_none_in (GArray *array_); + +GI_TEST_EXTERN +void gi_marshalling_tests_garray_utf8_none_in (GArray *array_); + +GI_TEST_EXTERN +void gi_marshalling_tests_garray_utf8_none_out (GArray **array_); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_garray_utf8_none_out_uninitialized (GArray **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_garray_utf8_container_out (GArray **array_); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_garray_utf8_container_out_uninitialized (GArray **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_garray_utf8_full_out (GArray **array_); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_garray_utf8_full_out_uninitialized (GArray **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_garray_utf8_full_out_caller_allocated (GArray *array_); + +GI_TEST_EXTERN +void gi_marshalling_tests_garray_utf8_none_inout (GArray **array_); + +GI_TEST_EXTERN +void gi_marshalling_tests_garray_utf8_container_inout (GArray **array_); + +GI_TEST_EXTERN +void gi_marshalling_tests_garray_utf8_full_inout (GArray **array_); + +GI_TEST_EXTERN +void gi_marshalling_tests_garray_bool_none_in (GArray *array_); + +GI_TEST_EXTERN +void gi_marshalling_tests_garray_unichar_none_in (GArray *array_); + +/* GPtrArray */ + +GI_TEST_EXTERN +GPtrArray *gi_marshalling_tests_gptrarray_utf8_none_return (void); + +GI_TEST_EXTERN +GPtrArray *gi_marshalling_tests_gptrarray_utf8_container_return (void); + +GI_TEST_EXTERN +GPtrArray *gi_marshalling_tests_gptrarray_utf8_full_return (void); + +GI_TEST_EXTERN +GPtrArray *gi_marshalling_tests_gptrarray_boxed_struct_full_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_gptrarray_utf8_none_in (GPtrArray *parray_); + +GI_TEST_EXTERN +void gi_marshalling_tests_gptrarray_utf8_none_out (GPtrArray **parray_); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_gptrarray_utf8_none_out_uninitialized (GPtrArray **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_gptrarray_utf8_container_out (GPtrArray **parray_); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_gptrarray_utf8_container_out_uninitialized (GPtrArray **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_gptrarray_utf8_full_out (GPtrArray **parray_); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_gptrarray_utf8_full_out_uninitialized (GPtrArray **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_gptrarray_utf8_none_inout (GPtrArray **parray_); + +GI_TEST_EXTERN +void gi_marshalling_tests_gptrarray_utf8_container_inout (GPtrArray **parray_); + +GI_TEST_EXTERN +void gi_marshalling_tests_gptrarray_utf8_full_inout (GPtrArray **parray_); + +/* GByteArray */ + +GI_TEST_EXTERN +GByteArray *gi_marshalling_tests_bytearray_full_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_bytearray_none_in (GByteArray *v); + +/* GBytes */ + +GI_TEST_EXTERN +GBytes *gi_marshalling_tests_gbytes_full_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_gbytes_none_in (GBytes *v); + +/* GStrv */ + +GI_TEST_EXTERN +GStrv gi_marshalling_tests_gstrv_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_gstrv_in (GStrv g_strv); + +GI_TEST_EXTERN +void gi_marshalling_tests_gstrv_out (GStrv *g_strv); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_gstrv_out_uninitialized (GStrv *v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_gstrv_inout (GStrv *g_strv); + +/* GList */ + +GI_TEST_EXTERN +GList *gi_marshalling_tests_glist_int_none_return (void); + +GI_TEST_EXTERN +GList *gi_marshalling_tests_glist_uint32_none_return (void); + +GI_TEST_EXTERN +GList *gi_marshalling_tests_glist_utf8_none_return (void); + +GI_TEST_EXTERN +GList *gi_marshalling_tests_glist_utf8_container_return (void); + +GI_TEST_EXTERN +GList *gi_marshalling_tests_glist_utf8_full_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_glist_int_none_in (GList *list); + +GI_TEST_EXTERN +void gi_marshalling_tests_glist_uint32_none_in (GList *list); + +GI_TEST_EXTERN +void gi_marshalling_tests_glist_utf8_none_in (GList *list); + +GI_TEST_EXTERN +void gi_marshalling_tests_glist_utf8_none_out (GList **list); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_glist_utf8_none_out_uninitialized (GList **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_glist_utf8_container_out (GList **list); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_glist_utf8_container_out_uninitialized (GList **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_glist_utf8_full_out (GList **list); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_glist_utf8_full_out_uninitialized (GList **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_glist_utf8_none_inout (GList **list); + +GI_TEST_EXTERN +void gi_marshalling_tests_glist_utf8_container_inout (GList **list); + +GI_TEST_EXTERN +void gi_marshalling_tests_glist_utf8_full_inout (GList **list); + +/* GSList */ + +GI_TEST_EXTERN +GSList *gi_marshalling_tests_gslist_int_none_return (void); + +GI_TEST_EXTERN +GSList *gi_marshalling_tests_gslist_utf8_none_return (void); + +GI_TEST_EXTERN +GSList *gi_marshalling_tests_gslist_utf8_container_return (void); + +GI_TEST_EXTERN +GSList *gi_marshalling_tests_gslist_utf8_full_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_gslist_int_none_in (GSList *list); + +GI_TEST_EXTERN +void gi_marshalling_tests_gslist_utf8_none_in (GSList *list); + +GI_TEST_EXTERN +void gi_marshalling_tests_gslist_utf8_none_out (GSList **list); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_gslist_utf8_none_out_uninitialized (GSList **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_gslist_utf8_container_out (GSList **list); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_gslist_utf8_container_out_uninitialized (GSList **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_gslist_utf8_full_out (GSList **list); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_gslist_utf8_full_out_uninitialized (GSList **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_gslist_utf8_none_inout (GSList **list); + +GI_TEST_EXTERN +void gi_marshalling_tests_gslist_utf8_container_inout (GSList **list); + +GI_TEST_EXTERN +void gi_marshalling_tests_gslist_utf8_full_inout (GSList **list); + +/* GHashTable */ + +GI_TEST_EXTERN +GHashTable *gi_marshalling_tests_ghashtable_int_none_return (void); + +GI_TEST_EXTERN +GHashTable *gi_marshalling_tests_ghashtable_utf8_none_return (void); + +GI_TEST_EXTERN +GHashTable *gi_marshalling_tests_ghashtable_utf8_container_return (void); + +GI_TEST_EXTERN +GHashTable *gi_marshalling_tests_ghashtable_utf8_full_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_ghashtable_int_none_in (GHashTable *hash_table); + +GI_TEST_EXTERN +void gi_marshalling_tests_ghashtable_utf8_none_in (GHashTable *hash_table); + +GI_TEST_EXTERN +void gi_marshalling_tests_ghashtable_double_in (GHashTable *hash_table); + +GI_TEST_EXTERN +void gi_marshalling_tests_ghashtable_float_in (GHashTable *hash_table); + +GI_TEST_EXTERN +void gi_marshalling_tests_ghashtable_int64_in (GHashTable *hash_table); + +GI_TEST_EXTERN +void gi_marshalling_tests_ghashtable_uint64_in (GHashTable *hash_table); + +GI_TEST_EXTERN +void gi_marshalling_tests_ghashtable_utf8_container_in (GHashTable *hash_table); + +GI_TEST_EXTERN +void gi_marshalling_tests_ghashtable_utf8_full_in (GHashTable *hash_table); + +GI_TEST_EXTERN +void gi_marshalling_tests_ghashtable_utf8_none_out (GHashTable **hash_table); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_ghashtable_utf8_none_out_uninitialized (GHashTable **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_ghashtable_utf8_container_out (GHashTable **hash_table); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_ghashtable_utf8_container_out_uninitialized (GHashTable **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_ghashtable_utf8_full_out (GHashTable **hash_table); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_ghashtable_utf8_full_out_uninitialized (GHashTable **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_ghashtable_utf8_none_inout (GHashTable **hash_table); + +GI_TEST_EXTERN +void gi_marshalling_tests_ghashtable_utf8_container_inout (GHashTable **hash_table); + +GI_TEST_EXTERN +void gi_marshalling_tests_ghashtable_utf8_full_inout (GHashTable **hash_table); + +/* GValue */ + +GI_TEST_EXTERN +GValue *gi_marshalling_tests_gvalue_return (void); + +GI_TEST_EXTERN +GValue *gi_marshalling_tests_gvalue_noncanonical_nan_float (void); + +GI_TEST_EXTERN +GValue *gi_marshalling_tests_gvalue_noncanonical_nan_double (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_gvalue_in (GValue *value); + +GI_TEST_EXTERN +void gi_marshalling_tests_gvalue_int64_in (GValue *value); + +GI_TEST_EXTERN +void gi_marshalling_tests_gvalue_in_with_type (GValue *value, GType type); + +GI_TEST_EXTERN +void gi_marshalling_tests_gvalue_in_with_modification (GValue *value); + +GI_TEST_EXTERN +void gi_marshalling_tests_gvalue_in_enum (GValue *value); + +GI_TEST_EXTERN +void gi_marshalling_tests_gvalue_in_flags (GValue *value); + +GI_TEST_EXTERN +void gi_marshalling_tests_gvalue_out (GValue **value); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_gvalue_out_uninitialized (GValue **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_gvalue_int64_out (GValue **value); + +GI_TEST_EXTERN +void gi_marshalling_tests_gvalue_out_caller_allocates (GValue *value); + +GI_TEST_EXTERN +void gi_marshalling_tests_gvalue_inout (GValue **value); + +GI_TEST_EXTERN +void gi_marshalling_tests_gvalue_flat_array (guint n_values, + const GValue *values); + +GI_TEST_EXTERN +GValue *gi_marshalling_tests_return_gvalue_flat_array (void); + +GI_TEST_EXTERN +GValue *gi_marshalling_tests_return_gvalue_zero_terminated_array (void); + +GI_TEST_EXTERN +GValue *gi_marshalling_tests_gvalue_round_trip (GValue *value); + +GI_TEST_EXTERN +GValue *gi_marshalling_tests_gvalue_copy (GValue *value); + +GI_TEST_EXTERN +GValue *gi_marshalling_tests_gvalue_flat_array_round_trip (const GValue one, + const GValue two, + const GValue three); + +/* GClosure */ + +GI_TEST_EXTERN +void gi_marshalling_tests_gclosure_in (GClosure *closure); + +GI_TEST_EXTERN +GClosure *gi_marshalling_tests_gclosure_return (void); + +/* Callback return values */ + +/** + * GIMarshallingTestsCallbackReturnValueOnly: + */ +typedef glong (*GIMarshallingTestsCallbackReturnValueOnly) (void); + +GI_TEST_EXTERN +glong gi_marshalling_tests_callback_return_value_only (GIMarshallingTestsCallbackReturnValueOnly callback); + +/** + * GIMarshallingTestsCallbackOneOutParameter: + * @a: (out): + */ +typedef void (*GIMarshallingTestsCallbackOneOutParameter) (gfloat *a); + +GI_TEST_EXTERN +void gi_marshalling_tests_callback_one_out_parameter (GIMarshallingTestsCallbackOneOutParameter callback, + gfloat *a); + +/** + * GIMarshallingTestsCallbackMultipleOutParameters: + * @a: (out): + * @b: (out): + */ +typedef void (*GIMarshallingTestsCallbackMultipleOutParameters) (gfloat *a, gfloat *b); + +GI_TEST_EXTERN +void gi_marshalling_tests_callback_multiple_out_parameters (GIMarshallingTestsCallbackMultipleOutParameters callback, + gfloat *a, + gfloat *b); + +/** + * GIMarshallingTestsCallbackReturnValueAndOneOutParameter: + * @a: (out): + */ +typedef glong (*GIMarshallingTestsCallbackReturnValueAndOneOutParameter) (glong *a); + +GI_TEST_EXTERN +glong gi_marshalling_tests_callback_return_value_and_one_out_parameter (GIMarshallingTestsCallbackReturnValueAndOneOutParameter callback, + glong *a); + +/** + * GIMarshallingTestsCallbackReturnValueAndMultipleOutParameters: + * @a: (out): + * @b: (out): + */ +typedef glong (*GIMarshallingTestsCallbackReturnValueAndMultipleOutParameters) (glong *a, glong *b); + +GI_TEST_EXTERN +glong gi_marshalling_tests_callback_return_value_and_multiple_out_parameters (GIMarshallingTestsCallbackReturnValueAndMultipleOutParameters callback, + glong *a, + glong *b); + +/** + * GIMarshallingTestsCallbackOwnedBoxed + * @box: (transfer none): the boxed structure. + */ +typedef void (*GIMarshallingTestsCallbackOwnedBoxed) (GIMarshallingTestsBoxedStruct *box, + void *user_data); + +GI_TEST_EXTERN +glong gi_marshalling_tests_callback_owned_boxed (GIMarshallingTestsCallbackOwnedBoxed callback, + void *callback_data); + +/* Pointer */ + +GI_TEST_EXTERN +gpointer gi_marshalling_tests_pointer_in_return (gpointer pointer); + +/* Structure */ + +struct _GIMarshallingTestsSimpleStruct +{ + glong long_; + gint8 int8; +}; + +typedef struct +{ + GIMarshallingTestsSimpleStruct simple_struct; +} GIMarshallingTestsNestedStruct; + +typedef struct +{ + GIMarshallingTestsNestedStruct *pointer; +} GIMarshallingTestsNotSimpleStruct; + +GI_TEST_EXTERN +GIMarshallingTestsSimpleStruct *gi_marshalling_tests_simple_struct_returnv (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_simple_struct_inv (GIMarshallingTestsSimpleStruct *struct_); + +GI_TEST_EXTERN +void gi_marshalling_tests_simple_struct_method (GIMarshallingTestsSimpleStruct *struct_); + +typedef struct +{ + glong long_; +} GIMarshallingTestsPointerStruct; + +GI_TEST_EXTERN +GType gi_marshalling_tests_pointer_struct_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +GIMarshallingTestsPointerStruct *gi_marshalling_tests_pointer_struct_returnv (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_pointer_struct_inv (GIMarshallingTestsPointerStruct *struct_); + +struct _GIMarshallingTestsBoxedStruct +{ + glong long_; + gchar *string_; + GStrv g_strv; +}; + +GI_TEST_EXTERN +GType gi_marshalling_tests_boxed_struct_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +GIMarshallingTestsBoxedStruct *gi_marshalling_tests_boxed_struct_new (void); + +GI_TEST_EXTERN +GIMarshallingTestsBoxedStruct *gi_marshalling_tests_boxed_struct_returnv (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_boxed_struct_inv (GIMarshallingTestsBoxedStruct *struct_); + +GI_TEST_EXTERN +void gi_marshalling_tests_boxed_struct_out (GIMarshallingTestsBoxedStruct **struct_); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_boxed_struct_out_uninitialized (GIMarshallingTestsBoxedStruct **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_boxed_struct_inout (GIMarshallingTestsBoxedStruct **struct_); + +typedef union +{ + glong long_; +} GIMarshallingTestsUnion; + +typedef union +{ + glong long_; + gsize size; + const gchar *str; +} GIMarshallingTestsUnregisteredUnion; + +GI_TEST_EXTERN +GType gi_marshalling_tests_union_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +GIMarshallingTestsUnion *gi_marshalling_tests_union_returnv (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_union_inv (GIMarshallingTestsUnion *union_); + +GI_TEST_EXTERN +void gi_marshalling_tests_union_method (GIMarshallingTestsUnion *union_); + +typedef enum +{ + GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_NONE, + GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_SIMPLE_STRUCT, + GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_NESTED_STRUCT, + GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_POINTER_STRUCT, + GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_BOXED_STRUCT, + GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_BOXED_STRUCT_PTR, + GI_MARSHALLING_TESTS_STRUCTURED_UNION_TYPE_SINGLE_UNION, +} GIMarshallingTestsStructuredUnionType; + +typedef struct +{ + GIMarshallingTestsStructuredUnionType type; + GIMarshallingTestsSimpleStruct parent; +} GIMarshallingTestsStructuredUnionSimpleStruct; + +typedef struct +{ + GIMarshallingTestsStructuredUnionType type; + GIMarshallingTestsNestedStruct parent; +} GIMarshallingTestsStructuredUnionNestedStruct; + +typedef struct +{ + GIMarshallingTestsStructuredUnionType type; + GIMarshallingTestsPointerStruct parent; +} GIMarshallingTestsStructuredUnionPointerStruct; + +typedef struct +{ + GIMarshallingTestsStructuredUnionType type; + GIMarshallingTestsBoxedStruct parent; +} GIMarshallingTestsStructuredUnionBoxedStruct; + +typedef struct +{ + GIMarshallingTestsStructuredUnionType type; + GIMarshallingTestsBoxedStruct *parent; +} GIMarshallingTestsStructuredUnionBoxedStructPtr; + +typedef struct +{ + GIMarshallingTestsStructuredUnionType type; + GIMarshallingTestsUnion union_; +} GIMarshallingTestsStructuredUnionUnionStruct; + +typedef union +{ + GIMarshallingTestsStructuredUnionUnionStruct parent; +} GIMarshallingTestsStructuredUnionSingleUnion; + +typedef union +{ + /*< private >*/ + GIMarshallingTestsStructuredUnionType type; + + GIMarshallingTestsStructuredUnionSimpleStruct simple_struct; + GIMarshallingTestsStructuredUnionNestedStruct nested_struct; + GIMarshallingTestsStructuredUnionPointerStruct pointer_struct; + GIMarshallingTestsStructuredUnionBoxedStruct boxed_struct; + GIMarshallingTestsStructuredUnionBoxedStructPtr boxed_struct_ptr; + GIMarshallingTestsStructuredUnionSingleUnion single_union; +} GIMarshallingTestsStructuredUnion; + +GI_TEST_EXTERN +GType gi_marshalling_tests_structured_union_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +GIMarshallingTestsStructuredUnion *gi_marshalling_tests_structured_union_new (GIMarshallingTestsStructuredUnionType type); + +/* we want this to clash with a field value name */ +GI_TEST_EXTERN +GIMarshallingTestsStructuredUnionType gi_marshalling_tests_structured_union_type (GIMarshallingTestsStructuredUnion *structured_union); + +typedef union +{ + GIMarshallingTestsStructuredUnionType type; + GIMarshallingTestsStructuredUnionSimpleStruct simple_struct1; + GIMarshallingTestsStructuredUnionSimpleStruct simple_struct2; +} GIMarshallingTestsStructuredUnionSingleType; + +/* Object */ + +#define GI_MARSHALLING_TESTS_TYPE_OBJECT (gi_marshalling_tests_object_get_type ()) +#define GI_MARSHALLING_TESTS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GI_MARSHALLING_TESTS_TYPE_OBJECT, GIMarshallingTestsObject)) +#define GI_MARSHALLING_TESTS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GI_MARSHALLING_TESTS_TYPE_OBJECT, GIMarshallingTestsObjectClass)) +#define GI_MARSHALLING_TESTS_IS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GI_MARSHALLING_TESTS_TYPE_OBJECT)) +#define GI_MARSHALLING_TESTS_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GI_MARSHALLING_TESTS_TYPE_OBJECT)) +#define GI_MARSHALLING_TESTS_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GI_MARSHALLING_TESTS_TYPE_OBJECT, GIMarshallingTestsObjectClass)) + +typedef struct _GIMarshallingTestsObjectClass GIMarshallingTestsObjectClass; +typedef struct _GIMarshallingTestsObject GIMarshallingTestsObject; + +typedef int (*GIMarshallingTestsCallbackIntInt) (int val, void *user_data); + +struct _GIMarshallingTestsObjectClass +{ + GObjectClass parent_class; + + /** + * GIMarshallingTestsObjectClass::method_int8_in: + * @in: (in): + */ + void (*method_int8_in) (GIMarshallingTestsObject *self, gint8 in); + + /** + * GIMarshallingTestsObjectClass::method_int8_out: + * @out: (out): + */ + void (*method_int8_out) (GIMarshallingTestsObject *self, gint8 *out); + + /** + * GIMarshallingTestsObjectClass::method_int8_arg_and_out_caller: + * @out: (out): + */ + void (*method_int8_arg_and_out_caller) (GIMarshallingTestsObject *self, gint8 arg, gint8 *out); + + /** + * GIMarshallingTestsObjectClass::method_int8_arg_and_out_callee: + * @out: (out): + */ + void (*method_int8_arg_and_out_callee) (GIMarshallingTestsObject *self, gint8 arg, gint8 **out); + + /** + * GIMarshallingTestsObjectClass::method_str_arg_out_ret: + * @out: (out): + * + * Returns: (transfer none) + */ + const gchar *(*method_str_arg_out_ret) (GIMarshallingTestsObject *self, const gchar *arg, guint *out); + + /** + * GIMarshallingTestsObjectClass::method_with_default_implementation: + * @in: (in): + */ + void (*method_with_default_implementation) (GIMarshallingTestsObject *self, gint8 in); + + /** + * GIMarshallingTestsObjectClass::method_deep_hierarchy: + * @in: (in): + */ + void (*method_deep_hierarchy) (GIMarshallingTestsObject *self, gint8 in); + + void (*vfunc_with_callback) (GIMarshallingTestsObject *self, + GIMarshallingTestsCallbackIntInt callback, + void *callback_data); + + /** + * GIMarshallingTestsObjectClass::vfunc_return_value_only: + */ + glong (*vfunc_return_value_only) (GIMarshallingTestsObject *self); + + /** + * GIMarshallingTestsObjectClass::vfunc_one_out_parameter: + * @a: (out): + */ + void (*vfunc_one_out_parameter) (GIMarshallingTestsObject *self, gfloat *a); + + /** + * GIMarshallingTestsObjectClass::vfunc_multiple_out_parameters: + * @a: (out): + * @b: (out): + */ + void (*vfunc_multiple_out_parameters) (GIMarshallingTestsObject *self, gfloat *a, gfloat *b); + + /** + * GIMarshallingTestsObjectClass::vfunc_one_inout_parameter: + * @a: (inout): + */ + void (*vfunc_one_inout_parameter) (GIMarshallingTestsObject *self, gfloat *a); + + /** + * GIMarshallingTestsObjectClass::vfunc_multiple_inout_parameters: + * @a: (inout): + * @b: (inout): + */ + void (*vfunc_multiple_inout_parameters) (GIMarshallingTestsObject *self, gfloat *a, gfloat *b); + + /** + * GIMarshallingTestsObjectClass::vfunc_caller_allocated_out_parameter: + * @a: (out): + */ + void (*vfunc_caller_allocated_out_parameter) (GIMarshallingTestsObject *self, GValue *a); + + /** + * GIMarshallingTestsObjectClass::vfunc_array_out_parameter: + * @a: (out) (array zero-terminated): + */ + void (*vfunc_array_out_parameter) (GIMarshallingTestsObject *self, gfloat **a); + + /** + * GIMarshallingTestsObjectClass::vfunc_return_value_and_one_out_parameter: + * @a: (out): + */ + glong (*vfunc_return_value_and_one_out_parameter) (GIMarshallingTestsObject *self, glong *a); + + /** + * GIMarshallingTestsObjectClass::vfunc_return_value_and_multiple_out_parameters: + * @a: (out): + * @b: (out): + */ + glong (*vfunc_return_value_and_multiple_out_parameters) (GIMarshallingTestsObject *self, glong *a, glong *b); + + /** + * GIMarshallingTestsObjectClass::vfunc_return_value_and_one_inout_parameter: + * @a: (inout): + */ + glong (*vfunc_return_value_and_one_inout_parameter) (GIMarshallingTestsObject *self, glong *a); + + /** + * GIMarshallingTestsObjectClass::vfunc_return_value_and_multiple_inout_parameters: + * @a: (inout): + * @b: (inout): + */ + glong (*vfunc_return_value_and_multiple_inout_parameters) (GIMarshallingTestsObject *self, glong *a, glong *b); + + /** + * GIMarshallingTestsObjectClass::vfunc_meth_with_err: + * @x: + * @error: A #GError + */ + gboolean (*vfunc_meth_with_err) (GIMarshallingTestsObject *object, gint x, GError **error); + + /** + * GIMarshallingTestsObjectClass::vfunc_return_enum: + */ + GIMarshallingTestsEnum (*vfunc_return_enum) (GIMarshallingTestsObject *self); + + /** + * GIMarshallingTestsObjectClass::vfunc_out_enum: + * @_enum: (out): + */ + void (*vfunc_out_enum) (GIMarshallingTestsObject *self, GIMarshallingTestsEnum *_enum); + + /** + * GIMarshallingTestsObjectClass::vfunc_return_object_transfer_none: + * + * Returns: (transfer none) + */ + GObject *(*vfunc_return_object_transfer_none) (GIMarshallingTestsObject *self); + + /** + * GIMarshallingTestsObjectClass::vfunc_return_object_transfer_full: + * + * Returns: (transfer full) + */ + GObject *(*vfunc_return_object_transfer_full) (GIMarshallingTestsObject *self); + + /** + * GIMarshallingTestsObjectClass::vfunc_out_object_transfer_none: + * @object: (out) (transfer none): + */ + void (*vfunc_out_object_transfer_none) (GIMarshallingTestsObject *self, GObject **object); + + /** + * GIMarshallingTestsObjectClass::vfunc_out_object_transfer_full: + * @object: (out) (transfer full): + */ + void (*vfunc_out_object_transfer_full) (GIMarshallingTestsObject *self, GObject **object); + + /** + * GIMarshallingTestsObjectClass::vfunc_in_object_transfer_none: + * @object: (in) (transfer none): + */ + void (*vfunc_in_object_transfer_none) (GIMarshallingTestsObject *self, GObject *object); + + /** + * GIMarshallingTestsObjectClass::vfunc_in_object_transfer_full: + * @object: (in) (transfer full): + */ + void (*vfunc_in_object_transfer_full) (GIMarshallingTestsObject *self, GObject *object); + + /** + * GIMarshallingTestsObjectClass::vfunc_return_flags: + */ + GIMarshallingTestsFlags (*vfunc_return_flags) (GIMarshallingTestsObject *self); + + /** + * GIMarshallingTestsObjectClass::vfunc_out_flags: + * @flags: (out): + */ + void (*vfunc_out_flags) (GIMarshallingTestsObject *self, GIMarshallingTestsFlags *flags); +}; + +struct _GIMarshallingTestsObject +{ + GObject parent_instance; + + gint int_; +}; + +GI_TEST_EXTERN +GType gi_marshalling_tests_object_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +void gi_marshalling_tests_object_static_method (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_method (GIMarshallingTestsObject *object); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_overridden_method (GIMarshallingTestsObject *object); + +GI_TEST_EXTERN +GIMarshallingTestsObject *gi_marshalling_tests_object_new (gint int_); + +GI_TEST_EXTERN +GIMarshallingTestsObject *gi_marshalling_tests_object_new_fail (gint int_, GError **error); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_method_array_in (GIMarshallingTestsObject *object, const gint *ints, gint length); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_method_array_out (GIMarshallingTestsObject *object, gint **ints, gint *length); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_method_array_inout (GIMarshallingTestsObject *object, gint **ints, gint *length); + +GI_TEST_EXTERN +const gint *gi_marshalling_tests_object_method_array_return (GIMarshallingTestsObject *object, gint *length); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_method_int8_in (GIMarshallingTestsObject *object, gint8 in); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_method_int8_out (GIMarshallingTestsObject *object, gint8 *out); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_method_int8_arg_and_out_caller (GIMarshallingTestsObject *object, gint8 arg, gint8 *out); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_method_int8_arg_and_out_callee (GIMarshallingTestsObject *object, gint8 arg, gint8 **out); + +GI_TEST_EXTERN +const gchar *gi_marshalling_tests_object_method_str_arg_out_ret (GIMarshallingTestsObject *object, const gchar *arg, guint *out); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_method_with_default_implementation (GIMarshallingTestsObject *object, gint8 in); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_method_variant_array_in (GIMarshallingTestsObject *object, GVariant **in, gsize n_in); + +GI_TEST_EXTERN +glong gi_marshalling_tests_object_vfunc_return_value_only (GIMarshallingTestsObject *self); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_vfunc_one_out_parameter (GIMarshallingTestsObject *self, gfloat *a); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_vfunc_multiple_out_parameters (GIMarshallingTestsObject *self, gfloat *a, gfloat *b); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_vfunc_one_inout_parameter (GIMarshallingTestsObject *self, gfloat *a); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_vfunc_multiple_inout_parameters (GIMarshallingTestsObject *self, gfloat *a, gfloat *b); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_vfunc_caller_allocated_out_parameter (GIMarshallingTestsObject *self, GValue *a); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_vfunc_array_out_parameter (GIMarshallingTestsObject *self, gfloat **a); + +GI_TEST_EXTERN +glong gi_marshalling_tests_object_vfunc_return_value_and_one_out_parameter (GIMarshallingTestsObject *self, glong *a); + +GI_TEST_EXTERN +glong gi_marshalling_tests_object_vfunc_return_value_and_multiple_out_parameters (GIMarshallingTestsObject *self, glong *a, glong *b); + +GI_TEST_EXTERN +glong gi_marshalling_tests_object_vfunc_return_value_and_one_inout_parameter (GIMarshallingTestsObject *self, glong *a); + +GI_TEST_EXTERN +glong gi_marshalling_tests_object_vfunc_return_value_and_multiple_inout_parameters (GIMarshallingTestsObject *self, glong *a, glong *b); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_object_vfunc_meth_with_error (GIMarshallingTestsObject *object, gint x, GError **error); + +GI_TEST_EXTERN +GIMarshallingTestsEnum gi_marshalling_tests_object_vfunc_return_enum (GIMarshallingTestsObject *self); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_vfunc_out_enum (GIMarshallingTestsObject *self, GIMarshallingTestsEnum *_enum); + +GI_TEST_EXTERN +GIMarshallingTestsFlags gi_marshalling_tests_object_vfunc_return_flags (GIMarshallingTestsObject *self); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_vfunc_out_flags (GIMarshallingTestsObject *self, GIMarshallingTestsFlags *flags); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_get_ref_info_for_vfunc_return_object_transfer_none (GIMarshallingTestsObject *self, guint *ref_count, gboolean *is_floating); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_get_ref_info_for_vfunc_return_object_transfer_full (GIMarshallingTestsObject *self, guint *ref_count, gboolean *is_floating); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_get_ref_info_for_vfunc_out_object_transfer_none (GIMarshallingTestsObject *self, guint *ref_count, gboolean *is_floating); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_get_ref_info_for_vfunc_out_object_transfer_full (GIMarshallingTestsObject *self, guint *ref_count, gboolean *is_floating); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_get_ref_info_for_vfunc_in_object_transfer_none (GIMarshallingTestsObject *self, GType type, guint *ref_count, gboolean *is_floating); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_get_ref_info_for_vfunc_in_object_transfer_full (GIMarshallingTestsObject *self, GType type, guint *ref_count, gboolean *is_floating); + +GI_TEST_EXTERN +GIMarshallingTestsObject *gi_marshalling_tests_object_none_return (void); + +GI_TEST_EXTERN +GIMarshallingTestsObject *gi_marshalling_tests_object_full_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_none_in (GIMarshallingTestsObject *object); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_full_in (GIMarshallingTestsObject *object); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_none_out (GIMarshallingTestsObject **object); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_object_none_out_uninitialized (GIMarshallingTestsObject **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_full_out (GIMarshallingTestsObject **object); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_object_full_out_uninitialized (GIMarshallingTestsObject **v G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_none_inout (GIMarshallingTestsObject **object); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_full_inout (GIMarshallingTestsObject **object); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_int8_in (GIMarshallingTestsObject *object, gint8 in); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_int8_out (GIMarshallingTestsObject *object, gint8 *out); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_vfunc_with_callback (GIMarshallingTestsObject *object, + GIMarshallingTestsCallbackIntInt callback, + void *callback_data); + +GI_TEST_EXTERN +void gi_marshalling_tests_object_call_vfunc_with_callback (GIMarshallingTestsObject *object); + +#define GI_MARSHALLING_TESTS_TYPE_SUB_OBJECT (gi_marshalling_tests_sub_object_get_type ()) +#define GI_MARSHALLING_TESTS_SUB_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GI_MARSHALLING_TESTS_TYPE_SUB_OBJECT, GIMarshallingTestsSubObject)) +#define GI_MARSHALLING_TESTS_SUB_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GI_MARSHALLING_TESTS_TYPE_SUB_OBJECT, GIMarshallingTestsSubObjectClass)) +#define GI_MARSHALLING_TESTS_IS_SUB_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GI_MARSHALLING_TESTS_TYPE_SUB_OBJECT)) +#define GI_MARSHALLING_TESTS_IS_SUB_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GI_MARSHALLING_TESTS_TYPE_SUB_OBJECT)) +#define GI_MARSHALLING_TESTS_SUB_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GI_MARSHALLING_TESTS_TYPE_SUB_OBJECT, GIMarshallingTestsSubObjectClass)) + +typedef struct _GIMarshallingTestsSubObjectClass GIMarshallingTestsSubObjectClass; +typedef struct _GIMarshallingTestsSubObject GIMarshallingTestsSubObject; + +struct _GIMarshallingTestsSubObjectClass +{ + GIMarshallingTestsObjectClass parent_class; +}; + +struct _GIMarshallingTestsSubObject +{ + GIMarshallingTestsObject parent_instance; +}; + +GI_TEST_EXTERN +GType gi_marshalling_tests_sub_object_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +void gi_marshalling_tests_sub_object_sub_method (GIMarshallingTestsSubObject *object); + +GI_TEST_EXTERN +void gi_marshalling_tests_sub_object_overwritten_method (GIMarshallingTestsSubObject *object); + +#define GI_MARSHALLING_TESTS_TYPE_SUB_SUB_OBJECT (gi_marshalling_tests_sub_sub_object_get_type ()) +#define GI_MARSHALLING_TESTS_SUB_SUB_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GI_MARSHALLING_TESTS_TYPE_SUB_SUB_OBJECT, GIMarshallingTestsSubSubObject)) +#define GI_MARSHALLING_TESTS_SUB_SUB_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GI_MARSHALLING_TESTS_TYPE_SUB_SUB_OBJECT, GIMarshallingTestsSubSubObjectClass)) +#define GI_MARSHALLING_TESTS_IS_SUB_SUB_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GI_MARSHALLING_TESTS_TYPE_SUB_SUB_OBJECT)) +#define GI_MARSHALLING_TESTS_IS_SUB_SUB_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GI_MARSHALLING_TESTS_TYPE_SUB_SUB_OBJECT)) +#define GI_MARSHALLING_TESTS_SUB_SUB_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GI_MARSHALLING_TESTS_TYPE_SUB_SUB_OBJECT, GIMarshallingTestsSubSubObjectClass)) + +typedef struct _GIMarshallingTestsSubSubObjectClass GIMarshallingTestsSubSubObjectClass; +typedef struct _GIMarshallingTestsSubSubObject GIMarshallingTestsSubSubObject; + +struct _GIMarshallingTestsSubSubObjectClass +{ + GIMarshallingTestsSubObjectClass parent_class; +}; + +struct _GIMarshallingTestsSubSubObject +{ + GIMarshallingTestsSubObject parent_instance; +}; + +GI_TEST_EXTERN +GType gi_marshalling_tests_sub_sub_object_get_type (void) G_GNUC_CONST; + +/* Interfaces */ + +#define GI_MARSHALLING_TESTS_TYPE_INTERFACE (gi_marshalling_tests_interface_get_type ()) +#define GI_MARSHALLING_TESTS_INTERFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GI_MARSHALLING_TESTS_TYPE_INTERFACE, GIMarshallingTestsInterface)) +#define GI_MARSHALLING_TESTS_IS_INTERFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GI_MARSHALLING_TESTS_TYPE_INTERFACE)) +#define GI_MARSHALLING_TESTS_INTERFACE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GI_MARSHALLING_TESTS_TYPE_INTERFACE, GIMarshallingTestsInterfaceIface)) + +typedef struct _GIMarshallingTestsInterface GIMarshallingTestsInterface; +typedef struct _GIMarshallingTestsInterfaceIface GIMarshallingTestsInterfaceIface; + +struct _GIMarshallingTestsInterfaceIface +{ + GTypeInterface base_iface; + + /** + * GIMarshallingTestsInterfaceIface::test_int8_in: + * @in: (in): + */ + void (*test_int8_in) (GIMarshallingTestsInterface *self, gint8 in); +}; + +GI_TEST_EXTERN +GType gi_marshalling_tests_interface_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +void gi_marshalling_tests_interface_test_int8_in (GIMarshallingTestsInterface *self, gint8 in); + +GI_TEST_EXTERN +void gi_marshalling_tests_test_interface_test_int8_in (GIMarshallingTestsInterface *test_iface, gint8 in); + +/* GIMarshallingTestsInterfaceImpl is a class that implements + GIMarshallingTestsInterface */ + +#define GI_MARSHALLING_TESTS_TYPE_INTERFACE_IMPL (gi_marshalling_tests_interface_impl_get_type ()) +#define GI_MARSHALLING_TESTS_INTERFACE_IMPL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GI_MARSHALLING_TESTS_TYPE_INTERFACE_IMPL, GIMarshallingTestsInterfaceImpl)) +#define GI_MARSHALLING_TESTS_INTERFACE_IMPL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GI_MARSHALLING_TESTS_TYPE_INTERFACE_IMPL, GIMarshallingTestsInterfaceImplClass)) +#define GI_MARSHALLING_TESTS_IS_INTERFACE_IMPL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GI_MARSHALLING_TESTS_TYPE_INTERFACE_IMPL)) +#define GI_MARSHALLING_TESTS_IS_INTERFACE_IMPL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GI_MARSHALLING_TESTS_TYPE_INTERFACE_IMPL)) +#define GI_MARSHALLING_TESTS_INTERFACE_IMPL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GI_MARSHALLING_TESTS_TYPE_INTERFACE_IMPL, GIMarshallingTestsInterfaceImplClass)) + +typedef struct _GIMarshallingTestsInterfaceImplClass GIMarshallingTestsInterfaceImplClass; +typedef struct _GIMarshallingTestsInterfaceImpl GIMarshallingTestsInterfaceImpl; + +struct _GIMarshallingTestsInterfaceImplClass +{ + GObjectClass parent_class; +}; + +struct _GIMarshallingTestsInterfaceImpl +{ + GObject parent_instance; + + gint int_; +}; + +GI_TEST_EXTERN +GType gi_marshalling_tests_interface_impl_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +GIMarshallingTestsInterface *gi_marshalling_tests_interface_impl_get_as_interface (GIMarshallingTestsInterfaceImpl *self); + +/* GIMarshallingTestsInterface2 allows us testing vfunc clashes when a class' + vfunc implementation ambiguously relates to its prototype */ + +#define GI_MARSHALLING_TESTS_TYPE_INTERFACE2 (gi_marshalling_tests_interface2_get_type ()) +#define GI_MARSHALLING_TESTS_INTERFACE2(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GI_MARSHALLING_TESTS_TYPE_INTERFACE2, GIMarshallingTestsInterface2)) +#define GI_MARSHALLING_TESTS_IS_INTERFACE2(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GI_MARSHALLING_TESTS_TYPE_INTERFACE2)) +#define GI_MARSHALLING_TESTS_INTERFACE2_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GI_MARSHALLING_TESTS_TYPE_INTERFACE2, GIMarshallingTestsInterface2Iface)) + +typedef struct _GIMarshallingTestsInterface2 GIMarshallingTestsInterface2; +typedef struct _GIMarshallingTestsInterface2Iface GIMarshallingTestsInterface2Iface; + +struct _GIMarshallingTestsInterface2Iface +{ + GTypeInterface base_iface; + + /** + * GIMarshallingTestsInterface2Iface::test_int8_in: + * @in: (in): + */ + void (*test_int8_in) (GIMarshallingTestsInterface2 *self, gint8 in); +}; + +GI_TEST_EXTERN +GType gi_marshalling_tests_interface2_get_type (void) G_GNUC_CONST; + +/* GIMarshallingTestsInterface3 tests passing arrays of variants from C to @lang */ + +#define GI_MARSHALLING_TESTS_TYPE_INTERFACE3 (gi_marshalling_tests_interface3_get_type ()) +#define GI_MARSHALLING_TESTS_INTERFACE3(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GI_MARSHALLING_TESTS_TYPE_INTERFACE3, GIMarshallingTestsInterface3)) +#define GI_MARSHALLING_TESTS_IS_INTERFACE3(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GI_MARSHALLING_TESTS_TYPE_INTERFACE3)) +#define GI_MARSHALLING_TESTS_INTERFACE3_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GI_MARSHALLING_TESTS_TYPE_INTERFACE3, GIMarshallingTestsInterface3Iface)) + +typedef struct _GIMarshallingTestsInterface3 GIMarshallingTestsInterface3; +typedef struct _GIMarshallingTestsInterface3Iface GIMarshallingTestsInterface3Iface; + +struct _GIMarshallingTestsInterface3Iface +{ + GTypeInterface base_iface; + + /** + * GIMarshallingTestsInterface3::test_variant_array_in: + * @in: (in) (array length=n_in): + */ + void (*test_variant_array_in) (GIMarshallingTestsInterface3 *self, GVariant **in, gsize n_in); +}; + +GI_TEST_EXTERN +GType gi_marshalling_tests_interface3_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +void gi_marshalling_tests_interface3_test_variant_array_in (GIMarshallingTestsInterface3 *self, GVariant **in, gsize n_in); + +/* Multiple output arguments */ + +GI_TEST_EXTERN +void gi_marshalling_tests_int_out_out (gint *int0, gint *int1); + +GI_TEST_EXTERN +void gi_marshalling_tests_int_three_in_three_out (gint a, gint b, gint c, gint *out0, gint *out1, gint *out2); + +GI_TEST_EXTERN +gint gi_marshalling_tests_int_return_out (gint *int_); + +/* Default arguments */ +GI_TEST_EXTERN +void gi_marshalling_tests_int_two_in_utf8_two_in_with_allow_none (gint a, gint b, const gchar *c, const gchar *d); + +GI_TEST_EXTERN +void gi_marshalling_tests_int_one_in_utf8_two_in_one_allows_none (gint a, const gchar *b, const gchar *c); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_in_utf8_two_in (const gint *ints, gint length, const gchar *a, const gchar *b); + +GI_TEST_EXTERN +void gi_marshalling_tests_array_in_utf8_two_in_out_of_order (gint length, const gchar *a, const gint *ints, const gchar *b); + +/* GError */ + +#define GI_MARSHALLING_TESTS_CONSTANT_GERROR_DOMAIN "gi-marshalling-tests-gerror-domain" +#define GI_MARSHALLING_TESTS_CONSTANT_GERROR_CODE 5 +#define GI_MARSHALLING_TESTS_CONSTANT_GERROR_MESSAGE "gi-marshalling-tests-gerror-message" +#define GI_MARSHALLING_TESTS_CONSTANT_GERROR_DEBUG_MESSAGE "we got an error, life is shit" + +GI_TEST_EXTERN +void gi_marshalling_tests_gerror (GError **error); + +GI_TEST_EXTERN +void gi_marshalling_tests_gerror_array_in (gint *in_ints, GError **error); + +GI_TEST_EXTERN +void gi_marshalling_tests_gerror_out (GError **error, gchar **debug); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_gerror_out_uninitialized (GError **v G_GNUC_UNUSED, gchar **v2 G_GNUC_UNUSED); + +GI_TEST_EXTERN +void gi_marshalling_tests_gerror_out_transfer_none (GError **err, const gchar **debug); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_gerror_out_transfer_none_uninitialized (GError **v G_GNUC_UNUSED, const gchar **v2 G_GNUC_UNUSED); + +GI_TEST_EXTERN +GError *gi_marshalling_tests_gerror_return (void); + +/* GParamSpec */ +GI_TEST_EXTERN +void gi_marshalling_tests_param_spec_in_bool (const GParamSpec *param); + +GI_TEST_EXTERN +GParamSpec *gi_marshalling_tests_param_spec_return (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_param_spec_out (GParamSpec **param); + +GI_TEST_EXTERN +gboolean gi_marshalling_tests_param_spec_out_uninitialized (GParamSpec **v G_GNUC_UNUSED); + +/* Overrides */ + +#define GI_MARSHALLING_TESTS_OVERRIDES_CONSTANT 42 + +typedef struct +{ + glong long_; +} GIMarshallingTestsOverridesStruct; + +GI_TEST_EXTERN +GType gi_marshalling_tests_overrides_struct_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +GIMarshallingTestsOverridesStruct *gi_marshalling_tests_overrides_struct_new (void); + +GI_TEST_EXTERN +glong gi_marshalling_tests_overrides_struct_method (GIMarshallingTestsOverridesStruct *struct_); + +GI_TEST_EXTERN +GIMarshallingTestsOverridesStruct *gi_marshalling_tests_overrides_struct_returnv (void); + +#define GI_MARSHALLING_TESTS_TYPE_OVERRIDES_OBJECT (gi_marshalling_tests_overrides_object_get_type ()) +#define GI_MARSHALLING_TESTS_OVERRIDES_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GI_MARSHALLING_TESTS_TYPE_OVERRIDES_OBJECT, GIMarshallingTestsOverridesObject)) +#define GI_MARSHALLING_TESTS_OVERRIDES_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GI_MARSHALLING_TESTS_TYPE_OVERRIDES_OBJECT, GIMarshallingTestsOverridesObjectClass)) +#define GI_MARSHALLING_TESTS_IS_OVERRIDES_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GI_MARSHALLING_TESTS_TYPE_OVERRIDES_OBJECT)) +#define GI_MARSHALLING_TESTS_IS_OVERRIDES_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GI_MARSHALLING_TESTS_TYPE_OVERRIDES_OBJECT)) +#define GI_MARSHALLING_TESTS_OVERRIDES_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GI_MARSHALLING_TESTS_TYPE_OVERRIDES_OBJECT, GIMarshallingTestsOverridesObjectClass)) + +typedef struct _GIMarshallingTestsOverridesObjectClass GIMarshallingTestsOverridesObjectClass; +typedef struct _GIMarshallingTestsOverridesObject GIMarshallingTestsOverridesObject; + +struct _GIMarshallingTestsOverridesObjectClass +{ + GObjectClass parent_class; +}; + +struct _GIMarshallingTestsOverridesObject +{ + GObject parent_instance; + + glong long_; +}; + +GI_TEST_EXTERN +GType gi_marshalling_tests_overrides_object_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +GIMarshallingTestsOverridesObject *gi_marshalling_tests_overrides_object_new (void); + +GI_TEST_EXTERN +glong gi_marshalling_tests_overrides_object_method (GIMarshallingTestsOverridesObject *object); + +GI_TEST_EXTERN +GIMarshallingTestsOverridesObject *gi_marshalling_tests_overrides_object_returnv (void); + +/* Properties Object */ + +#define GI_MARSHALLING_TESTS_TYPE_PROPERTIES_OBJECT (gi_marshalling_tests_properties_object_get_type ()) +#define GI_MARSHALLING_TESTS_PROPERTIES_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GI_MARSHALLING_TESTS_TYPE_PROPERTIES_OBJECT, GIMarshallingTestsPropertiesObject)) +#define GI_MARSHALLING_TESTS_PROPERTIES_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GI_MARSHALLING_TESTS_TYPE_PROPERTIES_OBJECT, GIMarshallingTestsPropertiesObjectClass)) +#define GI_MARSHALLING_TESTS_IS_PROPERTIES_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GI_MARSHALLING_TESTS_TYPE_PROPERTIES_OBJECT)) +#define GI_MARSHALLING_TESTS_IS_PROPERTIES_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GI_MARSHALLING_TESTS_TYPE_PROPERTIES_OBJECT)) +#define GI_MARSHALLING_TESTS_PROPERTIES_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GI_MARSHALLING_TESTS_TYPE_PROPERTIES_OBJECT, GIMarshallingTestsPropertiesObjectClass)) + +typedef struct _GIMarshallingTestsPropertiesObject GIMarshallingTestsPropertiesObject; +typedef struct _GIMarshallingTestsPropertiesObjectClass GIMarshallingTestsPropertiesObjectClass; + +struct _GIMarshallingTestsPropertiesObject +{ + GObject parent_instance; + + gboolean some_boolean; + gchar some_char; + guchar some_uchar; + gint some_int; + guint some_uint; + glong some_long; + gulong some_ulong; + gint64 some_int64; + guint64 some_uint64; + gfloat some_float; + gdouble some_double; + gchar *some_string; + gchar **some_strv; + GIMarshallingTestsBoxedStruct *some_boxed_struct; + GList *some_boxed_glist; + GValue *some_gvalue; + GVariant *some_variant; + GObject *some_object; + GIMarshallingTestsFlags some_flags; + GIMarshallingTestsGEnum some_enum; + GByteArray *some_byte_array; +}; + +struct _GIMarshallingTestsPropertiesObjectClass +{ + GObjectClass parent_class; +}; + +GI_TEST_EXTERN +GType gi_marshalling_tests_properties_object_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +GIMarshallingTestsPropertiesObject *gi_marshalling_tests_properties_object_new (void); + +/* Signals object */ + +#define GI_MARSHALLING_TESTS_TYPE_SIGNALS_OBJECT (gi_marshalling_tests_signals_object_get_type ()) +#define GI_MARSHALLING_TESTS_SIGNALS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GI_MARSHALLING_TESTS_TYPE_SIGNALS_OBJECT, GIMarshallingTestsSignalsObject)) +#define GI_MARSHALLING_TESTS_SIGNALS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GI_MARSHALLING_TESTS_TYPE_SIGNALS_OBJECT, GIMarshallingTestsSignalsObjectClass)) +#define GI_MARSHALLING_TESTS_IS_SIGNALS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GI_MARSHALLING_TESTS_TYPE_SIGNALS_OBJECT)) +#define GI_MARSHALLING_TESTS_IS_SIGNALS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GI_MARSHALLING_TESTS_TYPE_SIGNALS_OBJECT)) +#define GI_MARSHALLING_TESTS_SIGNALS_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GI_MARSHALLING_TESTS_TYPE_SIGNALS_OBJECT, GIMarshallingTestsSignalsObjectClass)) + +typedef struct _GIMarshallingTestsSignalsObject GIMarshallingTestsSignalsObject; +typedef struct _GIMarshallingTestsSignalsObjectClass GIMarshallingTestsSignalsObjectClass; + +struct _GIMarshallingTestsSignalsObject +{ + GObject parent_instance; +}; + +struct _GIMarshallingTestsSignalsObjectClass +{ + GObjectClass parent_class; +}; + +GI_TEST_EXTERN +GType gi_marshalling_tests_signals_object_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +GIMarshallingTestsSignalsObject *gi_marshalling_tests_signals_object_new (void); + +GI_TEST_EXTERN +void gi_marshalling_tests_signals_object_emit_boxed_gptrarray_utf8 (GIMarshallingTestsSignalsObject *object); + +GI_TEST_EXTERN +void gi_marshalling_tests_signals_object_emit_boxed_gptrarray_utf8_container (GIMarshallingTestsSignalsObject *object); + +GI_TEST_EXTERN +void gi_marshalling_tests_signals_object_emit_boxed_gptrarray_utf8_full (GIMarshallingTestsSignalsObject *object); + +GI_TEST_EXTERN +void gi_marshalling_tests_signals_object_emit_boxed_gptrarray_boxed_struct (GIMarshallingTestsSignalsObject *object); + +GI_TEST_EXTERN +void gi_marshalling_tests_signals_object_emit_boxed_gptrarray_boxed_struct_container (GIMarshallingTestsSignalsObject *object); + +GI_TEST_EXTERN +void gi_marshalling_tests_signals_object_emit_boxed_gptrarray_boxed_struct_full (GIMarshallingTestsSignalsObject *object); + +GI_TEST_EXTERN +void gi_marshalling_tests_signals_object_emit_hash_table_utf8_int (GIMarshallingTestsSignalsObject *object); + +GI_TEST_EXTERN +void gi_marshalling_tests_signals_object_emit_hash_table_utf8_int_container (GIMarshallingTestsSignalsObject *object); + +GI_TEST_EXTERN +void gi_marshalling_tests_signals_object_emit_hash_table_utf8_int_full (GIMarshallingTestsSignalsObject *object); + +GI_TEST_EXTERN +void gi_marshalling_tests_signals_object_emit_boxed_struct (GIMarshallingTestsSignalsObject *object); + +GI_TEST_EXTERN +void gi_marshalling_tests_signals_object_emit_boxed_struct_full (GIMarshallingTestsSignalsObject *object); diff --git a/subprojects/gobject-introspection-tests/gitestmacros.h b/subprojects/gobject-introspection-tests/gitestmacros.h new file mode 100644 index 000000000..033fa0f93 --- /dev/null +++ b/subprojects/gobject-introspection-tests/gitestmacros.h @@ -0,0 +1,9 @@ +/* +SPDX-FileCopyrightText: 2014 Chun-wei Fan +*/ + +#pragma once + +#ifndef GI_TEST_EXTERN +#define GI_TEST_EXTERN extern +#endif diff --git a/subprojects/gobject-introspection-tests/gobject-introspection-tests.doap b/subprojects/gobject-introspection-tests/gobject-introspection-tests.doap new file mode 100644 index 000000000..c22c394ad --- /dev/null +++ b/subprojects/gobject-introspection-tests/gobject-introspection-tests.doap @@ -0,0 +1,111 @@ + + + + + + GObject Introspection Tests + gobject-introspection-tests + + + Tests for GNOME language bindings + + + This is a test suite for language bindings for the GNOME platform that use + GObject Introspection. + + + + + + + + + + C + + + + Andy Holmes + + andyholmes + + + + + + Arjan Molenaar + + amolenaar + + + + + + Christoph Reiter + + creiter + + + + + + Colin Walters + + walters + + + + + + Dan Yeaw + + danyeaw + + + + + + Emmanuele Bassi + + ebassi + + + + + + Evan Welsh + + ewlsh + + + + + + Marco Trevisan (Treviño) + + 3v1n0 + marcotrevi + + + + + + Philip Chimento + + ptomato + pchimento + + + + + + Rico Tzschichholz + + ricotz + + + diff --git a/subprojects/gobject-introspection-tests/meson.build b/subprojects/gobject-introspection-tests/meson.build new file mode 100644 index 000000000..d42d51b9c --- /dev/null +++ b/subprojects/gobject-introspection-tests/meson.build @@ -0,0 +1,223 @@ +project( + 'gobject-introspection-tests', 'c', version: 'unversioned', + meson_version: '>= 0.61', + default_options: ['c_std=c99', 'warning_level=2'] +) + +gnome = import('gnome') + +cc = meson.get_compiler('c') +msvc = cc.get_argument_syntax() == 'msvc' + +build_cairo = get_option('cairo') +install_dir = get_option('install_dir') +install = (install_dir != '') + +glib_version = '>= 2.70' +glib_dep = dependency('glib-2.0', version: glib_version) +gobject_dep = dependency('gobject-2.0', version: glib_version) +gio_dep = dependency('gio-2.0', version: glib_version) + +if build_cairo + cairo_dep = dependency('cairo', required: not msvc) + cairo_gobject_dep = dependency('cairo-gobject', required: not msvc) + + # We might need to look for the headers and libs for Cairo manually on + # MSVC/clang-cl builds... + if not cairo_dep.found() + cairo_dep = cc.find_library( + 'cairo', + has_headers: ['cairo.h'], + required: true + ) + endif + if not cairo_gobject_dep.found() + cairo_gobject_dep = cc.find_library( + 'cairo-gobject', + has_headers: ['cairo-gobject.h'], + required: true + ) + endif +endif + +args = [] + +if host_machine.system() == 'windows' + extern_def = '__declspec(dllexport) extern' +else + extern_def = '__attribute__((visibility("default"))) extern' +endif +args += ['-DGI_TEST_EXTERN=@0@'.format(extern_def)] + +if not build_cairo + args += ['-DGI_TEST_DISABLE_CAIRO'] +endif + +add_project_arguments(args, language: 'c') + +utility_sources = ['utility.c', 'utility.h'] +regress_sources = [ + 'annotation.c', + 'annotation.h', + 'drawable.c', + 'drawable.h', + 'foo.c', + 'foo.h', + 'regress.c', + 'regress.h', +] +regress_unix_sources = ['regress-unix.c', 'regress-unix.h'] +warnlib_sources = ['warnlib.c', 'warnlib.h'] +gimarshallingtests_sources = ['gimarshallingtests.c', 'gimarshallingtests.h'] + +libutility = library( + 'utility', + utility_sources, + dependencies: [glib_dep, gobject_dep], + gnu_symbol_visibility: 'hidden', + install: install, + install_dir: install_dir, +) +utility_gir = gnome.generate_gir( + libutility, + sources: utility_sources, + includes: ['GObject-2.0'], + namespace: 'Utility', + nsversion: '1.0', + symbol_prefix: 'utility_', + header: 'utility.h', + fatal_warnings: get_option('werror'), + install_gir: false, + install_typelib: install, + install_dir_typelib: install_dir, +) +utility_typelib = utility_gir[1] + +regress_dependencies = [glib_dep, gobject_dep, gio_dep] +regress_gir_includes = ['Gio-2.0', utility_gir[0]] +if build_cairo + regress_gir_includes += 'cairo-1.0' + regress_dependencies += [cairo_dep, cairo_gobject_dep] +endif + +libregress = library( + 'regress', + regress_sources + regress_unix_sources, + dependencies: regress_dependencies, + gnu_symbol_visibility: 'hidden', + install: install, + install_dir: install_dir, + override_options: ['unity=off'], +) +regress_gir = gnome.generate_gir( + libregress, + sources: regress_sources, + includes: regress_gir_includes, + namespace: 'Regress', + nsversion: '1.0', + identifier_prefix: 'Regress', + symbol_prefix: 'regress_', + header: 'regress.h', + extra_args: ['--warn-all'], + include_directories: meson.current_build_dir(), + fatal_warnings: get_option('werror'), + install_gir: false, + install_typelib: install, + install_dir_typelib: install_dir, +) +regress_typelib = regress_gir[1] +if host_machine.system() != 'windows' + regress_unix_gir = gnome.generate_gir( + libregress, + sources: regress_unix_sources, + includes: regress_gir_includes, + namespace: 'RegressUnix', + nsversion: '1.0', + symbol_prefix: 'regress_unix_', + header: 'regress-unix.h', + include_directories: meson.current_build_dir(), + fatal_warnings: get_option('werror'), + install_gir: false, + install_typelib: install, + install_dir_typelib: install_dir, + ) +else + regress_unix_gir = [disabler(), disabler()] +endif +regress_unix_typelib = regress_unix_gir[1] + +libwarnlib = library( + 'warnlib', + warnlib_sources, + dependencies: [glib_dep, gobject_dep, gio_dep], + gnu_symbol_visibility: 'hidden', + install: install, + install_dir: install_dir, +) +# This should have --warn-all turned off, but there is currently no way to do so +# in gnome.generate_gir(). See https://github.com/mesonbuild/meson/issues/5876 +warnlib_gir = gnome.generate_gir( + libwarnlib, + includes: ['Gio-2.0'], + sources: warnlib_sources, + namespace: 'WarnLib', + nsversion: '1.0', + symbol_prefix: 'warnlib_', + header: 'warnlib.h', + fatal_warnings: false, + install_gir: false, + install_typelib: install, + install_dir_typelib: install_dir, +) +warnlib_typelib = warnlib_gir[1] + +libgimarshallingtests = library( + 'gimarshallingtests', + gimarshallingtests_sources, + dependencies: [glib_dep, gobject_dep, gio_dep], + gnu_symbol_visibility: 'hidden', + install: install, + install_dir: install_dir, +) +gimarshallingtests_gir = gnome.generate_gir( + libgimarshallingtests, + sources: gimarshallingtests_sources, + includes: ['Gio-2.0'], + namespace: 'GIMarshallingTests', + nsversion: '1.0', + symbol_prefix: 'gi_marshalling_tests_', + fatal_warnings: get_option('werror'), + install_gir: false, + install_typelib: install, + install_dir_typelib: install_dir, +) +gimarshallingtests_typelib = gimarshallingtests_gir[1] + +deps = [glib_dep] +if build_cairo + deps += [cairo_dep, cairo_gobject_dep] +endif +locations = [] +foreach dep: deps + if dep.type_name() == 'pkgconfig' + locations += 'in @0@'.format(dep.get_variable(pkgconfig: 'prefix')) + else + locations += dep.type_name() + endif +endforeach + +summary({ + 'Build type': get_option('buildtype'), + 'Install test libraries': install, + 'GLib': '@0@ (@1@)'.format(glib_dep.version(), locations[0]), + 'Cairo support': build_cairo, +}, bool_yn: true) +if build_cairo + summary({ + 'Cairo': '@0@ (@1@)'.format(cairo_dep.version(), locations[1]), + 'Cairo-gobject': '@0@ (@1@)'.format(cairo_gobject_dep.version(), locations[2]) + }) +endif +if install + summary('Install location', install_dir) +endif diff --git a/subprojects/gobject-introspection-tests/meson_options.txt b/subprojects/gobject-introspection-tests/meson_options.txt new file mode 100644 index 000000000..5b67b28b1 --- /dev/null +++ b/subprojects/gobject-introspection-tests/meson_options.txt @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: 2024 Philip Chimento + +option('cairo', type: 'boolean', value: true, description: 'Cairo support') +option('install_dir', type: 'string', + description: 'Location to install test libraries and typelibs') diff --git a/subprojects/gobject-introspection-tests/regress-unix.c b/subprojects/gobject-introspection-tests/regress-unix.c new file mode 100644 index 000000000..ffdc0892b --- /dev/null +++ b/subprojects/gobject-introspection-tests/regress-unix.c @@ -0,0 +1,39 @@ +/* +SPDX-FileCopyrightText: 2024 Simon McVittie +*/ + +#include "regress-unix.h" + +#ifdef G_OS_UNIX + +dev_t +regress_unix_test_devt (dev_t in) +{ + return in; +} + +gid_t +regress_unix_test_gidt (gid_t in) +{ + return in; +} + +pid_t +regress_unix_test_pidt (pid_t in) +{ + return in; +} + +socklen_t +regress_unix_test_socklent (socklen_t in) +{ + return in; +} + +uid_t +regress_unix_test_uidt (uid_t in) +{ + return in; +} + +#endif diff --git a/subprojects/gobject-introspection-tests/regress-unix.h b/subprojects/gobject-introspection-tests/regress-unix.h new file mode 100644 index 000000000..aa2cd14e0 --- /dev/null +++ b/subprojects/gobject-introspection-tests/regress-unix.h @@ -0,0 +1,31 @@ +/* +SPDX-FileCopyrightText: 2024 Simon McVittie +*/ + +#pragma once + +#include + +#ifdef G_OS_UNIX + +#include +#include + +#include "gitestmacros.h" + +GI_TEST_EXTERN +dev_t regress_unix_test_devt (dev_t in); + +GI_TEST_EXTERN +gid_t regress_unix_test_gidt (gid_t in); + +GI_TEST_EXTERN +pid_t regress_unix_test_pidt (pid_t in); + +GI_TEST_EXTERN +socklen_t regress_unix_test_socklent (socklen_t in); + +GI_TEST_EXTERN +uid_t regress_unix_test_uidt (uid_t in); + +#endif diff --git a/subprojects/gobject-introspection-tests/regress.c b/subprojects/gobject-introspection-tests/regress.c new file mode 100644 index 000000000..0cdaf909a --- /dev/null +++ b/subprojects/gobject-introspection-tests/regress.c @@ -0,0 +1,5100 @@ +/* +SPDX-FileCopyrightText: 2008-2015 Colin Walters +SPDX-FileCopyrightText: 2008 Johan Bilien +SPDX-FileCopyrightText: 2008 Lucas Almeida Rocha +SPDX-FileCopyrightText: 2008, 2010 Owen W. Taylor +SPDX-FileCopyrightText: 2008 Tommi Komulainen +SPDX-FileCopyrightText: 2009 Andreas Rottmann +SPDX-FileCopyrightText: 2009 Havoc Pennington +SPDX-FileCopyrightText: 2009-2010 Johan Dahlin +SPDX-FileCopyrightText: 2009-2011 litl, LLC +SPDX-FileCopyrightText: 2009 Mark Lee +SPDX-FileCopyrightText: 2009 Maxim Ermilov +SPDX-FileCopyrightText: 2009 Simon van der Linden +SPDX-FileCopyrightText: 2009-2010 Sugar Labs +SPDX-FileCopyrightText: 2010-2012, 2015 Collabora, Ltd. +SPDX-FileCopyrightText: 2010 Jonathan Matthew +SPDX-FileCopyrightText: 2010 Zach Goldberg +SPDX-FileCopyrightText: 2011-2012, 2014 Giovanni Campagna +SPDX-FileCopyrightText: 2011-2013 Martin Pitt +SPDX-FileCopyrightText: 2011 Pavel Holejsovsky +SPDX-FileCopyrightText: 2011, 2024 Red Hat, Inc. +SPDX-FileCopyrightText: 2011 Xavier Claessens +SPDX-FileCopyrightText: 2012 Bastian Winkler +SPDX-FileCopyrightText: 2012 Canonical Ltd. +SPDX-FileCopyrightText: 2012 Coeus Group +SPDX-FileCopyrightText: 2012 Dieter Verfaillie +SPDX-FileCopyrightText: 2012 Jasper St. Pierre +SPDX-FileCopyrightText: 2012 Jon Nordby +SPDX-FileCopyrightText: 2012 Paolo Borelli +SPDX-FileCopyrightText: 2012 Simon Feltman +SPDX-FileCopyrightText: 2012 Torsten Schönfeld +SPDX-FileCopyrightText: 2014-2015 RIFT.io, Inc. +SPDX-FileCopyrightText: 2015, 2018 Christoph Reiter +SPDX-FileCopyrightText: 2015 Debarshi Ray +SPDX-FileCopyrightText: 2015 Ben Iofel +SPDX-FileCopyrightText: 2016 Lionel Landwerlin +SPDX-FileCopyrightText: 2016-2019 Philip Chimento +SPDX-FileCopyrightText: 2017 Endless Mobile, Inc. +SPDX-FileCopyrightText: 2017 Rico Tzschichholz +SPDX-FileCopyrightText: 2018-2019 Tomasz Miąsko +SPDX-FileCopyrightText: 2019, 2021 Emmanuele Bassi +SPDX-FileCopyrightText: 2021, 2023 Marco Trevisan +SPDX-FileCopyrightText: 2023 Evan Welsh +SPDX-FileCopyrightText: 2024 Simon McVittie +*/ + +#include +#include + +#include +#include + +#ifndef GI_TEST_DISABLE_CAIRO +#include +#include +#endif /* GI_TEST_DISABLE_CAIRO */ + +#include "regress.h" + +static gboolean abort_on_error = TRUE; + +#define ASSERT_VALUE(condition) \ + if (abort_on_error) \ + g_assert (condition); \ + else \ + g_warn_if_fail (condition); + +void +regress_set_abort_on_error (gboolean in) +{ + abort_on_error = in; +} + +/* return annotations */ + +/** + * regress_test_return_allow_none: + * + * Returns: (allow-none): + */ +char * +regress_test_return_allow_none (void) +{ + return NULL; +} + +/** + * regress_test_return_nullable: + * + * Returns: (nullable): + */ +char * +regress_test_return_nullable (void) +{ + return NULL; +} + +/* basic types */ +gboolean +regress_test_boolean (gboolean in) +{ + return in; +} + +gboolean +regress_test_boolean_true (gboolean in) +{ + ASSERT_VALUE (in == TRUE); + return in; +} + +gboolean +regress_test_boolean_false (gboolean in) +{ + ASSERT_VALUE (in == FALSE); + return in; +} + +gint8 +regress_test_int8 (gint8 in) +{ + return in; +} + +guint8 +regress_test_uint8 (guint8 in) +{ + return in; +} + +gint16 +regress_test_int16 (gint16 in) +{ + return in; +} + +guint16 +regress_test_uint16 (guint16 in) +{ + return in; +} + +gint32 +regress_test_int32 (gint32 in) +{ + return in; +} + +guint32 +regress_test_uint32 (guint32 in) +{ + return in; +} + +gint64 +regress_test_int64 (gint64 in) +{ + return in; +} + +guint64 +regress_test_uint64 (guint64 in) +{ + return in; +} + +gshort +regress_test_short (gshort in) +{ + return in; +} + +gushort +regress_test_ushort (gushort in) +{ + return in; +} + +gint +regress_test_int (gint in) +{ + return in; +} + +guint +regress_test_uint (guint in) +{ + return in; +} + +glong +regress_test_long (glong in) +{ + return in; +} + +gulong +regress_test_ulong (gulong in) +{ + return in; +} + +gssize +regress_test_ssize (gssize in) +{ + return in; +} + +gsize +regress_test_size (gsize in) +{ + return in; +} + +gfloat +regress_test_float (gfloat in) +{ + return in; +} + +gdouble +regress_test_double (gdouble in) +{ + return in; +} + +gunichar +regress_test_unichar (gunichar in) +{ + return in; +} + +time_t +regress_test_timet (time_t in) +{ + return in; +} + +off_t +regress_test_offt (off_t in) +{ + return in; +} + +GType +regress_test_gtype (GType in) +{ + return in; +} + +int +regress_test_closure (GClosure *closure) +{ + GValue return_value = { + 0, + }; + int ret; + + g_value_init (&return_value, G_TYPE_INT); + + g_closure_invoke (closure, + &return_value, + 0, NULL, + NULL); + + ret = g_value_get_int (&return_value); + + g_value_unset (&return_value); + + return ret; +} + +int +regress_test_closure_one_arg (GClosure *closure, int arg) +{ + GValue return_value = { + 0, + }; + GValue arguments[1]; + int ret; + + g_value_init (&return_value, G_TYPE_INT); + + memset (&arguments[0], 0, sizeof (arguments)); + g_value_init (&arguments[0], G_TYPE_INT); + g_value_set_int (&arguments[0], arg); + + g_closure_invoke (closure, + &return_value, + 1, arguments, + NULL); + + ret = g_value_get_int (&return_value); + + g_value_unset (&return_value); + g_value_unset (&arguments[0]); + + return ret; +} + +/** + * regress_test_closure_variant: + * @closure: GClosure which takes one GVariant and returns a GVariant + * @arg: (allow-none) (transfer none): a GVariant passed as argument to @closure + * + * Return value: (transfer full): the return value of @closure + */ +GVariant * +regress_test_closure_variant (GClosure *closure, GVariant *arg) +{ + GValue return_value = { + 0, + }; + GValue arguments[1] = { { + 0, + } }; + GVariant *ret; + + g_value_init (&return_value, G_TYPE_VARIANT); + + g_value_init (&arguments[0], G_TYPE_VARIANT); + g_value_set_variant (&arguments[0], arg); + + g_closure_invoke (closure, + &return_value, + 1, arguments, + NULL); + + ret = g_value_get_variant (&return_value); + if (ret != NULL) + g_variant_ref (ret); + + g_value_unset (&return_value); + g_value_unset (&arguments[0]); + + return ret; +} + +/** + * regress_test_value_arg: + * @v: (transfer none): a GValue expected to contain an int + * + * Return value: the int contained in the GValue. + */ +int +regress_test_int_value_arg (const GValue *v) +{ + int i; + + i = g_value_get_int (v); + + return i; +} + +static GValue global_value; +/** + * regress_test_value_return: + * @i: an int + * + * Return value: (transfer none): the int wrapped in a GValue. + */ +const GValue * +regress_test_value_return (int i) +{ + memset (&global_value, '\0', sizeof (GValue)); + + g_value_init (&global_value, G_TYPE_INT); + g_value_set_int (&global_value, i); + + return &global_value; +} + +/************************************************************************/ +/* foreign structs */ + +#ifndef GI_TEST_DISABLE_CAIRO +/** + * regress_test_cairo_context_full_return: + * + * Returns: (transfer full): + */ +cairo_t * +regress_test_cairo_context_full_return (void) +{ + cairo_surface_t *surface; + cairo_t *cr; + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 10, 10); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + return cr; +} + +/** + * regress_test_cairo_context_none_in: + * @context: (transfer none): + */ +void +regress_test_cairo_context_none_in (cairo_t *context) +{ + cairo_surface_t *surface = cairo_get_target (context); + + 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); +} + +/** + * regress_test_cairo_surface_none_return: + * + * Returns: (transfer none): + */ +cairo_surface_t * +regress_test_cairo_surface_none_return (void) +{ + static cairo_surface_t *surface; + + if (surface == NULL) + { + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 10, 10); + } + + return surface; +} + +/** + * regress_test_cairo_surface_full_return: + * + * Returns: (transfer full): + */ +cairo_surface_t * +regress_test_cairo_surface_full_return (void) +{ + return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 10, 10); +} + +/** + * regress_test_cairo_surface_none_in: + * @surface: (transfer none): + */ +void +regress_test_cairo_surface_none_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); +} + +/** + * regress_test_cairo_surface_full_out: + * @surface: (out) (transfer full): + */ +void +regress_test_cairo_surface_full_out (cairo_surface_t **surface) +{ + *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 10, 10); +} +#endif /* GI_TEST_DISABLE_CAIRO */ + +/** + * regress_test_gvariant_i: + * + * Returns: (transfer none): New variant + */ +GVariant * +regress_test_gvariant_i (void) +{ + return g_variant_new_int32 (1); +} + +/** + * regress_test_gvariant_s: + * + * Returns: (transfer none): New variant + */ +GVariant * +regress_test_gvariant_s (void) +{ + return g_variant_new_string ("one"); +} + +/** + * regress_test_gvariant_asv: + * + * Returns: (transfer none): New variant + */ +GVariant * +regress_test_gvariant_asv (void) +{ + GVariantBuilder b; + + g_variant_builder_init (&b, G_VARIANT_TYPE ("a{sv}")); + + g_variant_builder_add (&b, "{sv}", "name", g_variant_new_string ("foo")); + g_variant_builder_add (&b, "{sv}", "timeout", g_variant_new_int32 (10)); + + return g_variant_builder_end (&b); +} + +/** + * regress_test_gvariant_v: + * + * Returns: (transfer none): New variant + */ +GVariant * +regress_test_gvariant_v (void) +{ + return g_variant_new_variant (g_variant_new_string ("contents")); +} + +/** + * regress_test_gvariant_as: + * + * Returns: (transfer none): New variant + */ +GVariant * +regress_test_gvariant_as (void) +{ + const char *as[] = { "one", "two", "three", NULL }; + + return g_variant_new_strv (as, -1); +} + +/************************************************************************/ +/* utf8 */ +/* insert BLACK HEART SUIT to ensure UTF-8 doesn't get mangled */ +static const char utf8_const[] = "const \xe2\x99\xa5 utf8"; +static const char utf8_nonconst[] = "nonconst \xe2\x99\xa5 utf8"; + +/** + * regress_test_utf8_const_return: + * + * Return value: UTF-8 string + */ +const char * +regress_test_utf8_const_return (void) +{ + /* transfer mode none */ + return utf8_const; +} + +/** + * regress_test_utf8_nonconst_return: + * + * Return value: (transfer full): UTF-8 string + */ +char * +regress_test_utf8_nonconst_return (void) +{ + return g_strdup (utf8_nonconst); +} + +/** + * regress_test_utf8_const_in: + * + */ +void +regress_test_utf8_const_in (const char *in) +{ + /* transfer mode none */ + g_assert (strcmp (in, utf8_const) == 0); +} + +/** + * regress_test_utf8_out: + * @out: (out) (transfer full): + */ +void +regress_test_utf8_out (char **out) +{ + /* out parameter, transfer mode full */ + *out = g_strdup (utf8_nonconst); +} + +/** + * regress_test_utf8_inout: + * @inout: (inout) (transfer full): + */ +void +regress_test_utf8_inout (char **inout) +{ + /* inout parameter, transfer mode full */ + g_assert (strcmp (*inout, utf8_const) == 0); + g_free (*inout); + *inout = g_strdup (utf8_nonconst); +} + +/** + * regress_test_filename_return: + * + * Return value: (element-type filename) (transfer full): list of strings + */ +GSList * +regress_test_filename_return (void) +{ + GSList *filenames = NULL; + filenames = g_slist_prepend (filenames, g_filename_from_utf8 ("/etc/fstab", -1, NULL, NULL, NULL)); + filenames = g_slist_prepend (filenames, g_filename_from_utf8 ("åäö", -1, NULL, NULL, NULL)); + return filenames; +} + +/* in arguments after out arguments */ + +/** + * regress_test_int_out_utf8: + * @length: (out): + * @in: + */ +void +regress_test_int_out_utf8 (int *length, const char *in) +{ + *length = g_utf8_strlen (in, -1); +} + +/* multiple output arguments */ + +/** + * regress_test_multi_double_args: + * @in: + * @one: (out): + * @two: (out): + */ +void +regress_test_multi_double_args (gdouble in, gdouble *one, gdouble *two) +{ + *one = in * 2; + *two = in * 3; +} + +/** + * regress_test_utf8_out_out: + * @out0: (out) (transfer full): a copy of "first" + * @out1: (out) (transfer full): a copy of "second" + */ +void +regress_test_utf8_out_out (char **out0, char **out1) +{ + *out0 = g_strdup ("first"); + *out1 = g_strdup ("second"); +} + +/** + * regress_test_utf8_out_nonconst_return: + * @out: (out) (transfer full): a copy of "second" + * + * Returns: (transfer full): a copy of "first" + */ +char * +regress_test_utf8_out_nonconst_return (char **out) +{ + *out = g_strdup ("second"); + return g_strdup ("first"); +} + +/** + * regress_test_utf8_null_in: + * @in: (allow-none): + */ +void +regress_test_utf8_null_in (char *in) +{ + g_assert (in == NULL); +} + +/** + * regress_test_utf8_null_out: + * @char_out: (allow-none) (out): + */ +void +regress_test_utf8_null_out (char **char_out) +{ + *char_out = NULL; +} + +/* non-basic-types */ + +static const char *test_sequence[] = { "1", "2", "3" }; + +/* array */ + +/** + * regress_test_array_int_in: + * @n_ints: + * @ints: (array length=n_ints): List of ints + */ +int +regress_test_array_int_in (int n_ints, int *ints) +{ + int i, sum = 0; + for (i = 0; i < n_ints; i++) + sum += ints[i]; + return sum; +} + +/** + * regress_test_array_int_out: + * @n_ints: (out): the length of @ints + * @ints: (out) (array length=n_ints) (transfer full): a list of 5 integers, from 0 to 4 in consecutive order + */ +void +regress_test_array_int_out (int *n_ints, int **ints) +{ + int i; + *n_ints = 5; + *ints = g_malloc0 (sizeof (**ints) * *n_ints); + for (i = 1; i < *n_ints; i++) + (*ints)[i] = (*ints)[i - 1] + 1; +} + +/** + * regress_test_array_int_inout: + * @n_ints: (inout): the length of @ints + * @ints: (inout) (array length=n_ints) (transfer full): a list of integers whose items will be increased by 1, except the first that will be dropped + */ +void +regress_test_array_int_inout (int *n_ints, int **ints) +{ + int i; + int *new_ints; + + if (0 < *n_ints) + { + *n_ints -= 1; + new_ints = g_malloc (sizeof (**ints) * *n_ints); + for (i = 0; i < *n_ints; i++) + new_ints[i] = (*ints)[i + 1] + 1; + + g_free (*ints); + *ints = new_ints; + } +} + +/** + * regress_test_array_gint8_in: + * @n_ints: + * @ints: (array length=n_ints): List of ints + */ +int +regress_test_array_gint8_in (int n_ints, gint8 *ints) +{ + int i, sum = 0; + for (i = 0; i < n_ints; i++) + sum += ints[i]; + return sum; +} + +/** + * regress_test_array_gint16_in: + * @n_ints: + * @ints: (array length=n_ints): List of ints + */ +int +regress_test_array_gint16_in (int n_ints, gint16 *ints) +{ + int i, sum = 0; + for (i = 0; i < n_ints; i++) + sum += ints[i]; + return sum; +} + +/** + * regress_test_array_gint32_in: + * @n_ints: + * @ints: (array length=n_ints): List of ints + */ +gint32 +regress_test_array_gint32_in (int n_ints, gint32 *ints) +{ + int i; + gint32 sum = 0; + for (i = 0; i < n_ints; i++) + sum += ints[i]; + return sum; +} + +/** + * regress_test_array_gint64_in: + * @n_ints: + * @ints: (array length=n_ints): List of ints + */ +gint64 +regress_test_array_gint64_in (int n_ints, gint64 *ints) +{ + int i; + gint64 sum = 0; + for (i = 0; i < n_ints; i++) + sum += ints[i]; + return sum; +} + +/** + * regress_test_strv_in: + * @arr: (array zero-terminated=1) (transfer none): + */ +gboolean +regress_test_strv_in (char **arr) +{ + if (g_strv_length (arr) != 3) + return FALSE; + if (strcmp (arr[0], "1") != 0) + return FALSE; + if (strcmp (arr[1], "2") != 0) + return FALSE; + if (strcmp (arr[2], "3") != 0) + return FALSE; + return TRUE; +} + +/** + * regress_test_array_gtype_in: + * @n_types: + * @types: (array length=n_types): List of types + * + * Return value: (transfer full): string representation of provided types + */ +char * +regress_test_array_gtype_in (int n_types, GType *types) +{ + GString *string; + int i; + + string = g_string_new ("["); + for (i = 0; i < n_types; i++) + { + g_string_append (string, g_type_name (types[i])); + g_string_append_c (string, ','); + } + g_string_append_c (string, ']'); + return g_string_free (string, FALSE); +} + +/** + * regress_test_strv_out: + * + * Returns: (transfer full): + */ +char ** +regress_test_strv_out (void) +{ + int i = 0; + int n = 6; + char **ret = g_new (char *, n); + ret[i++] = g_strdup ("thanks"); + ret[i++] = g_strdup ("for"); + ret[i++] = g_strdup ("all"); + ret[i++] = g_strdup ("the"); + ret[i++] = g_strdup ("fish"); + ret[i++] = NULL; + g_assert (i == n); + return ret; +} + +/** + * regress_test_strv_out_container: + * + * Return value: (array zero-terminated=1) (transfer container): + */ +const char ** +regress_test_strv_out_container (void) +{ + const char **ret = g_new (const char *, 4); + ret[0] = "1"; + ret[1] = "2"; + ret[2] = "3"; + ret[3] = NULL; + return ret; +} + +/** + * regress_test_strv_outarg: + * @retp: (array zero-terminated=1) (out) (transfer container): + */ +void +regress_test_strv_outarg (const char ***retp) +{ + const char **ret = g_new (const char *, 4); + ret[0] = "1"; + ret[1] = "2"; + ret[2] = "3"; + ret[3] = NULL; + *retp = ret; +} + +/** + * regress_test_array_fixed_size_int_in: + * @ints: (array fixed-size=5): a list of 5 integers + * + * Returns: the sum of the items in @ints + */ +int +regress_test_array_fixed_size_int_in (int *ints) +{ + int i, sum = 0; + for (i = 0; i < 5; i++) + sum += ints[i]; + return sum; +} + +/** + * regress_test_array_fixed_size_int_out: + * @ints: (out) (array fixed-size=5) (transfer full): a list of 5 integers ranging from 0 to 4 + */ +void +regress_test_array_fixed_size_int_out (int **ints) +{ + int i; + *ints = g_malloc0 (sizeof (**ints) * 5); + for (i = 1; i < 5; i++) + (*ints)[i] = (*ints)[i - 1] + 1; +} + +/** + * regress_test_array_fixed_size_int_return: + * + * Returns: (array fixed-size=5) (transfer full): a list of 5 integers ranging from 0 to 4 + */ +int * +regress_test_array_fixed_size_int_return (void) +{ + int i, *ints; + ints = g_malloc0 (sizeof (*ints) * 5); + for (i = 1; i < 5; i++) + ints[i] = ints[i - 1] + 1; + return ints; +} + +/** + * regress_test_array_static_in_int + * @x: (array fixed-size=10): a list of 10 integers + */ +#if (defined(__GNUC__) || defined(__clang__)) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +void +regress_test_array_static_in_int (int x[static 10] G_GNUC_UNUSED) +{ +} +#else +void +regress_test_array_static_in_int (int x[10]) +{ +} +#endif + +/** + * regress_test_strv_out_c: + * + * Returns: (transfer none): + */ +const char *const * +regress_test_strv_out_c (void) +{ + static char **ret = NULL; + + if (ret == NULL) + ret = regress_test_strv_out (); + + return (const char *const *) ret; +} + +/** + * regress_test_array_int_full_out: + * @len: length of the returned array. + * + * Returns: (array length=len) (transfer full): a new array of integers. + */ +int * +regress_test_array_int_full_out (int *len) +{ + int *result, i; + *len = 5; + result = g_malloc0 (sizeof (*result) * (*len)); + for (i = 1; i < (*len); i++) + result[i] = result[i - 1] + 1; + return result; +} + +/** + * regress_test_array_int_none_out: + * @len: length of the returned array. + * + * Returns: (array length=len) (transfer none): a static array of integers. + */ +int * +regress_test_array_int_none_out (int *len) +{ + static int result[5] = { 1, 2, 3, 4, 5 }; + *len = 5; + return result; +} + +/** + * regress_test_array_int_null_in: + * @arr: (array length=len) (allow-none): + * @len: length + */ +void +regress_test_array_int_null_in (int *arr, + int len G_GNUC_UNUSED) +{ + g_assert (arr == NULL); +} + +/** + * regress_test_array_int_null_out: + * @arr: (out) (array length=len) (allow-none): + * @len: (out) : length + */ +void +regress_test_array_int_null_out (int **arr, int *len) +{ + *arr = NULL; + *len = 0; +} + +/* interface */ + +/************************************************************************/ +/* GList */ + +static /*const*/ GList * +regress_test_sequence_list (void) +{ + static GList *list = NULL; + if (!list) + { + gsize i; + for (i = 0; i < G_N_ELEMENTS (test_sequence); ++i) + { + list = g_list_prepend (list, (gpointer) test_sequence[i]); + } + list = g_list_reverse (list); + } + return list; +} + +/** + * regress_test_glist_nothing_return: + * + * Return value: (element-type utf8) (transfer none): + */ +const GList * +regress_test_glist_nothing_return (void) +{ + return regress_test_sequence_list (); +} + +/** + * regress_test_glist_nothing_return2: + * + * Return value: (element-type utf8) (transfer none): + */ +GList * +regress_test_glist_nothing_return2 (void) +{ + return regress_test_sequence_list (); +} + +/** + * regress_test_glist_container_return: + * + * Return value: (element-type utf8) (transfer container): + */ +GList * +regress_test_glist_container_return (void) +{ + return g_list_copy (regress_test_sequence_list ()); +} + +/** + * regress_test_glist_everything_return: + * + * Return value: (element-type utf8) (transfer full): + */ +GList * +regress_test_glist_everything_return (void) +{ + GList *list; + GList *l; + + list = g_list_copy (regress_test_sequence_list ()); + for (l = list; l != NULL; l = l->next) + l->data = g_strdup (l->data); + return list; +} + +static void +regress_assert_test_sequence_list (const GList *in) +{ + const GList *l; + gsize i; + + for (i = 0, l = in; l != NULL; ++i, l = l->next) + { + g_assert (i < G_N_ELEMENTS (test_sequence)); + g_assert (strcmp (l->data, test_sequence[i]) == 0); + } + g_assert (i == G_N_ELEMENTS (test_sequence)); +} + +/** + * regress_test_glist_gtype_container_in: + * @in: (element-type GType) (transfer container): + */ +void +regress_test_glist_gtype_container_in (GList *in) +{ + GList *l = in; + + g_assert (GPOINTER_TO_SIZE (l->data) == REGRESS_TEST_TYPE_OBJ); + l = l->next; + g_assert (GPOINTER_TO_SIZE (l->data) == REGRESS_TEST_TYPE_SUB_OBJ); + l = l->next; + g_assert (l == NULL); + + g_list_free (in); +} + +/** + * regress_test_glist_nothing_in: + * @in: (element-type utf8): + */ +void +regress_test_glist_nothing_in (const GList *in) +{ + regress_assert_test_sequence_list (in); +} + +/** + * regress_test_glist_nothing_in2: + * @in: (element-type utf8): + */ +void +regress_test_glist_nothing_in2 (GList *in) +{ + regress_assert_test_sequence_list (in); +} + +/** + * regress_test_glist_null_in: + * @in: (element-type utf8) (allow-none): + */ +void +regress_test_glist_null_in (GSList *in) +{ + g_assert (in == NULL); +} + +/** + * regress_test_glist_null_out: + * @out_list: (out) (element-type utf8) (allow-none): + */ +void +regress_test_glist_null_out (GSList **out_list) +{ + *out_list = NULL; +} + +/************************************************************************/ +/* GSList */ + +static /*const*/ GSList * +regress_test_sequence_slist (void) +{ + static GSList *list = NULL; + if (!list) + { + gsize i; + for (i = 0; i < G_N_ELEMENTS (test_sequence); ++i) + { + list = g_slist_prepend (list, (gpointer) test_sequence[i]); + } + list = g_slist_reverse (list); + } + return list; +} + +/** + * regress_test_gslist_nothing_return: + * + * Return value: (element-type utf8) (transfer none): + */ +const GSList * +regress_test_gslist_nothing_return (void) +{ + return regress_test_sequence_slist (); +} + +/** + * regress_test_gslist_nothing_return2: + * + * Return value: (element-type utf8) (transfer none): + */ +GSList * +regress_test_gslist_nothing_return2 (void) +{ + return regress_test_sequence_slist (); +} + +/** + * regress_test_gslist_container_return: + * + * Return value: (element-type utf8) (transfer container): + */ +GSList * +regress_test_gslist_container_return (void) +{ + return g_slist_copy (regress_test_sequence_slist ()); +} + +/** + * regress_test_gslist_everything_return: + * + * Return value: (element-type utf8) (transfer full): + */ +GSList * +regress_test_gslist_everything_return (void) +{ + GSList *list; + GSList *l; + + list = g_slist_copy (regress_test_sequence_slist ()); + for (l = list; l != NULL; l = l->next) + l->data = g_strdup (l->data); + return list; +} + +static void +regress_assert_test_sequence_slist (const GSList *in) +{ + const GSList *l; + gsize i; + + for (i = 0, l = in; l != NULL; ++i, l = l->next) + { + g_assert (i < G_N_ELEMENTS (test_sequence)); + g_assert (strcmp (l->data, test_sequence[i]) == 0); + } + g_assert (i == G_N_ELEMENTS (test_sequence)); +} + +/** + * regress_test_gslist_nothing_in: + * @in: (element-type utf8): + */ +void +regress_test_gslist_nothing_in (const GSList *in) +{ + regress_assert_test_sequence_slist (in); +} + +/** + * regress_test_gslist_nothing_in2: + * @in: (element-type utf8): + */ +void +regress_test_gslist_nothing_in2 (GSList *in) +{ + regress_assert_test_sequence_slist (in); +} + +/** + * regress_test_gslist_null_in: + * @in: (element-type utf8) (allow-none): + */ +void +regress_test_gslist_null_in (GSList *in) +{ + g_assert (in == NULL); +} + +/** + * regress_test_gslist_null_out: + * @out_list: (out) (element-type utf8) (allow-none): + */ +void +regress_test_gslist_null_out (GSList **out_list) +{ + *out_list = NULL; +} + +/************************************************************************/ +/* GHash */ + +static const char *table_data[3][2] = { + { "foo", "bar" }, { "baz", "bat" }, { "qux", "quux" } +}; + +static GHashTable * +regress_test_table_ghash_new_container (void) +{ + GHashTable *hash; + int i; + hash = g_hash_table_new (g_str_hash, g_str_equal); + for (i = 0; i < 3; i++) + g_hash_table_insert (hash, + (gpointer) table_data[i][0], + (gpointer) table_data[i][1]); + return hash; +} + +static GHashTable * +regress_test_table_ghash_new_full (void) +{ + GHashTable *hash; + int i; + hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + for (i = 0; i < 3; i++) + g_hash_table_insert (hash, + g_strdup (table_data[i][0]), + g_strdup (table_data[i][1])); + return hash; +} + +static /*const*/ GHashTable * +regress_test_table_ghash_const (void) +{ + static GHashTable *hash = NULL; + if (!hash) + { + hash = regress_test_table_ghash_new_container (); + } + return hash; +} + +/** + * regress_test_ghash_null_return: + * + * Return value: (element-type utf8 utf8) (transfer none) (allow-none): + */ +const GHashTable * +regress_test_ghash_null_return (void) +{ + return NULL; +} + +/** + * regress_test_ghash_nothing_return: + * + * Return value: (element-type utf8 utf8) (transfer none): + */ +const GHashTable * +regress_test_ghash_nothing_return (void) +{ + return regress_test_table_ghash_const (); +} + +/** + * regress_test_ghash_nothing_return2: + * + * Return value: (element-type utf8 utf8) (transfer none): + */ +GHashTable * +regress_test_ghash_nothing_return2 (void) +{ + return regress_test_table_ghash_const (); +} + +static GValue * +g_value_new (GType type) +{ + GValue *value = g_slice_new0 (GValue); + g_value_init (value, type); + return value; +} + +static void +g_value_free (GValue *value) +{ + g_value_unset (value); + g_slice_free (GValue, value); +} + +static const gchar *string_array[] = { + "first", + "second", + "third", + NULL +}; + +/** + * regress_test_ghash_gvalue_return: + * + * Return value: (element-type utf8 GValue) (transfer none): + */ +GHashTable * +regress_test_ghash_gvalue_return (void) +{ + static GHashTable *hash = NULL; + + if (hash == NULL) + { + GValue *value; + hash = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) g_value_free); + + value = g_value_new (G_TYPE_INT); + g_value_set_int (value, 12); + g_hash_table_insert (hash, g_strdup ("integer"), value); + + value = g_value_new (G_TYPE_BOOLEAN); + g_value_set_boolean (value, TRUE); + g_hash_table_insert (hash, g_strdup ("boolean"), value); + + value = g_value_new (G_TYPE_STRING); + g_value_set_string (value, "some text"); + g_hash_table_insert (hash, g_strdup ("string"), value); + + value = g_value_new (G_TYPE_STRV); + g_value_set_boxed (value, string_array); + g_hash_table_insert (hash, g_strdup ("strings"), value); + + value = g_value_new (REGRESS_TEST_TYPE_FLAGS); + g_value_set_flags (value, REGRESS_TEST_FLAG1 | REGRESS_TEST_FLAG3); + g_hash_table_insert (hash, g_strdup ("flags"), value); + + value = g_value_new (regress_test_enum_get_type ()); + g_value_set_enum (value, REGRESS_TEST_VALUE2); + g_hash_table_insert (hash, g_strdup ("enum"), value); + } + + return hash; +} + +/** + * regress_test_ghash_gvalue_in: + * @hash: (element-type utf8 GValue): the hash table returned by + * regress_test_ghash_gvalue_return(). + */ +void +regress_test_ghash_gvalue_in (GHashTable *hash) +{ + GValue *value; + const gchar **strings; + int i; + + g_assert (hash != NULL); + + value = g_hash_table_lookup (hash, "integer"); + g_assert (value != NULL); + g_assert (G_VALUE_HOLDS_INT (value)); + g_assert (g_value_get_int (value) == 12); + + value = g_hash_table_lookup (hash, "boolean"); + g_assert (value != NULL); + g_assert (G_VALUE_HOLDS_BOOLEAN (value)); + g_assert (g_value_get_boolean (value) == TRUE); + + value = g_hash_table_lookup (hash, "string"); + g_assert (value != NULL); + g_assert (G_VALUE_HOLDS_STRING (value)); + g_assert (strcmp (g_value_get_string (value), "some text") == 0); + + value = g_hash_table_lookup (hash, "strings"); + g_assert (value != NULL); + g_assert (G_VALUE_HOLDS (value, G_TYPE_STRV)); + strings = g_value_get_boxed (value); + g_assert (strings != NULL); + for (i = 0; string_array[i] != NULL; i++) + g_assert (strcmp (strings[i], string_array[i]) == 0); + + value = g_hash_table_lookup (hash, "flags"); + g_assert (value != NULL); + g_assert (G_VALUE_HOLDS_FLAGS (value)); + g_assert (g_value_get_flags (value) == (REGRESS_TEST_FLAG1 | REGRESS_TEST_FLAG3)); + + value = g_hash_table_lookup (hash, "enum"); + g_assert (value != NULL); + g_assert (G_VALUE_HOLDS_ENUM (value)); + g_assert (g_value_get_enum (value) == REGRESS_TEST_VALUE2); +} + +/** + * regress_test_ghash_container_return: + * + * Return value: (element-type utf8 utf8) (transfer container): + */ +GHashTable * +regress_test_ghash_container_return (void) +{ + return regress_test_table_ghash_new_container (); +} + +/** + * regress_test_ghash_everything_return: + * + * Return value: (element-type utf8 utf8) (transfer full): + */ +GHashTable * +regress_test_ghash_everything_return (void) +{ + return regress_test_table_ghash_new_full (); +} + +static void +assert_test_table_ghash (const GHashTable *in) +{ + GHashTable *h = regress_test_table_ghash_const (); + GHashTableIter iter; + gpointer key, value; + + g_assert (g_hash_table_size (h) == + g_hash_table_size ((GHashTable *) in)); + + g_hash_table_iter_init (&iter, (GHashTable *) in); + while (g_hash_table_iter_next (&iter, &key, &value)) + g_assert (strcmp (g_hash_table_lookup (h, (char *) key), (char *) value) == 0); +} + +/** + * regress_test_ghash_null_in: + * @in: (element-type utf8 utf8) (allow-none): + */ +void +regress_test_ghash_null_in (const GHashTable *in) +{ + g_assert (in == NULL); +} + +/** + * regress_test_ghash_null_out: + * @out: (element-type utf8 utf8) (allow-none) (out): + */ +void +regress_test_ghash_null_out (const GHashTable **out) +{ + *out = NULL; +} + +/** + * regress_test_ghash_nothing_in: + * @in: (element-type utf8 utf8): + */ +void +regress_test_ghash_nothing_in (const GHashTable *in) +{ + assert_test_table_ghash (in); +} + +/** + * regress_test_ghash_nothing_in2: + * @in: (element-type utf8 utf8): + */ +void +regress_test_ghash_nothing_in2 (GHashTable *in) +{ + assert_test_table_ghash (in); +} + +/* Nested collection types */ + +/** + * regress_test_ghash_nested_everything_return: + * + * Specify nested parameterized types directly with the (type ) annotation. + * + * Return value: (type GLib.HashTable>) (transfer full): + */ +GHashTable * +regress_test_ghash_nested_everything_return (void) +{ + GHashTable *hash; + hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, + (void (*) (gpointer)) g_hash_table_destroy); + g_hash_table_insert (hash, g_strdup ("wibble"), regress_test_table_ghash_new_full ()); + return hash; +} + +/** + * regress_test_ghash_nested_everything_return2: + * + * Another way of specifying nested parameterized types: using the + * element-type annotation. + * + * Return value: (element-type utf8 GLib.HashTable) (transfer full): + */ +GHashTable * +regress_test_ghash_nested_everything_return2 (void) +{ + return regress_test_ghash_nested_everything_return (); +} + +/************************************************************************/ + +/** + * regress_test_garray_container_return: + * + * Returns: (transfer container) (type GLib.PtrArray) (element-type utf8): + */ +GPtrArray * +regress_test_garray_container_return (void) +{ + GPtrArray *array; + + array = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (array, g_strdup ("regress")); + + return array; +} + +/** + * regress_test_garray_full_return: + * + * Returns: (transfer full) (type GLib.PtrArray) (element-type utf8): + */ +GPtrArray * +regress_test_garray_full_return (void) +{ + GPtrArray *array; + + array = g_ptr_array_new (); + g_ptr_array_add (array, g_strdup ("regress")); + + return array; +} + +/************************************************************************/ + +/* error? */ + +/* enums / flags */ + +/** + * NUM_REGRESS_FOO: (skip) + * + * num of elements in RegressFoo + */ + +GType +regress_test_enum_get_type (void) +{ + static GType etype = 0; + if (G_UNLIKELY (etype == 0)) + { + static const GEnumValue values[] = { + { REGRESS_TEST_VALUE1, "REGRESS_TEST_VALUE1", "value1" }, + { REGRESS_TEST_VALUE2, "REGRESS_TEST_VALUE2", "value2" }, + { REGRESS_TEST_VALUE3, "REGRESS_TEST_VALUE3", "value3" }, + { REGRESS_TEST_VALUE4, "REGRESS_TEST_VALUE4", "value4" }, + { REGRESS_TEST_VALUE5, "REGRESS_TEST_VALUE5", "value5" }, + { 0, NULL, NULL } + }; + etype = g_enum_register_static (g_intern_static_string ("RegressTestEnum"), values); + } + + return etype; +} + +GType +regress_test_enum_unsigned_get_type (void) +{ + static GType etype = 0; + if (G_UNLIKELY (etype == 0)) + { + static const GEnumValue values[] = { + { REGRESS_TEST_UNSIGNED_VALUE1, "REGRESS_TEST_UNSIGNED_VALUE1", "value1" }, + { REGRESS_TEST_UNSIGNED_VALUE2, "REGRESS_TEST_UNSIGNED_VALUE2", "value2" }, + { 0, NULL, NULL } + }; + etype = g_enum_register_static (g_intern_static_string ("RegressTestEnumUnsigned"), values); + } + + return etype; +} + +GType +regress_test_flags_get_type (void) +{ + static GType etype = 0; + if (G_UNLIKELY (etype == 0)) + { + static const GFlagsValue values[] = { + { REGRESS_TEST_FLAG1, "TEST_FLAG1", "flag1" }, + { REGRESS_TEST_FLAG2, "TEST_FLAG2", "flag2" }, + { REGRESS_TEST_FLAG3, "TEST_FLAG3", "flag3" }, + { 0, NULL, NULL } + }; + etype = g_flags_register_static (g_intern_static_string ("RegressTestFlags"), values); + } + + return etype; +} + +const gchar * +regress_test_enum_param (RegressTestEnum e) +{ + GEnumValue *ev; + GEnumClass *ec; + + ec = g_type_class_ref (regress_test_enum_get_type ()); + ev = g_enum_get_value (ec, e); + g_type_class_unref (ec); + + return ev->value_nick; +} + +const gchar * +regress_test_unsigned_enum_param (RegressTestEnumUnsigned e) +{ + GEnumValue *ev; + GEnumClass *ec; + + ec = g_type_class_ref (regress_test_enum_unsigned_get_type ()); + ev = g_enum_get_value (ec, e); + g_type_class_unref (ec); + + return ev->value_nick; +} + +/** + * regress_global_get_flags_out: + * @v: (out): A flags value + * + */ +void +regress_global_get_flags_out (RegressTestFlags *v) +{ + *v = REGRESS_TEST_FLAG1 | REGRESS_TEST_FLAG3; +} + +/* error domains */ + +GType +regress_test_error_get_type (void) +{ + static GType etype = 0; + if (G_UNLIKELY (etype == 0)) + { + static const GEnumValue values[] = { + { REGRESS_TEST_ERROR_CODE1, "REGRESS_TEST_ERROR_CODE1", "code1" }, + { REGRESS_TEST_ERROR_CODE2, "REGRESS_TEST_ERROR_CODE2", "code2" }, + { REGRESS_TEST_ERROR_CODE3, "REGRESS_TEST_ERROR_CODE3", "code3" }, + { 0, NULL, NULL } + }; + etype = g_enum_register_static (g_intern_static_string ("RegressTestError"), values); + } + + return etype; +} + +GQuark +regress_test_error_quark (void) +{ + return g_quark_from_static_string ("regress-test-error"); +} + +GType +regress_test_abc_error_get_type (void) +{ + static GType etype = 0; + if (G_UNLIKELY (etype == 0)) + { + static const GEnumValue values[] = { + { REGRESS_TEST_ABC_ERROR_CODE1, "REGRESS_TEST_ABC_ERROR_CODE1", "code1" }, + { REGRESS_TEST_ABC_ERROR_CODE2, "REGRESS_TEST_ABC_ERROR_CODE2", "code2" }, + { REGRESS_TEST_ABC_ERROR_CODE3, "REGRESS_TEST_ABC_ERROR_CODE3", "code3" }, + { 0, NULL, NULL } + }; + etype = g_enum_register_static (g_intern_static_string ("RegressTestABCError"), values); + } + + return etype; +} + +GQuark +regress_test_abc_error_quark (void) +{ + return g_quark_from_static_string ("regress-test-abc-error"); +} + +GType +regress_test_unconventional_error_get_type (void) +{ + static GType etype = 0; + if (G_UNLIKELY (etype == 0)) + { + static const GEnumValue values[] = { + { REGRESS_TEST_OTHER_ERROR_CODE1, "REGRESS_TEST_OTHER_ERROR_CODE1", "code1" }, + { REGRESS_TEST_OTHER_ERROR_CODE2, "REGRESS_TEST_OTHER_ERROR_CODE2", "code2" }, + { REGRESS_TEST_OTHER_ERROR_CODE3, "REGRESS_TEST_OTHER_ERROR_CODE3", "code3" }, + { 0, NULL, NULL } + }; + etype = g_enum_register_static (g_intern_static_string ("RegressTestOtherError"), values); + } + + return etype; +} + +GQuark +regress_test_unconventional_error_quark (void) +{ + return g_quark_from_static_string ("regress-test-other-error"); +} + +GQuark +regress_test_def_error_quark (void) +{ + return g_quark_from_static_string ("regress-test-def-error"); +} + +GQuark +regress_atest_error_quark (void) +{ + return g_quark_from_static_string ("regress-atest-error"); +} + +/* structures */ + +/** + * regress_test_struct_a_clone: + * @a: the structure + * @a_out: (out caller-allocates): the cloned structure + * + * Make a copy of a RegressTestStructA + */ +void +regress_test_struct_a_clone (RegressTestStructA *a, + RegressTestStructA *a_out) +{ + *a_out = *a; +} + +/** + * regress_test_struct_a_parse: + * @a_out: (out caller-allocates): the structure that is to be filled + * @string: ignored + */ +void +regress_test_struct_a_parse (RegressTestStructA *a_out, + const gchar *string G_GNUC_UNUSED) +{ + a_out->some_int = 23; +} + +/** + * regress_test_array_struct_out: + * @arr: (out) (array length=len) (transfer full): + * @len: (out) + * + * This is similar to gdk_keymap_get_entries_for_keyval(). + */ +void +regress_test_array_struct_out (RegressTestStructA **arr, int *len) +{ + *arr = g_new0 (RegressTestStructA, 3); + (*arr)[0].some_int = 22; + (*arr)[1].some_int = 33; + (*arr)[2].some_int = 44; + *len = 3; +} + +/** + * regress_test_struct_b_clone: + * @b: the structure + * @b_out: (out): the cloned structure + * + * Make a copy of a RegressTestStructB + */ +void +regress_test_struct_b_clone (RegressTestStructB *b, + RegressTestStructB *b_out) +{ + *b_out = *b; +} + +/* plain-old-data boxed types */ + +RegressTestSimpleBoxedA * +regress_test_simple_boxed_a_copy (RegressTestSimpleBoxedA *a) +{ + RegressTestSimpleBoxedA *new_a = g_slice_new (RegressTestSimpleBoxedA); + + *new_a = *a; + + return new_a; +} + +static void +regress_test_simple_boxed_a_free (RegressTestSimpleBoxedA *a) +{ + g_slice_free (RegressTestSimpleBoxedA, a); +} + +GType +regress_test_simple_boxed_a_get_gtype (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_boxed_type_register_static (g_intern_static_string ("RegressTestSimpleBoxedA"), + (GBoxedCopyFunc) regress_test_simple_boxed_a_copy, + (GBoxedFreeFunc) regress_test_simple_boxed_a_free); + return our_type; +} + +RegressTestSimpleBoxedB * +regress_test_simple_boxed_b_copy (RegressTestSimpleBoxedB *b) +{ + RegressTestSimpleBoxedB *new_b = g_slice_new (RegressTestSimpleBoxedB); + + *new_b = *b; + + return new_b; +} + +gboolean +regress_test_simple_boxed_a_equals (RegressTestSimpleBoxedA *a, + RegressTestSimpleBoxedA *other_a) +{ + return (a->some_int == other_a->some_int && + a->some_int8 == other_a->some_int8 && + a->some_double == other_a->some_double); +} + +const RegressTestSimpleBoxedA * +regress_test_simple_boxed_a_const_return (void) +{ + static RegressTestSimpleBoxedA simple_a = { + 5, 6, 7.0, REGRESS_TEST_VALUE1 + }; + + return &simple_a; +} + +static void +regress_test_simple_boxed_b_free (RegressTestSimpleBoxedB *a) +{ + g_slice_free (RegressTestSimpleBoxedB, a); +} + +GType +regress_test_simple_boxed_b_get_type (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_boxed_type_register_static (g_intern_static_string ("RegressTestSimpleBoxedB"), + (GBoxedCopyFunc) regress_test_simple_boxed_b_copy, + (GBoxedFreeFunc) regress_test_simple_boxed_b_free); + return our_type; +} + +/* opaque boxed */ + +struct _RegressTestBoxedPrivate +{ + guint magic; +}; + +/** + * regress_test_boxed_new: + * + * Returns: (transfer full): + */ +RegressTestBoxed * +regress_test_boxed_new (void) +{ + RegressTestBoxed *boxed = g_slice_new0 (RegressTestBoxed); + boxed->priv = g_slice_new0 (RegressTestBoxedPrivate); + boxed->priv->magic = 0xdeadbeef; + + return boxed; +} + +/** + * regress_test_boxed_new_alternative_constructor1: + * + * Returns: (transfer full): + */ +RegressTestBoxed * +regress_test_boxed_new_alternative_constructor1 (int i) +{ + RegressTestBoxed *boxed = g_slice_new0 (RegressTestBoxed); + boxed->priv = g_slice_new0 (RegressTestBoxedPrivate); + boxed->priv->magic = 0xdeadbeef; + boxed->some_int8 = i; + + return boxed; +} + +/** + * regress_test_boxed_new_alternative_constructor2: + * + * Returns: (transfer full): + */ +RegressTestBoxed * +regress_test_boxed_new_alternative_constructor2 (int i, int j) +{ + RegressTestBoxed *boxed = g_slice_new0 (RegressTestBoxed); + boxed->priv = g_slice_new0 (RegressTestBoxedPrivate); + boxed->priv->magic = 0xdeadbeef; + boxed->some_int8 = i + j; + + return boxed; +} + +/** + * regress_test_boxed_new_alternative_constructor3: + * + * Returns: (transfer full): + */ +RegressTestBoxed * +regress_test_boxed_new_alternative_constructor3 (char *s) +{ + RegressTestBoxed *boxed = g_slice_new0 (RegressTestBoxed); + boxed->priv = g_slice_new0 (RegressTestBoxedPrivate); + boxed->priv->magic = 0xdeadbeef; + boxed->some_int8 = atoi (s); + + return boxed; +} + +/** + * regress_test_boxed_copy: + * + * Returns: (transfer full): + */ +RegressTestBoxed * +regress_test_boxed_copy (RegressTestBoxed *boxed) +{ + RegressTestBoxed *new_boxed = regress_test_boxed_new (); + RegressTestBoxedPrivate *save; + + save = new_boxed->priv; + *new_boxed = *boxed; + new_boxed->priv = save; + + return new_boxed; +} + +gboolean +regress_test_boxed_equals (RegressTestBoxed *boxed, + RegressTestBoxed *other) +{ + return (other->some_int8 == boxed->some_int8 && + regress_test_simple_boxed_a_equals (&other->nested_a, &boxed->nested_a)); +} + +void +regress_test_boxeds_not_a_method (RegressTestBoxed *boxed G_GNUC_UNUSED) +{ +} + +void +regress_test_boxeds_not_a_static (void) +{ +} + +static void +regress_test_boxed_free (RegressTestBoxed *boxed) +{ + g_assert (boxed->priv->magic == 0xdeadbeef); + + g_slice_free (RegressTestBoxedPrivate, boxed->priv); + g_slice_free (RegressTestBoxed, boxed); +} + +GType +regress_test_boxed_get_type (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_boxed_type_register_static (g_intern_static_string ("RegressTestBoxed"), + (GBoxedCopyFunc) regress_test_boxed_copy, + (GBoxedFreeFunc) regress_test_boxed_free); + return our_type; +} + +RegressTestBoxedB * +regress_test_boxed_b_new (gint8 some_int8, glong some_long) +{ + RegressTestBoxedB *boxed; + + boxed = g_slice_new (RegressTestBoxedB); + boxed->some_int8 = some_int8; + boxed->some_long = some_long; + + return boxed; +} + +RegressTestBoxedB * +regress_test_boxed_b_copy (RegressTestBoxedB *boxed) +{ + return regress_test_boxed_b_new (boxed->some_int8, boxed->some_long); +} + +static void +regress_test_boxed_b_free (RegressTestBoxedB *boxed) +{ + g_slice_free (RegressTestBoxedB, boxed); +} + +G_DEFINE_BOXED_TYPE (RegressTestBoxedB, + regress_test_boxed_b, + regress_test_boxed_b_copy, + regress_test_boxed_b_free); + +RegressTestBoxedC * +regress_test_boxed_c_new (void) +{ + RegressTestBoxedC *boxed; + + boxed = g_slice_new (RegressTestBoxedC); + boxed->refcount = 1; + boxed->another_thing = 42; /* what else */ + + return boxed; +} + +static RegressTestBoxedC * +regress_test_boxed_c_ref (RegressTestBoxedC *boxed) +{ + g_atomic_int_inc (&boxed->refcount); + return boxed; +} + +static void +regress_test_boxed_c_unref (RegressTestBoxedC *boxed) +{ + if (g_atomic_int_dec_and_test (&boxed->refcount)) + { + g_slice_free (RegressTestBoxedC, boxed); + } +} + +G_DEFINE_BOXED_TYPE (RegressTestBoxedC, + regress_test_boxed_c, + regress_test_boxed_c_ref, + regress_test_boxed_c_unref); + +struct _RegressTestBoxedD +{ + char *a_string; + gint a_int; +}; + +RegressTestBoxedD * +regress_test_boxed_d_new (const char *a_string, int a_int) +{ + RegressTestBoxedD *boxed; + + boxed = g_slice_new (RegressTestBoxedD); + boxed->a_string = g_strdup (a_string); + boxed->a_int = a_int; + + return boxed; +} + +RegressTestBoxedD * +regress_test_boxed_d_copy (RegressTestBoxedD *boxed) +{ + RegressTestBoxedD *ret; + + ret = g_slice_new (RegressTestBoxedD); + ret->a_string = g_strdup (boxed->a_string); + ret->a_int = boxed->a_int; + + return ret; +} + +void +regress_test_boxed_d_free (RegressTestBoxedD *boxed) +{ + g_free (boxed->a_string); + g_slice_free (RegressTestBoxedD, boxed); +} + +int +regress_test_boxed_d_get_magic (RegressTestBoxedD *boxed) +{ + return strlen (boxed->a_string) + boxed->a_int; +} + +G_DEFINE_BOXED_TYPE (RegressTestBoxedD, + regress_test_boxed_d, + regress_test_boxed_d_copy, + regress_test_boxed_d_free); + +G_DEFINE_TYPE (RegressTestObj, regress_test_obj, G_TYPE_OBJECT); + +enum +{ + PROP_TEST_OBJ_BARE = 1, + PROP_TEST_OBJ_BOXED, + PROP_TEST_OBJ_HASH_TABLE, + PROP_TEST_OBJ_LIST, + PROP_TEST_OBJ_PPTRARRAY, + PROP_TEST_OBJ_HASH_TABLE_OLD, + PROP_TEST_OBJ_LIST_OLD, + PROP_TEST_OBJ_INT, + PROP_TEST_OBJ_FLOAT, + PROP_TEST_OBJ_DOUBLE, + PROP_TEST_OBJ_STRING, + PROP_TEST_OBJ_GTYPE, + PROP_TEST_OBJ_NAME_CONFLICT, + PROP_TEST_OBJ_BYTE_ARRAY, + PROP_TEST_OBJ_WRITE_ONLY, +}; + +static void +regress_test_obj_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + RegressTestObj *self = REGRESS_TEST_OBJECT (object); + GList *list; + + switch (property_id) + { + case PROP_TEST_OBJ_BARE: + regress_test_obj_set_bare (self, g_value_get_object (value)); + break; + + case PROP_TEST_OBJ_BOXED: + if (self->boxed) + regress_test_boxed_free (self->boxed); + self->boxed = g_value_dup_boxed (value); + break; + + case PROP_TEST_OBJ_HASH_TABLE: + case PROP_TEST_OBJ_HASH_TABLE_OLD: + if (self->hash_table) + g_hash_table_unref (self->hash_table); + self->hash_table = g_hash_table_ref (g_value_get_boxed (value)); + break; + + case PROP_TEST_OBJ_LIST: + case PROP_TEST_OBJ_LIST_OLD: + g_list_free_full (self->list, g_free); + list = g_value_get_pointer (value); + self->list = g_list_copy_deep (list, (GCopyFunc) (void *) g_strdup, NULL); + break; + + case PROP_TEST_OBJ_INT: + self->some_int8 = g_value_get_int (value); + break; + + case PROP_TEST_OBJ_FLOAT: + self->some_float = g_value_get_float (value); + break; + + case PROP_TEST_OBJ_DOUBLE: + self->some_double = g_value_get_double (value); + break; + + case PROP_TEST_OBJ_STRING: + g_clear_pointer (&self->string, g_free); + self->string = g_value_dup_string (value); + break; + + case PROP_TEST_OBJ_GTYPE: + self->gtype = g_value_get_gtype (value); + break; + + case PROP_TEST_OBJ_NAME_CONFLICT: + self->name_conflict = g_value_get_int (value); + break; + + case PROP_TEST_OBJ_BYTE_ARRAY: + self->byte_array = g_value_get_boxed (value); + break; + + case PROP_TEST_OBJ_WRITE_ONLY: + if (g_value_get_boolean (value)) + self->some_int8 = 0; + break; + + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +regress_test_obj_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + RegressTestObj *self = REGRESS_TEST_OBJECT (object); + + switch (property_id) + { + case PROP_TEST_OBJ_BARE: + g_value_set_object (value, self->bare); + break; + + case PROP_TEST_OBJ_BOXED: + g_value_set_boxed (value, self->boxed); + break; + + case PROP_TEST_OBJ_HASH_TABLE: + case PROP_TEST_OBJ_HASH_TABLE_OLD: + if (self->hash_table != NULL) + g_hash_table_ref (self->hash_table); + g_value_set_boxed (value, self->hash_table); + break; + + case PROP_TEST_OBJ_LIST: + case PROP_TEST_OBJ_LIST_OLD: + g_value_set_pointer (value, self->list); + break; + + case PROP_TEST_OBJ_INT: + g_value_set_int (value, self->some_int8); + break; + + case PROP_TEST_OBJ_FLOAT: + g_value_set_float (value, self->some_float); + break; + + case PROP_TEST_OBJ_DOUBLE: + g_value_set_double (value, self->some_double); + break; + + case PROP_TEST_OBJ_STRING: + g_value_set_string (value, self->string); + break; + + case PROP_TEST_OBJ_GTYPE: + g_value_set_gtype (value, self->gtype); + break; + + case PROP_TEST_OBJ_NAME_CONFLICT: + g_value_set_int (value, self->name_conflict); + break; + + case PROP_TEST_OBJ_BYTE_ARRAY: + g_value_set_boxed (value, self->byte_array); + break; + + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +regress_test_obj_dispose (GObject *gobject) +{ + RegressTestObj *self = REGRESS_TEST_OBJECT (gobject); + + if (self->bare) + { + g_object_unref (self->bare); + + self->bare = NULL; + } + + if (self->boxed) + { + regress_test_boxed_free (self->boxed); + self->boxed = NULL; + } + + if (self->list) + { + g_list_free_full (self->list, g_free); + self->list = NULL; + } + + g_clear_pointer (&self->hash_table, g_hash_table_unref); + g_clear_pointer (&self->string, g_free); + + /* Chain up to the parent class */ + G_OBJECT_CLASS (regress_test_obj_parent_class)->dispose (gobject); +} + +static int +regress_test_obj_default_matrix (RegressTestObj *obj G_GNUC_UNUSED, + const char *somestr G_GNUC_UNUSED) +{ + return 42; +} + +enum +{ + REGRESS_TEST_OBJ_SIGNAL_SIG_NEW_WITH_ARRAY_PROP, + REGRESS_TEST_OBJ_SIGNAL_SIG_NEW_WITH_ARRAY_LEN_PROP, + REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_HASH_PROP, + REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_STRV, + REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_STRV_FULL, + REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_OBJ, + REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_OBJ_FULL, + REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_FOREIGN_STRUCT, + REGRESS_TEST_OBJ_SIGNAL_FIRST, + REGRESS_TEST_OBJ_SIGNAL_CLEANUP, + REGRESS_TEST_OBJ_SIGNAL_ALL, + REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_INT64_PROP, + REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_UINT64_PROP, + REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_INTARRAY_RET, + REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_INOUT_INT, + REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_GERROR, + N_REGRESS_TEST_OBJ_SIGNALS +}; + +static guint regress_test_obj_signals[N_REGRESS_TEST_OBJ_SIGNALS] = { 0 }; + +static void +regress_test_obj_class_init (RegressTestObjClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + GType param_types[1]; + + klass->test_signal = + g_signal_newv ("test", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + NULL /* closure */, + NULL /* accumulator */, + NULL /* accumulator data */, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE /* return_type */, + 0 /* n_params */, + NULL /* param_types */); + + param_types[0] = regress_test_simple_boxed_a_get_gtype () | G_SIGNAL_TYPE_STATIC_SCOPE; + klass->test_signal_with_static_scope_arg = + g_signal_newv ("test-with-static-scope-arg", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + NULL /* closure */, + NULL /* accumulator */, + NULL /* accumulator data */, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE /* return_type */, + 1 /* n_params */, + param_types); + + /** + * RegressTestObj::sig-with-array-prop: + * @self: an object + * @arr: (type GArray) (element-type uint): numbers + * + * This test signal is like TelepathyGlib's + * TpChannel:: group-members-changed-detailed: + */ + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_SIG_NEW_WITH_ARRAY_PROP] = + g_signal_new ("sig-with-array-prop", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, + 1, + G_TYPE_ARRAY); + + /** + * RegressTestObj::sig-with-array-len-prop: + * @self: an object + * @arr: (array length=len) (element-type uint) (allow-none): numbers, or %NULL + * @len: length of @arr, or 0 + * + * This test signal similar to GSettings::change-event. + * You can use this with regress_test_obj_emit_sig_with_array_len_prop(), or + * raise from the introspection client language. + */ + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_SIG_NEW_WITH_ARRAY_LEN_PROP] = + g_signal_new ("sig-with-array-len-prop", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 2, + G_TYPE_POINTER, + G_TYPE_INT); + + /** + * RegressTestObj::sig-with-hash-prop: + * @self: an object + * @hash: (element-type utf8 GObject.Value): + * + * This test signal is like TelepathyGlib's + * TpAccount::status-changed + */ + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_HASH_PROP] = + g_signal_new ("sig-with-hash-prop", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, + 1, + G_TYPE_HASH_TABLE); + + /** + * RegressTestObj::sig-with-strv: + * @self: an object + * @strs: strings + * + * Test GStrv as a param. + */ + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_STRV] = + g_signal_new ("sig-with-strv", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, + 1, + G_TYPE_STRV); + + /** + * RegressTestObj::sig-with-strv-full: + * @self: an object + * @strs: (transfer full): strings + * + * Test GStrv as a param. + */ + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_STRV_FULL] = + g_signal_new ("sig-with-strv-full", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, + 1, + G_TYPE_STRV); + + /** + * RegressTestObj::sig-with-obj: + * @self: an object + * @obj: (transfer none): A newly created RegressTestObj + * + * Test transfer none GObject as a param (tests refcounting). + * Use with regress_test_obj_emit_sig_with_obj + */ + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_OBJ] = + g_signal_new ("sig-with-obj", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + G_TYPE_OBJECT); + + /** + * RegressTestObj::sig-with-obj-full: + * @self: an object + * @obj: (transfer full): A newly created RegressTestObj + * + * Test transfer full GObject as a param (tests refcounting). + * Use with regress_test_obj_emit_sig_with_obj_full + */ + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_OBJ_FULL] = + g_signal_new ("sig-with-obj-full", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + G_TYPE_OBJECT); + +#ifndef GI_TEST_DISABLE_CAIRO + /** + * RegressTestObj::sig-with-foreign-struct: + * @self: an object + * @cr: (transfer none): A cairo context. + */ + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_FOREIGN_STRUCT] = + g_signal_new ("sig-with-foreign-struct", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 1, + CAIRO_GOBJECT_TYPE_CONTEXT); +#endif /* GI_TEST_DISABLE_CAIRO */ + + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_FIRST] = + g_signal_new ("first", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_CLEANUP] = + g_signal_new ("cleanup", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_CLEANUP, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_ALL] = + g_signal_new ("all", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_ACTION | G_SIGNAL_NO_HOOKS, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + /** + * RegressTestObj::sig-with-int64-prop: + * @self: an object + * @i: an integer + * + * You can use this with regress_test_obj_emit_sig_with_int64, or raise from + * the introspection client langage. + */ + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_INT64_PROP] = + g_signal_new ("sig-with-int64-prop", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_INT64, + 1, + G_TYPE_INT64); + + /** + * RegressTestObj::sig-with-uint64-prop: + * @self: an object + * @i: an integer + * + * You can use this with regress_test_obj_emit_sig_with_uint64, or raise from + * the introspection client langage. + */ + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_UINT64_PROP] = + g_signal_new ("sig-with-uint64-prop", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_UINT64, + 1, + G_TYPE_UINT64); + + /** + * RegressTestObj::sig-with-intarray-ret: + * @self: an object + * @i: an integer + * + * Returns: (array zero-terminated=1) (element-type gint) (transfer full): + */ + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_INTARRAY_RET] = + g_signal_new ("sig-with-intarray-ret", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_ARRAY, + 1, + G_TYPE_INT); + + /** + * RegressTestObj::sig-with-inout-int + * @self: The object that emitted the signal + * @position: (inout) (type int): The position, in characters, at which to + * insert the new text. This is an in-out paramter. After the signal + * emission is finished, it should point after the newly inserted text. + * + * This signal is modeled after GtkEditable::insert-text. + */ + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_INOUT_INT] = + g_signal_new ("sig-with-inout-int", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); + + /** + * RegressTestObj::sig-with-gerror: + * @self: The object that emitted the signal + * @error: (nullable) (type GLib.Error): A #GError if something went wrong + * internally in @self. You must not free this #GError. + * + * This signal is modeled after #GstDiscoverer::discovered, and is added to + * exercise the path of a #GError being marshalled as a boxed type instead of + * an exception in the introspected language. + * + * Use via regress_test_obj_emit_sig_with_error() and + * regress_test_obj_emit_sig_with_null_error(), or emit via the introspected + * language. + */ + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_GERROR] = + g_signal_new ("sig-with-gerror", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, + g_cclosure_marshal_generic, G_TYPE_NONE, 1, + G_TYPE_ERROR | G_SIGNAL_TYPE_STATIC_SCOPE); + + gobject_class->set_property = regress_test_obj_set_property; + gobject_class->get_property = regress_test_obj_get_property; + gobject_class->dispose = regress_test_obj_dispose; + + pspec = g_param_spec_object ("bare", + "Bare property", + "A contained object", + G_TYPE_OBJECT, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_TEST_OBJ_BARE, + pspec); + + pspec = g_param_spec_boxed ("boxed", + "Boxed property", + "A contained boxed struct", + REGRESS_TEST_TYPE_BOXED, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_TEST_OBJ_BOXED, + pspec); + + /** + * RegressTestObj:hash-table: (type GLib.HashTable(utf8,gint8)) (transfer container) + */ + pspec = g_param_spec_boxed ("hash-table", + "GHashTable property", + "A contained GHashTable", + G_TYPE_HASH_TABLE, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_TEST_OBJ_HASH_TABLE, + pspec); + + /** + * RegressTestObj:list: (type GLib.List(utf8)) (transfer none) (default-value NULL) + */ + pspec = g_param_spec_pointer ("list", + "GList property", + "A contained GList", + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_TEST_OBJ_LIST, + pspec); + + /** + * RegressTestObj:pptrarray: (type GLib.PtrArray(utf8)) (transfer none) + */ + pspec = g_param_spec_pointer ("pptrarray", + "PtrArray property as a pointer", + "Test annotating with GLib.PtrArray", + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_TEST_OBJ_PPTRARRAY, + pspec); + + /** + * RegressTestObj:hash-table-old: (type GLib.HashTable) (transfer container) + */ + pspec = g_param_spec_boxed ("hash-table-old", + "GHashTable property with <>", + "A contained GHashTable with <>", + G_TYPE_HASH_TABLE, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_TEST_OBJ_HASH_TABLE_OLD, + pspec); + + /** + * RegressTestObj:list-old: (type GLib.List) (transfer none) + */ + pspec = g_param_spec_pointer ("list-old", + "GList property with ()", + "A contained GList with <>", + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_TEST_OBJ_LIST_OLD, + pspec); + + /** + * RegressTestObj:int: + */ + pspec = g_param_spec_int ("int", + "int property", + "A contained int", + G_MININT, + G_MAXINT, + 0, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_TEST_OBJ_INT, + pspec); + + /** + * RegressTestObj:float: + */ + pspec = g_param_spec_float ("float", + "float property", + "A contained float", + G_MINFLOAT, + G_MAXFLOAT, + 1.0f, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_TEST_OBJ_FLOAT, + pspec); + + /** + * RegressTestObj:double: + */ + pspec = g_param_spec_double ("double", + "double property", + "A contained double", + G_MINDOUBLE, + G_MAXDOUBLE, + 1.0, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_TEST_OBJ_DOUBLE, + pspec); + + /** + * RegressTestObj:string: (setter set_string) (getter get_string) + */ + pspec = g_param_spec_string ("string", + "string property", + "A contained string", + NULL, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_TEST_OBJ_STRING, + pspec); + + /** + * RegressTestObj:gtype: (default-value G_TYPE_INVALID) + */ + pspec = g_param_spec_gtype ("gtype", + "GType property", + "A GType property", + G_TYPE_NONE, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_TEST_OBJ_GTYPE, + pspec); + + /** + * RegressTestObj:name-conflict: + */ + pspec = g_param_spec_int ("name-conflict", + "name-conflict property", + "A property name that conflicts with a method", + G_MININT, + G_MAXINT, + 42, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_TEST_OBJ_NAME_CONFLICT, + pspec); + + /** + * RegressTestObj:byte-array: + */ + pspec = g_param_spec_boxed ("byte-array", + "GByteArray property", + "A contained byte array without any element-type annotations", + G_TYPE_BYTE_ARRAY, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT); + g_object_class_install_property (gobject_class, + PROP_TEST_OBJ_BYTE_ARRAY, + pspec); + + /** + * RegressTestObj:write-only: + */ + pspec = g_param_spec_boolean ("write-only", "Write-only property", + "A write-only bool property that resets the value of TestObj:int to 0 when true", + FALSE, G_PARAM_WRITABLE); + g_object_class_install_property (gobject_class, PROP_TEST_OBJ_WRITE_ONLY, pspec); + + klass->matrix = regress_test_obj_default_matrix; +} + +static void +regress_test_obj_init (RegressTestObj *obj) +{ + obj->bare = NULL; + obj->boxed = NULL; + obj->hash_table = NULL; + obj->gtype = G_TYPE_INVALID; +} + +/** + * regress_test_obj_new: (constructor) + * @obj: A #RegressTestObj + */ +RegressTestObj * +regress_test_obj_new (RegressTestObj *obj G_GNUC_UNUSED) +{ + return g_object_new (REGRESS_TEST_TYPE_OBJ, NULL); +} + +/** + * regress_constructor: (constructor) + * + */ +RegressTestObj * +regress_constructor (void) +{ + return g_object_new (REGRESS_TEST_TYPE_OBJ, NULL); +} + +/** + * regress_test_obj_new_from_file: + */ +RegressTestObj * +regress_test_obj_new_from_file (const char *x G_GNUC_UNUSED, + GError **error G_GNUC_UNUSED) +{ + return g_object_new (REGRESS_TEST_TYPE_OBJ, NULL); +} + +/** + * regress_test_obj_set_bare: + * @bare: (allow-none): + */ +void +regress_test_obj_set_bare (RegressTestObj *obj, GObject *bare) +{ + if (obj->bare) + g_object_unref (obj->bare); + obj->bare = bare; + if (obj->bare) + g_object_ref (obj->bare); +} + +/** + * regress_test_obj_set_string: (set-property string) + * @obj: + * @str: + */ +void +regress_test_obj_set_string (RegressTestObj *obj, const char *str) +{ + if (g_strcmp0 (str, obj->string) == 0) + return; + + g_free (obj->string); + obj->string = g_strdup (str); + g_object_notify (G_OBJECT (obj), "string"); +} + +/** + * regress_test_obj_get_string: (get-property string) + * @obj: + * + * Returns: (transfer none): + */ +const char * +regress_test_obj_get_string (RegressTestObj *obj) +{ + return obj->string; +} + +void +regress_test_obj_emit_sig_with_obj (RegressTestObj *obj) +{ + RegressTestObj *obj_param = regress_constructor (); + g_object_set (obj_param, "int", 3, NULL); + g_signal_emit_by_name (obj, "sig-with-obj", obj_param); + g_object_unref (obj_param); +} + +void +regress_test_obj_emit_sig_with_obj_full (RegressTestObj *obj) +{ + RegressTestObj *obj_param = regress_constructor (); + g_object_set (obj_param, "int", 5, NULL); + g_signal_emit (obj, + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_OBJ_FULL], + 0, g_steal_pointer (&obj_param)); +} + +void +regress_test_obj_emit_sig_with_gstrv_full (RegressTestObj *obj) +{ + GStrvBuilder *builder = g_strv_builder_new (); + g_strv_builder_add_many (builder, "foo", "bar", "baz", NULL); + g_signal_emit (obj, + regress_test_obj_signals[REGRESS_TEST_OBJ_SIGNAL_SIG_WITH_STRV_FULL], + 0, g_strv_builder_end (builder)); + g_strv_builder_unref (builder); +} + +#ifndef GI_TEST_DISABLE_CAIRO +void +regress_test_obj_emit_sig_with_foreign_struct (RegressTestObj *obj) +{ + cairo_t *cr = regress_test_cairo_context_full_return (); + g_signal_emit_by_name (obj, "sig-with-foreign-struct", cr); + cairo_destroy (cr); +} +#endif /* GI_TEST_DISABLE_CAIRO */ + +void +regress_test_obj_emit_sig_with_int64 (RegressTestObj *obj) +{ + gint64 ret = 0; + RegressTestObj *obj_param = regress_constructor (); + g_signal_emit_by_name (obj, "sig-with-int64-prop", G_MAXINT64, &ret); + g_object_unref (obj_param); + g_assert (ret == G_MAXINT64); +} + +void +regress_test_obj_emit_sig_with_uint64 (RegressTestObj *obj) +{ + guint64 ret = 0; + RegressTestObj *obj_param = regress_constructor (); + g_signal_emit_by_name (obj, "sig-with-uint64-prop", G_MAXUINT64, &ret); + g_object_unref (obj_param); + g_assert (ret == G_MAXUINT64); +} + +/** + * regress_test_obj_emit_sig_with_array_len_prop: + */ +void +regress_test_obj_emit_sig_with_array_len_prop (RegressTestObj *obj) +{ + int arr[] = { 0, 1, 2, 3, 4 }; + g_signal_emit_by_name (obj, "sig-with-array-len-prop", &arr, 5); +} + +/** + * regress_test_obj_emit_sig_with_inout_int: + * @obj: The object to emit the signal. + * + * The signal handler must increment the inout parameter by 1. + */ +void +regress_test_obj_emit_sig_with_inout_int (RegressTestObj *obj) +{ + int inout = 42; + g_signal_emit_by_name (obj, "sig-with-inout-int", &inout); + g_assert_cmpint (inout, ==, 43); +} + +/** + * regress_test_obj_emit_sig_with_error: + * @self: The object to emit the signal. + */ +void +regress_test_obj_emit_sig_with_error (RegressTestObj *self) +{ + GError *err = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, + "Something failed"); + g_signal_emit_by_name (self, "sig-with-gerror", err); + g_error_free (err); +} + +/** + * regress_test_obj_emit_sig_with_null_error: + * @self: The object to emit the signal. + */ +void +regress_test_obj_emit_sig_with_null_error (RegressTestObj *self) +{ + g_signal_emit_by_name (self, "sig-with-gerror", NULL); +} + +int +regress_test_obj_instance_method (RegressTestObj *obj G_GNUC_UNUSED) +{ + return -1; +} + +/** + * regress_test_obj_instance_method_full: + * @obj: (transfer full): + * + */ +void +regress_test_obj_instance_method_full (RegressTestObj *obj) +{ + g_object_unref (obj); +} + +double +regress_test_obj_static_method (int x) +{ + return x; +} + +/** + * regress_forced_method: (method) + * @obj: A #RegressTestObj + * + */ +void +regress_forced_method (RegressTestObj *obj G_GNUC_UNUSED) +{ +} + +/** + * regress_test_obj_torture_signature_0: + * @obj: A #RegressTestObj + * @x: + * @y: (out): + * @z: (out): + * @foo: + * @q: (out): + * @m: + * + */ +void +regress_test_obj_torture_signature_0 (RegressTestObj *obj G_GNUC_UNUSED, + int x, + double *y, + int *z, + const char *foo, + int *q, + guint m) +{ + *y = x; + *z = x * 2; + *q = g_utf8_strlen (foo, -1) + m; +} + +/** + * regress_test_obj_torture_signature_1: + * @obj: A #RegressTestObj + * @x: + * @y: (out): + * @z: (out): + * @foo: + * @q: (out): + * @m: + * @error: A #GError + * + * This function throws an error if m is odd. + */ +gboolean +regress_test_obj_torture_signature_1 (RegressTestObj *obj G_GNUC_UNUSED, + int x, + double *y, + int *z, + const char *foo, + int *q, + guint m, + GError **error) +{ + *y = x; + *z = x * 2; + *q = g_utf8_strlen (foo, -1) + m; + if (m % 2 == 0) + return TRUE; + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "m is odd"); + return FALSE; +} + +/** + * regress_test_obj_skip_return_val: + * @obj: a #RegressTestObj + * @a: Parameter. + * @out_b: (out): A return value. + * @c: Other parameter. + * @inout_d: (inout): Will be incremented. + * @out_sum: (out): Return value. + * @num1: Number. + * @num2: Number. + * @error: Return location for error. + * + * Check that the return value is skipped + * + * Returns: (skip): %TRUE if the call succeeds, %FALSE if @error is set. + */ +gboolean +regress_test_obj_skip_return_val (RegressTestObj *obj G_GNUC_UNUSED, + gint a, + gint *out_b, + gdouble c G_GNUC_UNUSED, + gint *inout_d, + gint *out_sum, + gint num1, + gint num2, + GError **error G_GNUC_UNUSED) +{ + if (out_b != NULL) + *out_b = a + 1; + if (inout_d != NULL) + *inout_d = *inout_d + 1; + if (out_sum != NULL) + *out_sum = num1 + 10 * num2; + return TRUE; +} + +/** + * regress_test_obj_skip_return_val_no_out: + * @obj: a #RegressTestObj + * @a: Parameter. + * @error: Return location for error. + * + * Check that the return value is skipped. Succeed if a is nonzero, otherwise + * raise an error. + * + * Returns: (skip): %TRUE if the call succeeds, %FALSE if @error is set. + */ +gboolean +regress_test_obj_skip_return_val_no_out (RegressTestObj *obj G_GNUC_UNUSED, + gint a, + GError **error) +{ + if (a == 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "a is zero"); + return FALSE; + } + else + { + return TRUE; + } +} + +/** + * regress_test_obj_skip_param: + * @obj: A #RegressTestObj. + * @a: Parameter. + * @out_b: (out): Return value. + * @c: (skip): Other parameter. + * @inout_d: (inout): Will be incremented. + * @out_sum: (out): Return value. + * @num1: Number. + * @num2: Number. + * @error: Return location for error. + * + * Check that a parameter is skipped + * + * Returns: %TRUE if the call succeeds, %FALSE if @error is set. + */ +gboolean +regress_test_obj_skip_param (RegressTestObj *obj G_GNUC_UNUSED, + gint a, + gint *out_b, + gdouble c G_GNUC_UNUSED, + gint *inout_d, + gint *out_sum, + gint num1, + gint num2, + GError **error G_GNUC_UNUSED) +{ + if (out_b != NULL) + *out_b = a + 1; + if (inout_d != NULL) + *inout_d = *inout_d + 1; + if (out_sum != NULL) + *out_sum = num1 + 10 * num2; + return TRUE; +} + +/** + * regress_test_obj_skip_out_param: + * @obj: A #RegressTestObj. + * @a: Parameter. + * @out_b: (out) (skip): Return value. + * @c: Other parameter. + * @inout_d: (inout): Will be incremented. + * @out_sum: (out): Return value. + * @num1: Number. + * @num2: Number. + * @error: Return location for error. + * + * Check that the out value is skipped + * + * Returns: %TRUE if the call succeeds, %FALSE if @error is set. + */ +gboolean +regress_test_obj_skip_out_param (RegressTestObj *obj G_GNUC_UNUSED, + gint a, + gint *out_b, + gdouble c G_GNUC_UNUSED, + gint *inout_d, + gint *out_sum, + gint num1, + gint num2, + GError **error G_GNUC_UNUSED) +{ + if (out_b != NULL) + *out_b = a + 1; + if (inout_d != NULL) + *inout_d = *inout_d + 1; + if (out_sum != NULL) + *out_sum = num1 + 10 * num2; + return TRUE; +} + +/** + * regress_test_obj_skip_inout_param: + * @obj: A #RegressTestObj. + * @a: Parameter. + * @out_b: (out): Return value. + * @c: Other parameter. + * @inout_d: (inout) (skip): Will be incremented. + * @out_sum: (out): Return value. + * @num1: Number. + * @num2: Number. + * @error: Return location for error. + * + * Check that the out value is skipped + * + * Returns: %TRUE if the call succeeds, %FALSE if @error is set. + */ +gboolean +regress_test_obj_skip_inout_param (RegressTestObj *obj G_GNUC_UNUSED, + gint a, + gint *out_b, + gdouble c G_GNUC_UNUSED, + gint *inout_d, + gint *out_sum, + gint num1, + gint num2, + GError **error G_GNUC_UNUSED) +{ + if (out_b != NULL) + *out_b = a + 1; + if (inout_d != NULL) + *inout_d = *inout_d + 1; + if (out_sum != NULL) + *out_sum = num1 + 10 * num2; + return TRUE; +} + +/** + * regress_test_obj_do_matrix: (virtual matrix) + * @obj: A #RegressTestObj + * @somestr: Meaningless string + * + * This method is virtual. Notably its name differs from the virtual + * slot name, which makes it useful for testing bindings handle this + * case. + */ +int +regress_test_obj_do_matrix (RegressTestObj *obj, const char *somestr) +{ + return REGRESS_TEST_OBJ_GET_CLASS (obj)->matrix (obj, somestr); +} + +/** + * regress_func_obj_null_in: + * @obj: (allow-none): A #RegressTestObj + */ +void +regress_func_obj_null_in (RegressTestObj *obj G_GNUC_UNUSED) +{ +} + +/** + * regress_test_obj_null_out: + * @obj: (allow-none) (out): A #RegressTestObj + */ +void +regress_test_obj_null_out (RegressTestObj **obj) +{ + if (obj) + *obj = NULL; +} + +/** + * regress_func_obj_nullable_in: + * @obj: (nullable): A #RegressTestObj + */ +void +regress_func_obj_nullable_in (RegressTestObj *obj G_GNUC_UNUSED) +{ +} + +/** + * regress_test_obj_not_nullable_typed_gpointer_in: + * @obj: A #RegressTestObj + * @input: (type GObject): some #GObject + */ +void +regress_test_obj_not_nullable_typed_gpointer_in (RegressTestObj *obj G_GNUC_UNUSED, + gpointer input G_GNUC_UNUSED) +{ +} + +/** + * regress_test_obj_not_nullable_element_typed_gpointer_in: + * @obj: A #RegressTestObj + * @input: (element-type guint8) (array length=count): some uint8 array + * @count: length of @input + */ +void +regress_test_obj_not_nullable_element_typed_gpointer_in (RegressTestObj *obj G_GNUC_UNUSED, + gpointer input G_GNUC_UNUSED, + guint count G_GNUC_UNUSED) +{ +} + +/** + * regress_test_obj_name_conflict: + * @obj: A #RegressTestObj + */ +void +regress_test_obj_name_conflict (RegressTestObj *obj G_GNUC_UNUSED) +{ +} + +/** + * regress_test_array_fixed_out_objects: + * @objs: (out) (array fixed-size=2) (transfer full): An array of #RegressTestObj + */ +void +regress_test_array_fixed_out_objects (RegressTestObj ***objs) +{ + RegressTestObj **values = (RegressTestObj **) g_new (gpointer, 2); + + values[0] = regress_constructor (); + values[1] = regress_constructor (); + + *objs = values; +} + +typedef struct _CallbackInfo CallbackInfo; + +struct _CallbackInfo +{ + RegressTestCallbackUserData callback; + GDestroyNotify notify; + gpointer user_data; +}; + +static void +regress_test_sub_obj_iface_init (RegressTestInterfaceIface *iface G_GNUC_UNUSED) +{ +} + +enum +{ + PROP_TEST_SUB_OBJ_NUMBER = 1, + PROP_TEST_SUB_OBJ_BOOLEAN, +}; + +G_DEFINE_TYPE_WITH_CODE (RegressTestSubObj, regress_test_sub_obj, REGRESS_TEST_TYPE_OBJ, G_IMPLEMENT_INTERFACE (REGRESS_TEST_TYPE_INTERFACE, regress_test_sub_obj_iface_init)); + +static void +regress_test_sub_obj_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + RegressTestSubObj *self = REGRESS_TEST_SUB_OBJECT (object); + + switch (property_id) + { + case PROP_TEST_SUB_OBJ_NUMBER: + self->number = g_value_get_int (value); + break; + + case PROP_TEST_SUB_OBJ_BOOLEAN: + self->boolean = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +regress_test_sub_obj_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + RegressTestSubObj *self = REGRESS_TEST_SUB_OBJECT (object); + + switch (property_id) + { + case PROP_TEST_SUB_OBJ_NUMBER: + g_value_set_int (value, self->number); + break; + + case PROP_TEST_SUB_OBJ_BOOLEAN: + g_value_set_boolean (value, self->boolean); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +regress_test_sub_obj_class_init (RegressTestSubObjClass *klass) +{ + const guint flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS; + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + gobject_class->get_property = regress_test_sub_obj_get_property; + gobject_class->set_property = regress_test_sub_obj_set_property; + + g_object_class_install_property (gobject_class, PROP_TEST_SUB_OBJ_BOOLEAN, + g_param_spec_boolean ("boolean", "Boolean", "Boolean", + TRUE, flags)); + + g_object_class_override_property (gobject_class, PROP_TEST_SUB_OBJ_NUMBER, + "number"); +} + +static void +regress_test_sub_obj_init (RegressTestSubObj *self G_GNUC_UNUSED) +{ +} + +RegressTestObj * +regress_test_sub_obj_new (void) +{ + return g_object_new (REGRESS_TEST_TYPE_SUB_OBJ, NULL); +} + +int +regress_test_sub_obj_instance_method (RegressTestSubObj *self G_GNUC_UNUSED) +{ + return 0; +} + +void +regress_test_sub_obj_unset_bare (RegressTestSubObj *obj) +{ + regress_test_obj_set_bare (REGRESS_TEST_OBJECT (obj), NULL); +} + +/* RegressTestFundamental */ + +/** + * regress_test_fundamental_object_ref: + * + * Returns: (transfer full): A new #RegressTestFundamentalObject + */ +RegressTestFundamentalObject * +regress_test_fundamental_object_ref (RegressTestFundamentalObject *fundamental_object) +{ + g_return_val_if_fail (fundamental_object != NULL, NULL); + g_atomic_int_inc (&fundamental_object->refcount); + + return fundamental_object; +} + +static void +regress_test_fundamental_object_free (RegressTestFundamentalObject *fundamental_object) +{ + RegressTestFundamentalObjectClass *mo_class; + regress_test_fundamental_object_ref (fundamental_object); + + mo_class = REGRESS_TEST_FUNDAMENTAL_OBJECT_GET_CLASS (fundamental_object); + mo_class->finalize (fundamental_object); + + if (G_LIKELY (g_atomic_int_dec_and_test (&fundamental_object->refcount))) + { + g_type_free_instance ((GTypeInstance *) fundamental_object); + } +} + +void +regress_test_fundamental_object_unref (RegressTestFundamentalObject *fundamental_object) +{ + g_return_if_fail (fundamental_object != NULL); + g_return_if_fail (fundamental_object->refcount > 0); + + if (G_UNLIKELY (g_atomic_int_dec_and_test (&fundamental_object->refcount))) + { + regress_test_fundamental_object_free (fundamental_object); + } +} + +static void +regress_test_fundamental_object_replace (RegressTestFundamentalObject **olddata, RegressTestFundamentalObject *newdata) +{ + RegressTestFundamentalObject *olddata_val; + + g_return_if_fail (olddata != NULL); + + olddata_val = g_atomic_pointer_get ((gpointer *) olddata); + + if (olddata_val == newdata) + return; + + if (newdata) + regress_test_fundamental_object_ref (newdata); + + while (!g_atomic_pointer_compare_and_exchange ((gpointer *) olddata, + olddata_val, newdata)) + { + olddata_val = g_atomic_pointer_get ((gpointer *) olddata); + } + + if (olddata_val) + regress_test_fundamental_object_unref (olddata_val); +} + +static void +regress_test_value_fundamental_object_init (GValue *value) +{ + value->data[0].v_pointer = NULL; +} + +static void +regress_test_value_fundamental_object_free (GValue *value) +{ + if (value->data[0].v_pointer) + { + regress_test_fundamental_object_unref (REGRESS_TEST_FUNDAMENTAL_OBJECT_CAST (value->data[0].v_pointer)); + } +} + +static void +regress_test_value_fundamental_object_copy (const GValue *src_value, GValue *dest_value) +{ + if (src_value->data[0].v_pointer) + { + dest_value->data[0].v_pointer = + regress_test_fundamental_object_ref (REGRESS_TEST_FUNDAMENTAL_OBJECT_CAST (src_value->data[0].v_pointer)); + } + else + { + dest_value->data[0].v_pointer = NULL; + } +} + +static gpointer +regress_test_value_fundamental_object_peek_pointer (const GValue *value) +{ + return value->data[0].v_pointer; +} + +static gchar * +regress_test_value_fundamental_object_collect (GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags G_GNUC_UNUSED) +{ + g_assert (n_collect_values > 0); + + if (collect_values[0].v_pointer) + { + value->data[0].v_pointer = + regress_test_fundamental_object_ref (collect_values[0].v_pointer); + } + else + { + value->data[0].v_pointer = NULL; + } + + return NULL; +} + +static gchar * +regress_test_value_fundamental_object_lcopy (const GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags) +{ + gpointer *fundamental_object_p; + + g_assert (n_collect_values > 0); + + fundamental_object_p = collect_values[0].v_pointer; + + if (!fundamental_object_p) + { + return g_strdup_printf ("value location for '%s' passed as NULL", + G_VALUE_TYPE_NAME (value)); + } + + if (!value->data[0].v_pointer) + *fundamental_object_p = NULL; + else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) + *fundamental_object_p = value->data[0].v_pointer; + else + *fundamental_object_p = regress_test_fundamental_object_ref (value->data[0].v_pointer); + + return NULL; +} + +static void +regress_test_fundamental_object_finalize (RegressTestFundamentalObject *self G_GNUC_UNUSED) +{ +} + +static RegressTestFundamentalObject * +regress_test_fundamental_object_copy_default (const RegressTestFundamentalObject *self G_GNUC_UNUSED) +{ + g_warning ("RegressTestFundamentalObject classes must implement RegressTestFundamentalObject::copy"); + return NULL; +} + +static void +regress_test_fundamental_object_class_init (gpointer g_class, + gpointer class_data G_GNUC_UNUSED) +{ + RegressTestFundamentalObjectClass *mo_class = REGRESS_TEST_FUNDAMENTAL_OBJECT_CLASS (g_class); + + mo_class->copy = regress_test_fundamental_object_copy_default; + mo_class->finalize = regress_test_fundamental_object_finalize; +} + +static void +regress_test_fundamental_object_init (GTypeInstance *instance, + gpointer klass G_GNUC_UNUSED) +{ + RegressTestFundamentalObject *fundamental_object = REGRESS_TEST_FUNDAMENTAL_OBJECT_CAST (instance); + + fundamental_object->refcount = 1; +} + +/** + * RegressTestFundamentalObject: (ref-func regress_test_fundamental_object_ref) (unref-func regress_test_fundamental_object_unref) (set-value-func regress_test_value_set_fundamental_object) (get-value-func regress_test_value_get_fundamental_object) + */ + +GType +regress_test_fundamental_object_get_type (void) +{ + static GType _test_fundamental_object_type = 0; + + if (G_UNLIKELY (_test_fundamental_object_type == 0)) + { + static const GTypeValueTable value_table = { + regress_test_value_fundamental_object_init, + regress_test_value_fundamental_object_free, + regress_test_value_fundamental_object_copy, + regress_test_value_fundamental_object_peek_pointer, + (char *) "p", + regress_test_value_fundamental_object_collect, + (char *) "p", + regress_test_value_fundamental_object_lcopy + }; + static const GTypeInfo fundamental_object_info = { + sizeof (RegressTestFundamentalObjectClass), + NULL, NULL, + regress_test_fundamental_object_class_init, + NULL, + NULL, + sizeof (RegressTestFundamentalObject), + 0, + (GInstanceInitFunc) regress_test_fundamental_object_init, + &value_table + }; + static const GTypeFundamentalInfo fundamental_object_fundamental_info = { + (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | + G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) + }; + + _test_fundamental_object_type = g_type_fundamental_next (); + g_type_register_fundamental (_test_fundamental_object_type, "RegressTestFundamentalObject", + &fundamental_object_info, &fundamental_object_fundamental_info, G_TYPE_FLAG_ABSTRACT); + } + + return _test_fundamental_object_type; +} + +/** + * regress_test_value_set_fundamental_object: (skip) + * @value: + * @fundamental_object: + */ +void +regress_test_value_set_fundamental_object (GValue *value, RegressTestFundamentalObject *fundamental_object) +{ + gpointer *pointer_p; + + g_return_if_fail (REGRESS_TEST_VALUE_HOLDS_FUNDAMENTAL_OBJECT (value)); + g_return_if_fail (fundamental_object == NULL || REGRESS_TEST_IS_FUNDAMENTAL_OBJECT (fundamental_object)); + + pointer_p = &value->data[0].v_pointer; + + regress_test_fundamental_object_replace ((RegressTestFundamentalObject **) pointer_p, fundamental_object); +} + +/** + * regress_test_value_get_fundamental_object: (skip) + * @value: + */ +RegressTestFundamentalObject * +regress_test_value_get_fundamental_object (const GValue *value) +{ + g_return_val_if_fail (REGRESS_TEST_VALUE_HOLDS_FUNDAMENTAL_OBJECT (value), NULL); + + return value->data[0].v_pointer; +} + +static RegressTestFundamentalObjectClass *parent_class = NULL; + +G_DEFINE_TYPE (RegressTestFundamentalSubObject, regress_test_fundamental_sub_object, REGRESS_TEST_TYPE_FUNDAMENTAL_OBJECT); + +static RegressTestFundamentalSubObject * +_regress_test_fundamental_sub_object_copy (RegressTestFundamentalSubObject *fundamental_sub_object) +{ + RegressTestFundamentalSubObject *copy; + + copy = regress_test_fundamental_sub_object_new (NULL); + copy->data = g_strdup (fundamental_sub_object->data); + return copy; +} + +static void +regress_test_fundamental_sub_object_finalize (RegressTestFundamentalSubObject *fundamental_sub_object) +{ + g_return_if_fail (fundamental_sub_object != NULL); + + g_free (fundamental_sub_object->data); + regress_test_fundamental_object_finalize (REGRESS_TEST_FUNDAMENTAL_OBJECT (fundamental_sub_object)); +} + +static void +regress_test_fundamental_sub_object_class_init (RegressTestFundamentalSubObjectClass *klass) +{ + parent_class = g_type_class_peek_parent (klass); + + klass->fundamental_object_class.copy = (RegressTestFundamentalObjectCopyFunction) _regress_test_fundamental_sub_object_copy; + klass->fundamental_object_class.finalize = + (RegressTestFundamentalObjectFinalizeFunction) regress_test_fundamental_sub_object_finalize; +} + +static void +regress_test_fundamental_sub_object_init (RegressTestFundamentalSubObject *self G_GNUC_UNUSED) +{ +} + +/** + * regress_test_fundamental_sub_object_new: + */ +RegressTestFundamentalSubObject * +regress_test_fundamental_sub_object_new (const char *data) +{ + RegressTestFundamentalSubObject *object; + + object = (RegressTestFundamentalSubObject *) g_type_create_instance (regress_test_fundamental_sub_object_get_type ()); + object->data = g_strdup (data); + return object; +} + +/**/ + +#define regress_test_fundamental_hidden_sub_object_get_type \ + _regress_test_fundamental_hidden_sub_object_get_type + +GType regress_test_fundamental_hidden_sub_object_get_type (void); + +typedef struct _RegressTestFundamentalHiddenSubObject RegressTestFundamentalHiddenSubObject; +typedef struct _GObjectClass RegressTestFundamentalHiddenSubObjectClass; +struct _RegressTestFundamentalHiddenSubObject +{ + RegressTestFundamentalObject parent_instance; +}; + +G_DEFINE_TYPE (RegressTestFundamentalHiddenSubObject, + regress_test_fundamental_hidden_sub_object, + REGRESS_TEST_TYPE_FUNDAMENTAL_OBJECT); + +static void +regress_test_fundamental_hidden_sub_object_init (RegressTestFundamentalHiddenSubObject *self G_GNUC_UNUSED) +{ +} + +static void +regress_test_fundamental_hidden_sub_object_class_init (RegressTestFundamentalHiddenSubObjectClass *klass G_GNUC_UNUSED) +{ +} + +/** + * regress_test_create_fundamental_hidden_class_instance: + * + * Return value: (transfer full): + */ +RegressTestFundamentalObject * +regress_test_create_fundamental_hidden_class_instance (void) +{ + return (RegressTestFundamentalObject *) g_type_create_instance (_regress_test_fundamental_hidden_sub_object_get_type ()); +} + +/** + * RegressTestFundamentalObjectNoGetSetFunc: (ref-func regress_test_fundamental_object_ref) (unref-func regress_test_fundamental_object_unref) + * + * Just like a #RegressTestFundamentalObject but without gvalue setter and getter + */ + +static void +regress_test_fundamental_object_no_get_set_func_finalize (RegressTestFundamentalObjectNoGetSetFunc *self) +{ + g_clear_pointer (&self->data, g_free); +} + +static RegressTestFundamentalObjectNoGetSetFunc * +regress_test_fundamental_object_no_get_set_func_copy (RegressTestFundamentalObjectNoGetSetFunc *self) +{ + return regress_test_fundamental_object_no_get_set_func_new (self->data); +} + +static void +regress_test_fundamental_object_no_get_set_func_class_init (gpointer g_class, + gpointer class_data G_GNUC_UNUSED) +{ + RegressTestFundamentalObjectClass *mo_class = (RegressTestFundamentalObjectClass *) (g_class); + + mo_class->copy = (RegressTestFundamentalObjectCopyFunction) regress_test_fundamental_object_no_get_set_func_copy; + mo_class->finalize = (RegressTestFundamentalObjectFinalizeFunction) regress_test_fundamental_object_no_get_set_func_finalize; +} + +static void +regress_test_fundamental_object_no_get_set_func_init (GTypeInstance *instance, + gpointer klass G_GNUC_UNUSED) +{ + RegressTestFundamentalObject *object = (RegressTestFundamentalObject *) (instance); + object->refcount = 1; +} + +GType +regress_test_fundamental_object_no_get_set_func_get_type (void) +{ + static GType _test_fundamental_object_type = 0; + + if (G_UNLIKELY (_test_fundamental_object_type == 0)) + { + static const GTypeValueTable value_table = { + regress_test_value_fundamental_object_init, + regress_test_value_fundamental_object_free, + regress_test_value_fundamental_object_copy, + regress_test_value_fundamental_object_peek_pointer, + (char *) "p", + regress_test_value_fundamental_object_collect, + (char *) "p", + regress_test_value_fundamental_object_lcopy + }; + static const GTypeInfo fundamental_object_info = { + sizeof (RegressTestFundamentalObjectNoGetSetFuncClass), + NULL, NULL, + regress_test_fundamental_object_no_get_set_func_class_init, + NULL, + NULL, + sizeof (RegressTestFundamentalObjectNoGetSetFunc), + 0, + (GInstanceInitFunc) regress_test_fundamental_object_no_get_set_func_init, + &value_table + }; + static const GTypeFundamentalInfo fundamental_object_fundamental_info = { + (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | + G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) + }; + + _test_fundamental_object_type = g_type_fundamental_next (); + g_type_register_fundamental (_test_fundamental_object_type, "RegressTestFundamentalObjectNoGetSetFunc", + &fundamental_object_info, &fundamental_object_fundamental_info, 0); + } + + return _test_fundamental_object_type; +} + +/** + * regress_test_fundamental_object_no_get_set_func_new: + * + * Return value: (transfer full): + */ +RegressTestFundamentalObjectNoGetSetFunc * +regress_test_fundamental_object_no_get_set_func_new (const char *data) +{ + RegressTestFundamentalObjectNoGetSetFunc *object; + + object = (RegressTestFundamentalObjectNoGetSetFunc *) g_type_create_instance (regress_test_fundamental_object_no_get_set_func_get_type ()); + object->data = g_strdup (data); + + return object; +} + +const char * +regress_test_fundamental_object_no_get_set_func_get_data (RegressTestFundamentalObjectNoGetSetFunc *fundamental) +{ + g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (fundamental, regress_test_fundamental_object_no_get_set_func_get_type ()), NULL); + + return fundamental->data; +} + +G_DEFINE_TYPE (RegressTestFundamentalSubObjectNoGetSetFunc, regress_test_fundamental_sub_object_no_get_set_func, regress_test_fundamental_object_no_get_set_func_get_type ()); + +static void +regress_test_fundamental_sub_object_no_get_set_func_class_init (RegressTestFundamentalSubObjectNoGetSetFuncClass *klass G_GNUC_UNUSED) +{ +} + +static void +regress_test_fundamental_sub_object_no_get_set_func_init (RegressTestFundamentalSubObjectNoGetSetFunc *self G_GNUC_UNUSED) +{ +} + +/** + * regress_test_fundamental_sub_object_no_get_set_func_new: + * + * Return value: (transfer full): + */ +RegressTestFundamentalSubObjectNoGetSetFunc * +regress_test_fundamental_sub_object_no_get_set_func_new (const char *data) +{ + RegressTestFundamentalSubObjectNoGetSetFunc *object; + RegressTestFundamentalObjectNoGetSetFunc *parent_object; + + object = (RegressTestFundamentalSubObjectNoGetSetFunc *) g_type_create_instance (regress_test_fundamental_sub_object_no_get_set_func_get_type ()); + parent_object = (RegressTestFundamentalObjectNoGetSetFunc *) object; + parent_object->data = g_strdup (data); + + return object; +} + +static void +fundamental_object_no_get_set_func_transform_to_compatible_with_fundamental_sub_object (const GValue *src_value, + GValue *dest_value) +{ + RegressTestFundamentalObjectNoGetSetFunc *src_object; + RegressTestFundamentalSubObject *dest_object; + + g_return_if_fail (G_VALUE_TYPE (src_value) == regress_test_fundamental_object_no_get_set_func_get_type ()); + g_return_if_fail (G_VALUE_TYPE (dest_value) == regress_test_fundamental_sub_object_get_type ()); + + src_object = g_value_peek_pointer (src_value); + dest_object = regress_test_fundamental_sub_object_new (src_object->data); + + g_value_set_instance (dest_value, dest_object); + regress_test_fundamental_object_unref ((RegressTestFundamentalObject *) dest_object); +} + +void +regress_test_fundamental_object_no_get_set_func_make_compatible_with_fundamental_sub_object (void) +{ + g_value_register_transform_func ( + regress_test_fundamental_object_no_get_set_func_get_type (), + regress_test_fundamental_sub_object_get_type (), + fundamental_object_no_get_set_func_transform_to_compatible_with_fundamental_sub_object); +} + +/** + * regress_test_callback: + * @callback: (scope call) (allow-none): + * + **/ +int +regress_test_callback (RegressTestCallback callback) +{ + if (callback != NULL) + return callback (); + return 0; +} + +/** + * regress_test_multi_callback: + * @callback: (scope call) (allow-none): + * + **/ +int +regress_test_multi_callback (RegressTestCallback callback) +{ + int sum = 0; + if (callback != NULL) + { + sum += callback (); + sum += callback (); + } + + return sum; +} + +/** + * regress_test_array_callback: + * @callback: (scope call): + * + **/ +int +regress_test_array_callback (RegressTestCallbackArray callback) +{ + static const char *strings[] = { "one", "two", "three" }; + static int ints[] = { -1, 0, 1, 2 }; + int sum = 0; + + sum += callback (ints, 4, strings, 3); + sum += callback (ints, 4, strings, 3); + + return sum; +} + +/** + * regress_test_array_inout_callback: + * @callback: (scope call): + * + */ +int +regress_test_array_inout_callback (RegressTestCallbackArrayInOut callback) +{ + int *ints; + int length; + + ints = g_new (int, 5); + for (length = 0; length < 5; ++length) + ints[length] = length - 2; + + callback (&ints, &length); + + g_assert_cmpint (length, ==, 4); + for (length = 0; length < 4; ++length) + g_assert_cmpint (ints[length], ==, length - 1); + + callback (&ints, &length); + + g_assert_cmpint (length, ==, 3); + for (length = 0; length < 3; ++length) + g_assert_cmpint (ints[length], ==, length); + + g_free (ints); + return length; +} + +/** + * regress_test_simple_callback: + * @callback: (scope call) (allow-none): + * + **/ +void +regress_test_simple_callback (RegressTestSimpleCallback callback) +{ + if (callback != NULL) + callback (); + + return; +} + +/** + * regress_test_noptr_callback: + * @callback: (scope call) (allow-none): + * + **/ +void +regress_test_noptr_callback (RegressTestNoPtrCallback callback) +{ + if (callback != NULL) + callback (); + + return; +} + +/** + * regress_test_callback_user_data: + * @callback: (scope call): + * @user_data: (not nullable): + * + * Call - callback parameter persists for the duration of the method + * call and can be released on return. + **/ +int +regress_test_callback_user_data (RegressTestCallbackUserData callback, + gpointer user_data) +{ + return callback (user_data); +} + +/** + * regress_test_callback_return_full: + * @callback: (scope call): + * + **/ +void +regress_test_callback_return_full (RegressTestCallbackReturnFull callback) +{ + RegressTestObj *obj; + + obj = callback (); + g_object_unref (obj); +} + +static GSList *notified_callbacks = NULL; + +/** + * regress_test_callback_destroy_notify: + * @callback: (scope notified): + * + * Notified - callback persists until a DestroyNotify delegate + * is invoked. + **/ +int +regress_test_callback_destroy_notify (RegressTestCallbackUserData callback, + gpointer user_data, + GDestroyNotify notify) +{ + int retval; + CallbackInfo *info; + + retval = callback (user_data); + + info = g_slice_new (CallbackInfo); + info->callback = callback; + info->notify = notify; + info->user_data = user_data; + + notified_callbacks = g_slist_prepend (notified_callbacks, info); + + return retval; +} + +/** + * regress_test_callback_destroy_notify_no_user_data: + * @callback: (scope notified): + * + * Adds a scope notified callback with no user data. This can invoke an error + * condition in bindings which needs to be tested. + **/ +int +regress_test_callback_destroy_notify_no_user_data (RegressTestCallbackUserData callback, + GDestroyNotify notify) +{ + return regress_test_callback_destroy_notify (callback, NULL, notify); +} + +/** + * regress_test_callback_thaw_notifications: + * + * Invokes all callbacks installed by #test_callback_destroy_notify(), + * adding up their return values, and removes them, invoking the + * corresponding destroy notfications. + * + * Return value: Sum of the return values of the invoked callbacks. + */ +int +regress_test_callback_thaw_notifications (void) +{ + int retval = 0; + GSList *node; + + for (node = notified_callbacks; node != NULL; node = node->next) + { + CallbackInfo *info = node->data; + retval += info->callback (info->user_data); + if (info->notify) + info->notify (info->user_data); + g_slice_free (CallbackInfo, info); + } + + g_slist_free (notified_callbacks); + notified_callbacks = NULL; + + return retval; +} + +static GSList *async_callbacks = NULL; + +/** + * regress_test_callback_async: + * @callback: (scope async): + * + **/ +void +regress_test_callback_async (RegressTestCallbackUserData callback, + gpointer user_data) +{ + CallbackInfo *info; + + info = g_slice_new (CallbackInfo); + info->callback = callback; + info->user_data = user_data; + + async_callbacks = g_slist_prepend (async_callbacks, info); +} + +/** + * regress_test_callback_thaw_async: + */ +int +regress_test_callback_thaw_async (void) +{ + int retval = 0; + GSList *node; + + for (node = async_callbacks; node != NULL; node = node->next) + { + CallbackInfo *info = node->data; + retval = info->callback (info->user_data); + g_slice_free (CallbackInfo, info); + } + + g_slist_free (async_callbacks); + async_callbacks = NULL; + return retval; +} + +void +regress_test_async_ready_callback (GAsyncReadyCallback callback) +{ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + GSimpleAsyncResult *result = g_simple_async_result_new (NULL, callback, NULL, + regress_test_async_ready_callback); + g_simple_async_result_complete_in_idle (result); + g_object_unref (result); + G_GNUC_END_IGNORE_DEPRECATIONS +} + +/** + * regress_test_function_async: + * + */ +void +regress_test_function_async (int io_priority G_GNUC_UNUSED, + GCancellable *cancellable G_GNUC_UNUSED, + GAsyncReadyCallback callback G_GNUC_UNUSED, + gpointer user_data G_GNUC_UNUSED) +{ +} + +/** + * regress_test_function_finish: + * + */ +gboolean +regress_test_function_finish (GAsyncResult *res G_GNUC_UNUSED, GError **error G_GNUC_UNUSED) +{ + return TRUE; +} + +/** + * regress_test_function_sync: + * + */ +gboolean +regress_test_function_sync (int io_priority G_GNUC_UNUSED) +{ + return TRUE; +} + +/** + * regress_test_obj_instance_method_callback: + * @callback: (scope call) (allow-none): + * + **/ +void +regress_test_obj_instance_method_callback (RegressTestObj *self G_GNUC_UNUSED, + RegressTestCallback callback) +{ + if (callback != NULL) + callback (); +} + +/** + * regress_test_obj_static_method_callback: + * @callback: (scope call) (allow-none): + * + **/ +void +regress_test_obj_static_method_callback (RegressTestCallback callback) +{ + if (callback != NULL) + callback (); +} + +/** + * regress_test_obj_new_callback: + * @callback: (scope notified): + **/ +RegressTestObj * +regress_test_obj_new_callback (RegressTestCallbackUserData callback, gpointer user_data, GDestroyNotify notify) +{ + CallbackInfo *info; + + callback (user_data); + + info = g_slice_new (CallbackInfo); + info->callback = callback; + info->notify = notify; + info->user_data = user_data; + + notified_callbacks = g_slist_prepend (notified_callbacks, info); + + return g_object_new (REGRESS_TEST_TYPE_OBJ, NULL); +} + +/** + * regress_test_obj_new_async: + * + */ +void +regress_test_obj_new_async (const char *x G_GNUC_UNUSED, + GCancellable *cancellable G_GNUC_UNUSED, + GAsyncReadyCallback callback G_GNUC_UNUSED, + gpointer user_data G_GNUC_UNUSED) +{ +} + +/** + * regress_test_obj_new_finish: + * + */ +RegressTestObj * +regress_test_obj_new_finish (GAsyncResult *res G_GNUC_UNUSED, + GError **error G_GNUC_UNUSED) +{ + return g_object_new (REGRESS_TEST_TYPE_OBJ, NULL); +} + +/** + * regress_test_hash_table_callback: + * @data: (element-type utf8 gint): GHashTable that gets passed to callback + * @callback: (scope call): + **/ +void +regress_test_hash_table_callback (GHashTable *data, RegressTestCallbackHashtable callback) +{ + callback (data); +} + +/** + * regress_test_gerror_callback: + * @callback: (scope call): + **/ +void +regress_test_gerror_callback (RegressTestCallbackGError callback) +{ + GError *error; + + error = g_error_new_literal (G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "regression test error"); + callback (error); + g_error_free (error); +} + +/** + * regress_test_null_gerror_callback: + * @callback: (scope call): + **/ +void +regress_test_null_gerror_callback (RegressTestCallbackGError callback) +{ + callback (NULL); +} + +/** + * regress_test_owned_gerror_callback: + * @callback: (scope call): + **/ +void +regress_test_owned_gerror_callback (RegressTestCallbackOwnedGError callback) +{ + GError *error; + + error = g_error_new_literal (G_IO_ERROR, + G_IO_ERROR_PERMISSION_DENIED, + "regression test owned error"); + callback (error); +} + +/** + * regress_test_skip_unannotated_callback: (skip) + * @callback: No annotation here + * + * Should not emit a warning: + * https://bugzilla.gnome.org/show_bug.cgi?id=685399 + */ +void +regress_test_skip_unannotated_callback (RegressTestCallback callback G_GNUC_UNUSED) +{ +} + +/* interface */ + +typedef RegressTestInterfaceIface RegressTestInterfaceInterface; +G_DEFINE_INTERFACE (RegressTestInterface, regress_test_interface, G_TYPE_OBJECT) + +static void +regress_test_interface_default_init (RegressTestInterfaceIface *iface) +{ + const guint flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS; + static gboolean initialized = FALSE; + if (initialized) + return; + + /** + * RegressTestInterface::interface-signal: + * @self: the object which emitted the signal + * @ptr: (type int): the code must look up the signal with + * g_interface_info_find_signal() in order to get this to work. + */ + g_signal_new ("interface-signal", REGRESS_TEST_TYPE_INTERFACE, + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_POINTER); + + /** + * RegressTestInterface:number: + */ + g_object_interface_install_property (iface, + g_param_spec_int ("number", "Number", "Number", + 0, 10, 0, flags)); + + initialized = TRUE; +} + +/** + * regress_test_interface_emit_signal: + * @self: the object to emit the signal + */ +void +regress_test_interface_emit_signal (RegressTestInterface *self) +{ + g_signal_emit_by_name (self, "interface-signal", NULL); +} + +/* gobject with non-standard prefix */ +G_DEFINE_TYPE (RegressTestWi8021x, regress_test_wi_802_1x, G_TYPE_OBJECT); + +enum +{ + PROP_TEST_WI_802_1X_TESTBOOL = 1 +}; + +static void +regress_test_wi_802_1x_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + RegressTestWi8021x *self = REGRESS_TEST_WI_802_1X (object); + + switch (property_id) + { + case PROP_TEST_WI_802_1X_TESTBOOL: + regress_test_wi_802_1x_set_testbool (self, g_value_get_boolean (value)); + break; + + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +regress_test_wi_802_1x_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + RegressTestWi8021x *self = REGRESS_TEST_WI_802_1X (object); + + switch (property_id) + { + case PROP_TEST_WI_802_1X_TESTBOOL: + g_value_set_boolean (value, regress_test_wi_802_1x_get_testbool (self)); + break; + + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +regress_test_wi_802_1x_dispose (GObject *gobject) +{ + /* Chain up to the parent class */ + G_OBJECT_CLASS (regress_test_wi_802_1x_parent_class)->dispose (gobject); +} + +static void +regress_test_wi_802_1x_class_init (RegressTestWi8021xClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + gobject_class->set_property = regress_test_wi_802_1x_set_property; + gobject_class->get_property = regress_test_wi_802_1x_get_property; + gobject_class->dispose = regress_test_wi_802_1x_dispose; + + pspec = g_param_spec_boolean ("testbool", + "Nick for testbool", + "Blurb for testbool", + TRUE, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_TEST_WI_802_1X_TESTBOOL, + pspec); +} + +static void +regress_test_wi_802_1x_init (RegressTestWi8021x *obj) +{ + obj->testbool = TRUE; +} + +RegressTestWi8021x * +regress_test_wi_802_1x_new (void) +{ + return g_object_new (REGRESS_TEST_TYPE_WI_802_1X, NULL); +} + +void +regress_test_wi_802_1x_set_testbool (RegressTestWi8021x *obj, gboolean val) +{ + obj->testbool = val; +} + +gboolean +regress_test_wi_802_1x_get_testbool (RegressTestWi8021x *obj) +{ + return obj->testbool; +} + +int +regress_test_wi_802_1x_static_method (int x) +{ + return 2 * x; +} + +/* floating gobject */ +G_DEFINE_TYPE (RegressTestFloating, regress_test_floating, G_TYPE_INITIALLY_UNOWNED); + +static void +regress_test_floating_finalize (GObject *object) +{ + g_assert (!g_object_is_floating (object)); + + G_OBJECT_CLASS (regress_test_floating_parent_class)->finalize (object); +} + +static void +regress_test_floating_class_init (RegressTestFloatingClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + gobject_class->finalize = regress_test_floating_finalize; +} + +static void +regress_test_floating_init (RegressTestFloating *self G_GNUC_UNUSED) +{ +} + +/** + * regress_test_floating_new: + * + * Returns:: A new floating #RegressTestFloating + */ +RegressTestFloating * +regress_test_floating_new (void) +{ + return g_object_new (REGRESS_TEST_TYPE_FLOATING, NULL); +} + +/** + * regress_test_torture_signature_0: + * @x: + * @y: (out): + * @z: (out): + * @foo: + * @q: (out): + * @m: + * + */ +void +regress_test_torture_signature_0 (int x, + double *y, + int *z, + const char *foo, + int *q, + guint m) +{ + *y = x; + *z = x * 2; + *q = g_utf8_strlen (foo, -1) + m; +} + +/** + * regress_test_torture_signature_1: + * @x: + * @y: (out): + * @z: (out): + * @foo: + * @q: (out): + * @m: + * @error: A #GError + * + * This function throws an error if m is odd. + */ +gboolean +regress_test_torture_signature_1 (int x, + double *y, + int *z, + const char *foo, + int *q, + guint m, + GError **error) +{ + *y = x; + *z = x * 2; + *q = g_utf8_strlen (foo, -1) + m; + if (m % 2 == 0) + return TRUE; + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "m is odd"); + return FALSE; +} + +/** + * regress_test_torture_signature_2: + * @x: + * @callback: + * @user_data: + * @notify: + * @y: (out): + * @z: (out): + * @foo: + * @q: (out): + * @m: + * + */ +void +regress_test_torture_signature_2 (int x, + RegressTestCallbackUserData callback, + gpointer user_data, + GDestroyNotify notify, + double *y, + int *z, + const char *foo, + int *q, + guint m) +{ + *y = x; + *z = x * 2; + *q = g_utf8_strlen (foo, -1) + m; + callback (user_data); + notify (user_data); +} + +/** + * regress_test_date_in_gvalue: + * + * Returns: (transfer full): + */ +GValue * +regress_test_date_in_gvalue (void) +{ + GValue *value = g_new0 (GValue, 1); + GDate *date = g_date_new_dmy (5, 12, 1984); + + g_value_init (value, G_TYPE_DATE); + g_value_take_boxed (value, date); + + return value; +} + +/** + * regress_test_strv_in_gvalue: + * + * Returns: (transfer full): + */ +GValue * +regress_test_strv_in_gvalue (void) +{ + GValue *value = g_new0 (GValue, 1); + const char *strv[] = { "one", "two", "three", NULL }; + + g_value_init (value, G_TYPE_STRV); + g_value_set_boxed (value, strv); + + return value; +} + +/** + * regress_test_null_strv_in_gvalue: + * + * Returns: (transfer full): + */ +GValue * +regress_test_null_strv_in_gvalue (void) +{ + GValue *value = g_new0 (GValue, 1); + const char **strv = NULL; + + g_value_init (value, G_TYPE_STRV); + g_value_set_boxed (value, strv); + + return value; +} + +/** + * regress_test_multiline_doc_comments: + * + * This is a function. + * + * It has multiple lines in the documentation. + * + * The sky is blue. + * + * You will give me your credit card number. + */ +void +regress_test_multiline_doc_comments (void) +{ +} + +/** + * regress_test_nested_parameter: + * @a: An integer + * + * + * + * + * + * Syntax + * Explanation + * Examples + * + * + * + * + * rgb(@r, @g, @b) + * An opaque color; @r, @g, @b can be either integers between + * 0 and 255 or percentages + * rgb(128, 10, 54) + * rgb(20%, 30%, 0%) + * + * + * rgba(@r, @g, @b, @a) + * A translucent color; @r, @g, @b are as in the previous row, + * @a is a floating point number between 0 and 1 + * rgba(255, 255, 0, 0.5) + * + * + * + * + * + * What we're testing here is that the scanner ignores the @a nested inside XML. + */ +void +regress_test_nested_parameter (int a G_GNUC_UNUSED) +{ +} + +/** + * regress_introspectable_via_alias: + * + */ +void +regress_introspectable_via_alias (RegressPtrArrayAlias *data G_GNUC_UNUSED) +{ +} + +/** + * regress_not_introspectable_via_alias: + * + */ +void +regress_not_introspectable_via_alias (RegressVaListAlias ok G_GNUC_UNUSED) +{ +} + +/** + * regress_aliased_caller_alloc: + * @boxed: (out): + */ +void +regress_aliased_caller_alloc (RegressAliasedTestBoxed *boxed) +{ + boxed->priv = g_slice_new0 (RegressTestBoxedPrivate); + boxed->priv->magic = 0xdeadbeef; +} + +void +regress_test_struct_fixed_array_frob (RegressTestStructFixedArray *str) +{ + guint i; + str->just_int = 7; + + for (i = 0; i < G_N_ELEMENTS (str->array); i++) + str->array[i] = 42 + i; +} + +/** + * regress_has_parameter_named_attrs: + * @foo: some int + * @attributes: (type guint32) (array fixed-size=32): list of attributes + * + * This test case mirrors GnomeKeyringPasswordSchema from + * libgnome-keyring. + */ +void +regress_has_parameter_named_attrs (int foo G_GNUC_UNUSED, + gpointer attributes G_GNUC_UNUSED) +{ +} + +/** + * regress_test_versioning: + * + * Since: 1.32.1: Actually, this function was introduced earlier + * than this, but it didn't do anything before this version. + * Deprecated: 1.33.3: This function has been deprecated, + * because it sucks. Use foobar instead. + * Stability: Unstable: Maybe someday we will find the time + * to stabilize this function. Who knows? + */ +void +regress_test_versioning (void) +{ +} + +void +regress_like_xkl_config_item_set_name (RegressLikeXklConfigItem *self, + char const *name) +{ + strncpy (self->name, name, sizeof (self->name) - 1); + self->name[sizeof (self->name) - 1] = '\0'; +} + +/** + * regress_get_variant: + * + * Returns: (transfer floating): A new variant + */ +GVariant * +regress_get_variant (void) +{ + return g_variant_new_int32 (42); +} + +/** + * regress_test_array_struct_out_none: + * @arr: (out) (array length=len) (transfer none): An array + * @len: (out): Length of @arr + * + * Test flat array output with transfer none. + * + * Similar to: + * - mm_modem_peek_ports() with structs + * - gdk_query_visual_types() with enums + * - gdk_event_get_axes() with doubles + */ +void +regress_test_array_struct_out_none (RegressTestStructA **arr, gsize *len) +{ + static RegressTestStructA array[3] = { + { .some_int = 111 }, + { .some_int = 222 }, + { .some_int = 333 }, + }; + + *arr = array; + *len = 3; +} + +/** + * regress_test_array_struct_out_container: + * @arr: (out) (array length=len) (transfer container): An array + * @len: (out): Length of @arr + * + * Test flat array output with transfer container. + * + * Similar to pango_layout_get_log_attrs(). + */ +void +regress_test_array_struct_out_container (RegressTestStructA **arr, gsize *len) +{ + + *arr = g_new0 (RegressTestStructA, 5); + (*arr)[0].some_int = 11; + (*arr)[1].some_int = 13; + (*arr)[2].some_int = 17; + (*arr)[3].some_int = 19; + (*arr)[4].some_int = 23; + *len = 5; +} + +/** + * regress_test_array_struct_out_full_fixed: + * @arr: (out) (array fixed-size=4) (transfer full): An array + * + * Test flat fixed-size array output with transfer full. + */ +void +regress_test_array_struct_out_full_fixed (RegressTestStructA **arr) +{ + *arr = g_new0 (RegressTestStructA, 4); + (*arr)[0].some_int = 2; + (*arr)[1].some_int = 3; + (*arr)[2].some_int = 5; + (*arr)[3].some_int = 7; +} + +/** + * regress_test_array_struct_out_caller_alloc: + * @arr: (out caller-allocates) (array length=len): An array + * @len: Length of @arr + * + * Test flat caller-allocated array output. + * + * Similar to g_main_context_query(). + */ +void +regress_test_array_struct_out_caller_alloc (RegressTestStructA *arr, gsize len) +{ + guint i; + + g_assert (arr != NULL); + + memset (arr, 0, sizeof (RegressTestStructA) * len); + for (i = 0; i != len; ++i) + arr[i].some_int = 111 * (i + 1); +} + +/** + * regress_test_array_struct_in_full: + * @arr: (in) (array length=len) (transfer full): An array + * @len: Length of @arr + * + * Test flat array input with transfer full. + * + * Similar to: + * - gsf_property_settings_free() with structs but they contain pointers + * - g_byte_array_new_take() with guint8s + */ +void +regress_test_array_struct_in_full (RegressTestStructA *arr, gsize len) +{ + g_assert_cmpint (len, ==, 2); + g_assert_cmpint (arr[0].some_int, ==, 201); + g_assert_cmpint (arr[1].some_int, ==, 202); + g_free (arr); +} + +/** + * regress_test_array_struct_in_none: + * @arr: (in) (array length=len) (transfer none): An array. + * @len: Length of @arr + * + * Test flat array input with transfer none. + * + * Similar to g_main_context_check() or gtk_target_list_new(). + */ +void +regress_test_array_struct_in_none (RegressTestStructA *arr, gsize len) +{ + g_assert_cmpint (len, ==, 3); + g_assert_cmpint (arr[0].some_int, ==, 301); + g_assert_cmpint (arr[1].some_int, ==, 302); + g_assert_cmpint (arr[2].some_int, ==, 303); +} + +/** + * regress_test_obj_function_async: + * + */ +void +regress_test_obj_function_async (RegressTestObj *self G_GNUC_UNUSED, + int io_priority G_GNUC_UNUSED, + GCancellable *cancellable G_GNUC_UNUSED, + GAsyncReadyCallback callback G_GNUC_UNUSED, + gpointer user_data G_GNUC_UNUSED) +{ +} + +/** + * regress_test_obj_function_finish: + * + */ +gboolean +regress_test_obj_function_finish (RegressTestObj *self G_GNUC_UNUSED, GAsyncResult *res G_GNUC_UNUSED, GError **error G_GNUC_UNUSED) +{ + return TRUE; +} + +/** + * regress_test_obj_function_sync: + * + */ +gboolean +regress_test_obj_function_sync (RegressTestObj *self G_GNUC_UNUSED, int io_priority G_GNUC_UNUSED) +{ + return TRUE; +} diff --git a/subprojects/gobject-introspection-tests/regress.h b/subprojects/gobject-introspection-tests/regress.h new file mode 100644 index 000000000..d7e96ab9b --- /dev/null +++ b/subprojects/gobject-introspection-tests/regress.h @@ -0,0 +1,1713 @@ +/* +SPDX-FileCopyrightText: 2008-2013, 2015 Colin Walters +SPDX-FileCopyrightText: 2008 Johan Bilien +SPDX-FileCopyrightText: 2008-2010 Johan Dahlin +SPDX-FileCopyrightText: 2008 Lucas Almeida Rocha +SPDX-FileCopyrightText: 2008, 2010 Owen W. Taylor +SPDX-FileCopyrightText: 2009 Andreas Rottmann +SPDX-FileCopyrightText: 2009 Havoc Pennington +SPDX-FileCopyrightText: 2009-2010 litl, LLC +SPDX-FileCopyrightText: 2009 Mark Lee +SPDX-FileCopyrightText: 2009, 2011 Maxim Ermilov +SPDX-FileCopyrightText: 2009 Simon van der Linden +SPDX-FileCopyrightText: 2009-2010 Sugar Labs +SPDX-FileCopyrightText: 2010-2012, 2015 Collabora, Ltd. +SPDX-FileCopyrightText: 2010 Jonathan Matthew +SPDX-FileCopyrightText: 2010 Zach Goldberg +SPDX-FileCopyrightText: 2011-2012, 2014 Giovanni Campagna +SPDX-FileCopyrightText: 2011-2012 Martin Pitt +SPDX-FileCopyrightText: 2011 Pavel Holejsovsky +SPDX-FileCopyrightText: 2011, 2024 Red Hat, Inc. +SPDX-FileCopyrightText: 2011-2012 Torsten Schönfeld +SPDX-FileCopyrightText: 2011 Xavier Claessens +SPDX-FileCopyrightText: 2012 Alban Browaeys +SPDX-FileCopyrightText: 2012 Bastian Winkler +SPDX-FileCopyrightText: 2012 Canonical Ltd. +SPDX-FileCopyrightText: 2012 Coeus Group +SPDX-FileCopyrightText: 2012 Dieter Verfaillie +SPDX-FileCopyrightText: 2012-2013 Jasper St. Pierre +SPDX-FileCopyrightText: 2012 Jon Nordby +SPDX-FileCopyrightText: 2012 Krzesimir Nowak +SPDX-FileCopyrightText: 2012 Paolo Borelli +SPDX-FileCopyrightText: 2012, 2014 Simon Feltman +SPDX-FileCopyrightText: 2013, 2019, 2021-2022 Emmanuele Bassi +SPDX-FileCopyrightText: 2013 Florian Müllner +SPDX-FileCopyrightText: 2013 Stef Walter +SPDX-FileCopyrightText: 2014-2015 RIFT.io, Inc. +SPDX-FileCopyrightText: 2015 Ben Iofel +SPDX-FileCopyrightText: 2015 Christoph Reiter +SPDX-FileCopyrightText: 2015 Debarshi Ray +SPDX-FileCopyrightText: 2016 Intel +SPDX-FileCopyrightText: 2016 Lionel Landwerlin +SPDX-FileCopyrightText: 2017 Endless Mobile, Inc. +SPDX-FileCopyrightText: 2016-2019 Philip Chimento +SPDX-FileCopyrightText: 2017 Rico Tzschichholz +SPDX-FileCopyrightText: 2018-2019 Tomasz Miąsko +SPDX-FileCopyrightText: 2020 Centricular +SPDX-FileCopyrightText: 2021, 2023 Marco Trevisan +SPDX-FileCopyrightText: 2022 Lubomir Rintel +SPDX-FileCopyrightText: 2023-2024 Simon McVittie +SPDX-FileCopyrightText: 2023 Evan Welsh +*/ + +#pragma once + +#include +#include + +#include +#include +#include + +#ifndef GI_TEST_DISABLE_CAIRO +#include +#endif /* GI_TEST_DISABLE_CAIRO */ + +#include "gitestmacros.h" + +GI_TEST_EXTERN +void regress_set_abort_on_error (gboolean abort_on_error); + +/* return annotations */ +GI_TEST_EXTERN +char *regress_test_return_allow_none (void); + +GI_TEST_EXTERN +char *regress_test_return_nullable (void); + +/* basic types */ +GI_TEST_EXTERN +gboolean regress_test_boolean (gboolean in); + +GI_TEST_EXTERN +gboolean regress_test_boolean_true (gboolean in); + +GI_TEST_EXTERN +gboolean regress_test_boolean_false (gboolean in); + +GI_TEST_EXTERN +gint8 regress_test_int8 (gint8 in); + +GI_TEST_EXTERN +guint8 regress_test_uint8 (guint8 in); + +GI_TEST_EXTERN +gint16 regress_test_int16 (gint16 in); + +GI_TEST_EXTERN +guint16 regress_test_uint16 (guint16 in); + +GI_TEST_EXTERN +gint32 regress_test_int32 (gint32 in); + +GI_TEST_EXTERN +guint32 regress_test_uint32 (guint32 in); + +GI_TEST_EXTERN +gint64 regress_test_int64 (gint64 in); + +GI_TEST_EXTERN +guint64 regress_test_uint64 (guint64 in); + +GI_TEST_EXTERN +gshort regress_test_short (gshort in); + +GI_TEST_EXTERN +gushort regress_test_ushort (gushort in); + +GI_TEST_EXTERN +gint regress_test_int (gint in); + +GI_TEST_EXTERN +guint regress_test_uint (guint in); + +GI_TEST_EXTERN +glong regress_test_long (glong in); + +GI_TEST_EXTERN +gulong regress_test_ulong (gulong in); + +GI_TEST_EXTERN +gssize regress_test_ssize (gssize in); + +GI_TEST_EXTERN +gsize regress_test_size (gsize in); + +GI_TEST_EXTERN +gfloat regress_test_float (gfloat in); + +GI_TEST_EXTERN +gdouble regress_test_double (gdouble in); + +GI_TEST_EXTERN +gunichar regress_test_unichar (gunichar in); + +GI_TEST_EXTERN +time_t regress_test_timet (time_t in); + +GI_TEST_EXTERN +off_t regress_test_offt (off_t in); + +GI_TEST_EXTERN +GType regress_test_gtype (GType in); + +/* utf8 */ +GI_TEST_EXTERN +const char *regress_test_utf8_const_return (void); + +GI_TEST_EXTERN +char *regress_test_utf8_nonconst_return (void); + +GI_TEST_EXTERN +void regress_test_utf8_const_in (const char *in); + +GI_TEST_EXTERN +void regress_test_utf8_out (char **out); + +GI_TEST_EXTERN +void regress_test_utf8_inout (char **inout); + +GI_TEST_EXTERN +GSList *regress_test_filename_return (void); + +GI_TEST_EXTERN +void regress_test_utf8_null_in (char *in); + +GI_TEST_EXTERN +void regress_test_utf8_null_out (char **char_out); + +/* in arguments after out arguments */ +GI_TEST_EXTERN +void regress_test_int_out_utf8 (int *length, const char *in); + +/* multiple output arguments */ + +GI_TEST_EXTERN +void regress_test_multi_double_args (gdouble in, gdouble *one, gdouble *two); + +GI_TEST_EXTERN +void regress_test_utf8_out_out (char **out0, char **out1); + +GI_TEST_EXTERN +char *regress_test_utf8_out_nonconst_return (char **out); + +/* non-basic-types */ +/* array */ +GI_TEST_EXTERN +gboolean regress_test_strv_in (char **arr); + +GI_TEST_EXTERN +int regress_test_array_int_in (int n_ints, int *ints); + +GI_TEST_EXTERN +void regress_test_array_int_out (int *n_ints, int **ints); + +GI_TEST_EXTERN +void regress_test_array_int_inout (int *n_ints, int **ints); + +GI_TEST_EXTERN +int regress_test_array_gint8_in (int n_ints, gint8 *ints); + +GI_TEST_EXTERN +int regress_test_array_gint16_in (int n_ints, gint16 *ints); + +GI_TEST_EXTERN +gint32 regress_test_array_gint32_in (int n_ints, gint32 *ints); + +GI_TEST_EXTERN +gint64 regress_test_array_gint64_in (int n_ints, gint64 *ints); + +GI_TEST_EXTERN +char *regress_test_array_gtype_in (int n_types, GType *types); + +GI_TEST_EXTERN +const char **regress_test_strv_out_container (void); + +GI_TEST_EXTERN +char **regress_test_strv_out (void); + +GI_TEST_EXTERN +const char *const *regress_test_strv_out_c (void); + +GI_TEST_EXTERN +void regress_test_strv_outarg (const char ***retp); + +GI_TEST_EXTERN +int regress_test_array_fixed_size_int_in (int *ints); + +GI_TEST_EXTERN +void regress_test_array_fixed_size_int_out (int **ints); + +GI_TEST_EXTERN +int *regress_test_array_fixed_size_int_return (void); + +/* transfer tests */ +GI_TEST_EXTERN +int *regress_test_array_int_full_out (int *len); + +GI_TEST_EXTERN +int *regress_test_array_int_none_out (int *len); + +GI_TEST_EXTERN +void regress_test_array_int_null_in (int *arr, int len); + +GI_TEST_EXTERN +void regress_test_array_int_null_out (int **arr, int *len); + +/* interface */ +/* GList */ +GI_TEST_EXTERN +const GList *regress_test_glist_nothing_return (void); + +GI_TEST_EXTERN +GList *regress_test_glist_nothing_return2 (void); + +GI_TEST_EXTERN +GList *regress_test_glist_container_return (void); + +GI_TEST_EXTERN +GList *regress_test_glist_everything_return (void); + +GI_TEST_EXTERN +void regress_test_glist_gtype_container_in (GList *in); + +GI_TEST_EXTERN +void regress_test_glist_nothing_in (const GList *in); + +GI_TEST_EXTERN +void regress_test_glist_nothing_in2 (GList *in); + +GI_TEST_EXTERN +void regress_test_glist_null_in (GSList *in); + +GI_TEST_EXTERN +void regress_test_glist_null_out (GSList **out_list); + +/* GSList */ +GI_TEST_EXTERN +const GSList *regress_test_gslist_nothing_return (void); + +GI_TEST_EXTERN +GSList *regress_test_gslist_nothing_return2 (void); + +GI_TEST_EXTERN +GSList *regress_test_gslist_container_return (void); + +GI_TEST_EXTERN +GSList *regress_test_gslist_everything_return (void); + +GI_TEST_EXTERN +void regress_test_gslist_nothing_in (const GSList *in); + +GI_TEST_EXTERN +void regress_test_gslist_nothing_in2 (GSList *in); + +GI_TEST_EXTERN +void regress_test_gslist_null_in (GSList *in); + +GI_TEST_EXTERN +void regress_test_gslist_null_out (GSList **out_list); + +/* GHashTable */ +GI_TEST_EXTERN +const GHashTable *regress_test_ghash_null_return (void); + +GI_TEST_EXTERN +const GHashTable *regress_test_ghash_nothing_return (void); + +GI_TEST_EXTERN +GHashTable *regress_test_ghash_nothing_return2 (void); + +GI_TEST_EXTERN +GHashTable *regress_test_ghash_gvalue_return (void); + +GI_TEST_EXTERN +void regress_test_ghash_gvalue_in (GHashTable *hash); + +GI_TEST_EXTERN +GHashTable *regress_test_ghash_container_return (void); + +GI_TEST_EXTERN +GHashTable *regress_test_ghash_everything_return (void); + +GI_TEST_EXTERN +void regress_test_ghash_null_in (const GHashTable *in); + +GI_TEST_EXTERN +void regress_test_ghash_null_out (const GHashTable **out); + +GI_TEST_EXTERN +void regress_test_ghash_nothing_in (const GHashTable *in); + +GI_TEST_EXTERN +void regress_test_ghash_nothing_in2 (GHashTable *in); + +GI_TEST_EXTERN +GHashTable *regress_test_ghash_nested_everything_return (void); + +GI_TEST_EXTERN +GHashTable *regress_test_ghash_nested_everything_return2 (void); + +/* GPtrArray */ +GI_TEST_EXTERN +GPtrArray *regress_test_garray_container_return (void); + +GI_TEST_EXTERN +GPtrArray *regress_test_garray_full_return (void); + +/* error? */ + +/* closure */ +GI_TEST_EXTERN +int regress_test_closure (GClosure *closure); + +GI_TEST_EXTERN +int regress_test_closure_one_arg (GClosure *closure, int arg); + +GI_TEST_EXTERN +GVariant *regress_test_closure_variant (GClosure *closure, GVariant *arg); + +/* value */ +GI_TEST_EXTERN +int regress_test_int_value_arg (const GValue *v); + +GI_TEST_EXTERN +const GValue *regress_test_value_return (int i); + +/* foreign structs */ +#ifndef GI_TEST_DISABLE_CAIRO +GI_TEST_EXTERN +cairo_t *regress_test_cairo_context_full_return (void); + +GI_TEST_EXTERN +void regress_test_cairo_context_none_in (cairo_t *context); + +GI_TEST_EXTERN +cairo_surface_t *regress_test_cairo_surface_none_return (void); + +GI_TEST_EXTERN +cairo_surface_t *regress_test_cairo_surface_full_return (void); + +GI_TEST_EXTERN +void regress_test_cairo_surface_none_in (cairo_surface_t *surface); + +GI_TEST_EXTERN +void regress_test_cairo_surface_full_out (cairo_surface_t **surface); +#endif /* GI_TEST_DISABLE_CAIRO */ + +/* versioning (deprecated, since, stability) */ +GI_TEST_EXTERN +void regress_test_versioning (void); + +GI_TEST_EXTERN +GVariant *regress_test_gvariant_i (void); + +GI_TEST_EXTERN +GVariant *regress_test_gvariant_s (void); + +GI_TEST_EXTERN +GVariant *regress_test_gvariant_asv (void); + +GI_TEST_EXTERN +GVariant *regress_test_gvariant_v (void); + +GI_TEST_EXTERN +GVariant *regress_test_gvariant_as (void); + +/* enums / flags */ + +#define NUM_REGRESS_FOO + +/** + * RegressTestEnum: + * @REGRESS_TEST_VALUE1: value 1 + * @REGRESS_TEST_VALUE2: value 2 + * + * By purpose, not all members have documentation + */ +typedef enum +{ + REGRESS_TEST_VALUE1, + REGRESS_TEST_VALUE2, + REGRESS_TEST_VALUE3 = -1, + REGRESS_TEST_VALUE4 = '0', + REGRESS_TEST_VALUE5 +} RegressTestEnum; + +typedef enum +{ + REGRESS_TEST_UNSIGNED_VALUE1 = 1, + REGRESS_TEST_UNSIGNED_VALUE2 = 0x80000000 +} RegressTestEnumUnsigned; + +typedef enum +{ + REGRESS_TEST_FLAG1 = 1 << 0, + REGRESS_TEST_FLAG2 = 1 << 1, + REGRESS_TEST_FLAG3 = 1 << 2, +} RegressTestFlags; + +GI_TEST_EXTERN +GType regress_test_enum_get_type (void) G_GNUC_CONST; +#define REGRESS_TEST_TYPE_ENUM (regress_test_enum_get_type ()) + +GI_TEST_EXTERN +GType regress_test_enum_unsigned_get_type (void) G_GNUC_CONST; +#define REGRESS_TEST_TYPE_ENUM_UNSIGNED (regress_test_enum_unsigned_get_type ()) + +GI_TEST_EXTERN +GType regress_test_flags_get_type (void) G_GNUC_CONST; +#define REGRESS_TEST_TYPE_FLAGS (regress_test_flags_get_type ()) + +typedef enum +{ + REGRESS_TEST_REFERENCE_ZERO = 2 + 2, + REGRESS_TEST_REFERENCE_ONE = 1 + 1, + REGRESS_TEST_REFERENCE_TWO = 6 * 9, + REGRESS_TEST_REFERENCE_THREE = REGRESS_TEST_REFERENCE_ONE + REGRESS_TEST_REFERENCE_ONE, + REGRESS_TEST_REFERENCE_FOUR = REGRESS_TEST_REFERENCE_TWO * REGRESS_TEST_REFERENCE_THREE, + REGRESS_TEST_REFERENCE_FIVE = ~REGRESS_TEST_REFERENCE_FOUR, +} RegressTestReferenceEnum; + +/* this is not registered with GType */ +typedef enum +{ + REGRESS_TEST_EVALUE1, + REGRESS_TEST_EVALUE2 = 42, + REGRESS_TEST_EVALUE3 = '0' +} RegressTestEnumNoGEnum; + +/** + * REGRESS_TEST_EVALUE_DEPRECATED: + * + * Scanner used to replace %REGRESS_TEST_EVALUE1 with %REGRESS_TEST_EVALUE_DEPRECATED. + */ +#define REGRESS_TEST_EVALUE_DEPRECATED REGRESS_TEST_EVALUE1 + +GI_TEST_EXTERN +const gchar *regress_test_enum_param (RegressTestEnum e); + +GI_TEST_EXTERN +const gchar *regress_test_unsigned_enum_param (RegressTestEnumUnsigned e); + +GI_TEST_EXTERN +void regress_global_get_flags_out (RegressTestFlags *v); + +/* error domains */ + +typedef enum +{ + REGRESS_TEST_ERROR_CODE1 = 1, + REGRESS_TEST_ERROR_CODE2 = 2, + REGRESS_TEST_ERROR_CODE3 = 3 +} RegressTestError; + +GI_TEST_EXTERN +GType regress_test_error_get_type (void); + +GI_TEST_EXTERN +GQuark regress_test_error_quark (void); + +/* Test weird names, with and without + c_symbol_prefix given by a GType +*/ +typedef enum +{ + REGRESS_TEST_ABC_ERROR_CODE1 = 1, + REGRESS_TEST_ABC_ERROR_CODE2 = 2, + REGRESS_TEST_ABC_ERROR_CODE3 = 3 +} RegressTestABCError; + +GI_TEST_EXTERN +GType regress_test_abc_error_get_type (void); + +GI_TEST_EXTERN +GQuark regress_test_abc_error_quark (void); + +typedef enum +{ + REGRESS_TEST_OTHER_ERROR_CODE1 = 1, + REGRESS_TEST_OTHER_ERROR_CODE2 = 2, + REGRESS_TEST_OTHER_ERROR_CODE3 = 3 +} RegressTestOtherError; + +/* This returns a GType for RegressTestOtherError. + The difference is intentional, although it + is mainly meant for capitalization problems. +*/ +GI_TEST_EXTERN +GType regress_test_unconventional_error_get_type (void); + +GI_TEST_EXTERN +GQuark regress_test_unconventional_error_quark (void); + +typedef enum +{ + REGRESS_TEST_DEF_ERROR_CODE0 = 0, + REGRESS_TEST_DEF_ERROR_CODE1 = 1, + REGRESS_TEST_DEF_ERROR_CODE2 = 2 +} RegressTestDEFError; + +GI_TEST_EXTERN +GQuark regress_test_def_error_quark (void); + +/* the scanner used to have problem + with two uppercase letter right after + the identifier prefix, that's why + we break the RegressTest convention */ +typedef enum +{ + REGRESS_ATEST_ERROR_CODE0 = 0, + REGRESS_ATEST_ERROR_CODE1 = 1, + REGRESS_ATEST_ERROR_CODE2 = 2 +} RegressATestError; + +GI_TEST_EXTERN +GQuark regress_atest_error_quark (void); + +/* constants */ + +#define REGRESS_NEGATIVE_INT_CONSTANT -42 +#define REGRESS_INT_CONSTANT 4422 +#define REGRESS_DOUBLE_CONSTANT 44.22 +#define REGRESS_STRING_CONSTANT "Some String" +#define REGRESS_Mixed_Case_Constant 4423 +#define REGRESS_BOOL_CONSTANT TRUE +#define REGRESS_G_GINT64_CONSTANT (G_GINT64_CONSTANT (1000)) +#define REGRESS_GUINT64_CONSTANT ((guint64) - 1) +#define REGRESS_GOOD_EXPR_CONSTANT (1 + 2 * (3 + 2) << 13 - 4 >> REGRESS_ATEST_ERROR_CODE2) +#define REGRESS_BAD_EXPR_CONSTANT (1 + SOMETHING_UNDEFINED) + +typedef guint64 RegressTestTypeGUInt64; +#define REGRESS_GUINT64_CONSTANTA ((RegressTestTypeGUInt64) - 1) + +/* structures */ +typedef struct _RegressTestStructA RegressTestStructA; +typedef struct _RegressTestStructB RegressTestStructB; +typedef struct _RegressTestStructC RegressTestStructC; +typedef struct _RegressTestStructD RegressTestStructD; +typedef struct _RegressTestStructF RegressTestStructF; + +struct _RegressTestStructA +{ + gint some_int; + gint8 some_int8; + gdouble some_double; + RegressTestEnum some_enum; +}; + +GI_TEST_EXTERN +void regress_test_struct_a_clone (RegressTestStructA *a, + RegressTestStructA *a_out); + +GI_TEST_EXTERN +void regress_test_struct_a_parse (RegressTestStructA *a_out, const gchar *string); + +GI_TEST_EXTERN +void regress_test_array_struct_out (RegressTestStructA **arr, int *len); + +struct _RegressTestStructB +{ + gint8 some_int8; + RegressTestStructA nested_a; +}; + +GI_TEST_EXTERN +void regress_test_struct_b_clone (RegressTestStructB *b, + RegressTestStructB *b_out); + +/* This one has a non-basic member */ +struct _RegressTestStructC +{ + gint another_int; + GObject *obj; +}; + +/* This one has annotated fields */ +/** + * RegressTestStructD: + * @array1: (array zero-terminated=1): + * @array2: (array zero-terminated=1) (element-type RegressTestObj): + * @field: (type RegressTestObj): + * @list: (element-type RegressTestObj): + * @garray: (element-type RegressTestObj): + * @ref_count: + */ +struct _RegressTestStructD +{ + RegressTestStructA **array1; + gpointer *array2; + gpointer field; + GList *list; + GPtrArray *garray; +}; + +/* This one has an array of anonymous unions, inspired by GValue */ +struct RegressTestStructE +{ + GType some_type; + union + { + gint v_int; + guint v_uint; + glong v_long; + gulong v_ulong; + gint64 v_int64; + guint64 v_uint64; + gfloat v_float; + gdouble v_double; + gpointer v_pointer; + } some_union[2]; +}; + +/* This one has members with const or volatile modifiers. */ +struct _RegressTestStructF +{ + volatile gint ref_count; + const gint *data1; + const gint *const data2; + const gint *const *const data3; + const gint **const *data4; + volatile gint *const data5; + const gint *volatile data6; + volatile unsigned const char data7; +}; + +/* plain-old-data boxed types */ +typedef struct _RegressTestSimpleBoxedA RegressTestSimpleBoxedA; +typedef struct _RegressTestSimpleBoxedB RegressTestSimpleBoxedB; + +/** + * RegressTestSimpleBoxedA: (copy-func regress_test_simple_boxed_a_copy) + * @some_int: + * @some_int8: + * @some_double: + * @some_enum: + * + * ... + */ +struct _RegressTestSimpleBoxedA +{ + gint some_int; + gint8 some_int8; + gdouble some_double; + RegressTestEnum some_enum; +}; + +/* Intentionally uses _get_gtype */ +GI_TEST_EXTERN +GType regress_test_simple_boxed_a_get_gtype (void); + +GI_TEST_EXTERN +RegressTestSimpleBoxedA *regress_test_simple_boxed_a_copy (RegressTestSimpleBoxedA *a); + +GI_TEST_EXTERN +gboolean regress_test_simple_boxed_a_equals (RegressTestSimpleBoxedA *a, + RegressTestSimpleBoxedA *other_a); + +GI_TEST_EXTERN +const RegressTestSimpleBoxedA *regress_test_simple_boxed_a_const_return (void); + +struct _RegressTestSimpleBoxedB +{ + gint8 some_int8; + RegressTestSimpleBoxedA nested_a; +}; + +GI_TEST_EXTERN +GType regress_test_simple_boxed_b_get_type (void); + +GI_TEST_EXTERN +RegressTestSimpleBoxedB *regress_test_simple_boxed_b_copy (RegressTestSimpleBoxedB *b); + +/* opaque boxed */ +#define REGRESS_TEST_TYPE_BOXED (regress_test_boxed_get_type ()) + +typedef struct _RegressTestBoxed RegressTestBoxed; +typedef struct _RegressTestBoxedPrivate RegressTestBoxedPrivate; + +struct _RegressTestBoxed +{ + gint8 some_int8; + RegressTestSimpleBoxedA nested_a; + + RegressTestBoxedPrivate *priv; +}; + +GI_TEST_EXTERN +GType regress_test_boxed_get_type (void); + +GI_TEST_EXTERN +RegressTestBoxed *regress_test_boxed_new (void); + +GI_TEST_EXTERN +RegressTestBoxed *regress_test_boxed_new_alternative_constructor1 (int i); + +GI_TEST_EXTERN +RegressTestBoxed *regress_test_boxed_new_alternative_constructor2 (int i, int j); + +GI_TEST_EXTERN +RegressTestBoxed *regress_test_boxed_new_alternative_constructor3 (char *s); + +GI_TEST_EXTERN +RegressTestBoxed *regress_test_boxed_copy (RegressTestBoxed *boxed); + +GI_TEST_EXTERN +gboolean regress_test_boxed_equals (RegressTestBoxed *boxed, + RegressTestBoxed *other); + +GI_TEST_EXTERN +void regress_test_boxeds_not_a_method (RegressTestBoxed *boxed); + +GI_TEST_EXTERN +void regress_test_boxeds_not_a_static (void); + +typedef struct _RegressTestBoxedB RegressTestBoxedB; + +struct _RegressTestBoxedB +{ + gint8 some_int8; + glong some_long; +}; + +GI_TEST_EXTERN +GType regress_test_boxed_b_get_type (void); + +GI_TEST_EXTERN +RegressTestBoxedB *regress_test_boxed_b_new (gint8 some_int8, glong some_long); + +GI_TEST_EXTERN +RegressTestBoxedB *regress_test_boxed_b_copy (RegressTestBoxedB *boxed); + +typedef struct _RegressTestBoxedC RegressTestBoxedC; + +struct _RegressTestBoxedC +{ + guint refcount; + guint another_thing; +}; + +GI_TEST_EXTERN +GType regress_test_boxed_c_get_type (void); + +GI_TEST_EXTERN +RegressTestBoxedC *regress_test_boxed_c_new (void); + +/** + * RegressTestBoxedD: (copy-func regress_test_boxed_d_copy) + * (free-func regress_test_boxed_d_free) + * + */ +typedef struct _RegressTestBoxedD RegressTestBoxedD; + +GI_TEST_EXTERN +GType regress_test_boxed_d_get_type (void); + +GI_TEST_EXTERN +RegressTestBoxedD *regress_test_boxed_d_new (const char *a_string, int a_int); + +GI_TEST_EXTERN +RegressTestBoxedD *regress_test_boxed_d_copy (RegressTestBoxedD *boxed); + +GI_TEST_EXTERN +void regress_test_boxed_d_free (RegressTestBoxedD *boxed); + +GI_TEST_EXTERN +int regress_test_boxed_d_get_magic (RegressTestBoxedD *boxed); + +/* gobject */ +#define REGRESS_TEST_TYPE_OBJ (regress_test_obj_get_type ()) +#define REGRESS_TEST_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), REGRESS_TEST_TYPE_OBJ, RegressTestObj)) +#define REGRESS_TEST_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), REGRESS_TEST_TYPE_OBJ)) +#define REGRESS_TEST_OBJ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), REGRESS_TEST_TYPE_OBJ, RegressTestObjClass)) + +typedef struct _RegressTestObj RegressTestObj; +typedef struct _RegressTestObjClass RegressTestObjClass; + +/** + * RegressTestObj: + * @bare: (allow-none): + */ +struct _RegressTestObj +{ + GObject parent_instance; + + GObject *bare; + RegressTestBoxed *boxed; + GHashTable *hash_table; + GList *list; + gint8 some_int8; + float some_float; + double some_double; + char *string; + GType gtype; + gint name_conflict; + GByteArray *byte_array; + + /* < private > */ + void (*function_ptr) (void); +}; + +typedef void (*RegressTestExternallyDefinedCallback) (RegressTestObj *obj, int someint); + +struct _RegressTestObjClass +{ + GObjectClass parent_class; + + int (*matrix) (RegressTestObj *obj, const char *somestr); + + /** + * RegressTestObjClass::allow_none_vfunc: + * @two: (allow-none): Another object + */ + void (*allow_none_vfunc) (RegressTestObj *obj, RegressTestObj *two); + + guint test_signal; + guint test_signal_with_static_scope_arg; + + RegressTestExternallyDefinedCallback complex_vfunc; + + /* Should be replaced with simple "gpointer" and not be callback */ + void (*_regress_reserved1) (void); + void (*_regress_reserved2) (void); +}; + +GI_TEST_EXTERN +GType regress_test_obj_get_type (void); + +GI_TEST_EXTERN +RegressTestObj *regress_test_obj_new (RegressTestObj *obj); + +GI_TEST_EXTERN +RegressTestObj *regress_constructor (void); + +GI_TEST_EXTERN +RegressTestObj *regress_test_obj_new_from_file (const char *x, GError **error); + +GI_TEST_EXTERN +void regress_test_obj_set_bare (RegressTestObj *obj, GObject *bare); + +GI_TEST_EXTERN +void regress_test_obj_set_string (RegressTestObj *obj, const char *str); + +GI_TEST_EXTERN +const char *regress_test_obj_get_string (RegressTestObj *obj); + +GI_TEST_EXTERN +void regress_test_obj_emit_sig_with_obj (RegressTestObj *obj); + +GI_TEST_EXTERN +void regress_test_obj_emit_sig_with_obj_full (RegressTestObj *obj); + +GI_TEST_EXTERN +void regress_test_obj_emit_sig_with_gstrv_full (RegressTestObj *obj); + +GI_TEST_EXTERN +void regress_test_obj_emit_sig_with_foreign_struct (RegressTestObj *obj); + +GI_TEST_EXTERN +void regress_test_obj_emit_sig_with_int64 (RegressTestObj *obj); + +GI_TEST_EXTERN +void regress_test_obj_emit_sig_with_uint64 (RegressTestObj *obj); + +GI_TEST_EXTERN +void regress_test_obj_emit_sig_with_array_len_prop (RegressTestObj *obj); + +GI_TEST_EXTERN +void regress_test_obj_emit_sig_with_inout_int (RegressTestObj *obj); + +GI_TEST_EXTERN +void regress_test_obj_emit_sig_with_error (RegressTestObj *self); + +GI_TEST_EXTERN +void regress_test_obj_emit_sig_with_null_error (RegressTestObj *self); + +GI_TEST_EXTERN +int regress_test_obj_instance_method (RegressTestObj *obj); + +GI_TEST_EXTERN +void regress_test_obj_instance_method_full (RegressTestObj *obj); + +GI_TEST_EXTERN +double regress_test_obj_static_method (int x); + +GI_TEST_EXTERN +void regress_forced_method (RegressTestObj *obj); + +GI_TEST_EXTERN +void regress_test_array_fixed_out_objects (RegressTestObj ***objs); + +#if (defined(__GNUC__) || defined(__clang__)) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define G_GCC_STATIC static +#else +#define G_GCC_STATIC +#endif +GI_TEST_EXTERN +void regress_test_array_static_in_int (int x[G_GCC_STATIC 10]); + +GI_TEST_EXTERN +void regress_test_obj_torture_signature_0 (RegressTestObj *obj, + int x, + double *y, + int *z, + const char *foo, + int *q, + guint m); + +GI_TEST_EXTERN +gboolean regress_test_obj_torture_signature_1 (RegressTestObj *obj, + int x, + double *y, + int *z, + const char *foo, + int *q, + guint m, + GError **error); + +GI_TEST_EXTERN +gboolean regress_test_obj_skip_return_val (RegressTestObj *obj, + gint a, + gint *out_b, + gdouble c, + gint *inout_d, + gint *out_sum, + gint num1, + gint num2, + GError **error); + +GI_TEST_EXTERN +gboolean regress_test_obj_skip_return_val_no_out (RegressTestObj *obj, + gint a, + GError **error); + +GI_TEST_EXTERN +gboolean regress_test_obj_skip_param (RegressTestObj *obj, + gint a, + gint *out_b, + gdouble c, + gint *inout_d, + gint *out_sum, + gint num1, + gint num2, + GError **error); + +GI_TEST_EXTERN +gboolean regress_test_obj_skip_out_param (RegressTestObj *obj, + gint a, + gint *out_b, + gdouble c, + gint *inout_d, + gint *out_sum, + gint num1, + gint num2, + GError **error); + +GI_TEST_EXTERN +gboolean regress_test_obj_skip_inout_param (RegressTestObj *obj, + gint a, + gint *out_b, + gdouble c, + gint *inout_d, + gint *out_sum, + gint num1, + gint num2, + GError **error); + +/* virtual */ +GI_TEST_EXTERN +int regress_test_obj_do_matrix (RegressTestObj *obj, const char *somestr); + +GI_TEST_EXTERN +void regress_func_obj_null_in (RegressTestObj *obj); + +GI_TEST_EXTERN +void regress_test_obj_null_out (RegressTestObj **obj); + +GI_TEST_EXTERN +void regress_func_obj_nullable_in (RegressTestObj *obj); + +GI_TEST_EXTERN +void regress_test_obj_not_nullable_typed_gpointer_in (RegressTestObj *obj, + gpointer input); + +GI_TEST_EXTERN +void regress_test_obj_not_nullable_element_typed_gpointer_in (RegressTestObj *obj, + gpointer input, + guint count); + +GI_TEST_EXTERN +void regress_test_obj_name_conflict (RegressTestObj *obj); + +/* inheritance */ +#define REGRESS_TEST_TYPE_SUB_OBJ (regress_test_sub_obj_get_type ()) +#define REGRESS_TEST_SUB_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), REGRESS_TEST_TYPE_SUB_OBJ, RegressTestSubObj)) +#define REGRESS_TEST_IS_SUB_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), REGRESS_TEST_TYPE_SUB_OBJ)) +#define REGRESS_TEST_SUB_OBJ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), REGRESS_TEST_TYPE_SUB_OBJ, RegressTestSubObjClass)) + +typedef struct _RegressTestSubObj RegressTestSubObj; +typedef struct _RegressTestSubObjClass RegressTestSubObjClass; + +struct _RegressTestSubObj +{ + RegressTestObj parent_instance; + /*< private >*/ + gint number; + gboolean boolean; +}; + +struct _RegressTestSubObjClass +{ + RegressTestObjClass parent_class; +}; + +GI_TEST_EXTERN +GType regress_test_sub_obj_get_type (void); + +GI_TEST_EXTERN +RegressTestObj *regress_test_sub_obj_new (void); + +GI_TEST_EXTERN +void regress_test_sub_obj_unset_bare (RegressTestSubObj *obj); + +GI_TEST_EXTERN +int regress_test_sub_obj_instance_method (RegressTestSubObj *obj); + +/* fundamental object */ +#define REGRESS_TEST_TYPE_FUNDAMENTAL_OBJECT (regress_test_fundamental_object_get_type ()) +#define REGRESS_TEST_IS_FUNDAMENTAL_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), REGRESS_TEST_TYPE_FUNDAMENTAL_OBJECT)) +#define REGRESS_TEST_IS_FUNDAMENTAL_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), REGRESS_TEST_TYPE_FUNDAMENTAL_OBJECT)) +#define REGRESS_TEST_FUNDAMENTAL_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), REGRESS_TEST_TYPE_FUNDAMENTAL_OBJECT, RegressTestFundamentalObjectClass)) +#define REGRESS_TEST_FUNDAMENTAL_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), REGRESS_TEST_TYPE_FUNDAMENTAL_OBJECT, RegressTestFundamentalObject)) +#define REGRESS_TEST_FUNDAMENTAL_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), REGRESS_TEST_TYPE_FUNDAMENTAL_OBJECT, RegressTestFundamentalObjectClass)) +#define REGRESS_TEST_FUNDAMENTAL_OBJECT_CAST(obj) ((RegressTestFundamentalObject *) (obj)) + +typedef struct _RegressTestFundamentalObject RegressTestFundamentalObject; +typedef struct _RegressTestFundamentalObjectClass RegressTestFundamentalObjectClass; +/** + * RegressTestFundamentalObjectCopyFunction: + * + * Returns: (transfer full): + */ +typedef RegressTestFundamentalObject *(*RegressTestFundamentalObjectCopyFunction) (const RegressTestFundamentalObject *obj); +typedef void (*RegressTestFundamentalObjectFinalizeFunction) (RegressTestFundamentalObject *obj); + +struct _RegressTestFundamentalObject +{ + GTypeInstance instance; + gint refcount; + guint flags; +}; + +struct _RegressTestFundamentalObjectClass +{ + GTypeClass type_class; + + RegressTestFundamentalObjectCopyFunction copy; + RegressTestFundamentalObjectFinalizeFunction finalize; +}; + +GI_TEST_EXTERN +GType regress_test_fundamental_object_get_type (void); + +GI_TEST_EXTERN +RegressTestFundamentalObject *regress_test_fundamental_object_ref (RegressTestFundamentalObject *fundamental_object); + +GI_TEST_EXTERN +void regress_test_fundamental_object_unref (RegressTestFundamentalObject *fundamental_object); + +#define REGRESS_TEST_VALUE_HOLDS_FUNDAMENTAL_OBJECT(value) (G_VALUE_HOLDS (value, REGRESS_TEST_TYPE_FUNDAMENTAL_OBJECT)) + +GI_TEST_EXTERN +void regress_test_value_set_fundamental_object (GValue *value, RegressTestFundamentalObject *fundamental_object); + +GI_TEST_EXTERN +RegressTestFundamentalObject *regress_test_value_get_fundamental_object (const GValue *value); + +typedef struct _RegressTestFundamentalSubObject RegressTestFundamentalSubObject; +typedef struct _RegressTestFundamentalSubObjectClass RegressTestFundamentalSubObjectClass; + +struct _RegressTestFundamentalSubObject +{ + RegressTestFundamentalObject fundamental_object; + char *data; +}; + +struct _RegressTestFundamentalSubObjectClass +{ + RegressTestFundamentalObjectClass fundamental_object_class; +}; + +GI_TEST_EXTERN +GType regress_test_fundamental_sub_object_get_type (void); + +struct _RegressTestFundamentalObjectNoGetSetFunc +{ + /* This is not really an RegressTestFundamentalObject but we "inherit" + * the structure from it */ + /* < private > */ + RegressTestFundamentalObject fundamental_object; + + /* < public > */ + char *data; +}; + +struct _RegressTestFundamentalObjectNoGetSetFuncClass +{ + RegressTestFundamentalObjectClass fundamental_object_class; +}; + +typedef struct _RegressTestFundamentalObjectNoGetSetFunc RegressTestFundamentalObjectNoGetSetFunc; +typedef struct _RegressTestFundamentalObjectNoGetSetFuncClass RegressTestFundamentalObjectNoGetSetFuncClass; + +GI_TEST_EXTERN +GType regress_test_fundamental_object_no_get_set_func_get_type (void); + +struct _RegressTestFundamentalSubObjectNoGetSetFunc +{ + /* < private > */ + RegressTestFundamentalObjectNoGetSetFunc fundamental_object; +}; + +struct _RegressTestFundamentalSubObjectNoGetSetFuncClass +{ + RegressTestFundamentalObjectNoGetSetFuncClass fundamental_object_class; +}; + +typedef struct _RegressTestFundamentalSubObjectNoGetSetFunc RegressTestFundamentalSubObjectNoGetSetFunc; +typedef struct _RegressTestFundamentalSubObjectNoGetSetFuncClass RegressTestFundamentalSubObjectNoGetSetFuncClass; + +GI_TEST_EXTERN +GType regress_test_fundamental_sub_object_no_get_set_func_get_type (void); + +GI_TEST_EXTERN +RegressTestFundamentalSubObject * +regress_test_fundamental_sub_object_new (const char *data); + +GI_TEST_EXTERN +RegressTestFundamentalObject * +regress_test_create_fundamental_hidden_class_instance (void); + +GI_TEST_EXTERN +RegressTestFundamentalObjectNoGetSetFunc * +regress_test_fundamental_object_no_get_set_func_new (const char *data); + +GI_TEST_EXTERN +const char * +regress_test_fundamental_object_no_get_set_func_get_data (RegressTestFundamentalObjectNoGetSetFunc *fundamental); + +GI_TEST_EXTERN +RegressTestFundamentalSubObjectNoGetSetFunc * +regress_test_fundamental_sub_object_no_get_set_func_new (const char *data); + +GI_TEST_EXTERN +void +regress_test_fundamental_object_no_get_set_func_make_compatible_with_fundamental_sub_object (void); + +/* callback */ +typedef void (*RegressTestSimpleCallback) (void); +typedef void RegressTestNoPtrCallback (void); +typedef int (*RegressTestCallback) (void); +typedef int (*RegressTestCallbackUserData) (gpointer user_data); +/** + * RegressTestCallbackHashtable: + * @data: (element-type utf8 gint): a hash table; will be modified + */ +typedef void (*RegressTestCallbackHashtable) (GHashTable *data); +typedef void (*RegressTestCallbackGError) (const GError *error); +/** + * RegressTestCallbackOwnedGError: + * @error: (transfer full): GError instance; must be freed by the callback + */ +typedef void (*RegressTestCallbackOwnedGError) (GError *error); +/** + * RegressTestCallbackFull: + * @foo: the investment rate + * @bar: how much money + * @path: (type filename): Path to file + */ +typedef int (*RegressTestCallbackFull) (int foo, double bar, char *path); +/** + * RegressTestCallbackReturnFull: + * Return value: (transfer full): + */ +typedef RegressTestObj *(*RegressTestCallbackReturnFull) (void); +/** + * RegressTestCallbackArray: + * @one: (array length=one_length): + * @one_length: + * @two: (array length=two_length) (element-type utf8): + * @two_length: + */ +typedef int (*RegressTestCallbackArray) (int *one, gsize one_length, const char **two, int two_length); +/** + * RegressTestCallbackArrayInOut: + * @ints: (inout) (array length=length): + * @length: (inout): + */ +typedef void (*RegressTestCallbackArrayInOut) (int **ints, int *length); + +GI_TEST_EXTERN +void regress_test_simple_callback (RegressTestSimpleCallback callback); + +GI_TEST_EXTERN +void regress_test_noptr_callback (RegressTestNoPtrCallback callback); + +GI_TEST_EXTERN +int regress_test_callback (RegressTestCallback callback); + +GI_TEST_EXTERN +int regress_test_multi_callback (RegressTestCallback callback); + +GI_TEST_EXTERN +int regress_test_array_callback (RegressTestCallbackArray callback); + +GI_TEST_EXTERN +int regress_test_array_inout_callback (RegressTestCallbackArrayInOut callback); + +GI_TEST_EXTERN +int regress_test_callback_user_data (RegressTestCallbackUserData callback, + gpointer user_data); + +GI_TEST_EXTERN +void regress_test_callback_return_full (RegressTestCallbackReturnFull callback); + +GI_TEST_EXTERN +int regress_test_callback_destroy_notify (RegressTestCallbackUserData callback, + gpointer user_data, + GDestroyNotify notify); + +GI_TEST_EXTERN +int regress_test_callback_destroy_notify_no_user_data (RegressTestCallbackUserData callback, + GDestroyNotify notify); + +GI_TEST_EXTERN +int regress_test_callback_thaw_notifications (void); + +GI_TEST_EXTERN +void regress_test_callback_async (RegressTestCallbackUserData callback, gpointer user_data); + +GI_TEST_EXTERN +int regress_test_callback_thaw_async (void); + +GI_TEST_EXTERN +void regress_test_async_ready_callback (GAsyncReadyCallback callback); + +GI_TEST_EXTERN +void regress_test_function_async (int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GI_TEST_EXTERN +gboolean regress_test_function_finish (GAsyncResult *res, GError **error); + +GI_TEST_EXTERN +gboolean regress_test_function_sync (int io_priority); + +GI_TEST_EXTERN +void regress_test_obj_instance_method_callback (RegressTestObj *obj, RegressTestCallback callback); + +GI_TEST_EXTERN +void regress_test_obj_static_method_callback (RegressTestCallback callback); + +GI_TEST_EXTERN +RegressTestObj *regress_test_obj_new_callback (RegressTestCallbackUserData callback, + gpointer user_data, + GDestroyNotify notify); + +GI_TEST_EXTERN +void regress_test_obj_new_async (const char *x G_GNUC_UNUSED, + GCancellable *cancellable G_GNUC_UNUSED, + GAsyncReadyCallback callback G_GNUC_UNUSED, + gpointer user_data G_GNUC_UNUSED); +GI_TEST_EXTERN +RegressTestObj *regress_test_obj_new_finish (GAsyncResult *res G_GNUC_UNUSED, + GError **error G_GNUC_UNUSED); + +GI_TEST_EXTERN +void regress_test_hash_table_callback (GHashTable *data, RegressTestCallbackHashtable callback); + +GI_TEST_EXTERN +void regress_test_gerror_callback (RegressTestCallbackGError callback); + +GI_TEST_EXTERN +void regress_test_null_gerror_callback (RegressTestCallbackGError callback); + +GI_TEST_EXTERN +void regress_test_owned_gerror_callback (RegressTestCallbackOwnedGError callback); + +GI_TEST_EXTERN +void regress_test_skip_unannotated_callback (RegressTestCallback callback); + +typedef struct _RegressTestInterface RegressTestInterface; + +/* interface */ +#define REGRESS_TEST_TYPE_INTERFACE (regress_test_interface_get_type ()) +#define REGRESS_TEST_INTERFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), REGRESS_TEST_TYPE_INTERFACE, RegressTestInterface)) +#define REGRESS_TEST_IS_INTERFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), REGRESS_TEST_TYPE_INTERFACE)) +#define REGRESS_TEST_INTERFACE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), REGRESS_TEST_TYPE_INTERFACE, RegressTestInterfaceIface)) + +typedef struct _RegressTestInterfaceIface RegressTestInterfaceIface; + +struct _RegressTestInterfaceIface +{ + GTypeInterface base_iface; +}; + +GI_TEST_EXTERN +GType regress_test_interface_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +void regress_test_interface_emit_signal (RegressTestInterface *self); + +/* gobject with non-standard prefix */ +#define REGRESS_TEST_TYPE_WI_802_1X (regress_test_wi_802_1x_get_type ()) +#define REGRESS_TEST_WI_802_1X(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), REGRESS_TEST_TYPE_WI_802_1X, RegressTestWi8021x)) +#define REGRESS_TEST_IS_WI_802_1X(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), REGRESS_TEST_TYPE_WI_802_1X)) +#define REGRESS_TEST_WI_802_1X_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), REGRESS_TEST_TYPE_WI_802_1X, RegressTestWi8021xClass)) + +typedef struct +{ + GObject parent_instance; + + gboolean testbool; +} RegressTestWi8021x; + +typedef struct +{ + GObjectClass parent_class; +} RegressTestWi8021xClass; + +GI_TEST_EXTERN +GType regress_test_wi_802_1x_get_type (void); + +GI_TEST_EXTERN +RegressTestWi8021x *regress_test_wi_802_1x_new (void); + +GI_TEST_EXTERN +gboolean regress_test_wi_802_1x_get_testbool (RegressTestWi8021x *obj); + +GI_TEST_EXTERN +void regress_test_wi_802_1x_set_testbool (RegressTestWi8021x *obj, gboolean v); + +GI_TEST_EXTERN +int regress_test_wi_802_1x_static_method (int x); + +/* floating gobject */ +#define REGRESS_TEST_TYPE_FLOATING (regress_test_floating_get_type ()) +#define REGRESS_TEST_FLOATING(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), REGRESS_TEST_TYPE_FLOATING, RegressTestFloating)) +#define REGRESS_TEST_IS_FLOATING(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), REGRESS_TEST_TYPE_FLOATING)) +#define REGRESS_TEST_FLOATING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), REGRESS_TEST_TYPE_FLOATING, RegressTestFloatingClass)) + +typedef struct +{ + GInitiallyUnowned parent_instance; +} RegressTestFloating; + +typedef struct +{ + GInitiallyUnownedClass parent_class; +} RegressTestFloatingClass; + +GI_TEST_EXTERN +GType regress_test_floating_get_type (void); + +GI_TEST_EXTERN +RegressTestFloating *regress_test_floating_new (void); + +/* Function signature torture tests */ + +GI_TEST_EXTERN +void regress_test_torture_signature_0 (int x, + double *y, + int *z, + const char *foo, + int *q, + guint m); + +GI_TEST_EXTERN +gboolean regress_test_torture_signature_1 (int x, + double *y, + int *z, + const char *foo, + int *q, + guint m, + GError **error); + +GI_TEST_EXTERN +void regress_test_torture_signature_2 (int x, + RegressTestCallbackUserData callback, + gpointer user_data, + GDestroyNotify notify, + double *y, + int *z, + const char *foo, + int *q, + guint m); + +GI_TEST_EXTERN +GValue *regress_test_date_in_gvalue (void); + +GI_TEST_EXTERN +GValue *regress_test_strv_in_gvalue (void); + +GI_TEST_EXTERN +GValue *regress_test_null_strv_in_gvalue (void); + +GI_TEST_EXTERN +GObject *_regress_this_is_a_private_symbol (void); + +GI_TEST_EXTERN +void regress_test_multiline_doc_comments (void); + +GI_TEST_EXTERN +void regress_test_nested_parameter (int a); + +/** + * RegressSkippedStructure: (skip) + * + * This should be skipped, and moreover, all function which + * use it should be. + */ +typedef struct +{ + int x; + double v; +} RegressSkippedStructure; + +GI_TEST_EXTERN +void regress_random_function_with_skipped_structure (int x, + RegressSkippedStructure *foo, + double v); + +/** + * RegressIntset: + * + * Like telepathy-glib's TpIntset. + * + */ +typedef struct _RegressIntset RegressIntset; + +/** + * RegressIntsetAlias: (skip) + * + * Compatibility typedef, like telepathy-glib's TpIntSet + * + */ +typedef RegressIntset RegressIntsetAlias; + +/** + * RegressPtrArrayAlias: + * + * Typedef'd GPtrArray for some reason + */ +typedef GPtrArray RegressPtrArrayAlias; + +GI_TEST_EXTERN +void regress_introspectable_via_alias (RegressPtrArrayAlias *data); + +/** + * RegressVaListAlias: + * + * Typedef'd va_list for additional reasons + */ +typedef va_list RegressVaListAlias; + +GI_TEST_EXTERN +void regress_not_introspectable_via_alias (RegressVaListAlias ok); + +/** + * RegressAliasedTestBoxed: + * + * Typedef TestBoxed to test caller-allocates correctness + */ +typedef RegressTestBoxed RegressAliasedTestBoxed; + +GI_TEST_EXTERN +void regress_aliased_caller_alloc (RegressAliasedTestBoxed *boxed); + +/* private testing */ + +typedef struct +{ + gint this_is_public_before; + /* < private > */ + gint this_is_private; + /* < public > */ + gint this_is_public_after; +} RegressTestPrivateStruct; + +typedef enum +{ + REGRESS_TEST_PUBLIC_ENUM_BEFORE = 1 << 0, + /* */ + REGRESS_TEST_PRIVATE_ENUM = 1 << 1, + /* */ + REGRESS_TEST_PUBLIC_ENUM_AFTER = 1 << 2, +} RegressTestPrivateEnum; + +typedef struct +{ + gint just_int; + gint array[10]; +} RegressTestStructFixedArray; + +GI_TEST_EXTERN +void regress_test_struct_fixed_array_frob (RegressTestStructFixedArray *str); + +typedef struct +{ + gchar name[32]; +} RegressLikeXklConfigItem; + +GI_TEST_EXTERN +void regress_like_xkl_config_item_set_name (RegressLikeXklConfigItem *self, + char const *name); + +#define REGRESS_UTF8_CONSTANT "const \xe2\x99\xa5 utf8" + +#ifdef __GNUC__ +#define REGRESS_TEST_GNUC_EXTENSION_STMT(foo) (G_GNUC_EXTENSION ({ int x[10]; x[5] = 42; x[5]; })) +#endif + +/* https://bugzilla.gnome.org/show_bug.cgi?id=662888 */ +#define REGRESS_LONG_STRING_CONSTANT \ + "TYPE,VALUE,ENCODING,CHARSET,LANGUAGE,DOM,INTL,POSTAL,PARCEL," \ + "HOME,WORK,PREF,VOICE,FAX,MSG,CELL,PAGER,BBS,MODEM,CAR,ISDN,VIDEO," \ + "AOL,APPLELINK,ATTMAIL,CIS,EWORLD,INTERNET,IBMMAIL,MCIMAIL," \ + "POWERSHARE,PRODIGY,TLX,X400,GIF,CGM,WMF,BMP,MET,PMB,DIB,PICT,TIFF," \ + "PDF,PS,JPEG,QTIME,MPEG,MPEG2,AVI,WAVE,AIFF,PCM,X509,PGP" + +GI_TEST_EXTERN +void regress_has_parameter_named_attrs (int foo, + gpointer attributes); + +typedef struct +{ + int dummy; + struct + { + const char *name; + guint x; + } attributes[32]; + + double dummy2; +} RegressLikeGnomeKeyringPasswordSchema; + +/* Ensure we ignore symbols that start with _; in particular we don't + * want to issue a namespace warning. + */ +#define _DONTSCANTHIS 1 + +/* https://bugzilla.gnome.org/show_bug.cgi?id=685022 */ +#define REGRESS_MININT64 ((gint64) G_GINT64_CONSTANT (0x8000000000000000)) +#define REGRESS_MAXUINT64 (G_GINT64_CONSTANT (0xffffffffffffffffU)) + +/* https://bugzilla.gnome.org/show_bug.cgi?id=698367 */ +#ifndef __GI_SCANNER__ +#define REGRESS_DONTSCANTHIS 1 +#else +#define REGRESS_GI_SCANNER_ELSE 3 +#endif +#ifndef BLAH +#ifdef __GI_SCANNER__ +#define REGRESS_GI_SCANNER_IFDEF 3 +#endif +#endif + +/* This struct is one pattern by which padding can be consumed, if + * you're willing to take a hard dependency on anonymous unions. */ +typedef struct +{ + int x; + + union + { + RegressLikeGnomeKeyringPasswordSchema *a[2]; + + guint padding[4]; + }; +} RegressAnAnonymousUnion; + +typedef struct +{ + int x; + + union + { + struct + { + RegressLikeGnomeKeyringPasswordSchema *a; + RegressLikeXklConfigItem *b; + }; + + guint padding[4]; + }; +} RegressAnonymousUnionAndStruct; + +GI_TEST_EXTERN +GVariant *regress_get_variant (void); + +typedef struct _RegressTestReferenceCounters RegressTestReferenceCounters; + +struct _RegressTestReferenceCounters +{ + grefcount refcount; + gatomicrefcount atomicrefcount; +}; + +GI_TEST_EXTERN +void regress_test_array_struct_out_none (RegressTestStructA **arr, gsize *len); + +GI_TEST_EXTERN +void regress_test_array_struct_out_container (RegressTestStructA **arr, gsize *len); + +GI_TEST_EXTERN +void regress_test_array_struct_out_full_fixed (RegressTestStructA **arr); + +GI_TEST_EXTERN +void regress_test_array_struct_out_caller_alloc (RegressTestStructA *arr, gsize len); + +GI_TEST_EXTERN +void regress_test_array_struct_in_full (RegressTestStructA *arr, gsize len); + +GI_TEST_EXTERN +void regress_test_array_struct_in_none (RegressTestStructA *arr, gsize len); + +GI_TEST_EXTERN +void regress_test_obj_function_async (RegressTestObj *self, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GI_TEST_EXTERN +gboolean regress_test_obj_function_finish (RegressTestObj *self, GAsyncResult *res, GError **error); + +GI_TEST_EXTERN +gboolean regress_test_obj_function_sync (RegressTestObj *self, int io_priority); + +static inline gboolean regress_test_inline_function (gboolean foo); +/* + * regress_test_inline_function: + * + * An inline function that should be exposed as such + */ +static inline gboolean +regress_test_inline_function (gboolean foo) +{ + return foo; +} + +static inline gboolean regress_test_obj_inline_method (RegressTestObj *obj, gboolean foo); +/* + * regress_test_obj_inline_method: + * + * An inline function that should be exposed as such + */ +static inline gboolean +regress_test_obj_inline_method (RegressTestObj *obj G_GNUC_UNUSED, gboolean foo) +{ + return foo; +} diff --git a/subprojects/gobject-introspection-tests/tools/iwyu.imp b/subprojects/gobject-introspection-tests/tools/iwyu.imp new file mode 100644 index 000000000..c60aa05a7 --- /dev/null +++ b/subprojects/gobject-introspection-tests/tools/iwyu.imp @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: MIT OR LGPL-2.0-or-later +# SPDX-FileCopyrightText: 2024 Philip Chimento + +[ + {"include": ["", "private", "", "public"]}, + {"include": ["\"gobject/gclosure.h\"", "private", "", "public"]}, + {"include": ["\"gobject/glib-types.h\"", "private", "", "public"]}, + {"include": ["\"gobject/gmarshal.h\"", "private", "", "public"]}, +] diff --git a/subprojects/gobject-introspection-tests/tools/run_clang_format.sh b/subprojects/gobject-introspection-tests/tools/run_clang_format.sh new file mode 100644 index 000000000..cad287799 --- /dev/null +++ b/subprojects/gobject-introspection-tests/tools/run_clang_format.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# SPDX-License-Identifier: MIT OR LGPL-2.0-or-later +# SPDX-FileCopyrightText: 2024 Philip Chimento + +CLANG_FORMAT=${CLANG_FORMAT:-clang-format} +for file in *.c *.h; do + $CLANG_FORMAT -i $file +done diff --git a/subprojects/gobject-introspection-tests/tools/run_iwyu.sh b/subprojects/gobject-introspection-tests/tools/run_iwyu.sh new file mode 100644 index 000000000..e893f5626 --- /dev/null +++ b/subprojects/gobject-introspection-tests/tools/run_iwyu.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# SPDX-License-Identifier: MIT OR LGPL-2.0-or-later +# SPDX-FileCopyrightText: 2024 Philip Chimento + +IWYU=${IWYU:-include-what-you-use} +CFLAGS=$(pkg-config --cflags glib-2.0 gobject-2.0 gio-2.0 cairo-gobject) +for file in *.c; do + $IWYU -Xiwyu --mapping_file=tools/iwyu.imp -xc $CFLAGS $file +done diff --git a/subprojects/gobject-introspection-tests/utility.c b/subprojects/gobject-introspection-tests/utility.c new file mode 100644 index 000000000..e5bac32ca --- /dev/null +++ b/subprojects/gobject-introspection-tests/utility.c @@ -0,0 +1,55 @@ +/* +SPDX-FileCopyrightText: 2008 Johan Dahlin +SPDX-FileCopyrightText: 2009 Andreas Rottmann +*/ + +#include "utility.h" + +G_DEFINE_TYPE (UtilityObject, utility_object, G_TYPE_OBJECT); + +/** + * UtilityBuffer: + * @data: (type gpointer): the data + * + **/ + +static void +utility_object_class_init (UtilityObjectClass *klass G_GNUC_UNUSED) +{ +} + +static void +utility_object_init (UtilityObject *object G_GNUC_UNUSED) +{ +} + +/** + * utility_object_watch_dir: + * @object: + * @path: + * @func: (destroy destroy): + * @user_data: + * @destroy: + */ +void +utility_object_watch_dir (UtilityObject *object G_GNUC_UNUSED, + const char *path G_GNUC_UNUSED, + UtilityFileFunc func G_GNUC_UNUSED, + gpointer user_data G_GNUC_UNUSED, + GDestroyNotify destroy G_GNUC_UNUSED) +{ +} + +/** + * utility_dir_foreach: + * @path:: + * @func: (scope call): + * @user_data:: + * + */ +void +utility_dir_foreach (const char *path G_GNUC_UNUSED, + UtilityFileFunc func G_GNUC_UNUSED, + gpointer user_data G_GNUC_UNUSED) +{ +} diff --git a/subprojects/gobject-introspection-tests/utility.h b/subprojects/gobject-introspection-tests/utility.h new file mode 100644 index 000000000..c8aeb074e --- /dev/null +++ b/subprojects/gobject-introspection-tests/utility.h @@ -0,0 +1,105 @@ +/* +SPDX-FileCopyrightText: 2008 Colin Walters +SPDX-FileCopyrightText: 2008 Johan Dahlin +SPDX-FileCopyrightText: 2008-2009 Andreas Rottmann +*/ + +#pragma once + +#include +#include + +#include "gitestmacros.h" + +#define UTILITY_TYPE_OBJECT (utility_object_get_type ()) +#define UTILITY_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), UTILITY_TYPE_OBJECT, UtilityObject)) +#define UTILITY_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), UTILITY_TYPE_OBJECT)) + +typedef struct _UtilityObject UtilityObject; +typedef struct _UtilityObjectClass UtilityObjectClass; + +struct _UtilityObject +{ + GObject parent_instance; +}; + +struct _UtilityObjectClass +{ + GObjectClass parent_class; +}; + +/* This one is similar to Pango.Glyph */ +typedef guint32 UtilityGlyph; + +typedef struct +{ + int tag; + union + { + gpointer v_pointer; + double v_real; + long v_integer; + } value; +} UtilityTaggedValue; + +typedef union +{ + guint8 value; + struct + { + guint8 first_nibble : 4; + guint8 second_nibble : 4; + } parts; +} UtilityByte; + +/* This one is similiar to Soup.Buffer */ +typedef struct +{ + const char *data; + gsize length; +} UtilityBuffer; + +typedef void (*UtilityFileFunc) (const char *path, gpointer user_data); + +GI_TEST_EXTERN +GType utility_object_get_type (void) G_GNUC_CONST; + +GI_TEST_EXTERN +void utility_object_watch_dir (UtilityObject *object, + const char *path, + UtilityFileFunc func, + gpointer user_data, + GDestroyNotify destroy); + +typedef enum +{ + UTILITY_ENUM_A, + UTILITY_ENUM_B, + UTILITY_ENUM_C +} UtilityEnumType; + +/* The shift operators here should imply bitfield */ +typedef enum +{ + UTILITY_FLAG_A = 1 << 0, + UTILITY_FLAG_B = 1 << 1, + UTILITY_FLAG_C = 1 << 2 +} UtilityFlagType; + +typedef struct +{ + int field; + guint bitfield1 : 3; + guint bitfield2 : 2; + guint8 data[16]; +} UtilityStruct; + +typedef union +{ + char *pointer; + glong integer; + double real; +} UtilityUnion; + +GI_TEST_EXTERN +void utility_dir_foreach (const char *path, UtilityFileFunc func, gpointer user_data); diff --git a/subprojects/gobject-introspection-tests/warnlib.c b/subprojects/gobject-introspection-tests/warnlib.c new file mode 100644 index 000000000..9b844e700 --- /dev/null +++ b/subprojects/gobject-introspection-tests/warnlib.c @@ -0,0 +1,48 @@ +/* +SPDX-FileCopyrightText: 2012 Colin Walters +SPDX-FileCopyrightText: 2013 Dieter Verfaillie +*/ + +#include "warnlib.h" + +GQuark +warnlib_unpaired_error_quark (void) +{ + return g_quark_from_static_string ("warnlib-unpaired-error"); +} + +gboolean +warnlib_throw_unpaired (GError **error) +{ + g_set_error_literal (error, warnlib_unpaired_error_quark (), 0, + "Unpaired error"); + return FALSE; +} + +typedef WarnLibWhateverIface WarnLibWhateverInterface; +G_DEFINE_INTERFACE (WarnLibWhatever, warnlib_whatever, G_TYPE_OBJECT) + +static void +warnlib_whatever_default_init (WarnLibWhateverIface *iface G_GNUC_UNUSED) +{ +} + +void +warnlib_whatever_do_moo (WarnLibWhatever *self, int x, gpointer y) +{ + WARNLIB_WHATEVER_GET_IFACE (self)->do_moo (self, x, y); +} + +/** + * warnlib_whatever_do_boo: + * @self: a WarnLibWhatever + * @x: x parameter + * @y: y parameter + * + * Does boo. + */ +void +warnlib_whatever_do_boo (WarnLibWhatever *self, int x, gpointer y) +{ + WARNLIB_WHATEVER_GET_IFACE (self)->do_boo (self, x, y); +} diff --git a/subprojects/gobject-introspection-tests/warnlib.h b/subprojects/gobject-introspection-tests/warnlib.h new file mode 100644 index 000000000..8a1e52289 --- /dev/null +++ b/subprojects/gobject-introspection-tests/warnlib.h @@ -0,0 +1,52 @@ +/* +SPDX-FileCopyrightText: 2012 Colin Walters +SPDX-FileCopyrightText: 2013 Dieter Verfaillie +*/ + +#pragma once + +#include +#include + +#include "gitestmacros.h" + +#define WARNLIB_UNPAIRED_ERROR (warnlib_unpaired_error_quark ()) +GI_TEST_EXTERN +GQuark warnlib_unpaired_error_quark (void); + +GI_TEST_EXTERN +gboolean warnlib_throw_unpaired (GError **error); + +/* interface */ +#define WARNLIB_TYPE_WHATEVER (warnlib_whatever_get_type ()) +#define WARNLIB_WHATEVER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), WARNLIB_TYPE_WHATEVER, WarnLibWhatever)) +#define WARNLIB_IS_WHATEVER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), WARNLIB_TYPE_WHATEVER)) +#define WARNLIB_WHATEVER_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), WARNLIB_TYPE_WHATEVER, WarnLibWhateverIface)) + +typedef struct _WarnLibWhateverIface WarnLibWhateverIface; +typedef struct _WarnLibWhatever WarnLibWhatever; + +struct _WarnLibWhateverIface +{ + GTypeInterface parent_iface; + + /* virtual table */ + + /* explicitly test un-named parameters */ + void (*do_moo) (WarnLibWhatever *self, int, gpointer); + + void (*do_boo) (WarnLibWhatever *self, int x, gpointer y); +}; + +GI_TEST_EXTERN +void warnlib_whatever_do_moo (WarnLibWhatever *self, int, gpointer); +GI_TEST_EXTERN +void warnlib_whatever_do_boo (WarnLibWhatever *self, int, gpointer); + +GI_TEST_EXTERN +GType warnlib_whatever_get_type (void) G_GNUC_CONST; + +typedef enum +{ + WARNLIB_1ST = 1, +} WarnLibNumericEnum; diff --git a/test/check-headers.sh b/test/check-headers.sh new file mode 100644 index 000000000..56a977c44 --- /dev/null +++ b/test/check-headers.sh @@ -0,0 +1,181 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.0-or-later +# SPDX-FileCopyrightText: 2024 Philip Chimento + +# Drafted with assistance from ChatGPT. +# https://chat.openai.com/share/0cd77782-13b5-4775-80d0-c77c7749fb9d + +if [ -n "$SELFTEST" ]; then + unset SELFTEST + set -x + self="$(realpath "$0")" + test_paths=() + trap 'rm -rf -- "${test_paths[@]}"' EXIT + + test_env() { + local code_path + code_path=$(mktemp -d -t "check-pch-XXXXXX") + test_paths+=("$code_path") + cd "$code_path" || exit + mkdir gi gjs libgjs-private modules test util + } + + expect_success() { + "$self" || exit 1 + } + expect_failure() { + "$self" && exit 1 || true + } + + # config.h is included + test_env + echo "#include " > gjs/program.c + expect_success + + # config.h must be in angle brackets + test_env + echo '#include "config.h"' > gjs/program.c + expect_failure + + # public headers are skipped + test_env + echo "#include " > gjs/macros.h + expect_success + + # config.h must be included + test_env + echo "#include " > gjs/program.c + expect_failure + + # config.h is included first + test_env + echo '#include ' > gjs/program.c + echo '#include ' >> gjs/program.c + expect_success + + # config.h must be included first + test_env + echo '#include ' > gjs/program.c + echo '#include ' >> gjs/program.c + expect_failure + + # other non-include things can come before the include + test_env + cat > gjs/program.h < +EOF + expect_success + + # spaces are taken into account + test_env + cat > gjs/program.c < +#endif +#include +EOF + expect_failure + + # header blocks in right order + test_env + cat > gjs/program.c < +#include +#include +#include +#include +#include "program.h" +EOF + expect_success + + # header blocks in wrong order + test_env + cat > gjs/program.c < +#include +#include +#include +#include "program.h" +#include +EOF + expect_failure + + exit 0 +fi + +failed=0 + +function report_out_of_order { + file="$1" + shift + include="$1" + shift + descr="$1" + shift + headers=("$@") + + if [[ ${#headers[@]} -ne 0 ]]; then + echo "Error: $file: include $include before $descr header ${headers[0]}" + failed=1 + return 1 + fi + return 0 +} + +function check_config_header { + file="$1" + included_files=($(sed -nE 's/^#[[:space:]]*include[[:space:]]*([<"][^>"]+[>"]).*/\1/p' "$file")) + if [[ "${included_files[0]}" != "" ]]; then + echo "Error: $file: include as the first #include directive" + failed=1 + fi + + c_headers=() + cpp_headers=() + gnome_headers=() + moz_headers=() + gjs_headers=() + for include in "${included_files[@]:1}"; do + if [[ "$include" =~ \".*\.h\" ]]; then + gjs_headers+=("$include") + continue + fi + report_out_of_order "$file" "$include" "GJS" "${gjs_headers[@]}" || continue + if [[ "$include" =~ \<(js|mozilla).*\.h\> ]]; then + moz_headers+=("$include") + continue + fi + report_out_of_order "$file" "$include" "Mozilla" "${moz_headers[@]}" || continue + if [[ "$include" =~ \<(ffi|sysprof.*|cairo.*|g.*)\.h\> ]]; then + gnome_headers+=("$include") + continue + fi + report_out_of_order "$file" "$include" "GNOME platform" "${gnome_headers[@]}" || continue + if [[ "$include" =~ \<.*\.h\> ]]; then + report_out_of_order "$file" "$include" "C++ standard library" "${cpp_headers[@]}" || continue + c_headers+=("$include") + elif [[ "$include" =~ \<.*\> ]]; then + cpp_headers+=("$include") + else + echo "Error: Need to fix your regex to handle $include." + failed=1 + fi + done +} + +files=$(find gi gjs libgjs-private modules test util \ + -name '*.c' -o -name '*.cpp' -o -name '*.h') +for file in $files; do + if [[ "$file" == "gjs/gjs.h" || "$file" == "gjs/macros.h" ]]; then continue; fi + if grep -ql "^GJS_EXPORT" "$file"; then continue; fi + check_config_header "$file" +done + +if [[ $failed -ne 0 ]]; then + echo "Errors found." + exit 1 +else + echo "OK." +fi diff --git a/test/check-pch.sh b/test/check-pch.sh old mode 100755 new mode 100644 index 8a83fc2c7..fd27b10f5 --- a/test/check-pch.sh +++ b/test/check-pch.sh @@ -14,8 +14,8 @@ if [ -n "$SELFTEST" ]; then local code_path="$(mktemp -t -d "check-pch-XXXXXX")" test_paths+=("$code_path") cd "$code_path" - mkdir cjs gi - echo "#include " >> cjs/gjs_pch.hh + mkdir gjs gi + echo "#include " >> gjs/gjs_pch.hh } expect_success() { @@ -53,12 +53,12 @@ if [ -n "$SELFTEST" ]; then expect_failure test_env - echo "#include " >> cjs/gjs_pch.hh + echo "#include " >> gjs/gjs_pch.hh echo "#include " >> gi/code.c expect_failure test_env - echo "#include // check-pch: ignore, yes" >> cjs/gjs_pch.hh + echo "#include // check-pch: ignore, yes" >> gjs/gjs_pch.hh echo "#include " >> gi/code.c expect_success @@ -74,14 +74,14 @@ if [ -n "$SELFTEST" ]; then test_env echo "#include " >> gi/code.c - echo '#include "local/header.h"' >> cjs/gjs_pch.hh + echo '#include "local/header.h"' >> gjs/gjs_pch.hh expect_failure test_env echo "# include " >> gi/code.c echo "# include " >> gi/code.c echo " # include " >> gi/other-file.c - echo "# include " >> cjs/gjs_pch.hh + echo "# include " >> gjs/gjs_pch.hh expect_success test_env @@ -98,7 +98,7 @@ if [ -n "$SELFTEST" ]; then echo "#include " >> gi/code.c echo "//#include " >> gi/invalid-file.c echo "// #include " >> gi/invalid-file.c - echo "//#include " >> cjs/gjs_pch.hh + echo "//#include " >> gjs/gjs_pch.hh expect_success test_env @@ -114,10 +114,10 @@ if [ -n "$SELFTEST" ]; then exit 0 fi -PCH_FILES=(cjs/gjs_pch.hh) +PCH_FILES=(gjs/gjs_pch.hh) IGNORE_COMMENT="check-pch: ignore" -CODE_PATHS=(cjs gi) +CODE_PATHS=(gjs gi) INCLUDED_FILES=( \*.c \*.cpp diff --git a/test/extra/Dockerfile b/test/extra/Dockerfile index 82ae8d4de..14bcbe13c 100644 --- a/test/extra/Dockerfile +++ b/test/extra/Dockerfile @@ -3,22 +3,25 @@ # === Build Spidermonkey stage === -FROM registry.fedoraproject.org/fedora:38 AS mozjs-build -ARG MOZJS_BRANCH=mozjs102 +FROM registry.fedoraproject.org/fedora:40 AS mozjs-build +ARG MOZJS_BRANCH=mozjs115 ARG MOZJS_BUILDDEPS=${MOZJS_BRANCH} ARG BUILD_OPTS= ENV SHELL=/bin/bash -# mozjs102 cannot be built with python3.11 and possibly 3.10 +# mozjs115 cannot be built with python3.11 +# cbindgen should be included in builddep(mozjs128) RUN dnf -y install 'dnf-command(builddep)' \ autoconf213 \ + cbindgen \ clang \ git \ llvm \ llvm-devel \ make \ - python3.9 \ + python3.10 \ + python-packaging \ rust \ which \ xz @@ -31,7 +34,7 @@ RUN mkdir -p mozjs/_build WORKDIR /root/mozjs/_build -ENV PYTHON3=/usr/bin/python3.9 +ENV PYTHON3=/usr/bin/python3.10 RUN ../js/src/configure --prefix=/usr --libdir=/usr/lib64 --disable-jemalloc \ --with-system-zlib --with-intl-api ${BUILD_OPTS} RUN make -j$(nproc) @@ -40,7 +43,7 @@ RUN rm -f /root/mozjs-install/usr/lib64/libjs_static.ajs # === Actual Docker image === -FROM registry.fedoraproject.org/fedora:38 +FROM registry.fedoraproject.org/fedora:40 ARG LOCALES=tr_TR ENV SHELL=/bin/bash diff --git a/test/extra/Dockerfile.debug b/test/extra/Dockerfile.debug index 302a4d150..876e45727 100644 --- a/test/extra/Dockerfile.debug +++ b/test/extra/Dockerfile.debug @@ -3,16 +3,18 @@ # === Build stage === -FROM registry.fedoraproject.org/fedora:38 AS build -ARG MOZJS_BRANCH=mozjs102 +FROM registry.fedoraproject.org/fedora:40 AS build +ARG MOZJS_BRANCH=mozjs115 ARG MOZJS_BUILDDEPS=${MOZJS_BRANCH} ARG BUILD_OPTS= ENV SHELL=/bin/bash -# mozjs102 cannot be built with python3.11 and possibly 3.10 +# mozjs115 cannot be built with python3.11 +# cbindgen should be included in builddep(mozjs128) RUN dnf -y install 'dnf-command(builddep)' \ autoconf213 \ + cbindgen \ clang \ clang-devel \ cmake \ @@ -21,7 +23,8 @@ RUN dnf -y install 'dnf-command(builddep)' \ llvm-devel \ make \ ninja-build \ - python3.9 \ + python3.10 \ + python3-packaging \ rust \ which \ xz @@ -30,9 +33,9 @@ RUN dnf -y builddep ${MOZJS_BUILDDEPS} WORKDIR /root RUN mkdir -p include-what-you-use/_build -ADD https://include-what-you-use.org/downloads/include-what-you-use-0.20.src.tar.gz /root/include-what-you-use/ +ADD https://include-what-you-use.org/downloads/include-what-you-use-0.22.src.tar.gz /root/include-what-you-use/ WORKDIR /root/include-what-you-use -RUN tar xzf include-what-you-use-0.20.src.tar.gz --strip-components=1 +RUN tar xzf include-what-you-use-0.22.src.tar.gz --strip-components=1 WORKDIR /root/include-what-you-use/_build @@ -47,7 +50,7 @@ RUN mkdir -p mozjs/_build WORKDIR /root/mozjs/_build -ENV PYTHON3=/usr/bin/python3.9 +ENV PYTHON3=/usr/bin/python3.10 RUN ../js/src/configure --prefix=/usr --libdir=/usr/lib64 --disable-jemalloc \ --with-system-zlib --with-intl-api --enable-debug \ ${BUILD_OPTS} @@ -55,19 +58,9 @@ RUN make -j$(nproc) RUN DESTDIR=/root/mozjs-install make install RUN rm -f /root/mozjs-install/usr/lib64/libjs_static.ajs -WORKDIR /root - -# Install gnome-introspection from main, so that we can test against it -RUN dnf -y builddep gobject-introspection -RUN git clone https://gitlab.gnome.org/GNOME/gobject-introspection.git - -WORKDIR /root/gobject-introspection -RUN meson setup _build . --prefix=/opt/GNOME --buildtype debugoptimized -RUN DESTDIR=/root/g-i-install ninja -C _build install - # === Actual Docker image === -FROM registry.fedoraproject.org/fedora:38 +FROM registry.fedoraproject.org/fedora:40 ARG LOCALES=tr_TR ENV SHELL=/bin/bash @@ -126,7 +119,6 @@ RUN dnf -y install --enablerepo=fedora-debuginfo,updates-debuginfo \ COPY --from=build /root/mozjs-install/usr /usr COPY --from=build /root/iwyu-install/usr /usr -COPY --from=build /root/g-i-install/opt /opt RUN ln -s /usr/bin/iwyu_tool.py /usr/bin/iwyu_tool # Enable sudo for wheel users diff --git a/test/extra/do_environment.sh b/test/extra/do_environment.sh old mode 100755 new mode 100644 diff --git a/test/gjs-test-common.h b/test/gjs-test-common.h index adb1acec7..631614891 100644 --- a/test/gjs-test-common.h +++ b/test/gjs-test-common.h @@ -5,6 +5,8 @@ #ifndef TEST_GJS_TEST_COMMON_H_ #define TEST_GJS_TEST_COMMON_H_ +#include + struct JSContext; char* gjs_test_get_exception_message(JSContext* cx); diff --git a/test/gjs-test-coverage.cpp b/test/gjs-test-coverage.cpp index 95369b836..756d0edc1 100644 --- a/test/gjs-test-coverage.cpp +++ b/test/gjs-test-coverage.cpp @@ -3,6 +3,8 @@ // SPDX-FileCopyrightText: 2014 Endless Mobile, Inc. // SPDX-FileContributor: Authored By: Sam Spilsbury +#include + #include // for errno #include // for sscanf, size_t #include // for strtol, atoi, mkdtemp @@ -242,7 +244,7 @@ static void test_covered_file_is_duplicated_into_output_if_resource( void* fixture_data, const void*) { GjsCoverageFixture *fixture = (GjsCoverageFixture *) fixture_data; - const char *mock_resource_filename = "resource:///org/gnome/gjs/mock/test/gjs-test-coverage/loadedJSFromResource.js"; + const char *mock_resource_filename = "resource:///org/cinnamon/cjs/mock/test/gjs-test-coverage/loadedJSFromResource.js"; const char *coverage_scripts[] = { mock_resource_filename, NULL @@ -268,7 +270,7 @@ static void test_covered_file_is_duplicated_into_output_if_resource( GFile *expected_temporary_js_script = g_file_resolve_relative_path(fixture->lcov_output_dir, - "org/gnome/gjs/mock/test/gjs-test-coverage/loadedJSFromResource.js"); + "org/cinnamon/cjs/mock/test/gjs-test-coverage/loadedJSFromResource.js"); g_assert_true(g_file_query_exists(expected_temporary_js_script, NULL)); g_object_unref(expected_temporary_js_script); @@ -1226,87 +1228,87 @@ void gjs_test_add_tests_for_coverage() gjs_coverage_fixture_tear_down }; - add_test_for_fixture("/gjs/coverage/file_duplicated_into_output_path", + add_test_for_fixture("/cjs/coverage/file_duplicated_into_output_path", &coverage_fixture, test_covered_file_is_duplicated_into_output_if_path, NULL); - add_test_for_fixture("/gjs/coverage/file_duplicated_full_resource_path", + add_test_for_fixture("/cjs/coverage/file_duplicated_full_resource_path", &coverage_fixture, test_covered_file_is_duplicated_into_output_if_resource, NULL); - add_test_for_fixture("/gjs/coverage/contents_preserved_accumulate_mode", + add_test_for_fixture("/cjs/coverage/contents_preserved_accumulate_mode", &coverage_fixture, test_previous_contents_preserved, NULL); - add_test_for_fixture("/gjs/coverage/new_contents_appended_accumulate_mode", + add_test_for_fixture("/cjs/coverage/new_contents_appended_accumulate_mode", &coverage_fixture, test_new_contents_written, NULL); - add_test_for_fixture("/gjs/coverage/expected_source_file_name_written_to_coverage_data", + add_test_for_fixture("/cjs/coverage/expected_source_file_name_written_to_coverage_data", &coverage_fixture, test_expected_source_file_name_written_to_coverage_data, NULL); - add_test_for_fixture("/gjs/coverage/entry_not_written_for_nonexistent_file", + add_test_for_fixture("/cjs/coverage/entry_not_written_for_nonexistent_file", &coverage_fixture, test_expected_entry_not_written_for_nonexistent_file, NULL); - add_test_for_fixture("/gjs/coverage/single_branch_coverage_written_to_coverage_data", + add_test_for_fixture("/cjs/coverage/single_branch_coverage_written_to_coverage_data", &coverage_fixture, test_single_branch_coverage_written_to_coverage_data, NULL); - add_test_for_fixture("/gjs/coverage/multiple_branch_coverage_written_to_coverage_data", + add_test_for_fixture("/cjs/coverage/multiple_branch_coverage_written_to_coverage_data", &coverage_fixture, test_multiple_branch_coverage_written_to_coverage_data, NULL); - add_test_for_fixture("/gjs/coverage/branches_for_multiple_case_statements_fallthrough", + add_test_for_fixture("/cjs/coverage/branches_for_multiple_case_statements_fallthrough", &coverage_fixture, test_branches_for_multiple_case_statements_fallthrough, NULL); - add_test_for_fixture("/gjs/coverage/not_hit_branch_point_written_to_coverage_data", + add_test_for_fixture("/cjs/coverage/not_hit_branch_point_written_to_coverage_data", &coverage_fixture, test_branch_not_hit_written_to_coverage_data, NULL); - add_test_for_fixture("/gjs/coverage/function_names_written_to_coverage_data", + add_test_for_fixture("/cjs/coverage/function_names_written_to_coverage_data", &coverage_fixture, test_function_names_written_to_coverage_data, NULL); - add_test_for_fixture("/gjs/coverage/function_lines_written_to_coverage_data", + add_test_for_fixture("/cjs/coverage/function_lines_written_to_coverage_data", &coverage_fixture, test_function_lines_written_to_coverage_data, NULL); - add_test_for_fixture("/gjs/coverage/function_hit_counts_written_to_coverage_data", + add_test_for_fixture("/cjs/coverage/function_hit_counts_written_to_coverage_data", &coverage_fixture, test_function_hit_counts_written_to_coverage_data, NULL); - add_test_for_fixture("/gjs/coverage/big_function_hit_counts_written_to_coverage_data", + add_test_for_fixture("/cjs/coverage/big_function_hit_counts_written_to_coverage_data", &coverage_fixture, test_function_hit_counts_for_big_functions_written_to_coverage_data, NULL); - add_test_for_fixture("/gjs/coverage/little_function_hit_counts_written_to_coverage_data", + add_test_for_fixture("/cjs/coverage/little_function_hit_counts_written_to_coverage_data", &coverage_fixture, test_function_hit_counts_for_little_functions_written_to_coverage_data, NULL); - add_test_for_fixture("/gjs/coverage/total_function_coverage_written_to_coverage_data", + add_test_for_fixture("/cjs/coverage/total_function_coverage_written_to_coverage_data", &coverage_fixture, test_total_function_coverage_written_to_coverage_data, NULL); - add_test_for_fixture("/gjs/coverage/single_line_hit_written_to_coverage_data", + add_test_for_fixture("/cjs/coverage/single_line_hit_written_to_coverage_data", &coverage_fixture, test_single_line_hit_written_to_coverage_data, NULL); - add_test_for_fixture("/gjs/coverage/hits_on_multiline_if_cond", + add_test_for_fixture("/cjs/coverage/hits_on_multiline_if_cond", &coverage_fixture, test_hits_on_multiline_if_cond, NULL); - add_test_for_fixture("/gjs/coverage/full_line_tally_written_to_coverage_data", + add_test_for_fixture("/cjs/coverage/full_line_tally_written_to_coverage_data", &coverage_fixture, test_full_line_tally_written_to_coverage_data, NULL); - add_test_for_fixture("/gjs/coverage/no_hits_for_unexecuted_file", + add_test_for_fixture("/cjs/coverage/no_hits_for_unexecuted_file", &coverage_fixture, test_no_hits_to_coverage_data_for_unexecuted, NULL); - add_test_for_fixture("/gjs/coverage/end_of_record_section_written_to_coverage_data", + add_test_for_fixture("/cjs/coverage/end_of_record_section_written_to_coverage_data", &coverage_fixture, test_end_of_record_section_written_to_coverage_data, NULL); @@ -1317,11 +1319,11 @@ void gjs_test_add_tests_for_coverage() gjs_coverage_multiple_source_files_to_single_output_fixture_tear_down }; - add_test_for_fixture("/gjs/coverage/multiple_source_file_records_written_to_coverage_data", + add_test_for_fixture("/cjs/coverage/multiple_source_file_records_written_to_coverage_data", &coverage_for_multiple_files_to_single_output_fixture, test_multiple_source_file_records_written_to_coverage_data, NULL); - add_test_for_fixture("/gjs/coverage/correct_line_coverage_data_written_for_both_sections", + add_test_for_fixture("/cjs/coverage/correct_line_coverage_data_written_for_both_sections", &coverage_for_multiple_files_to_single_output_fixture, test_correct_line_coverage_data_written_for_both_source_file_sections, NULL); diff --git a/test/gjs-test-jsapi-utils.cpp b/test/gjs-test-jsapi-utils.cpp index 5f319e198..f52cb2850 100644 --- a/test/gjs-test-jsapi-utils.cpp +++ b/test/gjs-test-jsapi-utils.cpp @@ -5,11 +5,15 @@ * Copyright (c) 2020 Marco Trevisan */ -#include -#include +#include + #include // for NULL + #include // for move, swap +#include +#include + #include "cjs/jsapi-util.h" struct _GjsTestObject { @@ -588,108 +592,108 @@ static void test_gjs_error_out() { g_test_add(path, Fixture, nullptr, setup, func, teardown); void gjs_test_add_tests_for_jsapi_utils(void) { - g_test_add_func("/gjs/jsapi-utils/gjs-autopointer/size", + g_test_add_func("/cjs/jsapi-utils/gjs-autopointer/size", test_gjs_autopointer_size); - g_test_add_func("/gjs/jsapi-utils/gjs-autopointer/constructor/empty", + g_test_add_func("/cjs/jsapi-utils/gjs-autopointer/constructor/empty", test_gjs_autopointer_ctor_empty); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/constructor/basic", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/constructor/basic", test_gjs_autopointer_ctor_basic); ADD_AUTOPTRTEST( - "/gjs/jsapi-utils/gjs-autopointer/constructor/take_ownership", + "/cjs/jsapi-utils/gjs-autopointer/constructor/take_ownership", test_gjs_autopointer_ctor_take_ownership); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/constructor/assignment", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/constructor/assignment", test_gjs_autopointer_ctor_assign); ADD_AUTOPTRTEST( - "/gjs/jsapi-utils/gjs-autopointer/constructor/assignment/other", + "/cjs/jsapi-utils/gjs-autopointer/constructor/assignment/other", test_gjs_autopointer_ctor_assign_other); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/destructor", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/destructor", test_gjs_autopointer_dtor); ADD_AUTOPTRTEST( - "/gjs/jsapi-utils/gjs-autopointer/destructor/take_ownership", + "/cjs/jsapi-utils/gjs-autopointer/destructor/take_ownership", test_gjs_autopointer_dtor_take_ownership); - g_test_add_func("/gjs/jsapi-utils/gjs-autopointer/destructor/default_free", + g_test_add_func("/cjs/jsapi-utils/gjs-autopointer/destructor/default_free", test_gjs_autopointer_dtor_default_free); g_test_add_func( - "/gjs/jsapi-utils/gjs-autopointer/destructor/no_free_pointer", + "/cjs/jsapi-utils/gjs-autopointer/destructor/no_free_pointer", test_gjs_autopointer_dtor_no_free_pointer); - g_test_add_func("/gjs/jsapi-utils/gjs-autopointer/free_and_ref_funcs", + g_test_add_func("/cjs/jsapi-utils/gjs-autopointer/free_and_ref_funcs", test_gjs_autopointer_cast_free_func_type); - g_test_add_func("/gjs/jsapi-utils/gjs-autopointer/destructor/c++", + g_test_add_func("/cjs/jsapi-utils/gjs-autopointer/destructor/c++", test_gjs_autopointer_dtor_cpp); - g_test_add_func("/gjs/jsapi-utils/gjs-autopointer/destructor/c++-array", + g_test_add_func("/cjs/jsapi-utils/gjs-autopointer/destructor/c++-array", test_gjs_autopointer_dtor_cpp_array); - g_test_add_func("/gjs/jsapi-utils/gjs-autopointer/operator/assign", + g_test_add_func("/cjs/jsapi-utils/gjs-autopointer/operator/assign", test_gjs_autopointer_assign_operator); g_test_add_func( - "/gjs/jsapi-utils/gjs-autopointer/operator/assign/other_ptr", + "/cjs/jsapi-utils/gjs-autopointer/operator/assign/other_ptr", test_gjs_autopointer_assign_operator_other_ptr); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/operator/assign/self_ptr", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/operator/assign/self_ptr", test_gjs_autopointer_assign_operator_self_ptr); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/operator/assign/object", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/operator/assign/object", test_gjs_autopointer_assign_operator_object); g_test_add_func( - "/gjs/jsapi-utils/gjs-autopointer/operator/assign/other_object", + "/cjs/jsapi-utils/gjs-autopointer/operator/assign/other_object", test_gjs_autopointer_assign_operator_other_object); ADD_AUTOPTRTEST( - "/gjs/jsapi-utils/gjs-autopointer/operator/assign/self_object", + "/cjs/jsapi-utils/gjs-autopointer/operator/assign/self_object", test_gjs_autopointer_assign_operator_self_object); ADD_AUTOPTRTEST( - "/gjs/jsapi-utils/gjs-autopointer/operator/assign/copy_and_swap", + "/cjs/jsapi-utils/gjs-autopointer/operator/assign/copy_and_swap", test_gjs_autopointer_assign_operator_copy_and_swap); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/operator/move", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/operator/move", test_gjs_autopointer_operator_move); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/operator/swap", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/operator/swap", test_gjs_autopointer_operator_swap); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/operator/arrow", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/operator/arrow", test_gjs_autopointer_assign_operator_arrow); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/operator/deference", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/operator/deference", test_gjs_autopointer_assign_operator_deference); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/operator/bool", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/operator/bool", test_gjs_autopointer_assign_operator_bool); - g_test_add_func("/gjs/jsapi-utils/gjs-autopointer/operator/array", + g_test_add_func("/cjs/jsapi-utils/gjs-autopointer/operator/array", test_gjs_autopointer_assign_operator_array); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/method/get", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/method/get", test_gjs_autopointer_get); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/method/out", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/method/out", test_gjs_autopointer_out); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/method/release", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/method/release", test_gjs_autopointer_release); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/method/reset/nullptr", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/method/reset/nullptr", test_gjs_autopointer_reset_nullptr); - g_test_add_func("/gjs/jsapi-utils/gjs-autopointer/method/reset/other_ptr", + g_test_add_func("/cjs/jsapi-utils/gjs-autopointer/method/reset/other_ptr", test_gjs_autopointer_reset_other_ptr); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/method/reset/self_ptr", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/method/reset/self_ptr", test_gjs_autopointer_reset_self_ptr); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/method/swap/other_ptr", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/method/swap/other_ptr", test_gjs_autopointer_swap_other_ptr); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/method/swap/self_ptr", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/method/swap/self_ptr", test_gjs_autopointer_swap_self_ptr); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/method/swap/empty", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/method/swap/empty", test_gjs_autopointer_swap_empty); - ADD_AUTOPTRTEST("/gjs/jsapi-utils/gjs-autopointer/method/copy", + ADD_AUTOPTRTEST("/cjs/jsapi-utils/gjs-autopointer/method/copy", test_gjs_autopointer_copy); - g_test_add_func("/gjs/jsapi-utils/gjs-autopointer/method/as", + g_test_add_func("/cjs/jsapi-utils/gjs-autopointer/method/as", test_gjs_autopointer_as); // Other implementations - g_test_add_func("/gjs/jsapi-utils/gjs-autochar/init", + g_test_add_func("/cjs/jsapi-utils/gjs-autochar/init", test_gjs_autochar_init); - g_test_add_func("/gjs/jsapi-utils/gjs-autochar/init/take_ownership", + g_test_add_func("/cjs/jsapi-utils/gjs-autochar/init/take_ownership", test_gjs_autochar_init_take_ownership); - g_test_add_func("/gjs/jsapi-utils/gjs-autochar/copy", + g_test_add_func("/cjs/jsapi-utils/gjs-autochar/copy", test_gjs_autochar_copy); - g_test_add_func("/gjs/jsapi-utils/gjs-autostrv/init", + g_test_add_func("/cjs/jsapi-utils/gjs-autostrv/init", test_gjs_autostrv_init); - g_test_add_func("/gjs/jsapi-utils/gjs-autostrv/init/take_ownership", + g_test_add_func("/cjs/jsapi-utils/gjs-autostrv/init/take_ownership", test_gjs_autostrv_init_take_ownership); - g_test_add_func("/gjs/jsapi-utils/gjs-autostrv/copy", + g_test_add_func("/cjs/jsapi-utils/gjs-autostrv/copy", test_gjs_autostrv_copy); - g_test_add_func("/gjs/jsapi-utils/gjs-autotypeclass/init", + g_test_add_func("/cjs/jsapi-utils/gjs-autotypeclass/init", test_gjs_autotypeclass_init); - g_test_add_func("/gjs/jsapi-utils/gjs-autoerror/init", test_gjs_error_init); - g_test_add_func("/gjs/jsapi-utils/gjs-autoerror/as-out-value", + g_test_add_func("/cjs/jsapi-utils/gjs-autoerror/init", test_gjs_error_init); + g_test_add_func("/cjs/jsapi-utils/gjs-autoerror/as-out-value", test_gjs_error_out); } diff --git a/test/gjs-test-no-introspection-object.cpp b/test/gjs-test-no-introspection-object.cpp index 3ab60d348..8f249753d 100644 --- a/test/gjs-test-no-introspection-object.cpp +++ b/test/gjs-test-no-introspection-object.cpp @@ -2,6 +2,8 @@ // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later // SPDX-FileCopyrightText: 2020 Endless Mobile Inc. +#include + #include "test/gjs-test-no-introspection-object.h" struct _GjsTestNoIntrospectionObject { diff --git a/test/gjs-test-no-introspection-object.h b/test/gjs-test-no-introspection-object.h index eed31c8bd..7c759c9d6 100644 --- a/test/gjs-test-no-introspection-object.h +++ b/test/gjs-test-no-introspection-object.h @@ -5,6 +5,8 @@ #ifndef TEST_GJS_TEST_NO_INTROSPECTION_OBJECT_H_ #define TEST_GJS_TEST_NO_INTROSPECTION_OBJECT_H_ +#include + #include #define GJSTEST_TYPE_NO_INTROSPECTION_OBJECT \ diff --git a/test/gjs-test-rooting.cpp b/test/gjs-test-rooting.cpp index abf189e81..0eab6b3c4 100644 --- a/test/gjs-test-rooting.cpp +++ b/test/gjs-test-rooting.cpp @@ -40,7 +40,7 @@ struct GjsRootingFixture { bool finalized; bool notify_called; - GjsMaybeOwned *obj; /* only used in callback test cases */ + GjsMaybeOwned* obj; // only used in callback test cases }; static void test_obj_finalize(JS::GCContext*, JSObject* obj) { @@ -111,23 +111,23 @@ wait_for_gc(GjsRootingFixture *fx) static void test_maybe_owned_rooted_flag_set_when_rooted(GjsRootingFixture* fx, const void*) { - auto obj = new GjsMaybeOwned(); - obj->root(PARENT(fx)->cx, JS::TrueValue()); + auto* obj = new GjsMaybeOwned(); + obj->root(PARENT(fx)->cx, JS_NewPlainObject(PARENT(fx)->cx)); g_assert_true(obj->rooted()); delete obj; } static void test_maybe_owned_rooted_flag_not_set_when_not_rooted( - GjsRootingFixture*, const void*) { - auto obj = new GjsMaybeOwned(); - *obj = JS::TrueValue(); + GjsRootingFixture* fx, const void*) { + auto* obj = new GjsMaybeOwned(); + *obj = JS_NewPlainObject(PARENT(fx)->cx); g_assert_false(obj->rooted()); delete obj; } static void test_maybe_owned_rooted_keeps_alive_across_gc(GjsRootingFixture* fx, const void*) { - auto obj = new GjsMaybeOwned(); + auto* obj = new GjsMaybeOwned(); obj->root(PARENT(fx)->cx, test_obj_new(fx)); wait_for_gc(fx); @@ -140,7 +140,7 @@ static void test_maybe_owned_rooted_keeps_alive_across_gc(GjsRootingFixture* fx, static void test_maybe_owned_rooted_is_collected_after_reset( GjsRootingFixture* fx, const void*) { - auto obj = new GjsMaybeOwned(); + auto* obj = new GjsMaybeOwned(); obj->root(PARENT(fx)->cx, test_obj_new(fx)); obj->reset(); @@ -150,14 +150,14 @@ static void test_maybe_owned_rooted_is_collected_after_reset( } static void update_weak_pointer(JSTracer* trc, JS::Compartment*, void* data) { - auto* obj = static_cast*>(data); + auto* obj = static_cast(data); if (*obj) obj->update_after_gc(trc); } static void test_maybe_owned_weak_pointer_is_collected_by_gc( GjsRootingFixture* fx, const void*) { - auto obj = new GjsMaybeOwned(); + auto* obj = new GjsMaybeOwned(); *obj = test_obj_new(fx); JS_AddWeakPointerCompartmentCallback(PARENT(fx)->cx, &update_weak_pointer, @@ -171,7 +171,7 @@ static void test_maybe_owned_weak_pointer_is_collected_by_gc( static void test_maybe_owned_heap_rooted_keeps_alive_across_gc( GjsRootingFixture* fx, const void*) { - auto obj = new GjsMaybeOwned(); + auto* obj = new GjsMaybeOwned(); obj->root(PARENT(fx)->cx, test_obj_new(fx)); wait_for_gc(fx); @@ -185,7 +185,7 @@ static void test_maybe_owned_heap_rooted_keeps_alive_across_gc( static void test_maybe_owned_switching_mode_keeps_same_value( GjsRootingFixture* fx, const void*) { JSObject *test_obj = test_obj_new(fx); - auto obj = new GjsMaybeOwned(); + auto* obj = new GjsMaybeOwned(); *obj = test_obj; g_assert_true(*obj == test_obj); @@ -203,7 +203,7 @@ static void test_maybe_owned_switching_mode_keeps_same_value( static void test_maybe_owned_switch_to_rooted_prevents_collection( GjsRootingFixture* fx, const void*) { - auto obj = new GjsMaybeOwned(); + auto* obj = new GjsMaybeOwned(); *obj = test_obj_new(fx); obj->switch_to_rooted(PARENT(fx)->cx); @@ -215,7 +215,7 @@ static void test_maybe_owned_switch_to_rooted_prevents_collection( static void test_maybe_owned_switch_to_unrooted_allows_collection( GjsRootingFixture* fx, const void*) { - auto obj = new GjsMaybeOwned(); + auto* obj = new GjsMaybeOwned(); obj->root(PARENT(fx)->cx, test_obj_new(fx)); obj->switch_to_unrooted(PARENT(fx)->cx); @@ -240,7 +240,7 @@ static void context_destroyed(JSContext*, void* data) { static void test_maybe_owned_notify_callback_called_on_context_destroy( GjsRootingFixture* fx, const void*) { auto* gjs = GjsContextPrivate::from_cx(PARENT(fx)->cx); - fx->obj = new GjsMaybeOwned(); + fx->obj = new GjsMaybeOwned(); fx->obj->root(PARENT(fx)->cx, test_obj_new(fx)); gjs->register_notifier(context_destroyed, fx); @@ -252,7 +252,7 @@ static void test_maybe_owned_notify_callback_called_on_context_destroy( static void test_maybe_owned_object_destroyed_after_notify( GjsRootingFixture* fx, const void*) { auto* gjs = GjsContextPrivate::from_cx(PARENT(fx)->cx); - fx->obj = new GjsMaybeOwned(); + fx->obj = new GjsMaybeOwned(); fx->obj->root(PARENT(fx)->cx, test_obj_new(fx)); gjs->register_notifier(context_destroyed, fx); diff --git a/test/gjs-test-toggle-queue.cpp b/test/gjs-test-toggle-queue.cpp index 5ac8e6827..66655a371 100644 --- a/test/gjs-test-toggle-queue.cpp +++ b/test/gjs-test-toggle-queue.cpp @@ -5,7 +5,6 @@ #include -#include // for copy #include #include #include @@ -116,8 +115,7 @@ static ::ObjectInstance* new_test_gobject(GjsUnitTestFixture* fx) { GjsAutoUnref gobject( G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr))); auto* object = ObjectInstance::new_for_gobject(fx->cx, gobject); - g_assert_true( - static_cast(object)->ensure_uses_toggle_ref(fx->cx)); + static_cast(object)->ensure_uses_toggle_ref(fx->cx); return object; } diff --git a/test/gjs-test-utils.h b/test/gjs-test-utils.h index a751cda04..e3f8bdd40 100644 --- a/test/gjs-test-utils.h +++ b/test/gjs-test-utils.h @@ -18,10 +18,10 @@ #include // for g_assert_... -#include "cjs/context.h" - #include +#include "cjs/context.h" + struct GjsUnitTestFixture { GjsContext *gjs_context; JSContext *cx; diff --git a/test/gjs-tests.cpp b/test/gjs-tests.cpp index 962bd8b2f..6a2bba81a 100644 --- a/test/gjs-tests.cpp +++ b/test/gjs-tests.cpp @@ -183,7 +183,7 @@ static void gjstest_test_func_gjs_context_eval_dynamic_import_bad() { GjsAutoError error; int status; - g_test_expect_message("Gjs", G_LOG_LEVEL_WARNING, + g_test_expect_message("Cjs", G_LOG_LEVEL_WARNING, "*Unknown module: 'badmodule'*"); bool ok = gjs_context_eval(gjs, R"js( @@ -249,7 +249,7 @@ static void gjstest_test_func_gjs_context_eval_module_file() { GjsAutoError error; bool ok = gjs_context_eval_module_file( - gjs, "resource:///org/gnome/gjs/mock/test/modules/default.js", + gjs, "resource:///org/cinnamon/cjs/mock/test/modules/default.js", &exit_status, &error); g_assert_true(ok); @@ -263,10 +263,10 @@ static void gjstest_test_func_gjs_context_eval_module_file_throw() { uint8_t exit_status; GjsAutoError error; - g_test_expect_message("Gjs", G_LOG_LEVEL_CRITICAL, "*bad module*"); + g_test_expect_message("Cjs", G_LOG_LEVEL_CRITICAL, "*bad module*"); bool ok = gjs_context_eval_module_file( - gjs, "resource:///org/gnome/gjs/mock/test/modules/throws.js", + gjs, "resource:///org/cinnamon/cjs/mock/test/modules/throws.js", &exit_status, &error); g_assert_false(ok); @@ -282,7 +282,7 @@ static void gjstest_test_func_gjs_context_eval_module_file_exit() { uint8_t exit_status; bool ok = gjs_context_eval_module_file( - gjs, "resource:///org/gnome/gjs/mock/test/modules/exit0.js", + gjs, "resource:///org/cinnamon/cjs/mock/test/modules/exit0.js", &exit_status, &error); g_assert_false(ok); @@ -292,7 +292,7 @@ static void gjstest_test_func_gjs_context_eval_module_file_exit() { error.reset(); ok = gjs_context_eval_module_file( - gjs, "resource:///org/gnome/gjs/mock/test/modules/exit.js", + gjs, "resource:///org/cinnamon/cjs/mock/test/modules/exit.js", &exit_status, &error); g_assert_false(ok); @@ -305,12 +305,12 @@ static void gjstest_test_func_gjs_context_eval_module_file_fail_instantiate() { GjsAutoError error; uint8_t exit_status; - g_test_expect_message("Gjs", G_LOG_LEVEL_WARNING, "*foo*"); + g_test_expect_message("Cjs", G_LOG_LEVEL_WARNING, "*foo*"); // evaluating this module without registering 'foo' first should make it // fail ModuleLink bool ok = gjs_context_eval_module_file( - gjs, "resource:///org/gnome/gjs/mock/test/modules/import.js", + gjs, "resource:///org/cinnamon/cjs/mock/test/modules/import.js", &exit_status, &error); g_assert_false(ok); @@ -324,10 +324,10 @@ static void gjstest_test_func_gjs_context_eval_module_file_exit_code_omitted_war GjsAutoUnref gjs = gjs_context_new(); GjsAutoError error; - g_test_expect_message("Gjs", G_LOG_LEVEL_WARNING, "*foo*"); + g_test_expect_message("Cjs", G_LOG_LEVEL_WARNING, "*foo*"); bool ok = gjs_context_eval_module_file( - gjs, "resource:///org/gnome/gjs/mock/test/modules/import.js", nullptr, + gjs, "resource:///org/cinnamon/cjs/mock/test/modules/import.js", nullptr, &error); g_assert_false(ok); @@ -342,7 +342,7 @@ gjstest_test_func_gjs_context_eval_module_file_exit_code_omitted_no_warning() { GjsAutoError error; bool ok = gjs_context_eval_module_file( - gjs, "resource:///org/gnome/gjs/mock/test/modules/default.js", nullptr, + gjs, "resource:///org/cinnamon/cjs/mock/test/modules/default.js", nullptr, &error); g_assert_true(ok); @@ -353,10 +353,10 @@ static void gjstest_test_func_gjs_context_eval_file_exit_code_omitted_throw() { GjsAutoUnref gjs = gjs_context_new(); GjsAutoError error; - g_test_expect_message("Gjs", G_LOG_LEVEL_CRITICAL, "*bad module*"); + g_test_expect_message("Cjs", G_LOG_LEVEL_CRITICAL, "*bad module*"); bool ok = gjs_context_eval_file( - gjs, "resource:///org/gnome/gjs/mock/test/modules/throws.js", nullptr, + gjs, "resource:///org/cinnamon/cjs/mock/test/modules/throws.js", nullptr, &error); g_assert_false(ok); @@ -370,7 +370,7 @@ static void gjstest_test_func_gjs_context_eval_file_exit_code_omitted_no_throw() GjsAutoError error; bool ok = gjs_context_eval_file( - gjs, "resource:///org/gnome/gjs/mock/test/modules/nothrows.js", nullptr, + gjs, "resource:///org/cinnamon/cjs/mock/test/modules/nothrows.js", nullptr, &error); g_assert_true(ok); @@ -382,7 +382,7 @@ static void gjstest_test_func_gjs_context_register_module_eval_module() { GjsAutoError error; bool ok = gjs_context_register_module( - gjs, "foo", "resource:///org/gnome/gjs/mock/test/modules/default.js", + gjs, "foo", "resource:///org/cinnamon/cjs/mock/test/modules/default.js", &error); g_assert_true(ok); @@ -401,7 +401,7 @@ static void gjstest_test_func_gjs_context_register_module_eval_module_file() { GjsAutoError error; bool ok = gjs_context_register_module( - gjs, "foo", "resource:///org/gnome/gjs/mock/test/modules/default.js", + gjs, "foo", "resource:///org/cinnamon/cjs/mock/test/modules/default.js", &error); g_assert_true(ok); @@ -409,7 +409,7 @@ static void gjstest_test_func_gjs_context_register_module_eval_module_file() { uint8_t exit_status; ok = gjs_context_eval_module_file( - gjs, "resource:///org/gnome/gjs/mock/test/modules/import.js", + gjs, "resource:///org/cinnamon/cjs/mock/test/modules/import.js", &exit_status, &error); g_assert_true(ok); @@ -423,7 +423,7 @@ static void gjstest_test_func_gjs_context_register_module_eval_jsapi( bool ok = gjs_context_register_module( fx->gjs_context, "foo", - "resource:///org/gnome/gjs/mock/test/modules/default.js", &error); + "resource:///org/cinnamon/cjs/mock/test/modules/default.js", &error); g_assert_true(ok); g_assert_no_error(error); @@ -475,7 +475,7 @@ static void gjstest_test_func_gjs_context_register_module_eval_jsapi_rel( JS::RootedValue unused{fx->cx}; ok = JS::Evaluate(fx->cx, options, source, &unused); g_assert_false(ok); - g_test_expect_message("Gjs", G_LOG_LEVEL_WARNING, + g_test_expect_message("Cjs", G_LOG_LEVEL_WARNING, "JS ERROR: ImportError*relative*"); gjs_log_exception(fx->cx); g_test_assert_expected_messages(); @@ -518,7 +518,7 @@ static void gjstest_test_func_gjs_context_eval_module_exit_code_omitted_no_throw GjsAutoError error; bool ok = gjs_context_register_module( - gjs, "lies", "resource:///org/gnome/gjs/mock/test/modules/nothrows.js", + gjs, "lies", "resource:///org/cinnamon/cjs/mock/test/modules/nothrows.js", &error); g_assert_true(ok); @@ -536,7 +536,7 @@ static void gjstest_test_func_gjs_context_module_eval_jsapi_throws( bool ok = gjs_context_register_module( fx->gjs_context, "foo", - "resource:///org/gnome/gjs/mock/test/modules/throws.js", &error); + "resource:///org/cinnamon/cjs/mock/test/modules/throws.js", &error); g_assert_true(ok); g_assert_no_error(error); @@ -660,7 +660,7 @@ static void gjstest_test_func_gjs_context_eval_exit_code_omitted_throw() { GjsAutoUnref context = gjs_context_new(); GjsAutoError error; - g_test_expect_message("Gjs", G_LOG_LEVEL_CRITICAL, "*wrong code*"); + g_test_expect_message("Cjs", G_LOG_LEVEL_CRITICAL, "*wrong code*"); const char bad_js[] = "throw new Error('wrong code');"; @@ -742,25 +742,25 @@ static void gjstest_test_func_gjs_jsapi_util_error_throw(GjsUnitTestFixture* fx, static void test_jsapi_util_error_throw_cause(GjsUnitTestFixture* fx, const void*) { - g_test_expect_message("Gjs", G_LOG_LEVEL_WARNING, + g_test_expect_message("Cjs", G_LOG_LEVEL_WARNING, "JS ERROR: Error: Exception 1\n" - "Caused by: Error: Exception 2\n"); + "Caused by: Error: Exception 2"); gjs_throw(fx->cx, "Exception 1"); gjs_throw(fx->cx, "Exception 2"); gjs_log_exception(fx->cx); - g_test_expect_message("Gjs", G_LOG_LEVEL_WARNING, + g_test_expect_message("Cjs", G_LOG_LEVEL_WARNING, "JS ERROR: Error: Exception 1\n" "Caused by: Error: Exception 2\n" - "Caused by: Error: Exception 3\n"); + "Caused by: Error: Exception 3"); gjs_throw(fx->cx, "Exception 1"); gjs_throw(fx->cx, "Exception 2"); gjs_throw(fx->cx, "Exception 3"); gjs_log_exception(fx->cx); - g_test_expect_message("Gjs", G_LOG_LEVEL_WARNING, "JS ERROR: 42"); + g_test_expect_message("Cjs", G_LOG_LEVEL_WARNING, "JS ERROR: 42"); JS::RootedValue non_object(fx->cx, JS::Int32Value(42)); JS_SetPendingException(fx->cx, non_object); @@ -1180,49 +1180,49 @@ main(int argc, g_message("Using C++ random seed %u\n", cpp_random_seed); - g_test_add_func("/gjs/context/construct/destroy", gjstest_test_func_gjs_context_construct_destroy); - g_test_add_func("/gjs/context/construct/eval", gjstest_test_func_gjs_context_construct_eval); - g_test_add_func("/gjs/context/argv", + g_test_add_func("/cjs/context/construct/destroy", gjstest_test_func_gjs_context_construct_destroy); + g_test_add_func("/cjs/context/construct/eval", gjstest_test_func_gjs_context_construct_eval); + g_test_add_func("/cjs/context/argv", gjstest_test_func_gjs_context_argv_array); - g_test_add_func("/gjs/context/eval/dynamic-import", + g_test_add_func("/cjs/context/eval/dynamic-import", gjstest_test_func_gjs_context_eval_dynamic_import); - g_test_add_func("/gjs/context/eval/dynamic-import/relative", + g_test_add_func("/cjs/context/eval/dynamic-import/relative", gjstest_test_func_gjs_context_eval_dynamic_import_relative); - g_test_add_func("/gjs/context/eval/dynamic-import/bad", + g_test_add_func("/cjs/context/eval/dynamic-import/bad", gjstest_test_func_gjs_context_eval_dynamic_import_bad); - g_test_add_func("/gjs/context/eval/non-zero-terminated", + g_test_add_func("/cjs/context/eval/non-zero-terminated", gjstest_test_func_gjs_context_eval_non_zero_terminated); - g_test_add_func("/gjs/context/exit", gjstest_test_func_gjs_context_exit); - g_test_add_func("/gjs/context/eval-module-file", + g_test_add_func("/cjs/context/exit", gjstest_test_func_gjs_context_exit); + g_test_add_func("/cjs/context/eval-module-file", gjstest_test_func_gjs_context_eval_module_file); - g_test_add_func("/gjs/context/eval-module-file/throw", + g_test_add_func("/cjs/context/eval-module-file/throw", gjstest_test_func_gjs_context_eval_module_file_throw); - g_test_add_func("/gjs/context/eval-module-file/exit", + g_test_add_func("/cjs/context/eval-module-file/exit", gjstest_test_func_gjs_context_eval_module_file_exit); g_test_add_func( - "/gjs/context/eval-module-file/fail-instantiate", + "/cjs/context/eval-module-file/fail-instantiate", gjstest_test_func_gjs_context_eval_module_file_fail_instantiate); - g_test_add_func("/gjs/context/register-module/eval-module", + g_test_add_func("/cjs/context/register-module/eval-module", gjstest_test_func_gjs_context_register_module_eval_module); g_test_add_func( - "/gjs/context/register-module/eval-module-file", + "/cjs/context/register-module/eval-module-file", gjstest_test_func_gjs_context_register_module_eval_module_file); - g_test_add("/gjs/context/register-module/eval-jsapi", GjsUnitTestFixture, + g_test_add("/cjs/context/register-module/eval-jsapi", GjsUnitTestFixture, nullptr, gjs_unit_test_fixture_setup, gjstest_test_func_gjs_context_register_module_eval_jsapi, gjs_unit_test_fixture_teardown); - g_test_add("/gjs/context/register-module/eval-jsapi-relative", + g_test_add("/cjs/context/register-module/eval-jsapi-relative", GjsUnitTestFixture, nullptr, gjs_unit_test_fixture_setup, gjstest_test_func_gjs_context_register_module_eval_jsapi_rel, gjs_unit_test_fixture_teardown); - g_test_add_func("/gjs/context/register-module/non-existent", + g_test_add_func("/cjs/context/register-module/non-existent", gjstest_test_func_gjs_context_register_module_non_existent); - g_test_add_func("/gjs/context/eval-module/unregistered", + g_test_add_func("/cjs/context/eval-module/unregistered", gjstest_test_func_gjs_context_eval_module_unregistered); - g_test_add_func("/gjs/gobject/js_defined_type", gjstest_test_func_gjs_gobject_js_defined_type); - g_test_add_func("/gjs/gobject/without_introspection", + g_test_add_func("/cjs/gobject/js_defined_type", gjstest_test_func_gjs_gobject_js_defined_type); + g_test_add_func("/cjs/gobject/without_introspection", gjstest_test_func_gjs_gobject_without_introspection); - g_test_add_func("/gjs/profiler/start_stop", gjstest_test_profiler_start_stop); + g_test_add_func("/cjs/profiler/start_stop", gjstest_test_profiler_start_stop); g_test_add_func("/util/misc/strv/concat/null", gjstest_test_func_util_misc_strv_concat_null); g_test_add_func("/util/misc/strv/concat/pointers", @@ -1233,33 +1233,33 @@ main(int argc, gjstest_test_args_rounded_values); g_test_add_func( - "/gjs/context/eval-module-file/exit-code-omitted-warning", + "/cjs/context/eval-module-file/exit-code-omitted-warning", gjstest_test_func_gjs_context_eval_module_file_exit_code_omitted_warning); g_test_add_func( - "/gjs/context/eval-module-file/exit-code-omitted-no-warning", + "/cjs/context/eval-module-file/exit-code-omitted-no-warning", gjstest_test_func_gjs_context_eval_module_file_exit_code_omitted_no_warning); - g_test_add_func("/gjs/context/eval-file/exit-code-omitted-no-throw", + g_test_add_func("/cjs/context/eval-file/exit-code-omitted-no-throw", gjstest_test_func_gjs_context_eval_file_exit_code_omitted_no_throw); - g_test_add_func("/gjs/context/eval-file/exit-code-omitted-throw", + g_test_add_func("/cjs/context/eval-file/exit-code-omitted-throw", gjstest_test_func_gjs_context_eval_file_exit_code_omitted_throw); - g_test_add_func("/gjs/context/eval/exit-code-omitted-throw", + g_test_add_func("/cjs/context/eval/exit-code-omitted-throw", gjstest_test_func_gjs_context_eval_exit_code_omitted_throw); - g_test_add_func("/gjs/context/eval/exit-code-omitted-no-throw", + g_test_add_func("/cjs/context/eval/exit-code-omitted-no-throw", gjstest_test_func_gjs_context_eval_exit_code_omitted_no_throw); - g_test_add_func("/gjs/context/eval-module/exit-code-omitted-throw", + g_test_add_func("/cjs/context/eval-module/exit-code-omitted-throw", gjstest_test_func_gjs_context_eval_module_exit_code_omitted_throw); g_test_add_func( - "/gjs/context/eval-module/exit-code-omitted-no-throw", + "/cjs/context/eval-module/exit-code-omitted-no-throw", gjstest_test_func_gjs_context_eval_module_exit_code_omitted_no_throw); - g_test_add("/gjs/context/eval-module/jsapi-throw", GjsUnitTestFixture, + g_test_add("/cjs/context/eval-module/jsapi-throw", GjsUnitTestFixture, nullptr, gjs_unit_test_fixture_setup, gjstest_test_func_gjs_context_module_eval_jsapi_throws, gjs_unit_test_fixture_teardown); - g_test_add_func("/gjs/context/run-in-realm", + g_test_add_func("/cjs/context/run-in-realm", gjstest_test_func_gjs_context_run_in_realm); #define ADD_JSAPI_UTIL_TEST(path, func) \ - g_test_add("/gjs/jsapi/util/" path, GjsUnitTestFixture, NULL, \ + g_test_add("/cjs/jsapi/util/" path, GjsUnitTestFixture, NULL, \ gjs_unit_test_fixture_setup, func, \ gjs_unit_test_fixture_teardown) diff --git a/test/meson.build b/test/meson.build index b3ddd43a2..391663966 100644 --- a/test/meson.build +++ b/test/meson.build @@ -7,13 +7,13 @@ mock_js_resources_files = gnome.compile_resources('mock-js-resources', 'mock-js-resources.gresource.xml', c_name: 'mock_js_resources', source_dir: '..') -libgjs_tests_common = static_library('gjs-tests-common', +libcjs_tests_common = static_library('gjs-tests-common', sources: [ 'gjs-test-utils.cpp', 'gjs-test-utils.h', 'gjs-test-common.cpp', 'gjs-test-common.h', ], - cpp_args: libgjs_cpp_args, - include_directories: top_include, dependencies: libgjs_dependencies, + cpp_args: libcjs_cpp_args, + include_directories: top_include, dependencies: libcjs_dependencies, ) gjs_tests_sources = [ @@ -23,12 +23,12 @@ gjs_tests_sources = [ ] gjs_tests = executable('gjs-tests', gjs_tests_sources, mock_js_resources_files, - include_directories: top_include, dependencies: libgjs_dep, - link_with: libgjs_tests_common) + include_directories: top_include, dependencies: libcjs_dep, + link_with: libcjs_tests_common) test('API tests', gjs_tests, args: ['--tap', '--keep-going', '--verbose'], - depends: gjs_private_typelib, env: tests_environment, protocol: 'tap', - suite: 'C', timeout: 60) + depends: cjs_private_typelib, env: tests_environment, protocol: 'tap', + suite: 'C', timeout: 60, priority: 10) gjs_tests_internal = executable('gjs-tests-internal', sources: [ @@ -40,11 +40,11 @@ gjs_tests_internal = executable('gjs-tests-internal', module_resource_srcs, ], include_directories: top_include, - cpp_args: libgjs_cpp_args, - dependencies: [libgjs_dependencies, libgjstesttools_dep], - link_with: [libgjs_tests_common, libgjs_internal]) + cpp_args: libcjs_cpp_args, + dependencies: [libcjs_dependencies, libgjstesttools_dep], + link_with: [libcjs_tests_common, libcjs_internal]) test('Internal API tests', gjs_tests_internal, args: ['--tap', '--keep-going', '--verbose'], env: tests_environment, protocol: 'tap', - suite: 'C') + suite: 'C', priority: 10) diff --git a/test/mock-js-resources.gresource.xml b/test/mock-js-resources.gresource.xml index 2df75cdb8..718137b33 100644 --- a/test/mock-js-resources.gresource.xml +++ b/test/mock-js-resources.gresource.xml @@ -2,7 +2,7 @@ - + test/gjs-test-coverage/loadedJSFromResource.js test/modules/default.js test/modules/exit.js diff --git a/test/test-ci.sh b/test/test-ci.sh old mode 100755 new mode 100644 index ee7c9551f..9e33946d8 --- a/test/test-ci.sh +++ b/test/test-ci.sh @@ -19,17 +19,6 @@ do_Set_Env () { export SHELL=/bin/bash PATH=$PATH:~/.local/bin - if [ "$USE_UNSTABLE_GNOME_PREFIX" = "true" ]; then - prefix=/opt/GNOME - libdir=$prefix/lib64 - export PATH=$prefix/bin:$PATH - export LD_LIBRARY_PATH=$libdir:$LD_LIBRARY_PATH - export PKG_CONFIG_PATH=$libdir/pkgconfig:$PKG_CONFIG_PATH - export GI_TYPELIB_PATH=$libdir/girepository-1.0:$GI_TYPELIB_PATH - export XDG_DATA_DIRS=$prefix/share:$XDG_DATA_DIRS - export ACLOCAL_PATH=$prefix/share/aclocal:$ACLOCAL_PATH - fi - export DISPLAY="${DISPLAY:-:0}" } @@ -64,7 +53,7 @@ do_Get_Upstream_Base () { # Work out the newest common ancestor between the detached HEAD that this CI # job has checked out, and the upstream target branch (which will typically - # be `upstream/master` or `upstream/gnome-nn`). + # be `upstream/main` or `upstream/gnome-nn`). newest_common_ancestor_sha=$(git merge-base ci-upstream-base-branch HEAD) if test -z "$newest_common_ancestor_sha"; then echo "Couldn’t find common ancestor with the upstream main branch. This" @@ -149,8 +138,8 @@ if test "$1" = "SETUP"; then elif test "$1" = "BUILD"; then do_Set_Env - DEFAULT_CONFIG_OPTS="-Dcairo=enabled -Dreadline=enabled -Dprofiler=enabled \ - -Ddtrace=false -Dsystemtap=false -Dverbose_logs=false --werror" + DEFAULT_CONFIG_OPTS="-Dreadline=enabled -Dprofiler=enabled -Ddtrace=false \ + -Dsystemtap=false -Dverbose_logs=false --werror" meson setup _build $DEFAULT_CONFIG_OPTS $CONFIG_OPTS ninja -C _build diff --git a/tools/apply-format b/tools/apply-format old mode 100755 new mode 100644 index a14b76e17..fa3ddbe7e --- a/tools/apply-format +++ b/tools/apply-format @@ -305,8 +305,7 @@ else # Diff-only. -p1 \ -style="$style" \ -iregex='^.*\.(c|cpp|cxx|cc|h|m|mm|js|java)$' \ - > "$patch_dest" \ - || exit 1 + > "$patch_dest" if [ "$apply_to_staged" = true ]; then if [ ! -s "$patch_dest" ]; then diff --git a/tools/cppcheck.cfg b/tools/cppcheck.cfg index 7de4f6e10..17dea6c2d 100644 --- a/tools/cppcheck.cfg +++ b/tools/cppcheck.cfg @@ -2,16 +2,8 @@ - - - - - - - - - - - - + + + + diff --git a/tools/git-pre-commit-format b/tools/git-pre-commit-format old mode 100755 new mode 100644 diff --git a/tools/gjs-private-iwyu.imp b/tools/gjs-private-iwyu.imp index ce86e59e8..6b6bcf4ec 100644 --- a/tools/gjs-private-iwyu.imp +++ b/tools/gjs-private-iwyu.imp @@ -13,6 +13,7 @@ {"include": ["", "private", "", "public"]}, {"include": ["", "private", "", "public"]}, {"include": ["", "private", "", "public"]}, + {"include": ["<__stdarg_va_arg.h>", "private", "", "public"]}, {"include": ["@", "private", "", "public"]}, {"include": ["@\"gio/.*\"", "private", "", "public"]}, diff --git a/tools/gjs-public-iwyu.imp b/tools/gjs-public-iwyu.imp index 2d3fe0a12..714f683da 100644 --- a/tools/gjs-public-iwyu.imp +++ b/tools/gjs-public-iwyu.imp @@ -5,5 +5,5 @@ [ {"ref": "gjs-private-iwyu.imp"}, - {"include": ["\"cjs/macros.h\"", "private", "", "public"]} + {"include": ["\"gjs/macros.h\"", "private", "", "public"]} ] \ No newline at end of file diff --git a/tools/heapdot.py b/tools/heapdot.py index f47fdae70..2d56fb619 100644 --- a/tools/heapdot.py +++ b/tools/heapdot.py @@ -90,7 +90,7 @@ def output_dot_file(args, graph, targs, fname): if elabel in ['prototype', 'group_proto']: style += ',dashed' # Another object native to Gjs - elif label.startswith('Gjs') or label.startswith('GIR'): + elif label.startswith('Cjs') or label.startswith('GIR'): shape = 'octagon' elif label.startswith('Function'): fm = func_regex.match(label) diff --git a/tools/heapgraph.py b/tools/heapgraph.py old mode 100755 new mode 100644 index 365e965b3..3399f537d --- a/tools/heapgraph.py +++ b/tools/heapgraph.py @@ -49,6 +49,10 @@ action='append', default=[], help='Add a string literal or String() to the list of targets') +targ_opts.add_argument('--annotation', '-a', dest='annotation_targets', + action='append', default=[], + help=f'Add a {NAME_ANNOTATION} annotation to the list of targets') + ### Output Options out_opts = parser.add_argument_group('Output Options') @@ -99,6 +103,7 @@ 'GIRepositoryNamespace', 'GjsFileImporter', 'GjsGlobal', + 'GjsInternalGlobal', 'GjsModule'], help='Don\'t show nodes with labels containing LABEL') @@ -116,14 +121,14 @@ WeakMapEntry = namedtuple('WeakMapEntry', 'weakMap key keyDelegate value') -addr_regex = re.compile('[A-F0-9]+$|0x[a-f0-9]+$') -node_regex = re.compile ('((?:0x)?[a-fA-F0-9]+) (?:(B|G|W) )?([^\r\n]*)\r?$') -edge_regex = re.compile ('> ((?:0x)?[a-fA-F0-9]+) (?:(B|G|W) )?([^\r\n]*)\r?$') +addr_regex = re.compile(r'[A-F0-9]+$|0x[a-f0-9]+$') +node_regex = re.compile(r'((?:0x)?[a-fA-F0-9]+) (?:(B|G|W) )?([^\r\n]*)\r?$') +edge_regex = re.compile(r'> ((?:0x)?[a-fA-F0-9]+) (?:(B|G|W) )?([^\r\n]*)\r?$') wme_regex = re.compile(r'WeakMapEntry map=((?:0x)?[a-zA-Z0-9]+|\(nil\)) key=((?:0x)?[a-zA-Z0-9]+|\(nil\)) keyDelegate=((?:0x)?[a-zA-Z0-9]+|\(nil\)) value=((?:0x)?[a-zA-Z0-9]+)') -func_regex = re.compile('Function(?: ([^/]+)(?:/([<|\w]+))?)?') +func_regex = re.compile(r'Function(?: ([^/]+)(?:/([<|\w]+))?)?') priv_regex = re.compile(r'([^ ]+) (0x[a-fA-F0-9]+$)') -atom_regex = re.compile(r'^string (.*)\r?$') +string_regex = re.compile(r'^(?:sub)?string <(?:dependent|(?:permanent )?atom|(?:fat )?inline|linear): length (?:\d+)> (.*)\r?$') ############################################################################### # Heap Parsing @@ -193,16 +198,48 @@ def addEdge(source, target, edge_label): edge_labels[source].setdefault(target, []).append(edge_label) node_addr = None + second_pass_lines = [] for line in fobj: + if edge_regex.match(line): + second_pass_lines.append(line) + continue + + node = node_regex.match(line) + + if node: + second_pass_lines.append(line) + node_addr = node.group(1) + node_color = node.group(2) + node_label = node.group(3) + + # Don't hide strings matching hide_nodes, as they may be labels + if string_regex.match(node_label) is not None: + addNode(node_addr, node_label) + continue + + # Use this opportunity to map hide_nodes to addresses + for hide_node in args.hide_nodes: + if hide_node in node_label: + args.hide_addrs.append(node_addr) + break + else: + addNode(node_addr, node_label) + # Skip comments, arenas, realms and zones + elif line[0] == '#': + continue + else: + sys.stderr.write('Error: Unknown line: {}\n'.format(line[:-1])) + + for line in second_pass_lines: e = edge_regex.match(line) if e: target, edge_label = e.group(1, 3) if edge_label == NAME_ANNOTATION: - a = atom_regex.match(node_labels[target]) - if a: - annotations[node_addr] = a.group(1) + s = string_regex.match(node_labels[target]) + if s: + annotations[node_addr] = s.group(1) if (node_addr not in args.hide_addrs and edge_label not in args.hide_edges): @@ -212,21 +249,6 @@ def addEdge(source, target, edge_label): if node: node_addr = node.group(1) - node_color = node.group(2) - node_label = node.group(3) - - # Use this opportunity to map hide_nodes to addresses - for hide_node in args.hide_nodes: - if hide_node in node_label: - args.hide_addrs.append(node_addr) - break - else: - addNode(node_addr, node_label) - # Skip comments, arenas, realms and zones - elif line[0] == '#': - continue - else: - sys.stderr.write('Error: Unknown line: {}\n'.format(line[:-1])) # yar, should pass the root crud in and wedge it in here, or somewhere return [edges, edge_labels, node_labels, annotations] @@ -637,6 +659,14 @@ def target_type(graph, target): return targets +def target_annotation(graph, target): + targets = {addr for addr, label in graph.annotations.items() + if label == target} + + sys.stderr.write(f'Found {len(targets)} targets with annotation "{target}"\n') + return targets + + def select_targets(args, edges, graph): targets = set() for target in args.targets: @@ -657,6 +687,8 @@ def select_targets(args, edges, graph): targets.update(target_func(graph, target)) for target in args.string_targets: targets.update(target_string(graph, target)) + for target in args.annotation_targets: + targets.update(target_annotation(graph, target)) return list(targets) @@ -667,6 +699,7 @@ def select_targets(args, edges, graph): # Node and Root Filtering if args.show_global: args.hide_nodes.remove('GjsGlobal') + args.hide_nodes.remove('GjsInternalGlobal') if args.show_imports: args.hide_nodes.remove('GjsFileImporter') args.hide_nodes.remove('GjsModule') diff --git a/tools/package-lock.json b/tools/package-lock.json index f812d4a2f..27e486c11 100644 --- a/tools/package-lock.json +++ b/tools/package-lock.json @@ -1,7 +1,7 @@ { "name": "gjs-development-scripts", "version": "0.0.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -9,34 +9,67 @@ "version": "0.0.0", "license": "MIT OR LGPL-2.0-or-later", "devDependencies": { - "eslint": "^8.26.0", - "eslint-plugin-jsdoc": "^39.4.0" + "eslint": "^8.57.0", + "eslint-plugin-jsdoc": "^48.2.1" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.33.4.tgz", - "integrity": "sha512-02XyYuvR/Gn+3BT6idHVNQ4SSQlA1X1FeEfeKm2ypv8ANB6Lt9KRFZ2S7y5xjwR+EPQ/Rzb0XFaD+xKyqe4ALw==", + "version": "0.42.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.42.0.tgz", + "integrity": "sha512-R1w57YlVA6+YE01wch3GPYn6bCsrOV3YW/5oGGE2tmX6JcL9Nr+b5IikrjMPF+v9CV3ay+obImEdsDhovhJrzw==", + "dev": true, + "dependencies": { + "comment-parser": "1.4.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, "dependencies": { - "comment-parser": "1.3.1", - "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "~3.1.0" + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": "^14 || ^16 || ^17 || ^18 || ^19" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", + "espree": "^9.6.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -50,14 +83,23 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", - "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { @@ -78,9 +120,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, "node_modules/@nodelib/fs.scandir": { @@ -118,10 +160,16 @@ "node": ">= 8" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -179,6 +227,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -201,6 +258,18 @@ "concat-map": "0.0.1" } }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -245,9 +314,9 @@ "dev": true }, "node_modules/comment-parser": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", - "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", "dev": true, "engines": { "node": ">= 12.0.0" @@ -321,49 +390,48 @@ } }, "node_modules/eslint": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz", - "integrity": "sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.15.0", - "grapheme-splitter": "^1.0.4", + "globals": "^13.19.0", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -377,30 +445,32 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "39.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.4.0.tgz", - "integrity": "sha512-2FXAmh8lpO22aqZgu6NLB6berVnYgwbZx95BmjIIQjbRNwLIAwY0dtvSJDUZVW5nflv58c1gSWQjIJ8yLZ/+fw==", + "version": "48.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.2.1.tgz", + "integrity": "sha512-iUvbcyDZSO/9xSuRv2HQBw++8VkV/pt3UWtX9cpPH0l7GKPq78QC/6+PmyQHHvNZaTjAce6QVciEbnc6J/zH5g==", "dev": true, "dependencies": { - "@es-joy/jsdoccomment": "~0.33.4", - "comment-parser": "1.3.1", + "@es-joy/jsdoccomment": "~0.42.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", - "esquery": "^1.4.0", - "semver": "^7.3.8", - "spdx-expression-parse": "^3.0.1" + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.6.0", + "spdx-expression-parse": "^4.0.0" }, "engines": { - "node": "^14 || ^16 || ^17 || ^18 || ^19" + "node": ">=18" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -408,53 +478,32 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -464,9 +513,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -524,9 +573,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -561,12 +610,13 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "dependencies": { - "flatted": "^3.1.0", + "flatted": "^3.2.9", + "keyv": "^4.5.3", "rimraf": "^3.0.2" }, "engines": { @@ -574,9 +624,9 @@ } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, "node_modules/fs.realpath": { @@ -618,9 +668,9 @@ } }, "node_modules/globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -632,10 +682,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, "node_modules/has-flag": { @@ -648,9 +698,9 @@ } }, "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" @@ -697,6 +747,21 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -733,12 +798,6 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, - "node_modules/js-sdsl": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", - "integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==", - "dev": true - }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -752,14 +811,20 @@ } }, "node_modules/jsdoc-type-pratt-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz", - "integrity": "sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", "dev": true, "engines": { "node": ">=12.0.0" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -772,6 +837,15 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -852,17 +926,17 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -947,9 +1021,9 @@ } }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -975,18 +1049,6 @@ } ] }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -1045,9 +1107,9 @@ } }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -1081,15 +1143,15 @@ } }, "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "dev": true }, "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", "dev": true, "dependencies": { "spdx-exceptions": "^2.1.0", @@ -1097,9 +1159,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", "dev": true }, "node_modules/strip-ansi": { @@ -1192,15 +1254,6 @@ "node": ">= 8" } }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -1225,886 +1278,5 @@ "url": "https://github.com/sponsors/sindresorhus" } } - }, - "dependencies": { - "@es-joy/jsdoccomment": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.33.4.tgz", - "integrity": "sha512-02XyYuvR/Gn+3BT6idHVNQ4SSQlA1X1FeEfeKm2ypv8ANB6Lt9KRFZ2S7y5xjwR+EPQ/Rzb0XFaD+xKyqe4ALw==", - "dev": true, - "requires": { - "comment-parser": "1.3.1", - "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "~3.1.0" - } - }, - "@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@humanwhocodes/config-array": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", - "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "comment-parser": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", - "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz", - "integrity": "sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.15.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - } - }, - "eslint-plugin-jsdoc": { - "version": "39.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.4.0.tgz", - "integrity": "sha512-2FXAmh8lpO22aqZgu6NLB6berVnYgwbZx95BmjIIQjbRNwLIAwY0dtvSJDUZVW5nflv58c1gSWQjIJ8yLZ/+fw==", - "dev": true, - "requires": { - "@es-joy/jsdoccomment": "~0.33.4", - "comment-parser": "1.3.1", - "debug": "^4.3.4", - "escape-string-regexp": "^4.0.0", - "esquery": "^1.4.0", - "semver": "^7.3.8", - "spdx-expression-parse": "^3.0.1" - } - }, - "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - }, - "espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", - "dev": true, - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - } - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "js-sdsl": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", - "integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "jsdoc-type-pratt-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz", - "integrity": "sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", - "dev": true - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } } } diff --git a/tools/package.json b/tools/package.json index 200438edc..0713d818d 100644 --- a/tools/package.json +++ b/tools/package.json @@ -9,7 +9,7 @@ "fix": "npm run lint --fix" }, "devDependencies": { - "eslint": "^8.26.0", - "eslint-plugin-jsdoc": "^39.4.0" + "eslint": "^8.57.0", + "eslint-plugin-jsdoc": "^48.2.1" } } diff --git a/tools/process_iwyu.py b/tools/process_iwyu.py old mode 100755 new mode 100644 index 9f44ec0eb..f659817b4 --- a/tools/process_iwyu.py +++ b/tools/process_iwyu.py @@ -66,17 +66,7 @@ class Colors: # we don't need to have forward declarations of them as well ('gjs/atoms.h', 'class GjsAtoms;', ''), ('gjs/atoms.h', 'struct GjsSymbolAtom;', ''), - - # IWYU weird false positive when using std::vector::emplace_back() or - # std::vector::push_back() - # https://github.com/include-what-you-use/include-what-you-use/issues/908 - ('gi/function.cpp', '#include ', 'for max'), - ('gi/function.cpp', '#include ', 'for fill_n, max'), # also! - ('gi/private.cpp', '#include ', 'for max'), - ('gjs/importer.cpp', '#include ', 'for max'), - ('gjs/importer.cpp', '#include ', 'for max, copy'), # also! - ('gjs/module.cpp', '#include ', 'for copy'), - ('util/log.cpp', '#include ', 'for fill_n'), + ('gjs/mem-private.h', 'namespace Gjs { namespace Memory { struct Counter; } }', ''), # False positive when constructing JS::GCHashMap ('gi/boxed.h', '#include ', 'for move'), @@ -86,27 +76,18 @@ class Colors: # For some reason IWYU wants these with angle brackets when they are # already present with quotes # https://github.com/include-what-you-use/include-what-you-use/issues/1087 - ('gjs/context.cpp', '#include ', ''), - ('gjs/coverage.cpp', '#include ', ''), - ('gjs/error-types.cpp', '#include ', ''), - ('gjs/jsapi-util.cpp', '#include ', ''), - ('gjs/mem.cpp', '#include ', ''), - ('gjs/profiler.cpp', '#include ', ''), + ('gjs/context.cpp', '#include ', ''), + ('gjs/coverage.cpp', '#include ', ''), + ('gjs/error-types.cpp', '#include ', ''), + ('gjs/jsapi-util.cpp', '#include ', ''), + ('gjs/mem.cpp', '#include ', ''), + ('gjs/profiler.cpp', '#include ', ''), ) def output(): global file, state, add_fwd_header, there_were_errors - # Workaround for - # https://github.com/include-what-you-use/include-what-you-use/issues/226 - if CSTDINT in add: - why = add.pop(CSTDINT, None) - if STDINTH in remove: - remove.pop(STDINTH, None) - elif STDINTH not in all_includes: - add[STDINTH] = why - if add_fwd_header: if FWD_HEADER not in all_includes: if FWD_HEADER in remove: diff --git a/tools/run_coverage.sh b/tools/run_coverage.sh old mode 100755 new mode 100644 index 16bc72727..a8961f22b --- a/tools/run_coverage.sh +++ b/tools/run_coverage.sh @@ -3,12 +3,10 @@ # SPDX-FileCopyrightText: 2019 Philip Chimento SOURCEDIR=$(pwd) -GIDATADIR=$(pkg-config --variable=gidatadir gobject-introspection-1.0) - BUILDDIR="$(pwd)/_coverage_build" LCOV_ARGS="--config-file $SOURCEDIR/tools/lcovrc" GENHTML_ARGS='--legend --show-details --branch-coverage' -IGNORE="*/gjs/test/* *-resources.c *minijasmine.cpp */gjs/subprojects/*" +IGNORE="*/gjs/test/* *-resources.c *minijasmine.cpp */gjs/subprojects/glib/* */gjs/subprojects/gobject-introspection/*" rm -rf "$BUILDDIR" meson setup "$BUILDDIR" -Db_coverage=true @@ -18,9 +16,9 @@ VERSION=$(meson introspect "$BUILDDIR" --projectinfo | python -c 'import json, s mkdir -p _coverage meson test -C "$BUILDDIR" --num-processes 1 lcov --directory "$BUILDDIR" --capture --output-file _coverage/gjs.lcov.run --no-checksum $LCOV_ARGS -lcov --extract _coverage/gjs.lcov.run "$SOURCEDIR/*" "$GIDATADIR/tests/*" $LCOV_ARGS -o _coverage/gjs.lcov.sources +lcov --extract _coverage/gjs.lcov.run "$SOURCEDIR/*" $LCOV_ARGS -o _coverage/gjs.lcov.sources lcov --remove _coverage/gjs.lcov.sources $IGNORE $LCOV_ARGS -o _coverage/gjs.lcov -genhtml --prefix "$BUILDDIR/lcov/org/gnome/gjs" --prefix "$BUILDDIR" --prefix "$SOURCEDIR" --prefix "$GIDATADIR" \ +genhtml --prefix "$BUILDDIR/lcov/org/cinnamon/cjs" --prefix "$BUILDDIR" --prefix "$SOURCEDIR" \ --output-directory _coverage/html \ --title "gjs-$VERSION Code Coverage" \ $GENHTML_ARGS _coverage/gjs.lcov "$BUILDDIR"/lcov/coverage.lcov diff --git a/tools/run_cppcheck.sh b/tools/run_cppcheck.sh old mode 100755 new mode 100644 index aad20b2d6..314e413a9 --- a/tools/run_cppcheck.sh +++ b/tools/run_cppcheck.sh @@ -1,13 +1,33 @@ #!/bin/sh # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later # SPDX-FileCopyrightText: 2017 Claudio André +# SPDX-FileCopyrightText: 2021 Philip Chimento cd ${BUILDDIR:-_build} -if ! ninja -t compdb > compile_commands.json; then - echo 'Generating compile_commands.json failed.' +if ! test -f compile_commands.json; then + echo "compile_commands.json missing. Generate it with ninja -t compdb" exit 1 fi -cppcheck --project=compile_commands.json --inline-suppr \ - --enable=warning,performance,portability,missingInclude \ - -UHAVE_PRINTF_ALTERNATIVE_INT \ - --library=gtk,../tools/cppcheck.cfg --force --quiet $@ + +# Usage: +# add -q for just the errors and no progress reporting. +# add -f to force-check every configuration (takes a long time). +# add -j4 for faster execution with multiple jobs. +# add --enable=style to check style rules. There are some false positives. + +# duplInheritedMember: does not mix well with overshadowing constexpr static +# members in CRTP classes. +# incorrectStringBooleanError: does not mix well with the assertion message +# idiom. +# nullPointerRedundantCheck, nullPointerArithmeticRedundantCheck: False positive +# when using g_assert_nonnull(). Check again when +# https://github.com/danmar/cppcheck/pull/5830 is available. +cppcheck --project=compile_commands.json --check-level=exhaustive \ + --inline-suppr --error-exitcode=1 --enable=warning,performance,portability \ + --suppress=duplInheritedMember --suppress=incorrectStringBooleanError \ + --suppress=nullPointerArithmeticRedundantCheck \ + --suppress=nullPointerRedundantCheck \ + --suppress=*:subprojects/* --suppress=*:js-resources.c \ + --suppress=*:test/mock-js-resources.c \ + --suppress=*:installed-tests/js/jsunit-resources.c \ + --library=gtk,cairo,posix,../tools/cppcheck.cfg $@ diff --git a/tools/run_eslint.sh b/tools/run_eslint.sh old mode 100755 new mode 100644 diff --git a/tools/run_iwyu.sh b/tools/run_iwyu.sh old mode 100755 new mode 100644 index 6ff7e9719..b0292293a --- a/tools/run_iwyu.sh +++ b/tools/run_iwyu.sh @@ -47,7 +47,7 @@ IWYU="python3 $(which iwyu_tool || which iwyu-tool || which iwyu_tool.py) -p ." IWYU_TOOL_ARGS="-I../gjs" IWYU_ARGS="-Wno-pragma-once-outside-header" IWYU_RAW="include-what-you-use -xc++ -std=c++17 -Xiwyu --keep=config.h $IWYU_ARGS" -IWYU_RAW_INC="-I. -I.. $(pkg-config --cflags gobject-introspection-1.0 mozjs-115)" +IWYU_RAW_INC="-I. -I.. $(pkg-config --cflags gobject-introspection-1.0 mozjs-128)" PRIVATE_MAPPING="-Xiwyu --mapping_file=$SRCDIR/tools/gjs-private-iwyu.imp -Xiwyu --keep=config.h" PUBLIC_MAPPING="-Xiwyu --mapping_file=$SRCDIR/tools/gjs-public-iwyu.imp" POSTPROCESS="python3 $SRCDIR/tools/process_iwyu.py" diff --git a/util/console.h b/util/console.h index f4d4ace42..b11d867f6 100644 --- a/util/console.h +++ b/util/console.h @@ -7,6 +7,8 @@ #ifndef UTIL_CONSOLE_H_ #define UTIL_CONSOLE_H_ +#include + /* This file has to be valid C, because it's used in libgjs-private */ #include /* IWYU pragma: keep */ diff --git a/util/log.cpp b/util/log.cpp index d47570199..607cd3735 100644 --- a/util/log.cpp +++ b/util/log.cpp @@ -2,16 +2,12 @@ // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later // SPDX-FileCopyrightText: 2008 litl, LLC -#include // for atomic_bool -#include // for unique_ptr -#include // for string +#include #include -#include // for SEEK_END #include #include // for FILE, fprintf, fflush, fopen, fputs, fseek #include // for strchr, strcmp -#include "cjs/jsapi-util.h" #ifdef _WIN32 # include @@ -24,9 +20,13 @@ #endif #include +#include // for atomic_bool +#include // for unique_ptr +#include // for string #include +#include "cjs/jsapi-util.h" #include "util/log.h" #include "util/misc.h" diff --git a/util/log.h b/util/log.h index 93ce94f51..61467ca12 100644 --- a/util/log.h +++ b/util/log.h @@ -5,6 +5,8 @@ #ifndef UTIL_LOG_H_ #define UTIL_LOG_H_ +#include + /* The idea of this is to be able to have one big log file for the entire * environment, and grep out what you care about. So each module or app * should have its own entry in the enum. Be sure to add new enum entries diff --git a/util/misc.cpp b/util/misc.cpp index 9d6d1a0b2..60469840e 100644 --- a/util/misc.cpp +++ b/util/misc.cpp @@ -2,6 +2,8 @@ // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later // SPDX-FileCopyrightText: 2008 litl, LLC +#include + #include #include "util/misc.h" diff --git a/util/misc.h b/util/misc.h index 6c9b47120..5d495fcd7 100644 --- a/util/misc.h +++ b/util/misc.h @@ -5,6 +5,8 @@ #ifndef UTIL_MISC_H_ #define UTIL_MISC_H_ +#include + #include #include // for FILE, stdout #include // for memcpy From 07e81a43c299da6f2c0ab916dceb4a0970aec524 Mon Sep 17 00:00:00 2001 From: Fabio Fantoni Date: Mon, 17 Mar 2025 14:17:43 +0100 Subject: [PATCH 2/2] [mozjs-128] fix packaging (#128) * remove debian/watch* not needed for native package and was of gjs * d/copyright: restore cjs header * fix debian/shlibs.local * autopkgtest: partially fixed and disable installed test part for now * d/rules: restore strict check of symbols * d/gbp.conf: remove major of things as not needed or wrong for this repo * remove gitlab-ci of gjs * other fixes for autopkgtest build * d/control: replace old priority extra that was replaced by optional * debian: restore symbols with right cinnamon versions and readd the new ones * debian: fix version of new symbols --- .gitlab-ci.yml | 526 ----------------------------------- debian/control | 2 +- debian/copyright | 13 +- debian/gbp.conf | 12 - debian/libcjs0.symbols | 180 ++++++------ debian/rules | 1 + debian/shlibs.local | 2 +- debian/tests/build | 8 +- debian/tests/control | 14 +- debian/tests/installed-tests | 2 +- debian/watch | 4 - debian/watch.devel | 4 - 12 files changed, 108 insertions(+), 660 deletions(-) delete mode 100644 .gitlab-ci.yml delete mode 100644 debian/watch delete mode 100644 debian/watch.devel diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index e9e2d662a..000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,526 +0,0 @@ -# SPDX-License-Identifier: MIT OR LGPL-2.0-or-later -# SPDX-FileCopyrightText: 2017 Claudio André ---- -include: - - remote: 'https://gitlab.freedesktop.org/freedesktop/ci-templates/-/raw/b791bd48996e3ced9ca13f1c5ee82be8540b8adb/templates/alpine.yml' - -stages: - - prepare - - source_check - - test - - thorough_tests - - manual - - deploy - -.gjs-alpine: - variables: - FDO_DISTRIBUTION_TAG: '2024-07-28.0' - FDO_UPSTREAM_REPO: GNOME/gjs - -build-alpine-image: - extends: - - .fdo.container-build@alpine@x86_64 - - .gjs-alpine - stage: prepare - variables: - FDO_DISTRIBUTION_PACKAGES: | - bash cppcheck git grep npm py3-codespell python3 reuse - FDO_DISTRIBUTION_EXEC: | - mkdir -p /cwd && - apk add cpplint \ - --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing/ - -.coverage: &coverage - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug - variables: - GIT_SUBMODULE_STRATEGY: normal - coverage: '/^ lines.*(\d+\.\d+\%)/' - script: - - export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig - - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib - - 'export DISPLAY="${DISPLAY:-:0}"' - # This script runs the build inside its own build tree and generates the - # coverage report - - xvfb-run -a tools/run_coverage.sh - artifacts: - name: log_coverage - when: always - reports: - junit: _coverage_build/meson-logs/testlog*.junit.xml - expose_as: 'Coverage Report' - paths: - - _coverage/html/index.html - - _coverage/html - - _coverage_build/meson-logs - -.build: &build - when: on_success - artifacts: - reports: - junit: _build/meson-logs/testlog*.junit.xml - name: log - when: always - paths: - - _build/compile_commands.json - - _build/installed-tests/js/jsunit-resources.c - - _build/installed-tests/js/jsunit-resources.h - - _build/js-resources.c - - _build/js-resources.h - - _build/meson-logs/*log*.txt - - _build/test/mock-js-resources.c - - _build/test/mock-js-resources.h - script: - - test/test-ci.sh SETUP - - test/test-ci.sh BUILD - -############################################# -# Regular tests # -############################################# -# Test despite any changes in the Docker image -# SpiderMonkey has been configured with --enable-debug -build_recommended: - <<: *build - stage: source_check - image: registry.gitlab.gnome.org/gnome/gjs:job-4161430_fedora.mozjs128-debug # pinned on purpose - variables: - GIT_SUBMODULE_STRATEGY: normal - TEST_OPTS: --verbose --no-stdsplit --print-errorlogs --setup=verbose - except: - - schedules - -sanitizer_gcc: - <<: *build - stage: test - tags: - - asan # LSAN needs CAP_SYS_PTRACE - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug - variables: - GIT_SUBMODULE_STRATEGY: normal - CONFIG_OPTS: -Db_sanitize=address,undefined - TEST_OPTS: --timeout-multiplier=3 - # Override these during build, but they are overridden by meson anyways - ASAN_OPTIONS: start_deactivated=true,detect_leaks=0 - except: - - schedules - -sanitizer_thread_gcc: - <<: *build - stage: manual - when: manual - allow_failure: true - tags: - - asan # TSAN needs CAP_SYS_PTRACE - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug - variables: - GIT_SUBMODULE_STRATEGY: normal - CONFIG_OPTS: -Db_sanitize=thread - TEST_OPTS: --timeout-multiplier=3 --setup=verbose - except: - - schedules - -# There are a lot of debug log statements that are ifdef'd out in normal usage. -# These sometimes get invalid expressions in them, leading to annoyance the -# next time you try to use debug logging. -build_maximal: - when: on_success - stage: test - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug - variables: - GIT_SUBMODULE_STRATEGY: normal - CC: clang - CXX: clang++ - CONFIG_OPTS: >- - -Ddtrace=true -Dsystemtap=true -Dverbose_logs=true -Db_pch=false - ENABLE_GTK: "yes" - except: - - schedules - script: - - test/test-ci.sh SETUP - - test/test-ci.sh BUILD - - test/test-ci.sh SH_CHECKS - artifacts: - reports: - junit: _build/meson-logs/testlog*.junit.xml - name: log - when: always - paths: - - _build/compile_commands.json - - _build/meson-logs/*log*.txt - - scripts.log - -build_minimal: - <<: *build - stage: test - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128 - variables: - GIT_SUBMODULE_STRATEGY: normal - CONFIG_OPTS: -Dbuildtype=release -Dreadline=disabled -Dprofiler=disabled - TEST_OPTS: --setup=verbose - except: - - schedules - -build_unity: - <<: *build - stage: test - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128 - variables: - GIT_SUBMODULE_STRATEGY: normal - # unity-size here is forced to use an high number to check whether we can - # join all the sources together, but should not be used in real world to - # not to break multi-jobs compilation - CONFIG_OPTS: >- - -Dprofiler=disabled - --unity on --unity-size=10000 - TEST_OPTS: --setup=verbose - except: - - schedules - -# Generates -# The Code Coverage Report -coverage-automatic: - <<: *coverage - when: on_success - stage: source_check - except: - - schedules - only: - refs: - - master@GNOME/gjs - -# Publishes -# The code coverage report -pages: - stage: deploy - dependencies: - - coverage-automatic - script: - - mv $(pwd)/_coverage/html/ public/ || true - artifacts: - paths: - - public - only: - refs: - - master@GNOME/gjs - except: - variables: - - $CRON_TASK == "BUILD_CI_IMAGES" - -############################################# -# Static Analyzers # -############################################# -cppcheck: - when: on_success - extends: - - .fdo.distribution-image@alpine - - .gjs-alpine - stage: test # so that we have compile_commands.json and generated C files - script: - - cppcheck --version - # Create fake g-i test files, we are not analyzing them anyway - - mkdir -p subprojects/gobject-introspection-tests - - | - touch \ - subprojects/gobject-introspection-tests/annotation.{c,h} \ - subprojects/gobject-introspection-tests/drawable.{c,h} \ - subprojects/gobject-introspection-tests/foo.{c,h} \ - subprojects/gobject-introspection-tests/gimarshallingtests.{c,h} \ - subprojects/gobject-introspection-tests/regress.{c,h} \ - subprojects/gobject-introspection-tests/regress-unix.{c,h} \ - subprojects/gobject-introspection-tests/warnlib.{c,h} \ - subprojects/gobject-introspection-tests/utility.{c,h} - - ./tools/run_cppcheck.sh -q - except: - refs: - - schedules - - tags - variables: - - $CI_COMMIT_MESSAGE =~ /\[skip cppcheck\]/ - only: - changes: - - "**/*.c" - - "**/*.cpp" - - "**/*.h" - - "**/*.hh" - -cpplint: - when: on_success - stage: source_check - extends: - - .fdo.distribution-image@alpine - - .gjs-alpine - script: - - cpplint --version - - test/test-ci.sh CPPLINT - except: - refs: - - schedules - - tags - variables: - - $CI_COMMIT_MESSAGE =~ /\[skip cpplint\]/ - only: - changes: - - "**/*.cpp" - - "**/*.h" - - "**/*.hh" - -eslint: - when: on_success - extends: - - .fdo.distribution-image@alpine - - .gjs-alpine - stage: source_check - script: - - ./tools/run_eslint.sh --version - - ./tools/run_eslint.sh - except: - refs: - - schedules - - tags - variables: - - $CI_COMMIT_MESSAGE =~ /\[skip eslint\]/ - only: - changes: - - "**/*.js" - - .eslintignore - - .eslintrc.yml - - '**/.eslintrc.yml' - -headers_check: - when: on_success - stage: source_check - extends: - - .fdo.distribution-image@alpine - - .gjs-alpine - script: - - env SELFTEST=1 test/check-pch.sh - - env SELFTEST=1 test/check-headers.sh - - test/check-pch.sh - - test/check-headers.sh - except: - refs: - - schedules - - tags - variables: - - $CI_COMMIT_MESSAGE =~ /\[skip headers_check\]/ - only: - changes: - - "**/*.c" - - "**/*.cpp" - - "**/*.h" - - "**/*.hh" - - test/check-pch.sh - - test/check-headers.sh - -iwyu: - when: on_success - stage: source_check - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug - variables: - GIT_SUBMODULE_STRATEGY: normal - script: - - test/test-ci.sh UPSTREAM_BASE - - meson setup _build -Db_pch=false - - include-what-you-use --version - - ./tools/run_iwyu.sh ci-upstream-base - only: - refs: - - branches - except: - refs: - - schedules - - /^gnome-[-\d]+$/ - variables: - - $CI_COMMIT_MESSAGE =~ /\[skip iwyu\]/ - -codespell: - when: on_success - extends: - - .fdo.distribution-image@alpine - - .gjs-alpine - stage: source_check - script: - - codespell --version - - | - codespell -S "*.png,*.po,*.jpg,*.wrap,.git,LICENSES" -f \ - --builtin "code,usage,clear" \ - --skip="./build/maintainer-upload-release.sh,./installed-tests/js/jasmine.js,./README.md,./build/flatpak/*.json,./tools/package-lock.json" \ - --ignore-words-list="aas,afterall,deque,falsy,files',filetest,gir,inout,musl,nmake,stdio,uint,upto,ws,xdescribe" - except: - - schedules - -license-check: - when: on_success - stage: source_check - extends: - - .fdo.distribution-image@alpine - - .gjs-alpine - script: - - reuse --version - - reuse lint - except: - - schedules - -############################################# -# Manual Jobs # -############################################# -# Planned as daily -coverage: - <<: *coverage - stage: manual - when: manual - except: - - schedules - -iwyu-full: - when: manual - stage: manual - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug - variables: - GIT_SUBMODULE_STRATEGY: normal - script: - - meson setup _build - - ./tools/run_iwyu.sh - except: - - schedules - -sanitizer_clang: - <<: *build - stage: manual - tags: - - asan # LSAN needs CAP_SYS_PTRACE - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug - variables: - GIT_SUBMODULE_STRATEGY: normal - CC: clang - CXX: clang++ - # Override these during build, but they are overridden by meson anyways - ASAN_OPTIONS: start_deactivated=true,detect_leaks=0 - CONFIG_OPTS: -Db_sanitize=address,undefined -Db_lundef=false - TEST_OPTS: --timeout-multiplier=3 --setup=verbose - when: manual - except: - - schedules - -installed_tests: - <<: *build - stage: manual - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug - variables: - GIT_SUBMODULE_STRATEGY: normal - CONFIG_OPTS: -Dinstalled_tests=true -Dprefix=/usr - TEST: skip - when: manual - except: - - schedules - script: - - test/test-ci.sh SETUP - - test/test-ci.sh BUILD - - sudo ninja -C _build install - - xvfb-run -a dbus-run-session -- gnome-desktop-testing-runner gjs - -valgrind: - <<: *build - stage: manual - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug - variables: - GIT_SUBMODULE_STRATEGY: normal - TEST_OPTS: --setup=valgrind - allow_failure: true - when: manual - except: - - schedules - -# SpiderMonkey GC Tests (weekly) -zeal_2: - <<: *build - stage: manual - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug - variables: - GIT_SUBMODULE_STRATEGY: normal - TEST_OPTS: --setup=extra_gc - when: manual - except: - - schedules - -zeal_4: - <<: *build - stage: manual - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug - variables: - GIT_SUBMODULE_STRATEGY: normal - TEST_OPTS: --setup=pre_verify - when: manual - except: - - schedules - -zeal_11: - <<: *build - stage: manual - image: registry.gitlab.gnome.org/gnome/gjs:fedora.mozjs128-debug - variables: - GIT_SUBMODULE_STRATEGY: normal - TEST_OPTS: --setup=post_verify - when: manual - except: - - schedules - -############################################# -# Create CI Docker Images # -############################################# -.Docker image template: &create_docker_image - image: quay.io/freedesktop.org/ci-templates:container-build-base-2023-06-27.1 - stage: deploy - only: - variables: - - $CRON_TASK == "BUILD_CI_IMAGES" - - script: - # Newer versions of podman/buildah try to set overlayfs mount options when - # using the vfs driver, and this causes errors. - - sed -i '/^mountopt =.*/d' /etc/containers/storage.conf - - # Where the real magic happens - - buildah bud -f $DOCKERFILE -t "$CI_REGISTRY_IMAGE:$CI_JOB_NAME" $ARGS - - # Prepare to publish - - buildah tag "$CI_REGISTRY_IMAGE:$CI_JOB_NAME" "$CI_REGISTRY_IMAGE:job-${CI_JOB_ID}_$CI_JOB_NAME" - - buildah images - - buildah login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - - # Publish (if running on a schedule) - - | - if [[ "$CI_PIPELINE_SOURCE" == "schedule" ]]; then - buildah push "$CI_REGISTRY_IMAGE:$CI_JOB_NAME" - buildah push "$CI_REGISTRY_IMAGE:job-${CI_JOB_ID}_$CI_JOB_NAME" - fi - -.Docker variables: &docker_variables - STORAGE_DRIVER: vfs - BUILDAH_FORMAT: docker - BUILDAH_ISOLATION: chroot - -fedora.mozjs115: - <<: *create_docker_image - variables: - <<: *docker_variables - DOCKERFILE: test/extra/Dockerfile - -fedora.mozjs115-debug: - <<: *create_docker_image - variables: - <<: *docker_variables - DOCKERFILE: test/extra/Dockerfile.debug - -fedora.mozjs128: - <<: *create_docker_image - variables: - <<: *docker_variables - DOCKERFILE: test/extra/Dockerfile - ARGS: --build-arg MOZJS_BRANCH=mozjs128 --build-arg MOZJS_BUILDDEPS=mozjs115 - -fedora.mozjs128-debug: - <<: *create_docker_image - variables: - <<: *docker_variables - DOCKERFILE: test/extra/Dockerfile.debug - ARGS: --build-arg MOZJS_BRANCH=mozjs128 --build-arg MOZJS_BUILDDEPS=mozjs115 diff --git a/debian/control b/debian/control index 104900e69..200817de2 100644 --- a/debian/control +++ b/debian/control @@ -59,7 +59,7 @@ Description: Mozilla-based javascript bindings for the Cinnamon platform Package: libcjs-dbg Section: debug Architecture: any -Priority: extra +Priority: optional Depends: libcjs0 (= ${binary:Version}), ${misc:Depends}, diff --git a/debian/copyright b/debian/copyright index 724cd553a..4f6c7a9af 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,14 +1,7 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Source: https://download.gnome.org/sources/gjs/ -Comment: - This work was packaged for Debian by: - . - Gustavo Noronha Silva on Mon, 12 Oct 2009 18:38:36 -0300 - . - Upstream Author: - . - litl, LLC -Upstream-Name: gjs +Upstream-Name: cjs +Upstream-Contact: Clement Lefebvre +Source: https://github.com/linuxmint/cjs Files: * Copyright: diff --git a/debian/gbp.conf b/debian/gbp.conf index b37f0bdca..7db90fe6f 100644 --- a/debian/gbp.conf +++ b/debian/gbp.conf @@ -1,17 +1,5 @@ -[DEFAULT] -pristine-tar = True -debian-branch = debian/latest -upstream-branch = upstream/latest -upstream-vcs-tag = %(version)s - [buildpackage] sign-tags = True [dch] multimaint-merge = True - -[import-orig] -postimport = dch -v%(version)s New upstream release; git add debian/changelog; debcommit - -[pq] -patch-numbers = False diff --git a/debian/libcjs0.symbols b/debian/libcjs0.symbols index 76c03f230..a84d59777 100644 --- a/debian/libcjs0.symbols +++ b/debian/libcjs0.symbols @@ -1,92 +1,92 @@ libcjs.so.0 libcjs0 #MINVER# * Build-Depends-Package: libcjs-dev - gjs_bindtextdomain@Base 1.63.90 - gjs_cairo_pdf_surface_proto_props@Base 1.70.0 - gjs_clear_terminal@Base 1.70.0 - gjs_console_clear@Base 1.70.0 - gjs_console_is_tty@Base 1.70.0 - gjs_context_define_string_array@Base 1.63.90 - gjs_context_eval@Base 1.63.90 - gjs_context_eval_file@Base 1.63.90 - gjs_context_eval_module@Base 1.67.2 - gjs_context_eval_module_file@Base 1.67.2 - gjs_context_gc@Base 1.63.90 - gjs_context_get_all@Base 1.63.90 - gjs_context_get_current@Base 1.63.90 - gjs_context_get_native_context@Base 1.63.90 - gjs_context_get_profiler@Base 1.63.90 - gjs_context_get_type@Base 1.63.90 - gjs_context_make_current@Base 1.63.90 - gjs_context_maybe_gc@Base 1.63.90 - gjs_context_new@Base 1.63.90 - gjs_context_new_with_search_path@Base 1.63.90 - gjs_context_print_stack_stderr@Base 1.63.90 - gjs_context_register_module@Base 1.67.2 - gjs_context_run_in_realm@Base 1.77.90 - gjs_context_set_argv@Base 1.67.2 - gjs_context_setup_debugger_console@Base 1.63.90 - gjs_coverage_enable@Base 1.65.90 - gjs_coverage_get_type@Base 1.70.0 - gjs_coverage_new@Base 1.63.90 - gjs_coverage_write_statistics@Base 1.63.90 - gjs_dbus_implementation_emit_property_changed@Base 1.63.90 - gjs_dbus_implementation_emit_signal@Base 1.63.90 - gjs_dbus_implementation_get_type@Base 1.63.90 - gjs_dbus_implementation_unexport@Base 1.71.1 - gjs_dbus_implementation_unexport_from_connection@Base 1.71.1 - gjs_dumpstack@Base 1.63.90 - gjs_error_quark@Base 1.63.90 - gjs_format_int_alternative_output@Base 1.63.90 - gjs_g_binding_group_bind_full@Base 1.73.2 - gjs_g_object_bind_property_full@Base 1.70.0 - gjs_get_js_version@Base 1.63.90 - gjs_gobject_class_info@Base 1.70.0 - gjs_gobject_interface_info@Base 1.70.0 - gjs_gtk_container_child_set_property@Base 1.63.90 - gjs_gtk_custom_sorter_new@Base 1.71.1 - gjs_gtk_custom_sorter_set_sort_func@Base 1.71.1 - gjs_importer_class@Base 1.70.0 - gjs_importer_proto_funcs@Base 1.70.0 - gjs_js_error_get_type@Base 1.63.90 - gjs_js_error_quark@Base 1.63.90 - gjs_list_store_insert_sorted@Base 1.70.0 - gjs_list_store_sort@Base 1.70.0 - gjs_locale_category_get_type@Base 1.63.90 - gjs_log_set_writer_default@Base 1.70.0 - gjs_log_set_writer_func@Base 1.70.0 - gjs_match_info_expand_references@Base 1.81.2 - gjs_match_info_fetch@Base 1.81.2 - gjs_match_info_fetch_all@Base 1.81.2 - gjs_match_info_fetch_named@Base 1.81.2 - gjs_match_info_fetch_named_pos@Base 1.81.2 - gjs_match_info_fetch_pos@Base 1.81.2 - gjs_match_info_free@Base 1.81.2 - gjs_match_info_get_match_count@Base 1.81.2 - gjs_match_info_get_regex@Base 1.81.2 - gjs_match_info_get_string@Base 1.81.2 - gjs_match_info_get_type@Base 1.81.2 - gjs_match_info_is_partial_match@Base 1.81.2 - gjs_match_info_matches@Base 1.81.2 - gjs_match_info_next@Base 1.81.2 - gjs_match_info_ref@Base 1.81.2 - gjs_match_info_unref@Base 1.81.2 - gjs_memory_report@Base 1.63.90 - gjs_native_promise_module_funcs@Base 1.71.1 - gjs_param_class@Base 1.70.0 - gjs_param_spec_get_flags@Base 1.63.90 - gjs_param_spec_get_owner_type@Base 1.63.90 - gjs_param_spec_get_value_type@Base 1.63.90 - gjs_profiler_chain_signal@Base 1.63.90 - gjs_profiler_get_type@Base 1.63.90 - gjs_profiler_set_capture_writer@Base 1.67.2 - gjs_profiler_set_fd@Base 1.63.90 - gjs_profiler_set_filename@Base 1.63.90 - gjs_profiler_start@Base 1.63.90 - gjs_profiler_stop@Base 1.63.90 - gjs_regex_match@Base 1.81.2 - gjs_regex_match_all@Base 1.81.2 - gjs_regex_match_all_full@Base 1.81.2 - gjs_regex_match_full@Base 1.81.2 - gjs_repo_class@Base 1.70.0 - gjs_setlocale@Base 1.63.90 - gjs_textdomain@Base 1.63.90 + gjs_bindtextdomain@Base 2.4.1 + gjs_cairo_pdf_surface_proto_props@Base 5.4.0 + gjs_clear_terminal@Base 5.4.0 + gjs_console_clear@Base 5.4.0 + gjs_console_is_tty@Base 5.4.0 + gjs_context_define_string_array@Base 2.0.0 + gjs_context_eval@Base 2.0.0 + gjs_context_eval_file@Base 2.0.0 + gjs_context_eval_module@Base 5.4.0 + gjs_context_eval_module_file@Base 5.4.0 + gjs_context_gc@Base 2.0.0 + gjs_context_get_all@Base 2.0.0 + gjs_context_get_current@Base 2.4.1 + gjs_context_get_native_context@Base 2.0.0 + gjs_context_get_profiler@Base 4.0.0 + gjs_context_get_type@Base 2.0.0 + gjs_context_make_current@Base 2.4.1 + gjs_context_maybe_gc@Base 2.0.0 + gjs_context_new@Base 2.0.0 + gjs_context_new_with_search_path@Base 2.0.0 + gjs_context_print_stack_stderr@Base 2.0.0 + gjs_context_register_module@Base 5.4.0 + gjs_context_run_in_realm@Base 6.0.0 + gjs_context_set_argv@Base 5.4.0 + gjs_context_setup_debugger_console@Base 4.6.0 + gjs_coverage_enable@Base 4.6.0 + gjs_coverage_get_type@Base 5.4.0 + gjs_coverage_new@Base 2.4.1 + gjs_coverage_write_statistics@Base 2.4.1 + gjs_dbus_implementation_emit_property_changed@Base 2.0.0 + gjs_dbus_implementation_emit_signal@Base 2.0.0 + gjs_dbus_implementation_get_type@Base 2.0.0 + gjs_dbus_implementation_unexport@Base 5.7.0 + gjs_dbus_implementation_unexport_from_connection@Base 5.7.0 + gjs_dumpstack@Base 2.0.0 + gjs_error_quark@Base 2.0.0 + gjs_format_int_alternative_output@Base 2.4.1 + gjs_g_binding_group_bind_full@Base 5.7.0 + gjs_g_object_bind_property_full@Base 5.4.0 + gjs_get_js_version@Base 4.0.0 + gjs_gobject_class_info@Base 5.4.0 + gjs_gobject_interface_info@Base 5.4.0 + gjs_gtk_container_child_set_property@Base 2.4.1 + gjs_gtk_custom_sorter_new@Base 5.7.0 + gjs_gtk_custom_sorter_set_sort_func@Base 5.7.0 + gjs_importer_class@Base 5.4.0 + gjs_importer_proto_funcs@Base 5.4.0 + gjs_js_error_get_type@Base 4.0.0 + gjs_js_error_quark@Base 4.0.0 + gjs_list_store_insert_sorted@Base 5.4.0 + gjs_list_store_sort@Base 5.4.0 + gjs_locale_category_get_type@Base 3.4.4 + gjs_log_set_writer_default@Base 5.4.0 + gjs_log_set_writer_func@Base 5.4.0 + gjs_match_info_expand_references@Base 6.5.0 + gjs_match_info_fetch@Base 6.5.0 + gjs_match_info_fetch_all@Base 6.5.0 + gjs_match_info_fetch_named@Base 6.5.0 + gjs_match_info_fetch_named_pos@Base 6.5.0 + gjs_match_info_fetch_pos@Base 6.5.0 + gjs_match_info_free@Base 6.5.0 + gjs_match_info_get_match_count@Base 6.5.0 + gjs_match_info_get_regex@Base 6.5.0 + gjs_match_info_get_string@Base 6.5.0 + gjs_match_info_get_type@Base 6.5.0 + gjs_match_info_is_partial_match@Base 6.5.0 + gjs_match_info_matches@Base 6.5.0 + gjs_match_info_next@Base 6.5.0 + gjs_match_info_ref@Base 6.5.0 + gjs_match_info_unref@Base 6.5.0 + gjs_memory_report@Base 2.0.0 + gjs_native_promise_module_funcs@Base 5.7.0 + gjs_param_class@Base 5.4.0 + gjs_param_spec_get_flags@Base 3.4.4 + gjs_param_spec_get_owner_type@Base 3.4.4 + gjs_param_spec_get_value_type@Base 3.4.4 + gjs_profiler_chain_signal@Base 4.0.0 + gjs_profiler_get_type@Base 4.0.0 + gjs_profiler_set_capture_writer@Base 5.4.0 + gjs_profiler_set_fd@Base 4.6.0 + gjs_profiler_set_filename@Base 4.0.0 + gjs_profiler_start@Base 4.0.0 + gjs_profiler_stop@Base 4.0.0 + gjs_regex_match@Base 6.5.0 + gjs_regex_match_all@Base 6.5.0 + gjs_regex_match_all_full@Base 6.5.0 + gjs_regex_match_full@Base 6.5.0 + gjs_repo_class@Base 5.4.0 + gjs_setlocale@Base 3.4.4 + gjs_textdomain@Base 2.4.1 diff --git a/debian/rules b/debian/rules index b074acb4e..0ec4ca9c8 100755 --- a/debian/rules +++ b/debian/rules @@ -4,6 +4,7 @@ built_binaries := $(shell dh_listpackages) export DEB_BUILD_MAINT_OPTIONS = hardening=+all export DEB_LDFLAGS_MAINT_APPEND = -Wl,-z,defs +export DPKG_GENSYMBOLS_CHECK_LEVEL = 2 include /usr/share/dpkg/default.mk diff --git a/debian/shlibs.local b/debian/shlibs.local index 8423e79bf..4972e4394 100644 --- a/debian/shlibs.local +++ b/debian/shlibs.local @@ -1 +1 @@ -libgjs 0 libgjs0g (= ${binary:Version}) +libcjs 0 libcjs0 (= ${binary:Version}) diff --git a/debian/tests/build b/debian/tests/build index c3c439ed5..599fbc682 100644 --- a/debian/tests/build +++ b/debian/tests/build @@ -16,7 +16,7 @@ else CROSS_COMPILE= fi -cat < gjstest.c +cat < cjstest.c #include int main() @@ -29,8 +29,8 @@ EOF # Deliberately word-splitting, that's how pkg-config works: # shellcheck disable=SC2046 -"${CROSS_COMPILE}gcc" -o gjstest gjstest.c $("${CROSS_COMPILE}pkg-config" --cflags --libs gjs-1.0) +"${CROSS_COMPILE}gcc" -o cjstest cjstest.c $("${CROSS_COMPILE}pkg-config" --cflags --libs cjs-1.0) echo "build: OK" -[ -x gjstest ] -./gjstest +[ -x cjstest ] +./cjstest echo "run: OK" diff --git a/debian/tests/control b/debian/tests/control index 6316b0b12..f1ec55d1e 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -1,11 +1,11 @@ Tests: build Restrictions: superficial Depends: build-essential, - libgjs-dev + libcjs-dev -Tests: installed-tests -Depends: dbus-daemon, - gjs-tests, - gnome-desktop-testing, - xauth, - xvfb +#Tests: installed-tests +#Depends: dbus-daemon, +# cjs-tests, +# gnome-desktop-testing, +# xauth, +# xvfb diff --git a/debian/tests/installed-tests b/debian/tests/installed-tests index df28cae67..d4a7dd551 100644 --- a/debian/tests/installed-tests +++ b/debian/tests/installed-tests @@ -9,4 +9,4 @@ export XDG_RUNTIME_DIR=$AUTOPKGTEST_TMP export LC_ALL=C.UTF-8 # dbus outputs activation messages to stderr which fails the test -dbus-run-session -- xvfb-run -a gnome-desktop-testing-runner gjs 2> >(grep -vE '^(Activating|Successfully activated)')>&2 +dbus-run-session -- xvfb-run -a gnome-desktop-testing-runner cjs 2> >(grep -vE '^(Activating|Successfully activated)')>&2 diff --git a/debian/watch b/debian/watch deleted file mode 100644 index 1b6d01304..000000000 --- a/debian/watch +++ /dev/null @@ -1,4 +0,0 @@ -version=4 -opts="searchmode=plain, uversionmangle=s/\.(alpha|beta|rc)/~$1/, downloadurlmangle=s|cache.json||" \ -https://download.gnome.org/sources/@PACKAGE@/cache.json \ - [\d.]+[02468]/@PACKAGE@-([\d.]+)@ARCHIVE_EXT@ diff --git a/debian/watch.devel b/debian/watch.devel deleted file mode 100644 index 64675b41f..000000000 --- a/debian/watch.devel +++ /dev/null @@ -1,4 +0,0 @@ -version=4 -opts="searchmode=plain, uversionmangle=s/\.(alpha|beta|rc)/~$1/, downloadurlmangle=s|cache.json||" \ -https://download.gnome.org/sources/@PACKAGE@/cache.json \ - [\d.]+/@PACKAGE@-([\d.]+)@ARCHIVE_EXT@