From 646910d52fccb983857e13e539ebe1950677cb4c Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Fri, 20 May 2022 16:05:10 +0900 Subject: [PATCH 01/16] Fix memory leak This patch is removing memory leak detected by analysis tool. Change-Id: I473e2a6d20b92a9e28300ed758e9bd3508b78fcb --- registryd/registry.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/registryd/registry.c b/registryd/registry.c index 9757067..0e1703e 100644 --- a/registryd/registry.c +++ b/registryd/registry.c @@ -369,6 +369,8 @@ _unset_active_window (SpiRegistry *reg, const char* sender, const char *path) spi_reference_free (reg->active_win); reg->active_win = NULL; } + + spi_reference_free (ref); } static void -- 2.7.4 From d88142a637d082fcb1b386a2379c378442fbc3d3 Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Wed, 25 May 2022 13:47:14 +0900 Subject: [PATCH 02/16] registryd: handle 'showing' window For multi-window case and multi-AT-client case, registryd keep the information about 'showing' window. This patch works well with following related patch: https://review.tizen.org/gerrit/#/c/platform/core/accessibility/screen-reader/+/275382/ https://review.tizen.org/gerrit/#/c/platform/core/uifw/dali-adaptor/+/275412/ Change-Id: I39a7094c6745d5b83b480a589322b0bc35b9191e --- registryd/registry.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/registryd/registry.c b/registryd/registry.c index 0e1703e..089590a 100644 --- a/registryd/registry.c +++ b/registryd/registry.c @@ -464,8 +464,7 @@ handle_state_changed (DBusConnection *bus, DBusMessage *message, void *user_data dbus_message_iter_get_basic (&iter, &detail2); dbus_message_iter_next (&iter); - /* TODO: detail == showing */ - if (!detail || !_is_same (detail, "visible")) + if (!detail || (!_is_same (detail, "visible") && !_is_same (detail, "showing"))) return; AtspiAccessible *accessible; -- 2.7.4 From 902dc3558d17fce8d60117ca66c905fe8993f5c8 Mon Sep 17 00:00:00 2001 From: Lukasz Oleksak Date: Fri, 17 Jun 2022 11:11:42 +0200 Subject: [PATCH 03/16] Increasing cache maximum size to handle complex UIs Change-Id: I5a9072894df80214532c9521d0f30aa454d0a239 --- atspi/atspi-misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atspi/atspi-misc.c b/atspi/atspi-misc.c index be8030e..ae2de51 100644 --- a/atspi/atspi-misc.c +++ b/atspi/atspi-misc.c @@ -38,7 +38,7 @@ #include /* This value is not fixed, could be changed. */ -#define HASH_TABLE_SIZE_MAX 1000 +#define HASH_TABLE_SIZE_MAX 3000 static void handle_get_items (DBusPendingCall *pending, void *user_data); -- 2.7.4 From 23abf1e6f26e855879c534ebd07b370182704dee Mon Sep 17 00:00:00 2001 From: Lukasz Oleksak Date: Thu, 7 Jul 2022 21:00:49 +0200 Subject: [PATCH 04/16] Do not return intermediate results Intermediate result is a non-navigable Proxy object that is used only to continue searching of UI element in embeded GUIs. It should never be returned as a final result of search. Change-Id: I1c8962154e8955526074f37f32039100b68ea363 --- atspi/atspi-accessible.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index dddb8fe..d461055 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -493,10 +493,12 @@ atspi_accessible_get_navigable_at_point (AtspiAccessible *root, } break; } - - if (return_value) - g_object_unref(return_value); - return_value = root = tmp; + root = tmp; + if (!recurse) { + if (return_value) + g_object_unref(return_value); + return_value = tmp; + } } while(recurse); return return_value; } -- 2.7.4 From c572f70de5d589fdf871114164fbdbc6aa168b97 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Artur=20=C5=9Awigo=C5=84?= Date: Thu, 23 Feb 2023 10:16:54 +0100 Subject: [PATCH 05/16] 2.44.1 Change-Id: Id40e27e0a19f1d06e4bd8ce9fa68e433bfb53a11 --- .gitlab-ci.yml | 225 ++++++++++++++++++++++++++++++++++ .gitlab-ci/README.md | 76 ++++++++++++ .gitlab-ci/gen-coverage.sh | 30 +++++ .gitlab-ci/lcovrc | 13 ++ .gitlab-ci/opensuse.Dockerfile | 34 +++++ .gitlab-ci/run-docker.sh | 132 ++++++++++++++++++++ .gitlab-ci/run-style-check.sh | 33 +++++ .gitlab-ci/run-tests.sh | 17 +++ .gitlab-ci/search-common-ancestor.sh | 36 ++++++ NEWS | 29 +++++ README | 112 ----------------- README.md | 71 +++++++++++ at-spi2-core.doap | 7 ++ atspi/atspi-device-legacy.c | 2 +- atspi/atspi-device-listener.c | 2 +- atspi/atspi-device-x11.c | 2 +- atspi/atspi-event-listener.c | 9 ++ atspi/atspi-misc.c | 74 +++++------ atspi/atspi-registry.c | 22 ++-- bus/README | 10 -- bus/README.md | 98 +++++++++++++++ bus/at-spi-bus-launcher.c | 198 ++++++++++++++++++++++-------- dbind/dbind-any.c | 22 ++-- dbind/dbtest.c | 7 +- devel-docs/gitlab-ci.md | 188 ++++++++++++++++++++++++++++ meson.build | 7 +- po/LINGUAS | 1 + po/is.po | 26 ++++ registryd/deviceeventcontroller-x11.c | 96 +++++++-------- registryd/deviceeventcontroller-x11.h | 28 +++++ registryd/deviceeventcontroller.c | 65 +++++++--- registryd/deviceeventcontroller.h | 1 - registryd/registry.c | 10 +- test/memory.c | 15 ++- xml/Cache.xml | 4 +- 35 files changed, 1378 insertions(+), 324 deletions(-) create mode 100644 .gitlab-ci.yml create mode 100644 .gitlab-ci/README.md create mode 100644 .gitlab-ci/gen-coverage.sh create mode 100644 .gitlab-ci/lcovrc create mode 100644 .gitlab-ci/opensuse.Dockerfile create mode 100755 .gitlab-ci/run-docker.sh create mode 100755 .gitlab-ci/run-style-check.sh create mode 100755 .gitlab-ci/run-tests.sh create mode 100755 .gitlab-ci/search-common-ancestor.sh delete mode 100644 README create mode 100644 README.md delete mode 100644 bus/README create mode 100644 bus/README.md create mode 100644 devel-docs/gitlab-ci.md create mode 100644 po/is.po create mode 100644 registryd/deviceeventcontroller-x11.h diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..963a79e --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,225 @@ +# Continuous Integration configuration for at-spi2-core +# +# For documentation on how this works, see devel-docs/gitlab-ci.md +# +# Full documentation for Gitlab CI: https://docs.gitlab.com/ee/ci/ +# +# Introduction to Gitlab CI: https://docs.gitlab.com/ee/ci/quick_start/index.html + +variables: + OPENSUSE_TUMBLEWEED_IMAGE: "registry.gitlab.gnome.org/gnome/at-spi2-core/opensuse:latest" + +# Stages in the CI pipeline in which jobs will be run +stages: +# - style-check + - build + - analysis + - docs + - deploy + +# Base definition for jobs. +# +# We have the package dependencies to install on top of a stock opensuse/tumbleweed image, +# and the rules for when to run each job (on merge requests and on personal branches). +.only-default: + only: + - merge_requests + - branches + except: + - tags + +# C coding style checker. +# +# Disabled for now, since we need to decide to reindent all the code first. +# +# style-check-diff: +# extends: .only-default +# image: fedora:latest +# stage: style-check +# script: +# - dnf install -y clang-tools-extra curl diffutils git +# - sh -x ./.gitlab-ci/run-style-check.sh + + +# Template for the default build recipe. +# +# Depends on these variables: +# @MESON_EXTRA_FLAGS: extra arguments for the meson setup invocation +.build-default: + image: $OPENSUSE_TUMBLEWEED_IMAGE + extends: .only-default + script: + - meson setup ${MESON_EXTRA_FLAGS} --prefix /usr _build . + - meson compile -C _build + - meson install -C _build + - mkdir /tmp/test+dir+with+funny+chars + - export XDG_RUNTIME_DIR=/tmp/test+dir+with+funny+chars # See https://gitlab.gnome.org/GNOME/at-spi2-core/-/issues/48 + - dbus-run-session -- .gitlab-ci/run-tests.sh + artifacts: + reports: + junit: "_build/meson-logs/testlog.junit.xml" + when: always + name: "at-spi2-core-${CI_COMMIT_REF_NAME}" + paths: + - "${CI_PROJECT_DIR}/_build/meson-logs" + - "${CI_PROJECT_DIR}/_build/atspi/Atspi-2.0.gir" + +# Inherit to build the API reference via gi-docgen +# @PROJECT_DEPS: the dependencies of the project (on Fedora) +# @MESON_EXTRA_FLAGS: extra arguments for the meson setup invocation +# @DOCS_FLAGS: doc-related arguments for the meson setup invocation +# @DOCS_PATH: the docs output directory under the build directory +# .gidocgen-build: +# image: fedora:latest +# before_script: +# - export PATH="$HOME/.local/bin:$PATH" +# - dnf install -y python3 python3-pip python3-wheel gobject-introspection-devel graphviz ninja-build redhat-rpm-config +# - dnf install -y ${PROJECT_DEPS} +# - pip3 install --user meson==${MESON_VERSION} gi-docgen jinja2 Markdown markupsafe pygments toml typogrify +# script: +# - meson setup ${MESON_EXTRA_FLAGS} ${DOCS_FLAGS} _docs . +# - meson compile -C _docs +# - | +# pushd "_docs/${DOCS_PATH}" > /dev/null +# tar cf ${CI_PROJECT_NAME}-docs.tar . +# popd > /dev/null +# - mv _docs/${DOCS_PATH}/${CI_PROJECT_NAME}-docs.tar . +# artifacts: +# when: always +# name: 'Documentation' +# expose_as: 'Download the API reference' +# paths: +# - ${CI_PROJECT_NAME}-docs.tar + +# Build and run the test suite. +# +# Look at .build-default for where the artifacts are stored (build/test logs, built binaries). +opensuse-x86_64: + extends: .build-default + stage: build + needs: [] + variables: + MESON_EXTRA_FLAGS: "--buildtype=debug" # -Dwerror=true + +# Run static analysis on the code. +# +# The logs are part of the compilation stderr. +static-scan: + image: $OPENSUSE_TUMBLEWEED_IMAGE + stage: analysis + needs: [] + variables: + MESON_EXTRA_FLAGS: "--buildtype=debug -Dintrospection=no -Ddocs=false" + script: + - meson setup ${MESON_EXTRA_FLAGS} --prefix /usr _scan_build . + - ninja -C _scan_build scan-build + artifacts: + name: "at-spi2-core-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}" + when: always + paths: + - "_scan_build/meson-logs/scanbuild" + +# Build and run with address sanitizer (asan). +asan-build: + image: $OPENSUSE_TUMBLEWEED_IMAGE + stage: analysis + needs: [] + variables: + MESON_EXTRA_FLAGS: "--buildtype=debug -Db_sanitize=address -Db_lundef=false -Dintrospection=no -Ddocs=false" + script: + - CC=clang meson setup ${MESON_EXTRA_FLAGS} --prefix /usr _build . + - meson compile -C _build + - meson install -C _build + - dbus-run-session -- .gitlab-ci/run-tests.sh + artifacts: + name: "at-spi2-core-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}" + when: always + paths: + - "_asan_build/meson-logs" + allow_failure: true + +# Run the test suite and extract code coverage information. +# +# See the _coverage/ artifact for the HTML report. +coverage: + image: $OPENSUSE_TUMBLEWEED_IMAGE + stage: analysis + needs: [] + variables: + MESON_EXTRA_FLAGS: "--buildtype=debug -Ddocs=false -Dintrospection=no" + CFLAGS: "-coverage -ftest-coverage -fprofile-arcs" + script: + - meson setup ${MESON_EXTRA_FLAGS} --prefix /usr _build . + - meson compile -C _build + - meson install -C _build + - mkdir -p _coverage + - lcov --config-file .gitlab-ci/lcovrc --directory _build --capture --initial --output-file "_coverage/${CI_JOB_NAME}-baseline.lcov" + - dbus-run-session -- .gitlab-ci/run-tests.sh + - lcov --config-file .gitlab-ci/lcovrc --directory _build --capture --output-file "_coverage/${CI_JOB_NAME}.lcov" + - bash -x .gitlab-ci/gen-coverage.sh + - mkdir -p public/ + - cp -r _coverage public/coverage + coverage: '/^\s+lines\.+:\s+([\d.]+\%)\s+/' + artifacts: + name: "at-spi2-core-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}" + expire_in: 2 days + when: always + paths: + - "_build/meson-logs" + - public + +# Build the reference documentation. +# +# reference: +# stage: docs +# needs: [] +# extends: .gidocgen-build +# variables: +# PROJECT_DEPS: +# gdk-pixbuf2-devel +# geocode-glib-devel +# gettext +# git +# gobject-introspection-devel +# itstool +# libsoup-devel +# libxml2-devel +# ninja-build +# pylint +# python3 +# python3-gobject +# python3-pip +# python3-wheel +# redhat-rpm-config +# vala +# MESON_VERSION: "0.55.3" +# DOCS_FLAGS: -Dgtk_doc=true +# DOCS_PATH: doc/libgweather-4.0 +# +# +# Publish the generated HTML reference documentation. +# +# pages: +# stage: deploy +# needs: ['reference'] +# script: +# - mkdir public && cd public +# - tar xf ../${CI_PROJECT_NAME}-docs.tar +# artifacts: +# paths: +# - public +# only: +# - master +# - main + +# Publish the test coverage report +pages: + stage: deploy + needs: [ coverage ] + script: + - echo # dummy - contents were generated in another job + artifacts: + paths: + - public + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH diff --git a/.gitlab-ci/README.md b/.gitlab-ci/README.md new file mode 100644 index 0000000..9adfaac --- /dev/null +++ b/.gitlab-ci/README.md @@ -0,0 +1,76 @@ +# Continuous Integration scripts for at-spi2-core + +Please see the general [documentation for at-spi2-core's Gitlab CI][ci-docs]. + +This directory contains scripts which get called during a run of a CI +pipeline, and utilities to maintain the CI infrastructure. + +## Scripts used during a run of a CI pipeline: + +* `run-tests.sh` - Runs the test suite and prints other diagnostics. + +* `gen-coverage.sh` - After the test suite is run, merges the various + code coverage reports from `lcov`, and generates an HTML report. + +* `lcovrc` - Configuration file for `lcov`, used by `gen-coverage.sh`. + Among other things, this tells `lcov` to exclude branch coverage for + the unreachable branches of `g_return_if_fail()` and friends. + +* `run-style-check.sh` - Runs `clang-format-diff` to test for source + files with inconsistent formatting, and uploads the resulting report + to gitlab so it can be viewed as part of a merge request's analysis. + +* `search-common-ancestor.sh` - Utility used from + `run-style-check.sh`; finds a git branch point from the current + commit. + +## Utilities to maintain the CI infrastructure: + +To make pipelines fast, and avoid a lot of repeated downloads, +at-spi2-core uses pre-built container images for CI pipelines, instead +of using a stock image like opensuse/tumbleweed and then installing +all the dependencies on top of it every time. + +The prebuilt images are stored here: +https://gitlab.gnome.org/GNOME/at-spi2-core/container_registry + +Instead of maintaining those images by hand with `docker` or `podman` +commands, here is a little script (stolen from [glib][glib-ci]) to +maintain them, which you can start exploring with `./run-docker.sh help`. + +This script knows how to build and upload images from Dockerfiles +called `foo.Dockerfile`. The image configurations we have: + +* `opensuse.Dockerfile` - starts with an opensuse/tumbleweed image and + installs the package dependencies for building at-spi2-core. + +If you are one of at-spi2-core's maintainers, you'll want to update +the CI images periodically. First, install `podman` and +`podman-docker`. Then, run this: + +```sh +# "opensuse" in these commands indicates to use the opensuse.Dockerfile configuration + +./run-docker.sh build --base=opensuse # builds the image, takes a while + +./run-docker.sh run --base=opensuse # launch the container; poke around; see that it works + +./run-docker.sh push --base=opensuse # push the image to registry.gitlab.gnome.org +``` + +The `build` subcommand creates an image named +`registry.gitlab.gnome.org/gnome/at-spi2-core/opensuse/tumbleweed:latest` +**that is only stored in your localhost**. + +The `run` subcommand launches a container with that image and gives +you a shell prompt. This is equivalent to `podman run`. + +The `push` subcommand takes that built image and uploads it to +`registry.gitlab.gnome.org`. It will then be visible from +https://gitlab.gnome.org/GNOME/at-spi2-core/container_registry - the +CI configuration in [`.gitlab-ci.yml`](../.gitlab-ci.yml) uses this +image for the pipeline. + +[ci-docs]: ../devel-docs/gitlab-ci.md +[container-registry-docs]: https://gitlab.gnome.org/help/user/packages/container_registry/index +[glib-ci]: https://gitlab.gnome.org/GNOME/glib/-/tree/main/.gitlab-ci diff --git a/.gitlab-ci/gen-coverage.sh b/.gitlab-ci/gen-coverage.sh new file mode 100644 index 0000000..3949256 --- /dev/null +++ b/.gitlab-ci/gen-coverage.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +set -e + +for path in _coverage/*.lcov; do + lcov --config-file .gitlab-ci/lcovrc -r "${path}" '*/_build/*' -o "$(pwd)/${path}" + lcov --config-file .gitlab-ci/lcovrc -e "${path}" "$(pwd)/*" -o "$(pwd)/${path}" +done + +genhtml \ + --ignore-errors=source \ + --config-file .gitlab-ci/lcovrc \ + _coverage/*.lcov \ + -o _coverage/coverage + +cd _coverage +rm -f ./*.lcov + +cat >index.html < +at-spi2-core Coverage + + + + +EOL diff --git a/.gitlab-ci/lcovrc b/.gitlab-ci/lcovrc new file mode 100644 index 0000000..ac5997b --- /dev/null +++ b/.gitlab-ci/lcovrc @@ -0,0 +1,13 @@ +# lcov and genhtml configuration +# See http://ltp.sourceforge.net/coverage/lcov/lcovrc.5.php + +# Always enable branch coverage +lcov_branch_coverage = 1 + +# Exclude precondition assertions, as we can never reasonably get full branch +# coverage of them, as they should never normally fail. +# See https://github.com/linux-test-project/lcov/issues/44 +lcov_excl_br_line = LCOV_EXCL_BR_LINE|g_return_if_fail|g_return_val_if_fail|g_assert|g_assert_ + +# Similarly for unreachable assertions. +lcov_excl_line = LCOV_EXCL_LINE|g_return_if_reached|g_return_val_if_reached|g_assert_not_reached diff --git a/.gitlab-ci/opensuse.Dockerfile b/.gitlab-ci/opensuse.Dockerfile new file mode 100644 index 0000000..0bcdfe4 --- /dev/null +++ b/.gitlab-ci/opensuse.Dockerfile @@ -0,0 +1,34 @@ +# Dockerfile to build container images for Gitlab Continuous Integration +# +# This starts with an openSUSE Tumbleweed image, and installs the dependencies +# for building and testing at-spi2-core. +# +# See README.md for documentation. + +FROM opensuse/tumbleweed:latest + +RUN zypper refresh \ + && zypper install -y \ + clang \ + clang-tools \ + findutils \ + gcc \ + dbus-1 \ + dbus-1-devel \ + gettext \ + git \ + glib2-devel \ + gobject-introspection-devel \ + gsettings-desktop-schemas \ + itstool \ + libasan6 \ + libxml2-devel \ + libxkbcommon-devel \ + libXi-devel \ + libXtst-devel \ + lcov \ + meson \ + ninja \ + python38 \ + python38-gobject \ + && zypper clean --all diff --git a/.gitlab-ci/run-docker.sh b/.gitlab-ci/run-docker.sh new file mode 100755 index 0000000..d6be467 --- /dev/null +++ b/.gitlab-ci/run-docker.sh @@ -0,0 +1,132 @@ +#!/bin/bash + +read_arg() { + # $1 = arg name + # $2 = arg value + # $3 = arg parameter + local rematch='^[^=]*=(.*)$' + if [[ $2 =~ $rematch ]]; then + read -r "$1" <<< "${BASH_REMATCH[1]}" + else + read -r "$1" <<< "$3" + # There is no way to shift our callers args, so + # return 1 to indicate they should do it instead. + return 1 + fi +} + +SUDO_CMD="sudo" +if docker -v |& grep -q podman; then + # Using podman + SUDO_CMD="" + # Docker is actually implemented by podman, and its OCI output + # is incompatible with some of the dockerd instances on GitLab + # CI runners. + export BUILDAH_FORMAT=docker +fi + +set -e + +base="" +base_version="" +build=0 +run=0 +push=0 +list=0 +print_help=0 +no_login=0 + +while (($# > 0)); do + case "${1%%=*}" in + build) build=1;; + run) run=1;; + push) push=1;; + list) list=1;; + help) print_help=1;; + --base|-b) read_arg base "$@" || shift;; + --base-version) read_arg base_version "$@" || shift;; + --no-login) no_login=1;; + *) echo -e "\\e[1;31mERROR\\e[0m: Unknown option '$1'"; exit 1;; + esac + shift +done + +if [ $print_help == 1 ]; then + echo "$0 - Build and run Docker images" + echo "" + echo "Usage: $0 [options] [basename]" + echo "" + echo "Available commands" + echo "" + echo " build --base= - Build Docker image .Dockerfile" + echo " run --base= - Run Docker image " + echo " push --base= - Push Docker image to the registry" + echo " list - List available images" + echo " help - This help message" + echo "" + exit 0 +fi + +cd "$(dirname "$0")" + +if [ $list == 1 ]; then + echo "Available Docker images:" + for f in *.Dockerfile; do + filename=$( basename -- "$f" ) + basename="${filename%.*}" + + echo -e " \\e[1;39m$basename\\e[0m" + done + exit 0 +fi + +# All commands after this require --base to be set +if [ -z "${base}" ]; then + echo "Usage: $0 " + echo "Or use \"$0 help\" for a list of commands" + exit 1 +fi + +if [ ! -f "$base.Dockerfile" ]; then + echo -e "\\e[1;31mERROR\\e[0m: Dockerfile for '$base' not found" + exit 1 +fi + +if [ -z "${base_version}" ]; then + base_version="latest" +else + base_version="v$base_version" +fi + +TAG="registry.gitlab.gnome.org/gnome/at-spi2-core/${base}:${base_version}" + +if [ $build == 1 ]; then + echo -e "\\e[1;32mBUILDING\\e[0m: ${base} as ${TAG}" + $SUDO_CMD docker build \ + --tag "${TAG}" \ + --file "${base}.Dockerfile" . + exit $? +fi + +if [ $push == 1 ]; then + echo -e "\\e[1;32mPUSHING\\e[0m: ${base} as ${TAG}" + + if [ $no_login == 0 ]; then + $SUDO_CMD docker login registry.gitlab.gnome.org + fi + + $SUDO_CMD docker push $TAG + exit $? +fi + +if [ $run == 1 ]; then + echo -e "\\e[1;32mRUNNING\\e[0m: ${base} as ${TAG}" + $SUDO_CMD docker run \ + --rm \ + --volume "$(pwd)/..:/home/user/app" \ + --workdir "/home/user/app" \ + --tty \ + --interactive "${TAG}" \ + bash + exit $? +fi diff --git a/.gitlab-ci/run-style-check.sh b/.gitlab-ci/run-style-check.sh new file mode 100755 index 0000000..9d741bc --- /dev/null +++ b/.gitlab-ci/run-style-check.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +set -e + +ancestor_horizon=28 # days (4 weeks) + +# Wrap everything in a subshell so we can propagate the exit status. +( + +source .gitlab-ci/search-common-ancestor.sh + +git diff -U0 --no-color "${newest_common_ancestor_sha}" atspi/*.c bus/*.c dbind/*.c registryd/*.c test/*.c | clang-format-diff -p1 > format-diff.log + +) +exit_status=$? + +[ ${exit_status} == 0 ] || exit ${exit_status} + +format_diff="$( format.log + cat format-diff.log >> format.log + echo '```' >> format.log + [ -n "$CI_MERGE_REQUEST_IID" ] && curl \ + --request POST \ + --header "Private-Token: $STYLE_CHECK_TOKEN" \ + --data-urlencode "$(/dev/null 2>&1 ; then + git remote add upstream https://gitlab.gnome.org/GNOME/${CI_PROJECT_NAME}.git +fi +git fetch --shallow-since="$(date --date="${ancestor_horizon} days ago" +%Y-%m-%d)" upstream + +# 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/main` or `upstream/gnome-40`). +# `${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}` or `${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}` +# are only defined if we’re running in a merge request pipeline, +# fall back to `${CI_DEFAULT_BRANCH}` or `${CI_COMMIT_BRANCH}` respectively +# otherwise. + +source_branch="${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME:-${CI_COMMIT_BRANCH}}" +git fetch --shallow-since="$(date --date="${ancestor_horizon} days ago" +%Y-%m-%d)" origin "${source_branch}" + +newest_common_ancestor_sha=$(diff --old-line-format='' --new-line-format='' <(git rev-list --first-parent "upstream/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-${CI_DEFAULT_BRANCH}}") <(git rev-list --first-parent "origin/${source_branch}") | head -1) +if [ -z "${newest_common_ancestor_sha}" ]; then + echo "Couldn’t find common ancestor with upstream main branch. This typically" + echo "happens if you branched from main a long time ago. Please update" + echo "your clone, rebase, and re-push your branch." + exit 1 +fi diff --git a/NEWS b/NEWS index 6738a3d..b4c1230 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,32 @@ +What's new in at-spi2-core 2.44.1: + +* Fix use after free when removing a hung process. + +* Fix the build with X11 disabled. + +* Fix crash when NULL is passed to some listener-related functions. + +* impl_deregister_keystroke_listener: fix memory leak on iteration error. + +What's new in at-spi2-core 2.44.0: + +* Unlink the socket before binding when using dbus-broker. Fixes regression + introduced in 2.43.92 where restarting the bus launcher would fail. + +What's new in at-spi2-core 2.43.92: + +* The AT-SPI bus now uses the user's XDG_RUNTIME_DIR for its socket. +Fixes accessibility for Snap-confined applications. + +* Caps lock is now unlocked for key synthesis. Fixes cutting and +pasting from brltty when caps lock is on. + +* Several fixes to the dbus specification. + +* Fix the build when x11 is disabled. + +* Fix several compiler warnings. + What's new in at-spi2-core 2.42.0: * Set X root property when Xwayland starts on demand. diff --git a/README b/README deleted file mode 100644 index b377fca..0000000 --- a/README +++ /dev/null @@ -1,112 +0,0 @@ -D-Bus AT-SPI ------------- - -This version of at-spi is a major break from version 1.x. -It has been completely rewritten to use D-Bus rather than -ORBIT / CORBA for its transport protocol. - -An outdated page including instructions for testing, project status and -TODO items is at: - - https://wiki.linuxfoundation.org/accessibility/atk/at-spi/at-spi_on_d-bus - -The mailing list used for general questions is: - - https://lists.linuxfoundation.org/mailman/listinfo/accessibility-atspi - -For bug reports, feature requests, patches or enhancements please use: - - https://gitlab.gnome.org/GNOME/at-spi2-core/ - -A git repository with the latest development code is available at: - - https://gitlab.gnome.org/GNOME/at-spi2-core/ - -More information ----------------- - -The project was started with a D-Bus performance review -the results of which are available on the GNOME wiki. Keep in -mind that the D-Bus AT-SPI design documents on this page -have not been kept up to date. - - https://wiki.gnome.org/Accessibility/Documentation/GNOME2/ATSPI2-Investigation - -Other sources of relevant information about AT-SPI and Accessibility -include: - - https://wiki.gnome.org/Accessibility - https://community.kde.org/Accessibility - - -Contents of this package ------------------------- - -This package includes the protocol definitions for the new D-Bus -at-spi. - -Also included is the daemon necessary for forwarding device events -and registering accessible applicaitions. - - -Directory structure -------------------- - -The directories within this package are arranged as follows: - - xml - - This directory contains XML documents describing - the D-Bus protocol in the format used for D-Bus introspection. - - idl - - The D-Bus specification in an idl-like format. This is likely not - parseable by any existing tools, is not entirely up-to-date, and may - by removed in a future release. - - registryd - - The registry daemon code. The registry daemon - keeps a register of accessible applications and presents - this to clients (ATs). - It is also responsible for delivering device events. - - dbind - - Library to ease making D-Bus method calls, contains - marshalling code to convert function arguments - and a provided D-Bus signature into a D-Bus message. - - Used by libatspi. - - atspi - - C library for use by ATs. Wraps the various D-Bus calls, provides - an interface for listening to events, and caches some information about - accessible objects. Also contains some functions used by at-spi2-atk. - - bus - - A server that sits on the session bus and provides an interface - allowing applications to find the accessibility bus daemon, launching - it as needed. The accessibility bus is separate from the session bus - because it may in fact span user sessions if a user, for instance, - runs an application that escalates to run as root. The accessibility - bus is thus tied to the X session rather than the D-Bus session. - - doc - - Contains infrastructure for creating libatspi documentation. - - test - - Contains files that may be useful for testing AT-SPI. - - m4 - - Some macros used for building the module. - - po - - Infrastructure used for translation. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6085fa8 --- /dev/null +++ b/README.md @@ -0,0 +1,71 @@ +# Assistive Technology Service Provider Interface (AT-SPI) + +This repository contains the [DBus][DBus] interface definitions for AT-SPI, the Assistive +Technology Service Provider Interface — the core of an accessibility stack for free +software systems. It also contains the basic daemons of the accessibility stack. + +The version control repository and bug tracker are at https://gitlab.gnome.org/GNOME/at-spi2-core/ + +The code in this repository is not intended for application programmers. To write +accessible applications, look into [ATK][ATK] or your programming language's bindings for +the `xml` DBus interfaces mentioned below. + +While this module started within the [GNOME][GNOME] project's umbrella, it is not used +only in GNOME. Other sources of relevant information about AT-SPI and Accessibility +include: + +* [GNOME Accessibility wiki][gnome-a11y-wiki] +* [KDE Accessibility wiki][kde-a11y-wiki] +* [Accessibility documentation for GNOME users][docs-users] + + +## Summary of this repository's contents + +* `xml` - DBus interfaces for accessibility, described in DBus's XML introspection format. + Ideally, your programming language's implementation of DBus makes use of these files to + generate callable bindings. + +* `bus` - Launcher for the session's accessibility bus; see its [README.md](bus/README.md) + for details. + +* `registryd` - Daemon that keeps track of accessible applications in the user's session, + and lets them talk to each other and to assistive technologies (ATs) like screen + readers. + +* `atspi` - Hand-written binding for the `xml` DBus interface above, for use from C with + [GObject][GObject]. This is not normally what you would use; use a language-specific + binding instead. This module is for use mainly by [`at-spi2-atk`][at-spi2-atk]. + +* `dbind` - DBus utilities for use by `atspi` above. `atspi` was written before the more + modern C bindings like [GDBusConnection][GDBus] were available, so there is a lot of + hand-written IPC here. + +* Documentation for the Gitlab [Continuous Integration pipeline](devel-docs/gitlab-ci.md). + +## Historical note + +Versions 1.x of AT-SPI were based on [CORBA][CORBA] for inter-process communication (IPC), +using GNOME's ORBit implementation thereof. During the GNOME 2 and 3 release series, +CORBA was phased out in favor of [DBus][DBus], a more modern IPC mechanism. + +The original CORBA interfaces for AT-SPI were based on Java's implementation of +accessibility. Later, these CORBA interfaces were translated to DBus. This is why the +interfaces sometimes have a 1990s feeling to them. + +The project was started with a D-Bus performance review, the results of which are available +on the GNOME wiki. Keep in mind that the D-Bus AT-SPI design documents on this page have +not been kept up to date. + + https://wiki.gnome.org/Accessibility/Documentation/GNOME2/ATSPI2-Investigation + + +[CORBA]: https://en.wikipedia.org/wiki/Common_Object_Request_Broker_Architecture +[DBus]: https://www.freedesktop.org/wiki/Software/dbus/ +[GObject]: https://docs.gtk.org/gobject/ +[at-spi2-atk]: https://gitlab.gnome.org/GNOME/at-spi2-atk +[GDBus]: https://docs.gtk.org/gio/class.DBusConnection.html +[ATK]: https://gitlab.gnome.org/GNOME/atk/ +[GNOME]: https://www.gnome.org +[docs-users]: https://help.gnome.org/users/gnome-help/stable/a11y.html +[gnome-a11y-wiki]: https://wiki.gnome.org/Accessibility +[kde-a11y-wiki]: https://community.kde.org/Accessibility diff --git a/at-spi2-core.doap b/at-spi2-core.doap index 85d64df..7c1cde3 100644 --- a/at-spi2-core.doap +++ b/at-spi2-core.doap @@ -29,4 +29,11 @@ wrapper around the DBus interfaces. mgorse + + + Federico Mena Quintero + + federico + + diff --git a/atspi/atspi-device-legacy.c b/atspi/atspi-device-legacy.c index eb67768..bfb63d4 100644 --- a/atspi/atspi-device-legacy.c +++ b/atspi/atspi-device-legacy.c @@ -212,8 +212,8 @@ atspi_device_legacy_unmap_modifier (AtspiDevice *device, gint keycode) AtspiLegacyKeyModifier *entry = l->data; if (entry->keycode == keycode) { - g_free (entry); priv->modifiers = g_slist_remove (priv->modifiers, entry); + g_free (entry); return; } } diff --git a/atspi/atspi-device-listener.c b/atspi/atspi-device-listener.c index 69f77d1..9776ebd 100644 --- a/atspi/atspi-device-listener.c +++ b/atspi/atspi-device-listener.c @@ -53,7 +53,7 @@ device_event_handler_new (AtspiDeviceListenerCB callback, } static gboolean -device_remove_datum (const AtspiDeviceEvent *event, void *user_data) +device_remove_datum (AtspiDeviceEvent *event, void *user_data) { AtspiDeviceListenerSimpleCB cb = user_data; return cb (event); diff --git a/atspi/atspi-device-x11.c b/atspi/atspi-device-x11.c index 4f88e60..eafdba6 100644 --- a/atspi/atspi-device-x11.c +++ b/atspi/atspi-device-x11.c @@ -516,8 +516,8 @@ atspi_device_x11_unmap_modifier (AtspiDevice *device, gint keycode) AtspiX11KeyModifier *entry = l->data; if (entry->keycode == keycode) { - g_free (entry); priv->modifiers = g_slist_remove (priv->modifiers, entry); + g_free (entry); return; } } diff --git a/atspi/atspi-event-listener.c b/atspi/atspi-event-listener.c index 5455b58..5cdc806 100644 --- a/atspi/atspi-event-listener.c +++ b/atspi/atspi-event-listener.c @@ -1000,6 +1000,13 @@ _atspi_dbus_handle_event (DBusConnection *bus, DBusMessage *message, void *data) } category++; } + else + { + // TODO: Error + // Note that the single caller of this function, process_deferred_message(), ignores the return value. + // We should probably free the message if we aren't going to process it after all. + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } dbus_message_iter_get_basic (&iter, &detail); dbus_message_iter_next (&iter); dbus_message_iter_get_basic (&iter, &detail1); @@ -1087,6 +1094,8 @@ _atspi_dbus_handle_event (DBusConnection *bus, DBusMessage *message, void *data) break; } + g_assert (e.source != NULL); + dbus_message_iter_next (&iter); if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_ARRAY) { diff --git a/atspi/atspi-misc.c b/atspi/atspi-misc.c index 7af46e9..d896afb 100644 --- a/atspi/atspi-misc.c +++ b/atspi/atspi-misc.c @@ -877,43 +877,6 @@ atspi_dbus_filter (DBusConnection *bus, DBusMessage *message, void *data) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } -/* - * Returns a 'canonicalized' value for DISPLAY, - * with the screen number stripped off if present. - * - * TODO: Avoid having duplicate functions for this here and in at-spi2-atk - */ -static gchar * -spi_display_name (void) -{ - char *canonical_display_name = NULL; - const gchar *display_env = g_getenv ("AT_SPI_DISPLAY"); - - if (!display_env) - { - display_env = g_getenv ("DISPLAY"); - if (!display_env || !display_env[0]) - return NULL; - else - { - gchar *display_p, *screen_p; - canonical_display_name = g_strdup (display_env); - display_p = g_utf8_strrchr (canonical_display_name, -1, ':'); - screen_p = g_utf8_strrchr (canonical_display_name, -1, '.'); - if (screen_p && display_p && (screen_p > display_p)) - { - *screen_p = '\0'; - } - } - } - else - { - canonical_display_name = g_strdup (display_env); - } - - return canonical_display_name; -} - /** * atspi_init: * @@ -1499,6 +1462,43 @@ _atspi_error_quark (void) * Gets the IOR from the XDisplay. */ #ifdef HAVE_X11 +/* + * Returns a 'canonicalized' value for DISPLAY, + * with the screen number stripped off if present. + * + * TODO: Avoid having duplicate functions for this here and in at-spi2-atk + */ +static gchar * +spi_display_name (void) +{ + char *canonical_display_name = NULL; + const gchar *display_env = g_getenv ("AT_SPI_DISPLAY"); + + if (!display_env) + { + display_env = g_getenv ("DISPLAY"); + if (!display_env || !display_env[0]) + return NULL; + else + { + gchar *display_p, *screen_p; + canonical_display_name = g_strdup (display_env); + display_p = g_utf8_strrchr (canonical_display_name, -1, ':'); + screen_p = g_utf8_strrchr (canonical_display_name, -1, '.'); + if (screen_p && display_p && (screen_p > display_p)) + { + *screen_p = '\0'; + } + } + } + else + { + canonical_display_name = g_strdup (display_env); + } + + return canonical_display_name; +} + static char * get_accessibility_bus_address_x11 (void) { diff --git a/atspi/atspi-registry.c b/atspi/atspi-registry.c index dea5878..382308f 100644 --- a/atspi/atspi-registry.c +++ b/atspi/atspi-registry.c @@ -270,19 +270,22 @@ atspi_deregister_keystroke_listener (AtspiDeviceListener *listener, GError **error) { GArray *d_key_set; - gchar *path = _atspi_device_listener_get_path (listener); + gchar *path; gint i; dbus_uint32_t d_modmask = modmask; dbus_uint32_t d_event_types = event_types; DBusError d_error; GList *l; - dbus_error_init (&d_error); if (!listener) { return FALSE; } + dbus_error_init (&d_error); + + path = _atspi_device_listener_get_path (listener); + /* copy the keyval filter values from the C api into the DBind KeySet */ if (key_set) { @@ -363,15 +366,18 @@ atspi_register_device_event_listener (AtspiDeviceListener *listener, { gboolean retval = FALSE; dbus_uint32_t d_event_types = event_types; - gchar *path = _atspi_device_listener_get_path (listener); + gchar *path; DBusError d_error; - dbus_error_init (&d_error); if (!listener) { return retval; } + dbus_error_init (&d_error); + + path = _atspi_device_listener_get_path (listener); + dbind_method_call_reentrant (_atspi_bus(), atspi_bus_registry, atspi_path_dec, atspi_interface_dec, "RegisterDeviceEventListener", &d_error, "ou=>b", path, d_event_types, &retval); if (dbus_error_is_set (&d_error)) { @@ -400,16 +406,18 @@ atspi_deregister_device_event_listener (AtspiDeviceListener *listener, void *filter, GError **error) { dbus_uint32_t event_types = 0; - gchar *path = _atspi_device_listener_get_path (listener); + gchar *path; DBusError d_error; - dbus_error_init (&d_error); - if (!listener) { return FALSE; } + dbus_error_init (&d_error); + + path = _atspi_device_listener_get_path (listener); + event_types |= (1 << ATSPI_BUTTON_PRESSED_EVENT); event_types |= (1 << ATSPI_BUTTON_RELEASED_EVENT); diff --git a/bus/README b/bus/README deleted file mode 100644 index 40b9ad6..0000000 --- a/bus/README +++ /dev/null @@ -1,10 +0,0 @@ -The a11y bus is accessed via two mechanisms: - -1) The DBus session bus, service "org.a11y.Bus", method "GetAddress") -2) The X11 root window property AT_SPI_BUS - -If the "toolkit-accessibility" variable is set, the bus is launched -immediately (and will be accessible immediately via the X11 property). -Otherwise, it will be spawned dynamically. - - diff --git a/bus/README.md b/bus/README.md new file mode 100644 index 0000000..eb14e9f --- /dev/null +++ b/bus/README.md @@ -0,0 +1,98 @@ +# Launcher for the accessibility bus + +The communications mechanism for accessibility does not run through the user's session +DBus; it runs in a separate bus just for accessibility purposes. The accessibility +interfaces for DBus are very chatty; using a separate bus prevents the main session bus +from getting too much traffic. + +Throughout this document we will distinguish between the **session bus** and the +**accessibility bus**. + +## Who launches the accessibility bus? + +This source directory `bus` contains a little daemon, `at-spi-bus-launcher`, which +launches the **accessibility bus** and manages its lifetime according to the user's +session. + +The **accessibility bus** is just a separate instance of `dbus-daemon` or equivalent, like +`dbus-broker`. That bus allows communication using the accessibility interfaces defined +in the `xml` directory in this repository. It also has the accessibility registry — +`registryd` in this repository, which claims the name `org.a11y.atspi.Registry` in that +bus. + +## When does the accessibility bus get launched? + +When a normal application starts up, it will want to find the **accesibility bus**, and +then contact the accessibility registry in that bus (`registryd` in this repository) to +inform the world that they are up and running. Finding the accessibility bus can then be +done on demand for normal applications, via the `GetAddress` method described below. + +However, a screen reader is special: it needs to start up automatically during login, and +immediatelly tell the accessibility registry (... via the **accessibility bus**) that it +is running. If you need a screen reader to use your computer, you cannot easily launch it +by hand if there is no screen reader already running! + +That is, if a screen reader is turned on — and we assume it will start up turned on for +future sessions — we need to launch the **accessibility bus** unconditionally, not on +demand, at session startup. This is why `at-spi-dbus-bus.desktop`, described below, is an +[XDG autostart][xdg-autostart] file which runs `at-spi-bus-launcher --launch-immediately`, +but only if a certain GSettings key is turned on. + +In summary, `at-spi-bus-launcher` will launch the **accessibility bus** under two situations: + +* On demand via the `GetAddress` method; see below. + +* Shortly after `at-spi-bus-launcher` starts up, if the gsettings key + `org.gnome.desktop.interface toolkit-accessibility` is set to true, due to the + `at-spi-dbus-bus.desktop` XDG autostart file. + +* The gsettings key `org.gnome.desktop.a11y.applications screen-reader-enabled` is set to true. + +## Contents of this `bus` directory + +This `bus` source directory has a configuration file for the `dbus-daemon` which will run +as the **accessibility bus**, and a helper daemon called `at-spi-bus-launcher`, which actually +starts that bus and makes its address visible to the user's session. The files are as follows: + +* `accessibility.conf.in` - template for the configuration for the accessibility bus, + which gets installed in `$(datadir)/defaults/at-spi2/accessibility.conf`. + +* `at-spi-bus-launcher.c` - See [`at-spi-bus-launcher`](#at-spi-bus-launcher) below. + +* `at-spi-dbus-bus.service.in` - template for a systemd user service to start `at-spi-bus-launcher`. + +* `org.a11y.Bus.service.in` - template for a DBus user service to start `at-spi-bus-launcher`. + +* `at-spi-dbus-bus.desktop.in` - template for a XDG autostart file to start + `at-spi-bus-launcher` at session startup, only if the `org.gnome.desktop.interface + toolkit-accessibility` GSettings key is turned on. + +* `00-at-spi` - script to set the `AT_SPI_BUS` property on the X root window, for + Wayland-based systems where XWayland is started on demand. That X window property is an + alternative way of finding the address of the **accessibility bus**. + +## at-spi-bus-launcher + +This is a tiny daemon which registers a service in the normal **session bus**, and which +can then be used to query the address of the actual **accessibility bus**. The daemon +claims ownership of the `org.a11y.Bus` name in the **session bus**, and exports a +single object, `/org/a11y/bus`, with two interfaces: + +* `org.a11y.Bus` - has a single `GetAddress` method, which returns the address of the + actual **accessibility bus**. Accessibility clients must use this address when creating + their initial DBus connection. + +* `org.a11y.Status` - has properties to query whether the **accessibility bus** is enabled + and whether a screen reader is running. + +`at-spi-bus-launcher` starts the separate `dbus-daemon` (or `dbus-broker` equivalent) for +the **accessibility bus** on demand. The following actions can cause it to launch: + +* Calling the `GetAddress` method. The daemon gets launched and queried for its address; + the method returns that. This is the normal way to start the accessibility bus. + +* If `at-spi-bus-launcher` was run with the `--launch-immediately` option, the + accessibility bus launches as soon as `at-spi-bus-launcher` is able to claim ownership + of the `org.a11y.Bus` name in the session bus. This is intended for session startup. + +[xdg-autostart]: https://specifications.freedesktop.org/autostart-spec/autostart-spec-latest.html diff --git a/bus/at-spi-bus-launcher.c b/bus/at-spi-bus-launcher.c index d7c6690..0633c30 100644 --- a/bus/at-spi-bus-launcher.c +++ b/bus/at-spi-bus-launcher.c @@ -42,6 +42,7 @@ #ifdef DBUS_BROKER #include #endif +#include typedef enum { A11Y_BUS_STATE_IDLE = 0, @@ -64,7 +65,8 @@ typedef struct { A11yBusState state; /* -1 == error, 0 == pending, > 0 == running */ - int a11y_bus_pid; + GPid a11y_bus_pid; + char *socket_name; char *a11y_bus_address; #ifdef HAVE_X11 gboolean x11_prop_set; @@ -84,10 +86,10 @@ static const gchar introspection_xml[] = " " " " " " - "" - "" - "" - "" + " " + " " + " " + " " ""; static GDBusNodeInfo *introspection_data = NULL; @@ -248,19 +250,44 @@ name_appeared_handler (GDBusConnection *connection, * Read all data from a file descriptor to a C string buffer. */ static gboolean -unix_read_all_fd_to_string (int fd, - char *buf, - ssize_t max_bytes) +unix_read_all_fd_to_string (int fd, + char *buf, + ssize_t max_bytes, + char **error_msg) { - ssize_t bytes_read; + g_assert (max_bytes > 1); + *error_msg = NULL; + + max_bytes -= 1; /* allow space for nul terminator */ - while (max_bytes > 1 && (bytes_read = read (fd, buf, MIN (4096, max_bytes - 1)))) + while (max_bytes > 1) { - if (bytes_read < 0) - return FALSE; - buf += bytes_read; - max_bytes -= bytes_read; + ssize_t bytes_read; + + again: + bytes_read = read (fd, buf, max_bytes); + + if (bytes_read == 0) + { + break; + } + else if (bytes_read > 0) + { + buf += bytes_read; + max_bytes -= bytes_read; + } + else if (errno == EINTR) + { + goto again; + } + else + { + int err_save = errno; + *error_msg = g_strdup_printf ("Failed to read data from accessibility bus: %s", g_strerror (err_save)); + return FALSE; + } } + *buf = '\0'; return TRUE; } @@ -284,53 +311,69 @@ on_bus_exited (GPid pid, app->a11y_launch_error_message = g_strdup_printf ("Bus stopped by signal %d", WSTOPSIG (status)); } g_main_loop_quit (app->loop); -} +} #ifdef DBUS_DAEMON -static void -setup_bus_child_daemon (gpointer data) +static gboolean +ensure_a11y_bus_daemon (A11yBusLauncher *app, char *config_path) { - A11yBusLauncher *app = data; - (void) app; + char *address_param; - close (app->pipefd[0]); - dup2 (app->pipefd[1], 3); - close (app->pipefd[1]); + if (app->socket_name) + { + gchar *escaped_address = g_dbus_address_escape_value (app->socket_name); + address_param = g_strconcat ("--address=unix:path=", escaped_address, NULL); + g_free (escaped_address); + } + else + { + address_param = NULL; + } - /* On Linux, tell the bus process to exit if this process goes away */ -#ifdef __linux__ - prctl (PR_SET_PDEATHSIG, 15); -#endif -} + if (pipe (app->pipefd) < 0) + g_error ("Failed to create pipe: %s", strerror (errno)); -static gboolean -ensure_a11y_bus_daemon (A11yBusLauncher *app, char *config_path) -{ - char *argv[] = { DBUS_DAEMON, config_path, "--nofork", "--print-address", "3", NULL }; + char *print_address_fd_param = g_strdup_printf ("%d", app->pipefd[1]); + + char *argv[] = { DBUS_DAEMON, config_path, "--nofork", "--print-address", print_address_fd_param, address_param, NULL }; + gint source_fds[1] = { app->pipefd[1] }; + gint target_fds[1] = { app->pipefd[1] }; + G_STATIC_ASSERT (G_N_ELEMENTS (source_fds) == G_N_ELEMENTS (target_fds)); GPid pid; char addr_buf[2048]; GError *error = NULL; - - if (pipe (app->pipefd) < 0) - g_error ("Failed to create pipe: %s", strerror (errno)); + char *error_from_read; g_clear_pointer (&app->a11y_launch_error_message, g_free); - if (!g_spawn_async (NULL, - argv, - NULL, - G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, - setup_bus_child_daemon, - app, - &pid, - &error)) + if (!g_spawn_async_with_pipes_and_fds (NULL, + (const gchar * const *) argv, + NULL, + G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_LEAVE_DESCRIPTORS_OPEN, + NULL, /* child_setup */ + app, + -1, /* stdin_fd */ + -1, /* stdout_fd */ + -1, /* stdout_fd */ + source_fds, + target_fds, + G_N_ELEMENTS (source_fds), /* n_fds in source_fds and target_fds */ + &pid, + NULL, /* stdin_pipe_out */ + NULL, /* stdout_pipe_out */ + NULL, /* stderr_pipe_out */ + &error)) { app->a11y_bus_pid = -1; app->a11y_launch_error_message = g_strdup (error->message); g_clear_error (&error); + g_free (address_param); + g_free (print_address_fd_param); goto error; } + g_free (address_param); + g_free (print_address_fd_param); close (app->pipefd[1]); app->pipefd[1] = -1; @@ -339,10 +382,12 @@ ensure_a11y_bus_daemon (A11yBusLauncher *app, char *config_path) app->state = A11Y_BUS_STATE_READING_ADDRESS; app->a11y_bus_pid = pid; g_debug ("Launched a11y bus, child is %ld", (long) pid); - if (!unix_read_all_fd_to_string (app->pipefd[0], addr_buf, sizeof (addr_buf))) + error_from_read = NULL; + if (!unix_read_all_fd_to_string (app->pipefd[0], addr_buf, sizeof (addr_buf), &error_from_read)) { - app->a11y_launch_error_message = g_strdup_printf ("Failed to read address: %s", strerror (errno)); + app->a11y_launch_error_message = error_from_read; kill (app->a11y_bus_pid, SIGTERM); + g_spawn_close_pid (app->a11y_bus_pid); app->a11y_bus_pid = -1; goto error; } @@ -386,9 +431,6 @@ setup_bus_child_broker (gpointer data) pid_str = g_strdup_printf("%u", getpid()); g_setenv("LISTEN_PID", pid_str, TRUE); g_free(pid_str); - - /* Tell the bus process to exit if this process goes away */ - prctl (PR_SET_PDEATHSIG, SIGTERM); } static gboolean @@ -396,11 +438,17 @@ ensure_a11y_bus_broker (A11yBusLauncher *app, char *config_path) { char *argv[] = { DBUS_BROKER, config_path, "--scope", "user", NULL }; char *unit; - struct sockaddr_un addr = { .sun_family = AF_UNIX }; + struct sockaddr_un addr = { .sun_family = AF_UNIX, "" }; socklen_t addr_len = sizeof(addr); GPid pid; GError *error = NULL; + if (app->socket_name) + { + strcpy (addr.sun_path, app->socket_name); + unlink (app->socket_name); + } + /* This detects whether we are running under systemd. We only try to * use dbus-broker if we are running under systemd because D-Bus * service activation won't work otherwise. @@ -418,10 +466,11 @@ ensure_a11y_bus_broker (A11yBusLauncher *app, char *config_path) if ((app->listenfd = socket (PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) < 0) g_error ("Failed to create listening socket: %s", strerror (errno)); - if (bind (app->listenfd, (struct sockaddr *)&addr, sizeof(sa_family_t)) < 0) + if (bind (app->listenfd, (struct sockaddr *)&addr, addr_len) < 0) g_error ("Failed to bind listening socket: %s", strerror (errno)); - if (getsockname (app->listenfd, (struct sockaddr *)&addr, &addr_len) < 0) + if (!app->socket_name && + getsockname (app->listenfd, (struct sockaddr *)&addr, &addr_len) < 0) g_error ("Failed to get socket name for listening socket: %s", strerror(errno)); if (listen (app->listenfd, 1024) < 0) @@ -452,7 +501,10 @@ ensure_a11y_bus_broker (A11yBusLauncher *app, char *config_path) g_debug ("Launched a11y bus, child is %ld", (long) pid); app->state = A11Y_BUS_STATE_RUNNING; - app->a11y_bus_address = g_strconcat("unix:abstract=", addr.sun_path + 1, NULL); + if (app->socket_name) + app->a11y_bus_address = g_strconcat("unix:path=", addr.sun_path, NULL); + else + app->a11y_bus_address = g_strconcat("unix:abstract=", addr.sun_path + 1, NULL); g_debug ("a11y bus address: %s", app->a11y_bus_address); return TRUE; @@ -476,6 +528,7 @@ ensure_a11y_bus (A11yBusLauncher *app) { char *config_path = NULL; gboolean success = FALSE; + const gchar *xdg_runtime_dir; if (app->a11y_bus_pid != 0) return FALSE; @@ -485,6 +538,36 @@ ensure_a11y_bus (A11yBusLauncher *app) else config_path = "--config-file="DATADIR"/defaults/at-spi2/accessibility.conf"; + xdg_runtime_dir = g_get_user_runtime_dir (); + if (xdg_runtime_dir) + { + const gchar *display = g_getenv ("DISPLAY"); + gchar *at_spi_dir = g_strconcat (xdg_runtime_dir, "/at-spi", NULL); + gchar *p; + mkdir (xdg_runtime_dir, 0700); + if (!g_path_is_absolute (at_spi_dir)) + { + gchar *new_dir = g_canonicalize_filename (at_spi_dir, NULL); + g_free (at_spi_dir); + at_spi_dir = new_dir; + } + if (mkdir (at_spi_dir, 0700) == 0 || errno == EEXIST) + { + app->socket_name = g_strconcat (at_spi_dir, "/bus", display, NULL); + g_free (at_spi_dir); + p = strchr (app->socket_name, ':'); + if (p) + *p = '_'; + if (strlen (app->socket_name) >= 100) + { + g_free (app->socket_name); + app->socket_name = NULL; + } + } + else + g_free (at_spi_dir); + } + #ifdef WANT_DBUS_BROKER success = ensure_a11y_bus_broker (app, config_path); if (!success) @@ -816,6 +899,11 @@ get_schema (const gchar *name) { #if GLIB_CHECK_VERSION (2, 32, 0) GSettingsSchemaSource *source = g_settings_schema_source_get_default (); + if (!source) + { + g_error ("Cannot get the default GSettingsSchemaSource - is the gsettings-desktop-schemas package installed?"); + } + GSettingsSchema *schema = g_settings_schema_source_lookup (source, name, FALSE); if (schema == NULL) @@ -856,7 +944,7 @@ main (int argc, gboolean screen_reader_set = FALSE; gint i; - _global_app = g_slice_new0 (A11yBusLauncher); + _global_app = g_new0 (A11yBusLauncher, 1); _global_app->loop = g_main_loop_new (NULL, FALSE); for (i = 1; i < argc; i++) @@ -917,7 +1005,11 @@ main (int argc, g_main_loop_run (_global_app->loop); if (_global_app->a11y_bus_pid > 0) - kill (_global_app->a11y_bus_pid, SIGTERM); + { + kill (_global_app->a11y_bus_pid, SIGTERM); + g_spawn_close_pid (_global_app->a11y_bus_pid); + _global_app->a11y_bus_pid = -1; + } /* Clear the X property if our bus is gone; in the case where e.g. * GDM is launching a login on an X server it was using before, diff --git a/dbind/dbind-any.c b/dbind/dbind-any.c index efdba73..512c1b3 100644 --- a/dbind/dbind-any.c +++ b/dbind/dbind-any.c @@ -696,14 +696,8 @@ dbind_any_demarshal_va (DBusMessageIter *iter, { const char *p = *arg_types; - /* Pass in args */ + /* Just consume the in args without doing anything to them */ for (;*p != '\0' && *p != '=';) { - int intarg; - void *ptrarg; - double doublearg; - dbus_int64_t int64arg; - void *arg = NULL; - switch (*p) { case DBUS_TYPE_BYTE: case DBUS_TYPE_BOOLEAN: @@ -711,14 +705,14 @@ dbind_any_demarshal_va (DBusMessageIter *iter, case DBUS_TYPE_UINT16: case DBUS_TYPE_INT32: case DBUS_TYPE_UINT32: - intarg = va_arg (args, int); + va_arg (args, int); break; case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: - int64arg = va_arg (args, dbus_int64_t); + va_arg (args, dbus_int64_t); break; case DBUS_TYPE_DOUBLE: - doublearg = va_arg (args, double); + va_arg (args, double); break; /* ptr types */ case DBUS_TYPE_STRING: @@ -726,18 +720,18 @@ dbind_any_demarshal_va (DBusMessageIter *iter, case DBUS_TYPE_SIGNATURE: case DBUS_TYPE_ARRAY: case DBUS_TYPE_DICT_ENTRY: - ptrarg = va_arg (args, void *); + va_arg (args, void *); break; case DBUS_STRUCT_BEGIN_CHAR: - ptrarg = va_arg (args, void *); + va_arg (args, void *); break; case DBUS_DICT_ENTRY_BEGIN_CHAR: - ptrarg = va_arg (args, void *); + va_arg (args, void *); break; case DBUS_TYPE_VARIANT: fprintf (stderr, "No variant support yet - very toolkit specific\n"); - ptrarg = va_arg (args, void *); + va_arg (args, void *); break; default: fprintf (stderr, "Unknown / invalid arg type %c\n", *p); diff --git a/dbind/dbtest.c b/dbind/dbtest.c index b338c03..511839c 100644 --- a/dbind/dbtest.c +++ b/dbind/dbtest.c @@ -40,7 +40,10 @@ void demarshal (DBusMessage *msg, const char *type, void *ptr) DBusMessageIter iter; if (!dbus_message_iter_init (msg, &iter)) + { fprintf (stderr, "no data in msg\n"); + g_assert_not_reached (); + } else dbind_any_demarshal (&iter, &type, &ptr); } @@ -293,8 +296,8 @@ void test_struct_with_array () demarshal (msg, TYPEOF_ARRAYSTRUCT, &a2); q = &g_array_index (a2, ArrayStruct, 0); - g_assert (p[0].pad1 == 2); - g_assert (g_array_index (p[1].vals, dbus_uint32_t, 1) == 1000000000); + g_assert (q[0].pad1 == 2); + g_assert (g_array_index (q[1].vals, dbus_uint32_t, 1) == 1000000000); printf ("struct with array ok\n"); diff --git a/devel-docs/gitlab-ci.md b/devel-docs/gitlab-ci.md new file mode 100644 index 0000000..d7d675e --- /dev/null +++ b/devel-docs/gitlab-ci.md @@ -0,0 +1,188 @@ +# Gitlab Continuous Integration (CI) for at-spi2-core + +Summary: make the robots set up an environment for running the test +suite, run it, and report back to us. + +If you have questions about the CI, mail federico@gnome.org, or [file +an issue](https://gitlab.gnome.org/GNOME/at-spi2-core/-/issues) and +mention `@federico` in it. + +Table of contents: + +[[_TOC_]] + +# Quick overview + +By having a [`.gitlab-ci.yml`](../.gitlab-ci.yml) file in the toplevel +directory of a project, Gitlab knows that it must run a continuous +integration pipeline when certain events occur, for example, when +someone creates a merge request, or pushes to a branch. + +What's a pipeline? It is an automated version of the following. +Running the test suite for at-spi2-core involves some repetitive +steps: + +* Create a pristine and minimal environment for testing, without all the random + gunk from one's development system. Gitlab CI uses Linux containers, + with pre-built operating system images in the [Open Container + Initiative][OCI] format — this is what Docker, Podman, etc. all use. + +* Install the build-time dependencies (gcc, meson, libfoo-devel, + etc.), the test-time dependencies (dbus-daemon, etc.) in that + pristine environment, as well as special tools (lcov, libasan, + clang-tools). + +* Run the build and install it, and run the test suite. + +* Run variations of the build and test suite with other tools — for + example, using static analysis during compilation, or with address + sanitizer (asan), or with a code coverage tool. Gitlab can collect + the analysis results of each of these tools and present them as part + of the merge request that is being evaluated. It also lets + developers obtain those useful results without dealing with a lot of + fiddly tools on their own computers. + +Additionally, on each pipeline run we'd like to do extra repetitive +work like building the reference documentation, and publishing it on a +web page. + +The `.gitlab-ci.yml` file defines the CI pipeline, the jobs it will +run (build/test, coverage, asan, static-scan, etc.), and the locations +where each job's artifacts will be stored. + +What's an artifact or a job? Read on! + +# A little glossary + +**Pipeline** - A collection of **jobs**, which can be run in parallel +or sequentially. For example, a pair of "build" and "test" jobs would +need to run sequentially, but maybe a "render documentation" job can +run in parallel with them. Similarly, "build" jobs for various +distributions or configurations could be run in parallel. + +**Job** - Think of it as running a shell script within a container. +It can have input from other previous jobs: if you have separate +"build" and "test" jobs, then the "build" job will want to keep around +its compiled artifacts so that the "test" job can use them. It can +provide output artifacts that can be stored for human perusal, or for +use by other jobs. + +**Artifact** - Something produced from a job. If your job compiles +binaries, those binaries could be artifacts if you decide to keep them +around for use later. A documentation job can produce HTML artifacts +from the rendered documentation. A code coverage job will produce a +coverage report artifact. + +**Runner** - An operating system setup for running jobs. +Gitlab.gnome.org provides runners for Linux, BSD, Windows, and MacOS. +For example. the Linux runners let you use any OCI image, so you can +test on openSUSE, Fedora, a custom distro, etc. You don't normally +need to be concerned with runners; Gitlab assigns the shared runners +automatically to your pipeline. + +**Container** - You can think of it as a chroot with extra isolation, +or a lightweight virtual machine. Basically, the Linux kernel can +isolate groups of processes in control groups (cgroups). Each cgroup +can have a different view of the file system, as if you had a +different chroot for each cgroup. Cgroups can be isolated to be in +their own PID namespace, so running "ps" in the container will not +show all the processes in the system, but only those inside the +container's cgroup. File system overlays allow you to have read-only +images for the operating system (the OCI images we talked about above) +plus a read-write overlay that is kept around only during the lifetime +of a container, or persistently if one wants. For Gitlab CI one does +not need to deal with containers directly, but keep in mind that your +jobs will run inside a container, which is more limited than e.g. a +shell session on a graphical, development machine. + +# The CI pipeline for at-spi2-core + +The `.gitlab-ci.yml` file is a more-or-less declarative description +the CI pipeline, with some `script` sections which are imperative +commands to actually *do stuff*. + +Jobs are run in `stages`, and the names of the stages are declared +near the beginning of the YAML file. The stage names are arbitrary; +the ones here follow some informal GNOME conventions. + +Jobs are declared at the toplevel of the YAML file, and they are +distinguished from other declarations by having a container `image` +declared for them, as well as a `script` to execute. + +Many jobs need exactly the same kind of setup (same container images, +mostly same package dependencies), so they use `extends:` to use a +declared template with all that stuff instead of redeclaring it each +time. In our configuration, the `.only-default` template has the +`PROJECT_DEPS`, with the dependencies that most jobs need. The +`.build-setup` template is for the analysis jobs, and it lets them +declare `EXTRA_DEPS` as an environment variable with the names of +extra dependencies: for example, the coverage job puts `lcov` in +`EXTRA_DEPS`. The commands in `before_script` blocks use these +environment variables to install the package dependencies, for example +`zypper install -y ${PROJECT_DEPS}` for an openSUSE job. + +The `build` stage has these jobs: + +* `opensuse-x86_64` - Extends the `.build-default` rule, + builds/installs the code, and runs the tests. Generally this is the + job that one cares about during regular development. + +The `analysis` stage has these jobs: + +* `static-scan` - Runs static analysis during compilation, which + performs interprocedural analysis to detect things like double + `free()` or uninitialized struct fields across functions. + +* `asan-build` - Builds and runs with Address Sanitizer (libasan). + +* `coverage` - Instruments the build to get code coverage information, + and runs the test suite to see how much of the code it manages to + exercise. This is to see which code paths may be untested + automatically, and to decide which ones would require manual + testing, or refactoring to allow automated testing. + +As of 2021/Dec/15 there are some commented-out jobs to generate +documentation and publish it; this needs to be made to work. + +# General advice and future work + +A failed run of a CI pipeline should trouble you; it either means that +some test broke, or that something is not completely deterministic. +Fix it at once. + +Try not to accept merge requests that fail the CI, as this will make +`git bisect` hard in the future. There are tools like Marge-bot to +enforce this; ask federico@gnome.org about it. Read ["The Not Rocket +Science Rule Of Software +Engineering"](https://graydon.livejournal.com/186550.html), which can +be summarized as "automatically maintain a repository of code that +always passes all the tests" for inspiration. Marge-bot is an +implementation of that, and can be used with Gitlab. + +If your software can be configured to build with substantial changes, +the CI pipeline should have jobs that test each of those +configurations. For example, at-spi-bus-launcher operates differently +depending on whether dbus-daemon or dbus-broker are being used. As of +2021/Dec/15 the CI only tests dbus-daemon; there should be a test for +dbus-broker, too. + +Although the YAML syntax for `.gitlab-ci.yml` is a bit magic, the +scripts and configuration are quite amenable to refactoring. Do it +often! + +Minimizing the amount of time that CI takes to run is a good goal. It +reduces energy consumption in the build farm, and allows you to have a +faster feedback loop. Instead of installing package dependencies on +each job, we can move to prebuilt container images. + +# References + +Full documentation for Gitlab CI: https://docs.gitlab.com/ee/ci/ + +Introduction to Gitlab CI: https://docs.gitlab.com/ee/ci/quick_start/index.html + +at-spi2-core's CI pipeline is mostly [cut-and-pasted from +libgweather](https://gitlab.gnome.org/GNOME/libgweather/-/blob/main/.gitlab-ci.yml). +Thanks to Emmanuele Bassi for his advice on how to use it. + +[OCI]: https://opencontainers.org/ diff --git a/meson.build b/meson.build index b5104c8..c566b25 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('at-spi2-core', 'c', - version: '2.42.0', + version: '2.44.1', license: 'LGPLv2.1+', default_options: [ 'buildtype=debugoptimized', @@ -47,6 +47,7 @@ libdbus_req_version = '>= 1.5' glib_req_version = '>= 2.62.0' gobject_req_version = '>= 2.0.0' gio_req_version = '>= 2.28.0' +gir_req_version = '>= 0.6.7' libdbus_dep = dependency('dbus-1', version: libdbus_req_version) glib_dep = dependency('glib-2.0', version: glib_req_version) @@ -62,6 +63,8 @@ endif x11_deps = [] x11_option = get_option('x11') +# ensure x11_dep is defined for use elsewhere, such as bus/meson.build +x11_dep = dependency('', required: false) if x11_option != 'no' x11_dep = dependency('x11', required: false) @@ -104,7 +107,7 @@ have_gir = false introspection_option = get_option('introspection') if introspection_option != 'no' - gir_dep = dependency('gobject-introspection-1.0', version: '>= 0.6.7', required: false) + gir_dep = dependency('gobject-introspection-1.0', version: gir_req_version, required: false) if gir_dep.found() have_gir = true diff --git a/po/LINGUAS b/po/LINGUAS index 328b6c4..d590968 100644 --- a/po/LINGUAS +++ b/po/LINGUAS @@ -31,6 +31,7 @@ hi hr hu id +is it ja kk diff --git a/po/is.po b/po/is.po new file mode 100644 index 0000000..61246a7 --- /dev/null +++ b/po/is.po @@ -0,0 +1,26 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Sveinn í Felli , 2021. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/at-spi2-core/issues\n" +"POT-Creation-Date: 2021-12-08 22:05+0000\n" +"PO-Revision-Date: 2021-12-15 23:05+0000\n" +"Last-Translator: Sveinn í Felli \n" +"Language-Team: Icelandic \n" +"Language: is\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 19.12.3\n" + +#: atspi/atspi-component.c:332 atspi/atspi-misc.c:1105 atspi/atspi-value.c:111 +msgid "The application no longer exists" +msgstr "Forritið er ekki lengur til" + +#: atspi/atspi-misc.c:1888 +msgid "Attempted synchronous call where prohibited" +msgstr "Reyndi samhæft kall þegar slíkt er bannað" diff --git a/registryd/deviceeventcontroller-x11.c b/registryd/deviceeventcontroller-x11.c index 55239f4..6556048 100644 --- a/registryd/deviceeventcontroller-x11.c +++ b/registryd/deviceeventcontroller-x11.c @@ -34,11 +34,6 @@ #include #include -#include -#include -#include -#include - #define XK_MISCELLANY #define XK_LATIN1 #include @@ -54,6 +49,7 @@ #include "display.h" #include "event-source.h" +#include "deviceeventcontroller-x11.h" #include "deviceeventcontroller.h" #include "reentrant-list.h" @@ -89,31 +85,26 @@ static XModifierKeymap* xmkeymap = NULL; static int (*x_default_error_handler) (Display *display, XErrorEvent *error_event); -typedef struct { - Display *xevie_display; - unsigned int last_press_keycode; - unsigned int last_release_keycode; - struct timeval last_press_time; - struct timeval last_release_time; - int have_xkb; - int xkb_major_extension_opcode; - int xkb_base_event_code; - int xkb_base_error_code; - unsigned int xkb_latch_mask; - unsigned int pending_xkb_mod_relatch_mask; - XkbDescPtr xkb_desc; - KeyCode reserved_keycode; - KeySym reserved_keysym; - guint reserved_reset_timeout; -} DEControllerPrivateData; - static void spi_controller_register_with_devices (SpiDEController *controller); static gboolean spi_device_event_controller_forward_key_event (SpiDEController *controller, const XEvent *event); - static SpiDEController *saved_controller; +/* Normally this function would be provided by the macro call in deviceeventcontroller.c: + * G_DEFINE_TYPE_WITH_CODE (..., G_ADD_PRIVATE (SpiDEController)) + * + * However, that machinery creates a static function for + * _get_instance_private, so it is only visible in that file. Here + * we'll re-define it by hand, using the same name as that generated + * function in case we can later merge the implementations together. + */ +static SpiDEControllerPrivate * +spi_device_event_controller_get_instance_private (SpiDEController *controller) +{ + return g_type_instance_get_private ((GTypeInstance *) controller, SPI_DEVICE_EVENT_CONTROLLER_TYPE); +} + static unsigned int keysym_mod_mask (KeySym keysym, KeyCode keycode) { @@ -174,7 +165,7 @@ keysym_mod_mask (KeySym keysym, KeyCode keycode) } static gboolean -replace_map_keysym (DEControllerPrivateData *priv, KeyCode keycode, KeySym keysym) +replace_map_keysym (SpiDEControllerPrivate *priv, KeyCode keycode, KeySym keysym) { #ifdef HAVE_XKB Display *dpy = spi_get_display (); @@ -214,7 +205,7 @@ replace_map_keysym (DEControllerPrivateData *priv, KeyCode keycode, KeySym keysy static gboolean spi_dec_reset_reserved (gpointer data) { - DEControllerPrivateData *priv = data; + SpiDEControllerPrivate *priv = data; replace_map_keysym (priv, priv->reserved_keycode, priv->reserved_keysym); priv->reserved_reset_timeout = 0; return FALSE; @@ -233,7 +224,7 @@ spi_dec_x11_get_keycode (SpiDEController *controller, keycode = XKeysymToKeycode (spi_get_display (), (KeySym) keysym); if (!keycode && fix) { - DEControllerPrivateData *priv = controller->priv; + SpiDEControllerPrivate *priv = spi_device_event_controller_get_instance_private (controller); /* if there's no keycode available, fix it */ if (replace_map_keysym (priv, priv->reserved_keycode, keysym)) { @@ -258,7 +249,7 @@ spi_dec_x11_get_keycode (SpiDEController *controller, static void spi_dec_set_unlatch_pending (SpiDEController *controller, unsigned mask) { - DEControllerPrivateData *priv = controller->priv; + SpiDEControllerPrivate *priv = spi_device_event_controller_get_instance_private (controller); #ifdef SPI_XKB_DEBUG if (priv->xkb_latch_mask) fprintf (stderr, "unlatch pending! %x\n", priv->xkb_latch_mask); @@ -392,11 +383,15 @@ spi_dec_x11_mouse_check (SpiDEController *controller, Window root_return, child_return; Display *display = spi_get_display (); - if (display != NULL) - XQueryPointer(display, DefaultRootWindow (display), - &root_return, &child_return, - x, y, - &win_x_return, &win_y_return, &mask_return); + if (display == NULL) + { + return 0; + } + + XQueryPointer(display, DefaultRootWindow (display), + &root_return, &child_return, + x, y, + &win_x_return, &win_y_return, &mask_return); /* * Since many clients grab the pointer, and X goes an automatic * pointer grab on mouse-down, we often must detect mouse button events @@ -471,7 +466,7 @@ spi_dec_init_mouse_listener (SpiDEController *dec) static void spi_dec_clear_unlatch_pending (SpiDEController *controller) { - DEControllerPrivateData *priv = controller->priv; + SpiDEControllerPrivate *priv = spi_device_event_controller_get_instance_private (controller); priv->xkb_latch_mask = 0; } @@ -563,11 +558,9 @@ spi_device_event_controller_forward_mouse_event (SpiDEController *controller, static void global_filter_fn (XEvent *xevent, void *data) { - SpiDEController *controller; - DEControllerPrivateData *priv; + SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (data); + SpiDEControllerPrivate *priv = spi_device_event_controller_get_instance_private (controller); Display *display = spi_get_display (); - controller = SPI_DEVICE_EVENT_CONTROLLER (data); - priv = controller->priv; if (xevent->type == MappingNotify) xmkeymap = NULL; @@ -705,10 +698,9 @@ _spi_controller_device_error_handler (Display *display, XErrorEvent *error) static void spi_controller_register_with_devices (SpiDEController *controller) { - DEControllerPrivateData *priv; + SpiDEControllerPrivate *priv = spi_device_event_controller_get_instance_private (controller); int event_base, error_base, major_version, minor_version; - priv = controller->priv; if (XTestQueryExtension (spi_get_display(), &event_base, &error_base, &major_version, &minor_version)) { XTestGrabControl (spi_get_display (), True); @@ -973,7 +965,7 @@ static unsigned int xkb_get_slowkeys_delay (SpiDEController *controller) { unsigned int retval = 0; - DEControllerPrivateData *priv = controller->priv; + SpiDEControllerPrivate *priv = spi_device_event_controller_get_instance_private (controller); #ifdef HAVE_XKB #ifdef XKB_HAS_GET_SLOW_KEYS_DELAY retval = XkbGetSlowKeysDelay (spi_get_display (), @@ -1001,7 +993,7 @@ static unsigned int xkb_get_bouncekeys_delay (SpiDEController *controller) { unsigned int retval = 0; - DEControllerPrivateData *priv = controller->priv; + SpiDEControllerPrivate *priv = spi_device_event_controller_get_instance_private (controller); #ifdef HAVE_XKB #ifdef XKB_HAS_GET_BOUNCE_KEYS_DELAY retval = XkbGetBounceKeysDelay (spi_get_display (), @@ -1027,7 +1019,7 @@ xkb_get_bouncekeys_delay (SpiDEController *controller) static gboolean spi_dec_x11_synth_keycode_press (SpiDEController *controller, - unsigned int keycode) + unsigned int keycode) { unsigned int time = CurrentTime; unsigned int bounce_delay; @@ -1035,7 +1027,7 @@ spi_dec_x11_synth_keycode_press (SpiDEController *controller, unsigned int elapsed_msec; struct timeval tv; #endif - DEControllerPrivateData *priv = controller->priv; + SpiDEControllerPrivate *priv = spi_device_event_controller_get_instance_private (controller); spi_x_error_trap (); if (keycode == priv->last_release_keycode) @@ -1081,7 +1073,7 @@ spi_dec_x11_synth_keycode_release (SpiDEController *controller, unsigned int elapsed_msec; struct timeval tv; #endif - DEControllerPrivateData *priv = controller->priv; + SpiDEControllerPrivate *priv = spi_device_event_controller_get_instance_private (controller); spi_x_error_trap (); if (keycode == priv->last_press_keycode) @@ -1119,7 +1111,7 @@ spi_dec_x11_synth_keycode_release (SpiDEController *controller, static gboolean spi_dec_x11_lock_modifiers (SpiDEController *controller, unsigned modifiers) { - DEControllerPrivateData *priv = controller->priv; + SpiDEControllerPrivate *priv = spi_device_event_controller_get_instance_private (controller); if (priv->have_xkb) { return XkbLockModifiers (spi_get_display (), XkbUseCoreKbd, @@ -1138,7 +1130,7 @@ spi_dec_x11_lock_modifiers (SpiDEController *controller, unsigned modifiers) static gboolean spi_dec_x11_unlock_modifiers (SpiDEController *controller, unsigned modifiers) { - DEControllerPrivateData *priv = controller->priv; + SpiDEControllerPrivate *priv = spi_device_event_controller_get_instance_private (controller); if (priv->have_xkb) { return XkbLockModifiers (spi_get_display (), XkbUseCoreKbd, @@ -1238,7 +1230,7 @@ spi_dec_x11_synth_keystring (SpiDEController *controller, guint synth_type, gint static void spi_dec_x11_init (SpiDEController *controller) { - DEControllerPrivateData *priv = controller->priv; + SpiDEControllerPrivate *priv = spi_device_event_controller_get_instance_private (controller); spi_events_init (spi_get_display ()); @@ -1254,7 +1246,7 @@ spi_dec_x11_init (SpiDEController *controller) static void spi_dec_x11_finalize (SpiDEController *controller) { - DEControllerPrivateData *priv = controller->priv; + SpiDEControllerPrivate *priv = spi_device_event_controller_get_instance_private (controller); /* disconnect any special listeners, get rid of outstanding keygrabs */ XUngrabKey (spi_get_display (), AnyKey, AnyModifier, DefaultRootWindow (spi_get_display ())); @@ -1268,7 +1260,7 @@ static gboolean spi_device_event_controller_forward_key_event (SpiDEController *controller, const XEvent *event) { - DEControllerPrivateData *priv = controller->priv; + SpiDEControllerPrivate *priv = spi_device_event_controller_get_instance_private (controller); Accessibility_DeviceEvent key_event; gboolean ret; @@ -1411,8 +1403,6 @@ spi_dec_x11_generate_mouse_event (SpiDEController *controller, void spi_dec_setup_x11 (SpiDEControllerClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - klass->plat.get_keycode = spi_dec_x11_get_keycode; klass->plat.mouse_check = spi_dec_x11_mouse_check; klass->plat.synth_keycode_press = spi_dec_x11_synth_keycode_press; @@ -1427,6 +1417,4 @@ spi_dec_setup_x11 (SpiDEControllerClass *klass) klass->plat.init = spi_dec_x11_init; klass->plat.finalize = spi_dec_x11_finalize; - - g_type_class_add_private (object_class, sizeof (DEControllerPrivateData)); } diff --git a/registryd/deviceeventcontroller-x11.h b/registryd/deviceeventcontroller-x11.h new file mode 100644 index 0000000..62e2984 --- /dev/null +++ b/registryd/deviceeventcontroller-x11.h @@ -0,0 +1,28 @@ +#ifndef _DEVICEEVENTCONTROLLER_X11_H_ +#define _DEVICEEVENTCONTROLLER_X11_H_ + +#include +#include +#include +#include +#include + +typedef struct { + Display *xevie_display; + unsigned int last_press_keycode; + unsigned int last_release_keycode; + struct timeval last_press_time; + struct timeval last_release_time; + int have_xkb; + int xkb_major_extension_opcode; + int xkb_base_event_code; + int xkb_base_error_code; + unsigned int xkb_latch_mask; + unsigned int pending_xkb_mod_relatch_mask; + XkbDescPtr xkb_desc; + KeyCode reserved_keycode; + KeySym reserved_keysym; + guint reserved_reset_timeout; +} SpiDEControllerPrivate; + +#endif /* _DEVICEEVENTCONTROLLER_X11_H_ */ diff --git a/registryd/deviceeventcontroller.c b/registryd/deviceeventcontroller.c index 942f383..0fe6555 100644 --- a/registryd/deviceeventcontroller.c +++ b/registryd/deviceeventcontroller.c @@ -43,16 +43,16 @@ #include "de-marshaller.h" #include "keymasks.h" +#include "deviceeventcontroller.h" +#include "reentrant-list.h" +#include "introspection.h" + #ifdef HAVE_X11 +#include "deviceeventcontroller-x11.h" #include "display.h" #include "event-source.h" #endif -#include "deviceeventcontroller.h" -#include "reentrant-list.h" - -#include "introspection.h" - #define CHECK_RELEASE_DELAY 20 #define BIT(c, x) (c[x/8]&(1<<(x%8))) static SpiDEController *saved_controller; @@ -60,6 +60,16 @@ static SpiDEController *saved_controller; /* Our parent Gtk object type */ #define PARENT_TYPE G_TYPE_OBJECT +#ifndef HAVE_X11 +/* If we are using X11, SpiDEControllerPrivate is defined in deviceeventcontroller-x11.h. + * Otherwise, there is no private data and so we use a dummy struct. + * This is so that G_ADD_PRIVATE() will have a type to work with. + */ +typedef struct { + int _dummy; +} SpiDEControllerPrivate; +#endif + /* A pointer to our parent object class */ static int spi_error_code = 0; struct _SpiPoint { @@ -97,7 +107,8 @@ static gboolean eventtype_seq_contains_event (dbus_uint32_t types, static gboolean spi_dec_poll_mouse_moving (gpointer data); static gboolean spi_dec_poll_mouse_idle (gpointer data); -G_DEFINE_TYPE(SpiDEController, spi_device_event_controller, G_TYPE_OBJECT) +G_DEFINE_TYPE_WITH_CODE(SpiDEController, spi_device_event_controller, G_TYPE_OBJECT, + G_ADD_PRIVATE (SpiDEController)) static gint spi_dec_plat_get_keycode (SpiDEController *controller, @@ -111,7 +122,13 @@ spi_dec_plat_get_keycode (SpiDEController *controller, if (klass->plat.get_keycode) return klass->plat.get_keycode (controller, keysym, key_str, fix, modmask); else - return keysym; + { + if (modmask) + { + *modmask = 0; + } + return keysym; + } } static guint @@ -123,7 +140,13 @@ spi_dec_plat_mouse_check (SpiDEController *controller, if (klass->plat.mouse_check) return klass->plat.mouse_check (controller, x, y, moved); else - return 0; + { + if (moved) + { + *moved = FALSE; + } + return 0; + } } static gboolean @@ -873,8 +896,9 @@ reset_hung_process (DBusPendingCall *pending, void *data) { if (!strcmp (l->data, dest)) { - g_free (l->data); - hung_processes = g_slist_remove (hung_processes, l->data); + gpointer l_data = l->data; + hung_processes = g_slist_remove (hung_processes, l_data); + g_free (l_data); break; } } @@ -898,8 +922,9 @@ reset_hung_process_from_ping (DBusPendingCall *pending, void *data) { if (!strcmp (l->data, data)) { - g_free (l->data); - hung_processes = g_slist_remove (hung_processes, l->data); + gpointer l_data = l->data; + hung_processes = g_slist_remove (hung_processes, l_data); + g_free (l_data); break; } } @@ -1365,6 +1390,7 @@ impl_register_keystroke_listener (DBusConnection *bus, Accessibility_KeyDefinition *kd = (Accessibility_KeyDefinition *)g_malloc(sizeof(Accessibility_KeyDefinition)); if (!spi_dbus_message_iter_get_struct(&iter_array, DBUS_TYPE_INT32, &kd->keycode, DBUS_TYPE_INT32, &kd->keysym, DBUS_TYPE_STRING, &keystring, DBUS_TYPE_INVALID)) { + g_free(kd); break; } kd->keystring = g_strdup (keystring); @@ -1575,6 +1601,7 @@ impl_deregister_keystroke_listener (DBusConnection *bus, if (!spi_dbus_message_iter_get_struct(&iter_array, DBUS_TYPE_INT32, &kd->keycode, DBUS_TYPE_INT32, &kd->keysym, DBUS_TYPE_STRING, &keystring, DBUS_TYPE_INVALID)) { + g_free(kd); break; } kd->keystring = g_strdup (keystring); @@ -1675,6 +1702,7 @@ impl_get_device_event_listeners (DBusConnection *bus, static unsigned get_modifier_state (SpiDEController *controller) { + spi_dec_poll_mouse_moved (controller); return mouse_mask_state; } @@ -1696,12 +1724,17 @@ spi_dec_synth_keysym (SpiDEController *controller, long keysym) if (synth_mods != modifiers) { lock_mods = synth_mods & ~modifiers; spi_dec_plat_lock_modifiers (controller, lock_mods); + if (modifiers & SPI_KEYMASK_SHIFTLOCK) + spi_dec_plat_unlock_modifiers (controller, SPI_KEYMASK_SHIFTLOCK); } spi_dec_plat_synth_keycode_press (controller, key_synth_code); spi_dec_plat_synth_keycode_release (controller, key_synth_code); - if (synth_mods != modifiers) + if (synth_mods != modifiers) { spi_dec_plat_unlock_modifiers (controller, lock_mods); + if (modifiers & SPI_KEYMASK_SHIFTLOCK) + spi_dec_plat_lock_modifiers (controller, SPI_KEYMASK_SHIFTLOCK); + } return TRUE; } @@ -1858,9 +1891,7 @@ spi_device_event_controller_class_init (SpiDEControllerClass *klass) #ifdef HAVE_X11 if (g_getenv ("DISPLAY") != NULL && g_getenv ("WAYLAND_DISPLAY") == NULL) spi_dec_setup_x11 (klass); - else #endif - g_type_class_add_private (object_class, sizeof (long)); /* dummy */ } static void @@ -1869,10 +1900,6 @@ spi_device_event_controller_init (SpiDEController *device_event_controller) SpiDEControllerClass *klass; klass = SPI_DEVICE_EVENT_CONTROLLER_GET_CLASS (device_event_controller); - /* TODO: shouldn't be gpointer below */ - device_event_controller->priv = G_TYPE_INSTANCE_GET_PRIVATE (device_event_controller, - SPI_DEVICE_EVENT_CONTROLLER_TYPE, - gpointer); device_event_controller->message_queue = g_queue_new (); saved_controller = device_event_controller; diff --git a/registryd/deviceeventcontroller.h b/registryd/deviceeventcontroller.h index 94c01cf..46ea169 100644 --- a/registryd/deviceeventcontroller.h +++ b/registryd/deviceeventcontroller.h @@ -52,7 +52,6 @@ struct _SpiDEController { GList *keygrabs_list; GQueue *message_queue; guint message_queue_idle; - gpointer priv; }; typedef enum { diff --git a/registryd/registry.c b/registryd/registry.c index 8d35f8e..e22fbcb 100644 --- a/registryd/registry.c +++ b/registryd/registry.c @@ -248,8 +248,8 @@ remove_events (SpiRegistry *registry, const char *bus_name, const char *event) g_strfreev (evdata->data); g_free (evdata->bus_name); g_slist_free_full (evdata->properties, g_free); - g_free (evdata); registry->events = g_list_remove (registry->events, evdata); + g_free (evdata); } else { @@ -1056,7 +1056,7 @@ emit_event (DBusConnection *bus, const char *path) { DBusMessage *sig; - DBusMessageIter iter, iter_variant; + DBusMessageIter iter, iter_variant, iter_array; sig = dbus_message_new_signal(SPI_DBUS_PATH_ROOT, klass, major); @@ -1071,9 +1071,9 @@ emit_event (DBusConnection *bus, append_reference (&iter_variant, name, path); dbus_message_iter_close_container (&iter, &iter_variant); - append_reference (&iter, - dbus_bus_get_unique_name (bus), - SPI_DBUS_PATH_ROOT); + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}", + &iter_array); + dbus_message_iter_close_container (&iter, &iter_array); dbus_connection_send(bus, sig, NULL); dbus_message_unref(sig); diff --git a/test/memory.c b/test/memory.c index 2f53dd7..54f0652 100644 --- a/test/memory.c +++ b/test/memory.c @@ -47,7 +47,7 @@ end (void *data) static gboolean kill_child (void *data) { - kill (child_pid, SIGTERM); + g_assert_no_errno (kill (child_pid, SIGTERM)); return FALSE; } @@ -56,6 +56,7 @@ on_event (AtspiEvent *event, void *data) { if (atspi_accessible_get_role (event->source, NULL) == ATSPI_ROLE_DESKTOP_FRAME) { + printf ("memory: event: %s\n", event->type); if (strstr (event->type, "add")) { AtspiAccessible *desktop = atspi_get_desktop (0); @@ -83,8 +84,16 @@ main() listener = atspi_event_listener_new (on_event, NULL, NULL); atspi_event_listener_register (listener, "object:children-changed", NULL); child_pid = fork (); - if (!child_pid) - execlp ("test/test-application", "test/test-application", NULL); + if (child_pid == 0) + { + g_assert_no_errno (execlp ("test/test-application", "test/test-application", NULL)); + } + else if (child_pid == -1) + { + const char *error = g_strerror (errno); + g_error ("could not fork test-application child: %s", error); + } + printf ("memory: child pid: %d\n", (int) child_pid); atspi_event_main (); return 0; } diff --git a/xml/Cache.xml b/xml/Cache.xml index ce06ba4..8954616 100644 --- a/xml/Cache.xml +++ b/xml/Cache.xml @@ -3,12 +3,12 @@ - + - + -- 2.7.4 From 34cee6b9389a671e8e08fc0ee8f875ecb632375b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Artur=20=C5=9Awigo=C5=84?= Date: Fri, 24 Feb 2023 09:49:14 +0100 Subject: [PATCH 06/16] Fix merging errors Change-Id: Ib0534823627f61af248909a8bb47ace6d4ee38a3 --- atspi/atspi-registry.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/atspi/atspi-registry.c b/atspi/atspi-registry.c index 465083d..f906126 100644 --- a/atspi/atspi-registry.c +++ b/atspi/atspi-registry.c @@ -385,7 +385,6 @@ atspi_deregister_keystroke_listener (AtspiDeviceListener *listener, { return FALSE; } - path = _atspi_device_listener_get_path (listener); dbus_error_init (&d_error); @@ -478,7 +477,6 @@ atspi_register_device_event_listener (AtspiDeviceListener *listener, { return retval; } - path = _atspi_device_listener_get_path (listener); dbus_error_init (&d_error); @@ -519,7 +517,6 @@ atspi_deregister_device_event_listener (AtspiDeviceListener *listener, { return FALSE; } - path = _atspi_device_listener_get_path (listener); dbus_error_init (&d_error); -- 2.7.4 From 98cabb9ce5fc1a7e9ed3808b60f8b2c73d2d91ba Mon Sep 17 00:00:00 2001 From: =?utf8?q?Artur=20=C5=9Awigo=C5=84?= Date: Fri, 24 Feb 2023 09:49:55 +0100 Subject: [PATCH 07/16] Null-check dbus_message_get_path() result Change-Id: I0abcb6981030269af20b796e4cf68bec055328c7 --- atspi/atspi-device-listener.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atspi/atspi-device-listener.c b/atspi/atspi-device-listener.c index 9776ebd..f09ff41 100644 --- a/atspi/atspi-device-listener.c +++ b/atspi/atspi-device-listener.c @@ -357,7 +357,7 @@ _atspi_dbus_handle_DeviceEvent (DBusConnection *bus, DBusMessage *message, void goto done; } - if (sscanf (path, "/org/a11y/atspi/listeners/%d", &id) != 1) + if (!path || sscanf (path, "/org/a11y/atspi/listeners/%d", &id) != 1) { g_warning ("AT-SPI: Bad listener path: %s\n", path); goto done; -- 2.7.4 From 8065e1146c0775090aca0ff7e6f24b4eec7b589c Mon Sep 17 00:00:00 2001 From: Woochan Lee Date: Fri, 17 Feb 2023 09:42:49 +0900 Subject: [PATCH 08/16] [Tizen] Provide SetListenPostRender interface Asks the UI Toolkit listen for post render callback to get post render event in client. Change-Id: Ie2b95ff4f02888b1266fb621c3990565f3f69bf8 --- atspi/atspi-accessible.c | 15 +++++++++++++++ atspi/atspi-accessible.h | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index d461055..faba394 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -1465,6 +1465,21 @@ atspi_accessible_get_id (AtspiAccessible *obj, GError **error) return ret; } +//TIZEN_ONLY(20230307) Provide post render callback to client +/** + * atspi_accessible_set_listen_post_render: + * @obj: a pointer to the #AtspiAccessible object on which to operate. + * @enabled: a boolean true listen post render callback, false otherwise. + * + * Asks the UI Toolkit listen for the post render callback. + **/ +void +atspi_accessible_set_listen_post_render(AtspiAccessible *obj, gboolean enabled, GError **error) +{ + g_return_val_if_fail (obj != NULL, FALSE); + + _atspi_dbus_call (obj, atspi_interface_accessible, "SetListenPostRender", error, "b", enabled, NULL); +} /* Interface query methods */ diff --git a/atspi/atspi-accessible.h b/atspi/atspi-accessible.h index 5211972..364e75e 100644 --- a/atspi/atspi-accessible.h +++ b/atspi/atspi-accessible.h @@ -159,6 +159,10 @@ gint atspi_accessible_get_id (AtspiAccessible *obj, GError **error); AtspiAccessible * atspi_accessible_get_application (AtspiAccessible *obj, GError **error); +//TIZEN_ONLY(20230307) Provide post render callback to client +void atspi_accessible_set_listen_post_render(AtspiAccessible *obj, gboolean enabled, GError **error); +// + #ifndef ATSPI_DISABLE_DEPRECATED AtspiAction * atspi_accessible_get_action (AtspiAccessible *obj); -- 2.7.4 From 99201d6e99f7a16d3299350117fe21ed407584c4 Mon Sep 17 00:00:00 2001 From: Woochan Lee Date: Thu, 9 Mar 2023 19:12:37 +0900 Subject: [PATCH 09/16] [Tizen] Fix build warning. Change-Id: Ia163d957c06b715295c22423975fc2a9f0f95649 --- atspi/atspi-accessible.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index faba394..e5a2c7c 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -1476,7 +1476,7 @@ atspi_accessible_get_id (AtspiAccessible *obj, GError **error) void atspi_accessible_set_listen_post_render(AtspiAccessible *obj, gboolean enabled, GError **error) { - g_return_val_if_fail (obj != NULL, FALSE); + g_return_if_fail (obj != NULL); _atspi_dbus_call (obj, atspi_interface_accessible, "SetListenPostRender", error, "b", enabled, NULL); } -- 2.7.4 From 34a26a69425377e18b52474d46db5a20bf1d3197 Mon Sep 17 00:00:00 2001 From: Maria Bialota Date: Tue, 14 Mar 2023 15:04:05 +0100 Subject: [PATCH 10/16] at-spi-bus-launcher: fixed memory leak Change-Id: Ieb4985780a21f4608f11d1e8e51aef1c401b1637 --- bus/at-spi-bus-launcher.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bus/at-spi-bus-launcher.c b/bus/at-spi-bus-launcher.c index 36c8f73..7877fd4 100644 --- a/bus/at-spi-bus-launcher.c +++ b/bus/at-spi-bus-launcher.c @@ -383,7 +383,10 @@ ensure_a11y_bus_daemon (A11yBusLauncher *app, char *config_path) } if (app->a11y_bus_pid != 0) - return FALSE; + { + g_free(address_param); + return FALSE; + } if (pipe (app->pipefd) < 0) { -- 2.7.4 From 32c7ce95032c5e6f3e26ba9713702627d67671a5 Mon Sep 17 00:00:00 2001 From: Maria Bialota Date: Tue, 14 Mar 2023 16:20:38 +0100 Subject: [PATCH 11/16] at-spi-bus-launcher: Added checking return value when creating directory Change-Id: I44aa5995488a466a5610887bfa2067ed1b739538 --- bus/at-spi-bus-launcher.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bus/at-spi-bus-launcher.c b/bus/at-spi-bus-launcher.c index 7877fd4..2950a45 100644 --- a/bus/at-spi-bus-launcher.c +++ b/bus/at-spi-bus-launcher.c @@ -610,12 +610,11 @@ ensure_a11y_bus (A11yBusLauncher *app) config_path = "--config-file="DATADIR"/defaults/at-spi2/accessibility.conf"; xdg_runtime_dir = g_get_user_runtime_dir (); - if (xdg_runtime_dir) + if (xdg_runtime_dir && (mkdir (xdg_runtime_dir, 0700) == 0 || errno == EEXIST)) { const gchar *display = g_getenv ("DISPLAY"); gchar *at_spi_dir = g_strconcat (xdg_runtime_dir, "/at-spi", NULL); gchar *p; - mkdir (xdg_runtime_dir, 0700); if (!g_path_is_absolute (at_spi_dir)) { gchar *new_dir = g_canonicalize_filename (at_spi_dir, NULL); -- 2.7.4 From 1f22a43b3cbe2975976c96da94db4d67f1d4e148 Mon Sep 17 00:00:00 2001 From: Woochan Lee Date: Wed, 15 Mar 2023 20:22:56 +0900 Subject: [PATCH 12/16] [Tizen] Introduce atspi_accessible_get_children API We called child count and child at index API to get child list. It will helps to reduce dbus method call count and usage also better. Change-Id: Iabd81f3988da0beb9ffcf224584f205489946872 --- atspi/atspi-accessible.c | 39 +++++++++++++++++++++++++++++++++++++++ atspi/atspi-accessible.h | 4 ++++ 2 files changed, 43 insertions(+) diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index e5a2c7c..a0ebf6e 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -985,6 +985,45 @@ atspi_accessible_get_child_count (AtspiAccessible *obj, GError **error) return obj->children->len; } +//TIZEN_ONLY(20230315) Add new API to get children +/** + * atspi_accessible_get_children: + * @obj: a pointer to the #AtspiAccessible object on which to operate. + * + * Gets the children array contained by an #AtspiAccessible object. + * + * Returns: (element-type AtspiAccessible*) (transfer full): a #GArray of + * #AtspiAccessible pointers or NULL on exception. + * + **/ +GArray * +atspi_accessible_get_children (AtspiAccessible *obj, GError **error) +{ + DBusMessage *reply; + DBusMessageIter iter, iter_array; + GArray *ret; + + g_return_val_if_fail (obj != NULL, NULL); + + reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetChildren", error, ""); + if (!reply) + return NULL; + + ret = g_array_new (TRUE, TRUE, sizeof (AtspiAccessible *)); + dbus_message_iter_init (reply, &iter); + dbus_message_iter_recurse (&iter, &iter_array); + while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID) + { + AtspiAccessible *accessible; + accessible = _atspi_dbus_return_accessible_from_iter (&iter_array); + ret = g_array_append_val (ret, accessible); + } + dbus_message_unref (reply); + + return ret; +} +// + /** * atspi_accessible_get_child_at_index: * @obj: a pointer to the #AtspiAccessible object on which to operate. diff --git a/atspi/atspi-accessible.h b/atspi/atspi-accessible.h index 364e75e..28b8881 100644 --- a/atspi/atspi-accessible.h +++ b/atspi/atspi-accessible.h @@ -131,6 +131,10 @@ AtspiAccessible * atspi_accessible_get_parent (AtspiAccessible *obj, GError **er gint atspi_accessible_get_child_count (AtspiAccessible *obj, GError **error); +//TIZEN_ONLY(20230315) Add new API to get children +GArray * atspi_accessible_get_children (AtspiAccessible *obj, GError **error); +// + AtspiAccessible * atspi_accessible_get_child_at_index (AtspiAccessible *obj, gint child_index, GError **error); gint atspi_accessible_get_index_in_parent (AtspiAccessible *obj, GError **error); -- 2.7.4 From ae24eb55b47e52da0ef9b60ec30efeafd41918af Mon Sep 17 00:00:00 2001 From: Woochan Lee Date: Fri, 17 Mar 2023 12:25:43 +0900 Subject: [PATCH 13/16] [Tizen] Avoid cache-related code when atspi_no_cache flag on atspi_state_set_contains() is a performance degradation factor for client that don't need cache. Change-Id: I9110f7e5916241635a03be80c4568fb6d55c0eb3 --- atspi/atspi-accessible.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index a0ebf6e..f322b5b 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -2428,6 +2428,11 @@ _atspi_accessible_get_cache_mask (AtspiAccessible *accessible) gboolean _atspi_accessible_test_cache (AtspiAccessible *accessible, AtspiCache flag) { + //TIZEN_ONLY(20230318) Avoid unnecessary cache-related codes + if (atspi_no_cache) + return FALSE; + // + AtspiCache mask = _atspi_accessible_get_cache_mask (accessible); AtspiCache result = accessible->cached_properties & mask & flag; if (accessible->states && atspi_state_set_contains (accessible->states, ATSPI_STATE_TRANSIENT)) -- 2.7.4 From f4f0af8cac396f001ff0634542af3cd298e460f4 Mon Sep 17 00:00:00 2001 From: Woochan Lee Date: Thu, 23 Mar 2023 18:16:50 +0900 Subject: [PATCH 14/16] Revert "[Tizen] Avoid cache-related code when atspi_no_cache flag on" This reverts commit ae24eb55b47e52da0ef9b60ec30efeafd41918af. Change-Id: I7258c17706cf3c673c6423348d46095a632db929 --- atspi/atspi-accessible.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index f322b5b..a0ebf6e 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -2428,11 +2428,6 @@ _atspi_accessible_get_cache_mask (AtspiAccessible *accessible) gboolean _atspi_accessible_test_cache (AtspiAccessible *accessible, AtspiCache flag) { - //TIZEN_ONLY(20230318) Avoid unnecessary cache-related codes - if (atspi_no_cache) - return FALSE; - // - AtspiCache mask = _atspi_accessible_get_cache_mask (accessible); AtspiCache result = accessible->cached_properties & mask & flag; if (accessible->states && atspi_state_set_contains (accessible->states, ATSPI_STATE_TRANSIENT)) -- 2.7.4 From fcba1e05746d7dd5525ac72a42e7dc0151074ba1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Artur=20=C5=9Awigo=C5=84?= Date: Wed, 12 Apr 2023 12:21:50 +0200 Subject: [PATCH 15/16] Backport atspi_value_get_text() from 2.46 This API provides a string value from the Value interface, customizable by the application, which can be read as-is by the ScreenReader. Change-Id: I054cc7253deac9d6ca9629fc2e813f7a5af24709 --- atspi/atspi-value.c | 22 ++++++++++++++++++++++ atspi/atspi-value.h | 1 + 2 files changed, 23 insertions(+) diff --git a/atspi/atspi-value.c b/atspi/atspi-value.c index 28acade..1f90f37 100644 --- a/atspi/atspi-value.c +++ b/atspi/atspi-value.c @@ -152,6 +152,28 @@ atspi_value_get_minimum_increment (AtspiValue *obj, GError **error) return retval; } +/** + * atspi_value_get_text: + * @obj: a pointer to the #AtspiValue implementor on which to operate. + * + * Gets the human readable text alternative associated with the value. + * @text is a newly created string, that must be freed by the + * caller. Can be NULL if no descriptor is available. + * + * Since: 2.46 + **/ +gchar * +atspi_value_get_text (AtspiValue *obj, GError **error) +{ + gchar *retval = NULL; + + g_return_val_if_fail (obj != NULL, NULL); + + _atspi_dbus_get_property (obj, atspi_interface_value, "Text", error, "s", &retval); + + return retval; +} + static void atspi_value_base_init (AtspiValue *klass) { diff --git a/atspi/atspi-value.h b/atspi/atspi-value.h index a012793..478ea95 100644 --- a/atspi/atspi-value.h +++ b/atspi/atspi-value.h @@ -56,6 +56,7 @@ gboolean atspi_value_set_current_value (AtspiValue *obj, gdouble new_value, GErr gdouble atspi_value_get_minimum_increment (AtspiValue *obj, GError **error); +gchar *atspi_value_get_text (AtspiValue *obj, GError **error); G_END_DECLS #endif /* _ATSPI_VALUE_H_ */ -- 2.7.4 From 9a6fbb8c326963845125a7d54c7710feaed92388 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Artur=20=C5=9Awigo=C5=84?= Date: Wed, 12 Apr 2023 15:15:26 +0200 Subject: [PATCH 16/16] Add value_text to AtspiAccessibleReadingMaterial This field contains the value of the org.a11y.atspi.Value.Text property. Change-Id: I1bbcb2b391473078e8a14daf992f4d39dce79f05 --- atspi/atspi-accessible.c | 7 ++++++- atspi/atspi-accessible.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index a0ebf6e..625e3b7 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -545,7 +545,7 @@ atspi_accessible_get_reading_material (AtspiAccessible *obj, GError **error) reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetReadingMaterial", error, ""); - _ATSPI_DBUS_CHECK_SIG (reply, "a{ss}sssuausiddddsibbii(so)auiui(so)", NULL, NULL); + _ATSPI_DBUS_CHECK_SIG (reply, "a{ss}sssuausidsdddsibbii(so)auiui(so)", NULL, NULL); reading_material = calloc(1, sizeof(AtspiAccessibleReadingMaterial)); if (!reading_material) @@ -602,6 +602,11 @@ atspi_accessible_get_reading_material (AtspiAccessible *obj, GError **error) reading_material->value = current_value; dbus_message_iter_next (&iter); + /* get current formatted value */ + dbus_message_iter_get_basic (&iter, &name); + reading_material->value_text = g_strdup (name); + dbus_message_iter_next (&iter); + /* get minimum increment */ dbus_message_iter_get_basic (&iter, ¤t_value); reading_material->increment = current_value; diff --git a/atspi/atspi-accessible.h b/atspi/atspi-accessible.h index 28b8881..058ae2c 100644 --- a/atspi/atspi-accessible.h +++ b/atspi/atspi-accessible.h @@ -64,6 +64,7 @@ struct _AtspiAccessibleReadingMaterial char *text_interface_name; char *localized_role_name; char *description; + char *value_text; gdouble value; gdouble increment; gdouble lower; -- 2.7.4