aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com>2023-08-17 00:07:28 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-08-17 00:07:28 +0000
commit43fb25f235b333bf436c0b790dfa12b5b11725c1 (patch)
tree71181f84a33360ed77e4342ccd550aa6b78cffa0
parent28e86b61c69b3b42385b0c535c2044e84657cffb (diff)
parent8e0233feec80c9fc25dab874723009612ee64563 (diff)
downloadwayland-43fb25f235b333bf436c0b790dfa12b5b11725c1.tar.gz
Merge changes I50045de0,I91b450f1 into main am: 8e0233feec
Original change: https://android-review.googlesource.com/c/platform/external/wayland/+/2699957 Change-Id: Ie0881cff0d49f699110bf032c0210e312ad85b28 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--.gitignore40
-rw-r--r--.gitlab-ci.yml378
-rw-r--r--.mailmap3
-rw-r--r--COPYING1
-rw-r--r--METADATA4
-rw-r--r--Makefile.am341
-rw-r--r--README.md (renamed from README)12
-rwxr-xr-xautogen.sh9
-rw-r--r--configure.ac202
-rw-r--r--cursor/meson.build22
-rw-r--r--cursor/os-compatibility.c34
-rw-r--r--cursor/wayland-cursor-uninstalled.pc.in8
-rw-r--r--cursor/wayland-cursor.c75
-rw-r--r--cursor/wayland-cursor.pc.in10
-rw-r--r--cursor/xcursor.c1195
-rw-r--r--cursor/xcursor.h45
-rw-r--r--doc/Makefile.am1
-rw-r--r--doc/doxygen/Makefile.am113
-rw-r--r--doc/doxygen/meson.build8
-rw-r--r--doc/meson.build6
-rw-r--r--doc/publican/Makefile.am169
-rw-r--r--doc/publican/meson.build1
-rw-r--r--doc/publican/sources/Protocol.xml24
-rw-r--r--egl/meson.build13
-rw-r--r--egl/wayland-egl-backend.h4
-rw-r--r--egl/wayland-egl-backend.pc.in9
-rw-r--r--egl/wayland-egl.c14
-rw-r--r--egl/wayland-egl.pc.in11
-rw-r--r--m4/.gitignore5
-rw-r--r--m4/weston.m437
-rw-r--r--meson.build63
-rw-r--r--meson_options.txt12
-rw-r--r--protocol/wayland.dtd1
-rw-r--r--protocol/wayland.xml367
-rwxr-xr-xpublish-doc15
-rwxr-xr-xrelease.sh79
-rw-r--r--releasing.txt34
-rw-r--r--src/connection.c157
-rw-r--r--src/dtddata.S50
-rw-r--r--src/embed.py45
-rw-r--r--src/event-loop.c18
-rw-r--r--src/meson.build64
-rw-r--r--src/scanner.c103
-rw-r--r--src/wayland-client-core.h119
-rw-r--r--src/wayland-client-uninstalled.pc.in9
-rw-r--r--src/wayland-client.c506
-rw-r--r--src/wayland-client.pc.in12
-rw-r--r--src/wayland-os.c91
-rw-r--r--src/wayland-os.h12
-rw-r--r--src/wayland-private.h5
-rw-r--r--src/wayland-scanner-uninstalled.pc.in6
-rw-r--r--src/wayland-scanner.pc.in9
-rw-r--r--src/wayland-server-core.h21
-rw-r--r--src/wayland-server-uninstalled.pc.in9
-rw-r--r--src/wayland-server.c301
-rw-r--r--src/wayland-server.pc.in12
-rw-r--r--src/wayland-shm.c103
-rw-r--r--src/wayland-util.c77
-rw-r--r--src/wayland-util.h28
-rw-r--r--src/wayland-version.h4
-rw-r--r--tests/client-test.c62
-rw-r--r--tests/compositor-introspection-test.c2
-rw-r--r--tests/connection-test.c47
-rw-r--r--tests/data/example-client.h306
-rw-r--r--tests/data/example-server.h20
-rw-r--r--tests/data/example.xml28
-rw-r--r--tests/data/small-client-core.h14
-rw-r--r--tests/data/small-client.h14
-rw-r--r--tests/display-test.c83
-rw-r--r--tests/event-loop-test.c35
-rw-r--r--tests/fixed-test.c1
-rw-r--r--tests/map-test.c16
-rw-r--r--tests/meson.build25
-rw-r--r--tests/message-test.c8
-rw-r--r--tests/os-wrappers-test.c79
-rw-r--r--tests/protocol-logger-test.c772
-rw-r--r--tests/queue-test.c215
-rw-r--r--tests/sanity-test.c63
-rw-r--r--tests/signal-test.c41
-rw-r--r--tests/socket-test.c2
-rw-r--r--tests/test-compositor.c72
-rw-r--r--tests/test-compositor.h10
-rw-r--r--tests/test-helpers.c32
-rw-r--r--tests/test-runner.c26
84 files changed, 4311 insertions, 2788 deletions
diff --git a/.gitignore b/.gitignore
index eadea12..4fefe5d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,48 +1,8 @@
*.announce
-*.deps
-*.jpg
-*.la
-*.lo
-*.o
-*.pc
*.sig
-*.so
*.swp
-*.3
-*.7
*.log
-*.trs
*.tar.xz
*~
-*-test
-.libs
-.dirstamp
cscope.out
ctags
-/aclocal.m4
-/wayland-scanner.m4
-/autom4te.cache
-/compile
-/config.guess
-/config.h
-/config.h.in
-/config.log
-/config.mk
-/config.status
-/config.sub
-/configure
-/depcomp
-/install-sh
-/libtool
-/ltmain.sh
-/missing
-/stamp-h1
-/test-driver
-/tests/output/
-Makefile
-Makefile.in
-exec-fd-leak-checker
-fixed-benchmark
-/wayland-egl-abi-check
-/wayland-scanner
-protocol/*.[ch]
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b2e174f..f7f74ec 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,90 +1,352 @@
-.templates_sha: &template_sha bd8010dd0123d3f0dda4ef691078566af2842613 # see https://docs.gitlab.com/ee/ci/yaml/#includefile
+# This file uses the freedesktop ci-templates to build Wayland and run our
+# tests in CI.
+#
+# ci-templates uses a multi-stage build process. First, the base container
+# image is built which contains the core distribution, the toolchain, and
+# all our build dependencies. This container is aggressively cached; if a
+# container image matching $FDO_DISTRIBUTION_TAG is found in either the
+# upstream repo (wayland/weston) or the user's downstream repo, it is
+# reused for the build. This gives us predictability of build and far
+# quicker runtimes, however it means that any changes to the base container
+# must also change $FDO_DISTRIBUTION_TAG. When changing this, please use
+# the current date as well as a unique build identifier.
+#
+# After the container is either rebuilt (tag mismatch) or reused (tag
+# previously used), the build stage executes within this container.
+#
+# The final stage is used to expose documentation and coverage information,
+# including publishing documentation to the public site when built on the
+# main branch.
+#
+# Apart from the 'variables', 'include', and 'stages' top-level anchors,
+# everything not beginning with a dot ('.') is the name of a job which will
+# be executed as part of CI, unless the rules specify that it should not be
+# run.
+#
+# Variables prefixed with CI_ are generally provided by GitLab itself;
+# variables prefixed with FDO_ and templates prefixed by .fdo are provided
+# by the ci-templates.
+#
+# For more information on GitLab CI, including the YAML syntax, see:
+# https://docs.gitlab.com/ee/ci/yaml/README.html
+#
+# Note that freedesktop.org uses the 'Community Edition' of GitLab, so features
+# marked as 'premium' or 'ultimate' are not available to us.
+#
+# For more information on ci-templates, see:
+# - documentation at https://freedesktop.pages.freedesktop.org/ci-templates/
+# - repo at https://gitlab.freedesktop.org/freedesktop/ci-templates/
+# Here we use a fixed ref in order to isolate ourselves from ci-templates
+# API changes. If you need new features from ci-templates you must bump
+# this to the current SHA you require from the ci-templates repo, however
+# be aware that you may need to account for API changes when doing so.
+.templates_sha: &template_sha d5aa3941aa03c2f716595116354fb81eb8012acb # see https://docs.gitlab.com/ee/ci/yaml/#includefile
include:
- # Debian container builder template
- project: 'freedesktop/ci-templates'
ref: *template_sha
- file: '/templates/debian.yml'
+ file:
+ - '/templates/debian.yml'
+ - '/templates/freebsd.yml'
+ - '/templates/ci-fairy.yml'
+
+variables:
+ FDO_UPSTREAM_REPO: wayland/wayland
+ FDO_REPO_SUFFIX: "$BUILD_OS/$BUILD_ARCH"
+# Define the build stages. These are used for UI grouping as well as
+# dependencies.
stages:
- - prep
- - build
+ - "Merge request checks"
+ - "Base container"
+ - "Build and test"
+ - "Other build configurations"
+.ci-rules:
+ rules:
+ - when: on_success
-variables:
- DEBIAN_PACKAGES: 'build-essential automake autoconf libtool pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build'
- DEBIAN_EXEC: 'pip3 install meson==0.52.1'
- # these tags should be updated each time the list of packages is updated
- # changing these will force rebuilding the associated image
- # Note: these tags have no meaning and are not tied to a particular
- # wayland version
- DEBIAN_TAG: '2020-06-05.1'
- FDO_UPSTREAM_REPO: wayland/wayland
+# Base variables used for anything using a Debian environment
+.os-debian:
+ variables:
+ BUILD_OS: debian
+ FDO_DISTRIBUTION_VERSION: bullseye
+ FDO_DISTRIBUTION_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build'
+ FDO_DISTRIBUTION_EXEC: 'pip3 install meson==0.56.0'
+ # bump this tag every time you change something which requires rebuilding the
+ # base image
+ FDO_DISTRIBUTION_TAG: "2022-08-08.0"
+
+.debian-x86_64:
+ extends:
+ - .os-debian
+ variables:
+ BUILD_ARCH: "x86-64"
+
+.debian-aarch64:
+ extends:
+ - .os-debian
+ variables:
+ BUILD_ARCH: "aarch64"
+
+.debian-armv7:
+ extends:
+ - .os-debian
+ variables:
+ BUILD_ARCH: "armv7"
+
+
+# Does not inherit .ci-rules as we only want it to run in MR context.
+check-commit:
+ extends:
+ - .fdo.ci-fairy
+ stage: "Merge request checks"
+ rules:
+ - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
+ when: always
+ - when: never
+ script:
+ - ci-fairy check-commits --signed-off-by --junit-xml=results.xml
+ variables:
+ GIT_DEPTH: 100
+ artifacts:
+ reports:
+ junit: results.xml
-.debian.buster:
+# Build our base container image, which contains the core distribution, the
+# toolchain, and all our build dependencies. This will be reused in the build
+# stage.
+x86_64-debian-container_prep:
+ extends:
+ - .ci-rules
+ - .debian-x86_64
+ - .fdo.container-build@debian
+ stage: "Base container"
variables:
- FDO_DISTRIBUTION_PACKAGES: $DEBIAN_PACKAGES
- FDO_DISTRIBUTION_TAG: $DEBIAN_TAG
- FDO_DISTRIBUTION_VERSION: 'buster'
- FDO_DISTRIBUTION_EXEC: $DEBIAN_EXEC
+ GIT_STRATEGY: none
+aarch64-debian-container_prep:
+ extends:
+ - .ci-rules
+ - .debian-aarch64
+ - .fdo.container-build@debian
+ tags:
+ - aarch64
+ stage: "Base container"
+ variables:
+ GIT_STRATEGY: none
-debian:buster@container-prep:
+armv7-debian-container_prep:
extends:
- - .debian.buster
+ - .ci-rules
+ - .debian-armv7
- .fdo.container-build@debian
- stage: prep
+ tags:
+ - aarch64
+ stage: "Base container"
variables:
GIT_STRATEGY: none
+ FDO_BASE_IMAGE: "arm32v7/debian:$FDO_DISTRIBUTION_VERSION"
+
+
+# Core build environment.
+.build-env:
+ variables:
+ MESON_BUILD_TYPE: "-Dbuildtype=debug -Doptimization=0 -Db_sanitize=address,undefined"
+ # See https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/154
+ ASAN_OPTIONS: "detect_odr_violation=0"
+ before_script:
+ - export BUILD_ID="wayland-$CI_JOB_NAME"
+ - export PREFIX="${CI_PROJECT_DIR}/prefix-${BUILD_ID}"
+ - export BUILDDIR="${CI_PROJECT_DIR}/build-${BUILD_ID}"
+ - mkdir "$BUILDDIR" "$PREFIX"
+
+# Build variants to be stacked on as required.
+.build-release:
+ stage: "Other build configurations"
+ variables:
+ MESON_BUILD_TYPE: "-Dbuildtype=release"
+
+
+# OS/architecture-specific variants
+.build-env-debian-x86_64:
+ extends:
+ - .fdo.suffixed-image@debian
+ - .debian-x86_64
+ - .build-env
+ needs:
+ - job: x86_64-debian-container_prep
+ artifacts: false
-build-native-autotools:
+.build-env-debian-aarch64:
extends:
- - .debian.buster
- - .fdo.distribution-image@debian
- stage: build
+ - .fdo.suffixed-image@debian
+ - .debian-aarch64
+ - .build-env
+ variables:
+ # At least with the versions we have, the LSan runtime makes fork unusably
+ # slow on AArch64, which is bad news since the test suite decides to fork
+ # for every single subtest. For now, in order to get AArch64 builds and
+ # tests into CI, just assume that we're not going to leak any more on
+ # AArch64 than we would on ARMv7 or x86-64.
+ ASAN_OPTIONS: "detect_leaks=0,detect_odr_violation=0"
+ tags:
+ - aarch64
+ needs:
+ - job: aarch64-debian-container_prep
+ artifacts: false
+
+.build-env-debian-armv7:
+ extends:
+ - .fdo.suffixed-image@debian
+ - .debian-armv7
+ - .build-env
+ tags:
+ - aarch64
+ needs:
+ - job: armv7-debian-container_prep
+ artifacts: false
+
+
+# Full build and test.
+.do-build:
+ extends:
+ - .ci-rules
+ stage: "Build and test"
script:
- - export BUILD_ID="wayland-$CI_JOB_NAME_$CI_COMMIT_SHA-$CI_JOB_ID"
- - export PREFIX="$(pwd)/prefix-$BUILD_ID"
- - export BUILDDIR="$(pwd)/build-$BUILD_ID"
- - export MAKEFLAGS="-j4"
- - mkdir "$BUILDDIR" "$PREFIX"
- - cd "$BUILDDIR"
- - ../autogen.sh --prefix="$PREFIX" --with-icondir=/usr/share/X11/icons
- - make all
- - make check
- - make install
- - make distcheck
+ - cd "$BUILDDIR"
+ - meson --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons -Dwerror=true ${MESON_BUILD_TYPE} ..
+ - ninja -k0 -j${FDO_CI_CONCURRENT:-4}
+ - meson test --num-processes ${FDO_CI_CONCURRENT:-4}
+ - ninja clean
artifacts:
- name: wayland-$CI_COMMIT_SHA-$CI_JOB_ID
+ name: wayland-$CI_JOB_NAME
when: always
paths:
- - build-*/wayland-*.tar.xz
- - build-*/wayland*/_build/sub/*.log
- - build-*/*.log
- - prefix-*
-
+ - build-*/meson-logs
+ - prefix-*
+ reports:
+ junit: build-*/meson-logs/testlog.junit.xml
-build-native-meson:
+# Full build and test.
+.do-build-qemu:
extends:
- - .debian.buster
- - .fdo.distribution-image@debian
- stage: build
+ - .ci-rules
+ stage: "Build and test"
script:
- - export BUILD_ID="wayland-$CI_JOB_NAME_$CI_COMMIT_SHA-$CI_JOB_ID"
- - export PREFIX="$(pwd)/prefix-$BUILD_ID"
- - export BUILDDIR="$(pwd)/build-$BUILD_ID"
- - mkdir "$BUILDDIR" "$PREFIX"
- - cd "$BUILDDIR"
- - meson --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons ..
- - ninja -k0 test
- - ninja clean
+ # Start the VM and copy our workspace to the VM
+ - /app/vmctl start
+ - scp -r $PWD "vm:"
+ # The `set +e is needed to ensure that we always copy the meson logs back to
+ # the workspace to see details about the failed tests.
+ - |
+ set +e
+ /app/vmctl exec "pkg info; cd $CI_PROJECT_NAME ; meson $BUILDDIR --prefix=$PREFIX $MESON_BUILD_TYPE $MESON_ARGS && ninja -C $BUILDDIR -j${FDO_CI_CONCURRENT:-4}"
+ /app/vmctl exec "meson test --print-errorlogs -C $BUILDDIR --num-processes ${FDO_CI_CONCURRENT:-4}" && touch .tests-successful
+ set -ex
+ scp -r vm:$BUILDDIR/meson-logs .
+ /app/vmctl exec "ninja -C $BUILDDIR install"
+ mkdir -p $PREFIX && scp -r vm:$PREFIX/ $PREFIX/
+ # Finally, shut down the VM.
+ - /app/vmctl stop
+ - test -f .tests-successful || exit 1
artifacts:
- name: wayland-meson-$CI_COMMIT_SHA-$CI_JOB_ID
+ name: wayland-$CI_JOB_NAME
when: always
paths:
- - build-meson/meson-logs
- - prefix-*
+ - meson-logs
+ - prefix-*
+ reports:
+ junit: meson-logs/testlog.junit.xml
+
+# Full build and test.
+x86_64-debian-build:
+ extends:
+ - .build-env-debian-x86_64
+ - .do-build
+
+x86_64-release-debian-build:
+ extends:
+ - .build-env-debian-x86_64
+ - .do-build
+ - .build-release
+
+aarch64-debian-build:
+ extends:
+ - .build-env-debian-aarch64
+ - .do-build
+
+aarch64-release-debian-build:
+ extends:
+ - .build-env-debian-aarch64
+ - .do-build
+ - .build-release
+
+armv7-debian-build:
+ extends:
+ - .build-env-debian-armv7
+ - .do-build
+
+armv7-release-debian-build:
+ extends:
+ - .build-env-debian-armv7
+ - .do-build
+ - .build-release
+
+# Base variables used for anything using a FreeBSD environment
+.os-freebsd:
+ variables:
+ BUILD_OS: freebsd
+ FDO_DISTRIBUTION_VERSION: "13.1"
+ FDO_DISTRIBUTION_PACKAGES: 'libxslt meson ninja pkgconf expat libffi libepoll-shim libxml2'
+ # bump this tag every time you change something which requires rebuilding the
+ # base image
+ FDO_DISTRIBUTION_TAG: "2022-09-08.0"
+ # Don't build documentation since installing the required tools massively
+ # increases the VM image (and therefore container) size.
+ MESON_ARGS: "-Ddocumentation=false"
+
+.freebsd-x86_64:
+ extends:
+ - .os-freebsd
+ variables:
+ BUILD_ARCH: "x86_64"
+
+x86_64-freebsd-container_prep:
+ extends:
+ - .ci-rules
+ - .freebsd-x86_64
+ - .fdo.qemu-build@freebsd@x86_64
+ stage: "Base container"
+ variables:
+ GIT_STRATEGY: none
+
+.build-env-freebsd-x86_64:
+ variables:
+ # Compiling with ASan+UBSan appears to trigger an infinite loop in the
+ # compiler shipped with FreeBSD 13.0, so we only use UBSan here.
+ # Additionally, sanitizers can't be used with b_lundef on FreeBSD.
+ MESON_BUILD_TYPE: "-Dbuildtype=debug -Db_sanitize=undefined -Db_lundef=false"
+ extends:
+ - .fdo.suffixed-image@freebsd
+ - .freebsd-x86_64
+ - .build-env
+ needs:
+ - job: x86_64-freebsd-container_prep
+ artifacts: false
+
+# Full build and test.
+x86_64-freebsd-build:
+ extends:
+ - .build-env-freebsd-x86_64
+ - .do-build-qemu
+
+x86_64-release-freebsd-build:
+ extends:
+ - .build-env-freebsd-x86_64
+ - .do-build-qemu
+ - .build-release
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000..bdb791e
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,3 @@
+Faith Ekstrand <faith@gfxstrand.net> <jason@jlekstrand.net>
+Faith Ekstrand <faith@gfxstrand.net> <jason.ekstrand@intel.com>
+Faith Ekstrand <faith@gfxstrand.net> <jason.ekstrand@collabora.com>
diff --git a/COPYING b/COPYING
index eb25a4e..843b844 100644
--- a/COPYING
+++ b/COPYING
@@ -2,6 +2,7 @@ Copyright © 2008-2012 Kristian Høgsberg
Copyright © 2010-2012 Intel Corporation
Copyright © 2011 Benjamin Franzke
Copyright © 2012 Collabora, Ltd.
+Copyright 2022 Google LLC
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
diff --git a/METADATA b/METADATA
index dc52692..f09055f 100644
--- a/METADATA
+++ b/METADATA
@@ -16,7 +16,7 @@ third_party {
type: GIT
value: "https://gitlab.freedesktop.org/wayland/wayland.git"
}
- version: "1.19.0"
- last_upgrade_date { year: 2021 month: 2 day: 9 }
+ version: "1.22.0"
+ last_upgrade_date { year: 2023 month: 8 day: 8 }
license_type: NOTICE
}
diff --git a/Makefile.am b/Makefile.am
deleted file mode 100644
index b9438b7..0000000
--- a/Makefile.am
+++ /dev/null
@@ -1,341 +0,0 @@
-if BUILD_DOCS
-SUBDIRS = doc
-endif
-
-ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
-
-AM_CPPFLAGS = \
- -I$(top_builddir)/src \
- -I$(top_srcdir)/src \
- -I$(top_builddir)/protocol
-
-AM_CFLAGS = $(GCC_CFLAGS)
-
-aclocaldir = $(datadir)/aclocal
-dist_aclocal_DATA = wayland-scanner.m4
-
-dist_pkgdata_DATA = \
- wayland-scanner.mk \
- protocol/wayland.xml \
- protocol/wayland.dtd
-
-pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA =
-
-bin_PROGRAMS = wayland-scanner
-wayland_scanner_SOURCES = src/scanner.c
-wayland_scanner_CPPFLAGS = $(AM_CPPFLAGS) -include config.h
-wayland_scanner_CFLAGS = $(EXPAT_CFLAGS) $(LIBXML_CFLAGS) $(AM_CFLAGS)
-wayland_scanner_LDADD = $(EXPAT_LIBS) $(LIBXML_LIBS) libwayland-util.la
-pkgconfig_DATA += src/wayland-scanner.pc
-
-if DTD_VALIDATION
-wayland_scanner_SOURCES += src/dtddata.S
-endif
-src/dtddata.o: protocol/wayland.dtd
-
-if USE_HOST_SCANNER
-wayland_scanner = wayland-scanner
-else
-$(BUILT_SOURCES) : wayland-scanner
-wayland_scanner = $(top_builddir)/wayland-scanner
-endif
-
-libwayland_util_la_CFLAGS = $(AM_CFLAGS)
-libwayland_util_la_SOURCES = \
- src/wayland-util.c \
- src/wayland-util.h
-
-noinst_LTLIBRARIES = libwayland-util.la
-
-if ENABLE_LIBRARIES
-noinst_LTLIBRARIES += libwayland-private.la
-lib_LTLIBRARIES = libwayland-server.la libwayland-client.la
-
-libwayland_private_la_CFLAGS = $(FFI_CFLAGS) $(AM_CFLAGS)
-libwayland_private_la_SOURCES = \
- src/connection.c \
- src/wayland-os.c \
- src/wayland-os.h \
- src/wayland-private.h \
- src/wayland-server-private.h
-
-include_HEADERS = \
- src/wayland-util.h \
- src/wayland-server.h \
- src/wayland-server-core.h \
- src/wayland-client.h \
- src/wayland-client-core.h \
- src/wayland-version.h
-
-nodist_include_HEADERS = \
- protocol/wayland-server-protocol.h \
- protocol/wayland-client-protocol.h
-
-libwayland_server_la_CFLAGS = $(FFI_CFLAGS) $(AM_CFLAGS) -pthread
-libwayland_server_la_LIBADD = $(FFI_LIBS) libwayland-private.la libwayland-util.la $(RT_LIBS) -lm
-libwayland_server_la_LDFLAGS = -version-info 1:0:1
-libwayland_server_la_SOURCES = \
- src/wayland-server.c \
- src/wayland-shm.c \
- src/event-loop.c
-
-nodist_libwayland_server_la_SOURCES = \
- protocol/wayland-server-protocol.h \
- protocol/wayland-protocol.c
-
-libwayland_client_la_CFLAGS = $(FFI_CFLAGS) $(AM_CFLAGS) -pthread
-libwayland_client_la_LIBADD = $(FFI_LIBS) libwayland-private.la libwayland-util.la $(RT_LIBS) -lm
-libwayland_client_la_LDFLAGS = -version-info 3:0:3
-libwayland_client_la_SOURCES = \
- src/wayland-client.c
-
-nodist_libwayland_client_la_SOURCES = \
- protocol/wayland-client-protocol.h \
- protocol/wayland-protocol.c
-
-pkgconfig_DATA += src/wayland-client.pc src/wayland-server.pc
-
-protocol/%-protocol.c : $(top_srcdir)/protocol/%.xml
-if USE_HOST_SCANNER
- $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s code $< $@
-else
- $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s public-code $< $@
-endif
-
-protocol/%-server-protocol.h : $(top_srcdir)/protocol/%.xml
- $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s server-header $< $@
-
-protocol/%-client-protocol.h : $(top_srcdir)/protocol/%.xml
- $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s client-header $< $@
-
-protocol/%-server-protocol-core.h : $(top_srcdir)/protocol/%.xml
- $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s server-header -c < $< > $@
-
-protocol/%-client-protocol-core.h : $(top_srcdir)/protocol/%.xml
- $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s client-header -c < $< > $@
-
-BUILT_SOURCES = \
- $(nodist_libwayland_server_la_SOURCES) \
- $(nodist_libwayland_client_la_SOURCES) \
- $(nodist_headers_test_SOURCES) \
- $(nodist_display_test_SOURCES)
-
-CLEANFILES = $(BUILT_SOURCES) doc/doxygen/doxygen_sqlite3.db
-DISTCLEANFILES = src/wayland-version.h
-EXTRA_DIST = CONTRIBUTING.md
-
-
-
-lib_LTLIBRARIES += libwayland-cursor.la
-
-include_HEADERS += cursor/wayland-cursor.h
-
-libwayland_cursor_la_SOURCES = \
- cursor/wayland-cursor.c \
- cursor/os-compatibility.c \
- cursor/os-compatibility.h \
- cursor/cursor-data.h \
- cursor/xcursor.c \
- cursor/xcursor.h
-libwayland_cursor_la_LIBADD = libwayland-client.la
-
-pkgconfig_DATA += cursor/wayland-cursor.pc
-
-libwayland_cursor_la_CFLAGS = \
- $(AM_CFLAGS) \
- -I$(top_builddir)/src \
- -I$(top_srcdir)/src \
- -DICONDIR=\"$(ICONDIR)\"
-
-lib_LTLIBRARIES += libwayland-egl.la
-
-include_HEADERS += egl/wayland-egl.h
-include_HEADERS += egl/wayland-egl-core.h
-
-libwayland_egl_la_SOURCES = egl/wayland-egl.c
-libwayland_egl_la_LDFLAGS = -version-info 1
-
-pkgconfig_DATA += egl/wayland-egl.pc
-
-## XXX: backend interface
-include_HEADERS += egl/wayland-egl-backend.h
-pkgconfig_DATA += egl/wayland-egl-backend.pc
-
-built_test_programs = \
- array-test \
- client-test \
- display-test \
- connection-test \
- event-loop-test \
- fixed-test \
- interface-test \
- list-test \
- map-test \
- os-wrappers-test \
- sanity-test \
- socket-test \
- queue-test \
- proxy-test \
- signal-test \
- newsignal-test \
- resources-test \
- message-test \
- headers-test \
- compositor-introspection-test \
- protocol-logger-test \
- wayland-egl-abi-check
-
-EXTRA_DIST += egl/wayland-egl-symbols-check
-
-check_PROGRAMS = wayland-egl-abi-check
-wayland_egl_abi_check_SOURCES = egl/wayland-egl-abi-check.c
-
-if ENABLE_CPP_TEST
-built_test_programs += cpp-compile-test
-endif
-
-AM_TESTS_ENVIRONMENT = \
- export WAYLAND_SCANNER='$(top_builddir)/wayland-scanner' \
- TEST_DATA_DIR='$(top_srcdir)/tests/data' \
- TEST_OUTPUT_DIR='$(top_builddir)/tests/output' \
- WAYLAND_EGL_LIB='$(top_builddir)/.libs/libwayland-egl.so' \
- SED=$(SED) \
- NM='$(NM)' \
- ;
-
-TESTS = $(built_test_programs) \
- egl/wayland-egl-symbols-check \
- tests/scanner-test.sh
-
-noinst_PROGRAMS = \
- $(built_test_programs) \
- exec-fd-leak-checker \
- fixed-benchmark
-
-noinst_LTLIBRARIES += \
- libtest-runner.la \
- libtest-helpers.la
-
-libtest_helpers_la_SOURCES = tests/test-helpers.c
-
-libtest_runner_la_SOURCES = \
- tests/test-runner.c \
- tests/test-runner.h \
- tests/test-compositor.h \
- tests/test-compositor.c
-libtest_runner_la_LIBADD = \
- libwayland-private.la \
- libwayland-util.la \
- libwayland-client.la \
- libwayland-server.la \
- libtest-helpers.la \
- $(RT_LIBS) $(DL_LIBS) $(FFI_LIBS)
-
-array_test_SOURCES = tests/array-test.c
-array_test_LDADD = libtest-runner.la
-client_test_SOURCES = tests/client-test.c
-client_test_LDADD = libtest-runner.la
-display_test_CFLAGS = -pthread
-display_test_SOURCES = tests/display-test.c
-display_test_LDADD = libtest-runner.la
-nodist_display_test_SOURCES = \
- protocol/tests-server-protocol.h \
- protocol/tests-client-protocol.h \
- protocol/tests-protocol.c
-connection_test_SOURCES = tests/connection-test.c
-connection_test_LDADD = libtest-runner.la
-event_loop_test_SOURCES = tests/event-loop-test.c
-event_loop_test_LDADD = libtest-runner.la
-fixed_test_SOURCES = tests/fixed-test.c
-fixed_test_LDADD = libtest-runner.la
-interface_test_SOURCES = tests/interface-test.c
-interface_test_LDADD = libtest-runner.la
-list_test_SOURCES = tests/list-test.c
-list_test_LDADD = libtest-runner.la
-map_test_SOURCES = tests/map-test.c
-map_test_LDADD = libtest-runner.la
-sanity_test_SOURCES = tests/sanity-test.c
-sanity_test_LDADD = libtest-runner.la
-socket_test_SOURCES = tests/socket-test.c
-socket_test_LDADD = libtest-runner.la
-queue_test_SOURCES = tests/queue-test.c
-queue_test_LDADD = libtest-runner.la
-proxy_test_SOURCES = tests/proxy-test.c
-proxy_test_LDADD = libtest-runner.la
-signal_test_SOURCES = tests/signal-test.c
-signal_test_LDADD = libtest-runner.la
-# wayland-server.c is needed here to access wl_priv_* functions
-newsignal_test_SOURCES = tests/newsignal-test.c src/wayland-server.c
-newsignal_test_LDADD = libtest-runner.la
-resources_test_SOURCES = tests/resources-test.c
-resources_test_LDADD = libtest-runner.la
-message_test_SOURCES = tests/message-test.c
-message_test_LDADD = libtest-runner.la
-compositor_introspection_test_SOURCES = tests/compositor-introspection-test.c
-compositor_introspection_test_LDADD = libtest-runner.la
-protocol_logger_test_SOURCES = tests/protocol-logger-test.c
-protocol_logger_test_LDADD = libtest-runner.la
-headers_test_SOURCES = tests/headers-test.c \
- tests/headers-protocol-test.c \
- tests/headers-protocol-core-test.c
-nodist_headers_test_SOURCES = \
- protocol/wayland-server-protocol-core.h \
- protocol/wayland-client-protocol-core.h
-
-if ENABLE_CPP_TEST
-cpp_compile_test_SOURCES = tests/cpp-compile-test.cpp
-endif
-
-fixed_benchmark_SOURCES = tests/fixed-benchmark.c
-fixed_benchmark_LDADD = $(RT_LIBS)
-
-os_wrappers_test_SOURCES = tests/os-wrappers-test.c
-os_wrappers_test_LDADD = libtest-runner.la
-
-exec_fd_leak_checker_SOURCES = tests/exec-fd-leak-checker.c
-exec_fd_leak_checker_LDADD = libtest-helpers.la
-
-EXTRA_DIST += tests/scanner-test.sh \
- protocol/tests.xml \
- tests/data/bad-identifier-arg.xml \
- tests/data/bad-identifier-entry.xml \
- tests/data/bad-identifier-enum.xml \
- tests/data/bad-identifier-event.xml \
- tests/data/bad-identifier-interface.xml \
- tests/data/bad-identifier-protocol.xml \
- tests/data/bad-identifier-request.xml \
- tests/data/example.xml \
- tests/data/example-client.h \
- tests/data/example-server.h \
- tests/data/example-code.c \
- tests/data/small.xml \
- tests/data/small-code.c \
- tests/data/small-client.h \
- tests/data/small-server.h \
- tests/data/small-code-core.c \
- tests/data/small-client-core.h \
- tests/data/small-server-core.h \
- tests/data/small-private-code.c \
- meson.build \
- meson_options.txt \
- cursor/meson.build \
- doc/meson.build \
- doc/doxygen/mainpage.dox \
- doc/doxygen/meson.build \
- doc/doxygen/gen-doxygen.py \
- doc/doxygen/xml/meson.build \
- doc/doxygen/xml/Client/meson.build \
- doc/doxygen/xml/Server/meson.build \
- doc/publican/meson.build \
- doc/publican/sources/meson.build \
- egl/meson.build \
- src/meson.build \
- tests/meson.build
-
-tests/scanner-test.sh: $(top_builddir)/wayland-scanner
-
-clean-local:
- -rm -rf tests/output
-
-endif #ENABLE_LIBRARIES
diff --git a/README b/README.md
index ad06dce..437b39d 100644
--- a/README
+++ b/README.md
@@ -1,4 +1,4 @@
-What is Wayland?
+# Wayland
Wayland is a project to define a protocol for a compositor to talk to
its clients as well as a library implementation of the protocol. The
@@ -17,10 +17,6 @@ protocol does not handle rendering, which is one of the features that
makes wayland so simple. All clients are expected to handle rendering
themselves, typically through cairo or OpenGL.
-The weston compositor is a reference implementation of a wayland
-compositor and the weston repository also includes a few example
-clients.
-
Building the wayland libraries is fairly simple, aside from libffi,
they don't have many dependencies:
@@ -29,6 +25,6 @@ they don't have many dependencies:
$ meson build/ --prefix=PREFIX
$ ninja -C build/ install
-where PREFIX is where you want to install the libraries. See
-https://wayland.freedesktop.org for more complete build instructions
-for wayland, weston, xwayland and various toolkits.
+where PREFIX is where you want to install the libraries.
+
+See https://wayland.freedesktop.org for documentation.
diff --git a/autogen.sh b/autogen.sh
deleted file mode 100755
index 916169a..0000000
--- a/autogen.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#! /bin/sh
-
-test -n "$srcdir" || srcdir=`dirname "$0"`
-test -n "$srcdir" || srcdir=.
-(
- cd "$srcdir" &&
- autoreconf --force -v --install
-) || exit
-test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
diff --git a/configure.ac b/configure.ac
deleted file mode 100644
index 7f2f393..0000000
--- a/configure.ac
+++ /dev/null
@@ -1,202 +0,0 @@
-AC_PREREQ([2.64])
-
-m4_define([wayland_major_version], [1])
-m4_define([wayland_minor_version], [19])
-m4_define([wayland_micro_version], [0])
-m4_define([wayland_version],
- [wayland_major_version.wayland_minor_version.wayland_micro_version])
-
-AC_INIT([wayland],
- [wayland_version],
- [https://gitlab.freedesktop.org/wayland/wayland/issues/],
- [wayland],
- [https://wayland.freedesktop.org/])
-
-AC_SUBST([WAYLAND_VERSION_MAJOR], [wayland_major_version])
-AC_SUBST([WAYLAND_VERSION_MINOR], [wayland_minor_version])
-AC_SUBST([WAYLAND_VERSION_MICRO], [wayland_micro_version])
-AC_SUBST([WAYLAND_VERSION], [wayland_version])
-
-AC_CONFIG_HEADERS([config.h])
-AC_CONFIG_MACRO_DIR([m4])
-
-AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects])
-
-AM_SILENT_RULES([yes])
-
-# Check for programs
-AC_PROG_CC
-AC_PROG_CXX
-AC_PROG_GREP
-AM_PROG_AS
-AC_PROG_NM
-
-# check if we have C++ compiler. This is hacky workaround,
-# for a reason why it is this way see
-# http://lists.gnu.org/archive/html/bug-autoconf/2010-05/msg00001.html
-have_cpp_compiler=yes
-
-if ! which "$CXX" &>/dev/null; then
- have_cpp_compiler=no
-fi
-
-AM_CONDITIONAL(ENABLE_CPP_TEST, test "x$have_cpp_compiler" = "xyes")
-
-# Initialize libtool
-LT_PREREQ([2.2])
-LT_INIT([disable-static])
-
-PKG_PROG_PKG_CONFIG()
-
-AC_ARG_ENABLE([fatal-warnings],
- AC_HELP_STRING([--enable-fatal-warnings],
- [Build with -Werror]),
- [enable_fatal_warnings=$enableval],
- [enable_fatal_warnings=no])
-AS_IF([test x"$enable_fatal_warnings" != "xno"], [
- WERROR_CFLAGS="-Werror"
-])
-
-if test "x$GCC" = "xyes"; then
- GCC_CFLAGS="$WERROR_CFLAGS -Wall -Wextra -Wno-unused-parameter -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden"
-fi
-AC_SUBST(GCC_CFLAGS)
-
-AC_CHECK_HEADERS([sys/prctl.h])
-AC_CHECK_FUNCS([accept4 mkostemp posix_fallocate prctl memfd_create strndup])
-
-# *BSD don't have libdl, but they have its functions in libc
-WESTON_SEARCH_LIBS([DL], [dl], [dlsym])
-
-# OpenBSD doesn't have librt, but it has its functions in libc
-WESTON_SEARCH_LIBS([RT], [rt], [clock_gettime])
-
-AC_ARG_ENABLE([libraries],
- [AC_HELP_STRING([--disable-libraries],
- [Disable compilation of wayland libraries])],
- [],
- [enable_libraries=yes])
-
-AC_ARG_WITH([host-scanner],
- [AC_HELP_STRING([--with-host-scanner],
- [Use installed wayland-scanner from host PATH during build])],
- [],
- [with_host_scanner=no])
-
-AC_ARG_ENABLE([documentation],
- [AC_HELP_STRING([--disable-documentation],
- [Disable building the documentation])],
- [],
- [enable_documentation=yes])
-
-AC_ARG_ENABLE([dtd-validation],
- [AC_HELP_STRING([--disable-dtd-validation],
- [Disable DTD validation of the protocol])],
- [],
- [enable_dtd_validation=yes])
-
-AM_CONDITIONAL(USE_HOST_SCANNER, test "x$with_host_scanner" = xyes)
-
-AM_CONDITIONAL(ENABLE_LIBRARIES, test "x$enable_libraries" = xyes)
-
-AC_ARG_WITH(icondir, [ --with-icondir=<dir> Look for cursor icons here],
- [ ICONDIR=$withval],
- [ ICONDIR=${datadir}/icons])
-AC_SUBST([ICONDIR])
-
-if test "x$enable_libraries" = "xyes"; then
- PKG_CHECK_MODULES(FFI, [libffi])
- AC_CHECK_DECL(SFD_CLOEXEC,[],
- [AC_MSG_ERROR("SFD_CLOEXEC is needed to compile wayland libraries")],
- [[#include <sys/signalfd.h>]])
- AC_CHECK_DECL(TFD_CLOEXEC,[],
- [AC_MSG_ERROR("TFD_CLOEXEC is needed to compile wayland libraries")],
- [[#include <sys/timerfd.h>]])
- AC_CHECK_DECL(CLOCK_MONOTONIC,[],
- [AC_MSG_ERROR("CLOCK_MONOTONIC is needed to compile wayland libraries")],
- [[#include <time.h>]])
-fi
-
-PKG_CHECK_MODULES(EXPAT, [expat])
-
-AM_CONDITIONAL([DTD_VALIDATION], [test "x$enable_dtd_validation" = "xyes"])
-if test "x$enable_dtd_validation" = "xyes"; then
- PKG_CHECK_MODULES(LIBXML, [libxml-2.0])
- AC_DEFINE(HAVE_LIBXML, 1, [libxml-2.0 is available])
- AC_CONFIG_LINKS([src/wayland.dtd.embed:protocol/wayland.dtd])
-fi
-
-AC_PATH_PROG(XSLTPROC, xsltproc)
-AM_CONDITIONAL([HAVE_XSLTPROC], [test "x$XSLTPROC" != "x"])
-
-
-AM_CONDITIONAL(BUILD_DOCS, [test x$enable_documentation = xyes])
-if test "x$enable_documentation" = "xyes"; then
- AC_PATH_PROG(DOXYGEN, doxygen)
-
- if test "x$DOXYGEN" = "x"; then
- AC_MSG_ERROR([Documentation build requested but doxygen not found. Install doxygen or disable the documentation using --disable-documentation])
- fi
-
- AC_MSG_CHECKING([for compatible doxygen version])
- doxygen_version=`$DOXYGEN --version`
- AS_VERSION_COMPARE([$doxygen_version], [1.6.0],
- [AC_MSG_RESULT([no])
- AC_MSG_ERROR([Doxygen $doxygen_version too old. Doxygen 1.6+ required for documentation build. Install required doxygen version or disable the documentation using --disable-documentation])],
- [AC_MSG_RESULT([yes])],
- [AC_MSG_RESULT([yes])])
-
- AC_PATH_PROG(XMLTO, xmlto)
-
- if test "x$XMLTO" = "x"; then
- AC_MSG_ERROR([Documentation build requested but xmlto not found. Install xmlto or disable the documentation using --disable-documentation])
- fi
-
- AC_PATH_PROG(DOT, dot)
- if test "x$DOT" = "x"; then
- AC_MSG_ERROR([Documentation build requested but graphviz's dot not found. Install graphviz or disable the documentation using --disable-documentation])
- fi
- AC_MSG_CHECKING([for compatible dot version])
- dot_version=`$DOT -V 2>&1|$GREP -o ['[0-9]*\.[0-9]*\.[0-9]*']`
- AS_VERSION_COMPARE([$dot_version], [2.26.0],
- [AC_MSG_RESULT([no])
- AC_MSG_ERROR([Graphviz dot $dot_version too old. Graphviz 2.26+ required for documentation build. Install required graphviz version or disable the documentation using --disable-documentation])],
- [AC_MSG_RESULT([yes])],
- [AC_MSG_RESULT([yes])])
-
- AC_MSG_CHECKING([for docbook stylesheets])
- DOCS_STYLESHEET=http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl
- AC_PATH_PROGS_FEATURE_CHECK([XSLTPROC_TMP], [xsltproc],
- AS_IF([`"$ac_path_XSLTPROC_TMP" --nonet "$DOCS_STYLESHEET" > /dev/null 2>&1`],
- [HAVE_DOCS_STYLESHEET=yes]))
- if test "x$HAVE_DOCS_STYLESHEET" != "xyes"; then
- AC_MSG_RESULT([no])
- AC_MSG_ERROR([Documentation build requested but docbook-xsl stylesheets are not found. Install the docbook-xsl package or disable the documentation using --disable-documentation])
- fi
-
- AC_MSG_RESULT([yes])
- AC_SUBST(DOCS_STYLESHEET)
-
- AC_CONFIG_FILES([
- doc/doxygen/wayland.doxygen
- ])
-
-fi
-AM_CONDITIONAL([HAVE_XMLTO], [test "x$XMLTO" != "x"])
-
-AC_CONFIG_FILES([Makefile
- cursor/wayland-cursor.pc
- cursor/wayland-cursor-uninstalled.pc
- doc/Makefile
- doc/publican/Makefile
- doc/doxygen/Makefile
- egl/wayland-egl.pc
- egl/wayland-egl-backend.pc
- src/wayland-server-uninstalled.pc
- src/wayland-client-uninstalled.pc
- src/wayland-scanner-uninstalled.pc
- src/wayland-server.pc
- src/wayland-client.pc
- src/wayland-scanner.pc
- src/wayland-version.h])
-AC_OUTPUT
diff --git a/cursor/meson.build b/cursor/meson.build
index ae85ed9..f7d82e4 100644
--- a/cursor/meson.build
+++ b/cursor/meson.build
@@ -3,6 +3,15 @@ if icondir == ''
icondir = join_paths(get_option('prefix'), get_option('datadir'), 'icons')
endif
+if wayland_version[0] != '1'
+ # The versioning used for the shared libraries assumes that the major
+ # version of Wayland as a whole will increase to 2 if and only if there
+ # is an ABI break, at which point we should probably bump the SONAME of
+ # all libraries to .so.2. For more details see
+ # https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/177
+ error('We probably need to bump the SONAME of libwayland-cursor')
+endif
+
wayland_cursor = library(
'wayland-cursor',
sources: [
@@ -10,7 +19,9 @@ wayland_cursor = library(
'os-compatibility.c',
'xcursor.c',
],
- version: '0.0.0',
+ # To avoid an unnecessary SONAME bump, wayland 1.x.y produces
+ # libwayland-cursor.so.0.x.y.
+ version: '.'.join(['0', wayland_version[1], wayland_version[2]]),
dependencies: [ wayland_client_dep ],
c_args: [ '-DICONDIR="@0@"'.format(icondir) ],
install: true,
@@ -25,3 +36,12 @@ pkgconfig.generate(
libraries: wayland_cursor,
filebase: 'wayland-cursor',
)
+
+wayland_cursor_dep = declare_dependency(
+ link_with: wayland_cursor,
+ include_directories: [ root_inc, include_directories('.') ],
+)
+
+if meson.version().version_compare('>= 0.54.0')
+ meson.override_dependency('wayland-cursor', wayland_cursor_dep)
+endif
diff --git a/cursor/os-compatibility.c b/cursor/os-compatibility.c
index 8d51e52..f2445ce 100644
--- a/cursor/os-compatibility.c
+++ b/cursor/os-compatibility.c
@@ -31,7 +31,9 @@
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
+#include <signal.h>
#include <string.h>
+#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_MEMFD_CREATE
@@ -118,6 +120,7 @@ os_create_anonymous_file(off_t size)
static const char template[] = "/wayland-cursor-shared-XXXXXX";
const char *path;
char *name;
+ size_t name_size;
int fd;
#ifdef HAVE_MEMFD_CREATE
@@ -134,17 +137,17 @@ os_create_anonymous_file(off_t size)
#endif
{
path = getenv("XDG_RUNTIME_DIR");
- if (!path) {
+ if (!path || path[0] != '/') {
errno = ENOENT;
return -1;
}
- name = malloc(strlen(path) + sizeof(template));
+ name_size = strlen(path) + sizeof(template);
+ name = malloc(name_size);
if (!name)
return -1;
- strcpy(name, path);
- strcat(name, template);
+ snprintf(name, name_size, "%s%s", path, template);
fd = create_tmpfile_cloexec(name);
@@ -166,11 +169,28 @@ int
os_resize_anonymous_file(int fd, off_t size)
{
#ifdef HAVE_POSIX_FALLOCATE
- /*
- * Filesystems that do support fallocate will return EINVAL or
+ sigset_t mask;
+ sigset_t old_mask;
+
+ /*
+ * posix_fallocate() might be interrupted, so we need to check
+ * for EINTR and retry in that case.
+ * However, in the presence of an alarm, the interrupt may trigger
+ * repeatedly and prevent a large posix_fallocate() to ever complete
+ * successfully, so we need to first block SIGALRM to prevent
+ * this.
+ */
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGALRM);
+ sigprocmask(SIG_BLOCK, &mask, &old_mask);
+ /*
+ * Filesystems that do not support fallocate will return EINVAL or
* EOPNOTSUPP. In this case we need to fall back to ftruncate
*/
- errno = posix_fallocate(fd, 0, size);
+ do {
+ errno = posix_fallocate(fd, 0, size);
+ } while (errno == EINTR);
+ sigprocmask(SIG_SETMASK, &old_mask, NULL);
if (errno == 0)
return 0;
else if (errno != EINVAL && errno != EOPNOTSUPP)
diff --git a/cursor/wayland-cursor-uninstalled.pc.in b/cursor/wayland-cursor-uninstalled.pc.in
deleted file mode 100644
index f52b113..0000000
--- a/cursor/wayland-cursor-uninstalled.pc.in
+++ /dev/null
@@ -1,8 +0,0 @@
-libdir=@abs_builddir@/.libs
-includedir=@abs_srcdir@
-
-Name: Wayland Cursor
-Description: Wayland cursor helper library (not installed)
-Version: @WAYLAND_VERSION@
-Cflags: -I${includedir}
-Libs: -L${libdir} -lwayland-cursor
diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c
index 4e2dc50..156f0a8 100644
--- a/cursor/wayland-cursor.c
+++ b/cursor/wayland-cursor.c
@@ -92,7 +92,7 @@ shm_pool_resize(struct shm_pool *pool, int size)
pool->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
pool->fd, 0);
- if (pool->data == (void *)-1)
+ if (pool->data == MAP_FAILED)
return 0;
pool->size = size;
@@ -129,7 +129,6 @@ struct wl_cursor_theme {
struct wl_cursor **cursors;
struct wl_shm *shm;
struct shm_pool *pool;
- char *name;
int size;
};
@@ -152,32 +151,32 @@ struct cursor {
* the returned buffer.
*/
WL_EXPORT struct wl_buffer *
-wl_cursor_image_get_buffer(struct wl_cursor_image *_img)
+wl_cursor_image_get_buffer(struct wl_cursor_image *image)
{
- struct cursor_image *image = (struct cursor_image *) _img;
- struct wl_cursor_theme *theme = image->theme;
+ struct cursor_image *img = (struct cursor_image *) image;
+ struct wl_cursor_theme *theme = img->theme;
- if (!image->buffer) {
- image->buffer =
+ if (!img->buffer) {
+ img->buffer =
wl_shm_pool_create_buffer(theme->pool->pool,
- image->offset,
- _img->width, _img->height,
- _img->width * 4,
+ img->offset,
+ image->width, image->height,
+ image->width * 4,
WL_SHM_FORMAT_ARGB8888);
};
- return image->buffer;
+ return img->buffer;
}
static void
-wl_cursor_image_destroy(struct wl_cursor_image *_img)
+wl_cursor_image_destroy(struct wl_cursor_image *image)
{
- struct cursor_image *image = (struct cursor_image *) _img;
+ struct cursor_image *img = (struct cursor_image *) image;
- if (image->buffer)
- wl_buffer_destroy(image->buffer);
+ if (img->buffer)
+ wl_buffer_destroy(img->buffer);
- free(image);
+ free(img);
}
static void
@@ -252,13 +251,10 @@ err_free_cursor:
}
static void
-load_default_theme(struct wl_cursor_theme *theme)
+load_fallback_theme(struct wl_cursor_theme *theme)
{
uint32_t i;
- free(theme->name);
- theme->name = strdup("default");
-
theme->cursor_count = ARRAY_LENGTH(cursor_metadata);
theme->cursors = malloc(theme->cursor_count * sizeof(*theme->cursors));
@@ -278,7 +274,7 @@ load_default_theme(struct wl_cursor_theme *theme)
}
static struct wl_cursor *
-wl_cursor_create_from_xcursor_images(XcursorImages *images,
+wl_cursor_create_from_xcursor_images(struct xcursor_images *images,
struct wl_cursor_theme *theme)
{
struct cursor *cursor;
@@ -339,13 +335,13 @@ wl_cursor_create_from_xcursor_images(XcursorImages *images,
}
static void
-load_callback(XcursorImages *images, void *data)
+load_callback(struct xcursor_images *images, void *data)
{
struct wl_cursor_theme *theme = data;
struct wl_cursor *cursor;
if (wl_cursor_theme_get_cursor(theme, images->name)) {
- XcursorImagesDestroy(images);
+ xcursor_images_destroy(images);
return;
}
@@ -365,7 +361,7 @@ load_callback(XcursorImages *images, void *data)
}
}
- XcursorImagesDestroy(images);
+ xcursor_images_destroy(images);
}
/** Load a cursor theme to memory shared with the compositor
@@ -391,9 +387,6 @@ wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm)
if (!name)
name = "default";
- theme->name = strdup(name);
- if (!theme->name)
- goto out_error_name;
theme->size = size;
theme->cursor_count = 0;
theme->cursors = NULL;
@@ -405,13 +398,14 @@ wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm)
xcursor_load_theme(name, size, load_callback, theme);
if (theme->cursor_count == 0)
- load_default_theme(theme);
+ xcursor_load_theme(NULL, size, load_callback, theme);
+
+ if (theme->cursor_count == 0)
+ load_fallback_theme(theme);
return theme;
out_error_pool:
- free(theme->name);
-out_error_name:
free(theme);
return NULL;
}
@@ -430,7 +424,6 @@ wl_cursor_theme_destroy(struct wl_cursor_theme *theme)
shm_pool_destroy(theme->pool);
- free(theme->name);
free(theme->cursors);
free(theme);
}
@@ -468,21 +461,21 @@ wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme,
* given time in the cursor animation.
*/
WL_EXPORT int
-wl_cursor_frame_and_duration(struct wl_cursor *_cursor, uint32_t time,
+wl_cursor_frame_and_duration(struct wl_cursor *cursor, uint32_t time,
uint32_t *duration)
{
- struct cursor *cursor = (struct cursor *) _cursor;
+ struct cursor *cur = (struct cursor *) cursor;
uint32_t t;
int i;
- if (cursor->cursor.image_count == 1) {
+ if (cur->cursor.image_count == 1 || cur->total_delay == 0) {
if (duration)
*duration = 0;
return 0;
}
i = 0;
- t = time % cursor->total_delay;
+ t = time % cur->total_delay;
/* If there is a 0 delay in the image set then this
* loop breaks on it and we display that cursor until
@@ -491,8 +484,8 @@ wl_cursor_frame_and_duration(struct wl_cursor *_cursor, uint32_t time,
* seen one in a cursor file, we haven't bothered to
* "fix" this.
*/
- while (t - cursor->cursor.images[i]->delay < t)
- t -= cursor->cursor.images[i++]->delay;
+ while (t - cur->cursor.images[i]->delay < t)
+ t -= cur->cursor.images[i++]->delay;
if (!duration)
return i;
@@ -500,10 +493,10 @@ wl_cursor_frame_and_duration(struct wl_cursor *_cursor, uint32_t time,
/* Make sure we don't accidentally tell the caller this is
* a static cursor image.
*/
- if (t >= cursor->cursor.images[i]->delay)
+ if (t >= cur->cursor.images[i]->delay)
*duration = 1;
else
- *duration = cursor->cursor.images[i]->delay - t;
+ *duration = cur->cursor.images[i]->delay - t;
return i;
}
@@ -517,7 +510,7 @@ wl_cursor_frame_and_duration(struct wl_cursor *_cursor, uint32_t time,
* given time in the cursor animation.
*/
WL_EXPORT int
-wl_cursor_frame(struct wl_cursor *_cursor, uint32_t time)
+wl_cursor_frame(struct wl_cursor *cursor, uint32_t time)
{
- return wl_cursor_frame_and_duration(_cursor, time, NULL);
+ return wl_cursor_frame_and_duration(cursor, time, NULL);
}
diff --git a/cursor/wayland-cursor.pc.in b/cursor/wayland-cursor.pc.in
deleted file mode 100644
index fbbf5ff..0000000
--- a/cursor/wayland-cursor.pc.in
+++ /dev/null
@@ -1,10 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: Wayland Cursor
-Description: Wayland cursor helper library
-Version: @WAYLAND_VERSION@
-Cflags: -I${includedir}
-Libs: -L${libdir} -lwayland-cursor
diff --git a/cursor/xcursor.c b/cursor/xcursor.c
index 1f1360f..43a5292 100644
--- a/cursor/xcursor.c
+++ b/cursor/xcursor.c
@@ -23,20 +23,15 @@
* SOFTWARE.
*/
+#define _GNU_SOURCE
#include "xcursor.h"
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
/*
- * From libXcursor/include/X11/extensions/Xcursor.h
- */
-
-#define XcursorTrue 1
-#define XcursorFalse 0
-
-/*
* Cursor files start with a header. The header
* contains a magic number, a version number and a
* table of contents which has type and offset information
@@ -67,43 +62,31 @@
* CARD32 position absolute file position
*/
-#define XCURSOR_MAGIC 0x72756358 /* "Xcur" LSBFirst */
-
-/*
- * Current Xcursor version number. Will be substituted by configure
- * from the version in the libXcursor configure.ac file.
- */
-
-#define XCURSOR_LIB_MAJOR 1
-#define XCURSOR_LIB_MINOR 1
-#define XCURSOR_LIB_REVISION 13
-#define XCURSOR_LIB_VERSION ((XCURSOR_LIB_MAJOR * 10000) + \
- (XCURSOR_LIB_MINOR * 100) + \
- (XCURSOR_LIB_REVISION))
+#define XCURSOR_MAGIC 0x72756358 /* "Xcur" LSBFirst */
/*
* This version number is stored in cursor files; changes to the
* file format require updating this version number
*/
-#define XCURSOR_FILE_MAJOR 1
-#define XCURSOR_FILE_MINOR 0
-#define XCURSOR_FILE_VERSION ((XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR))
-#define XCURSOR_FILE_HEADER_LEN (4 * 4)
-#define XCURSOR_FILE_TOC_LEN (3 * 4)
-
-typedef struct _XcursorFileToc {
- XcursorUInt type; /* chunk type */
- XcursorUInt subtype; /* subtype (size for images) */
- XcursorUInt position; /* absolute position in file */
-} XcursorFileToc;
-
-typedef struct _XcursorFileHeader {
- XcursorUInt magic; /* magic number */
- XcursorUInt header; /* byte length of header */
- XcursorUInt version; /* file version number */
- XcursorUInt ntoc; /* number of toc entries */
- XcursorFileToc *tocs; /* table of contents */
-} XcursorFileHeader;
+#define XCURSOR_FILE_MAJOR 1
+#define XCURSOR_FILE_MINOR 0
+#define XCURSOR_FILE_VERSION ((XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR))
+#define XCURSOR_FILE_HEADER_LEN (4 * 4)
+#define XCURSOR_FILE_TOC_LEN (3 * 4)
+
+struct xcursor_file_toc {
+ uint32_t type; /* chunk type */
+ uint32_t subtype; /* subtype (size for images) */
+ uint32_t position; /* absolute position in file */
+};
+
+struct xcursor_file_header {
+ uint32_t magic; /* magic number */
+ uint32_t header; /* byte length of header */
+ uint32_t version; /* file version number */
+ uint32_t ntoc; /* number of toc entries */
+ struct xcursor_file_toc *tocs; /* table of contents */
+};
/*
* The rest of the file is a list of chunks, each tagged by type
@@ -121,42 +104,14 @@ typedef struct _XcursorFileHeader {
* CARD32 version chunk type version
*/
-#define XCURSOR_CHUNK_HEADER_LEN (4 * 4)
+#define XCURSOR_CHUNK_HEADER_LEN (4 * 4)
-typedef struct _XcursorChunkHeader {
- XcursorUInt header; /* bytes in chunk header */
- XcursorUInt type; /* chunk type */
- XcursorUInt subtype; /* chunk subtype (size for images) */
- XcursorUInt version; /* version of this type */
-} XcursorChunkHeader;
-
-/*
- * Here's a list of the known chunk types
- */
-
-/*
- * Comments consist of a 4-byte length field followed by
- * UTF-8 encoded text
- *
- * Comment:
- * ChunkHeader header chunk header
- * CARD32 length bytes in text
- * LISTofCARD8 text UTF-8 encoded text
- */
-
-#define XCURSOR_COMMENT_TYPE 0xfffe0001
-#define XCURSOR_COMMENT_VERSION 1
-#define XCURSOR_COMMENT_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (1 *4))
-#define XCURSOR_COMMENT_COPYRIGHT 1
-#define XCURSOR_COMMENT_LICENSE 2
-#define XCURSOR_COMMENT_OTHER 3
-#define XCURSOR_COMMENT_MAX_LEN 0x100000
-
-typedef struct _XcursorComment {
- XcursorUInt version;
- XcursorUInt comment_type;
- char *comment;
-} XcursorComment;
+struct xcursor_chunk_header {
+ uint32_t header; /* bytes in chunk header */
+ uint32_t type; /* chunk type */
+ uint32_t subtype; /* chunk subtype (size for images) */
+ uint32_t version; /* version of this type */
+};
/*
* Each cursor image occupies a separate image chunk.
@@ -174,439 +129,354 @@ typedef struct _XcursorComment {
* LISTofCARD32 pixels ARGB pixels
*/
-#define XCURSOR_IMAGE_TYPE 0xfffd0002
-#define XCURSOR_IMAGE_VERSION 1
-#define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5*4))
-#define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */
-
-typedef struct _XcursorFile XcursorFile;
-
-struct _XcursorFile {
- void *closure;
- int (*read) (XcursorFile *file, unsigned char *buf, int len);
- int (*write) (XcursorFile *file, unsigned char *buf, int len);
- int (*seek) (XcursorFile *file, long offset, int whence);
-};
-
-typedef struct _XcursorComments {
- int ncomment; /* number of comments */
- XcursorComment **comments; /* array of XcursorComment pointers */
-} XcursorComments;
+#define XCURSOR_IMAGE_TYPE 0xfffd0002
+#define XCURSOR_IMAGE_VERSION 1
+#define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5*4))
+#define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */
/*
* From libXcursor/src/file.c
*/
-static XcursorImage *
-XcursorImageCreate (int width, int height)
+static struct xcursor_image *
+xcursor_image_create(int width, int height)
{
- XcursorImage *image;
-
- if (width < 0 || height < 0)
- return NULL;
- if (width > XCURSOR_IMAGE_MAX_SIZE || height > XCURSOR_IMAGE_MAX_SIZE)
- return NULL;
-
- image = malloc (sizeof (XcursorImage) +
- width * height * sizeof (XcursorPixel));
- if (!image)
- return NULL;
- image->version = XCURSOR_IMAGE_VERSION;
- image->pixels = (XcursorPixel *) (image + 1);
- image->size = width > height ? width : height;
- image->width = width;
- image->height = height;
- image->delay = 0;
- return image;
+ struct xcursor_image *image;
+
+ if (width < 0 || height < 0)
+ return NULL;
+ if (width > XCURSOR_IMAGE_MAX_SIZE || height > XCURSOR_IMAGE_MAX_SIZE)
+ return NULL;
+
+ image = malloc(sizeof(struct xcursor_image) +
+ width * height * sizeof(uint32_t));
+ if (!image)
+ return NULL;
+ image->version = XCURSOR_IMAGE_VERSION;
+ image->pixels = (uint32_t *) (image + 1);
+ image->size = width > height ? width : height;
+ image->width = width;
+ image->height = height;
+ image->delay = 0;
+ return image;
}
static void
-XcursorImageDestroy (XcursorImage *image)
+xcursor_image_destroy(struct xcursor_image *image)
{
- free (image);
+ free(image);
}
-static XcursorImages *
-XcursorImagesCreate (int size)
+static struct xcursor_images *
+xcursor_images_create(int size)
{
- XcursorImages *images;
-
- images = malloc (sizeof (XcursorImages) +
- size * sizeof (XcursorImage *));
- if (!images)
- return NULL;
- images->nimage = 0;
- images->images = (XcursorImage **) (images + 1);
- images->name = NULL;
- return images;
+ struct xcursor_images *images;
+
+ images = malloc(sizeof(struct xcursor_images) +
+ size * sizeof(struct xcursor_image *));
+ if (!images)
+ return NULL;
+ images->nimage = 0;
+ images->images = (struct xcursor_image **) (images + 1);
+ images->name = NULL;
+ return images;
}
void
-XcursorImagesDestroy (XcursorImages *images)
-{
- int n;
-
- if (!images)
- return;
-
- for (n = 0; n < images->nimage; n++)
- XcursorImageDestroy (images->images[n]);
- if (images->name)
- free (images->name);
- free (images);
-}
-
-static void
-XcursorImagesSetName (XcursorImages *images, const char *name)
+xcursor_images_destroy(struct xcursor_images *images)
{
- char *new;
+ int n;
- if (!images || !name)
- return;
-
- new = malloc (strlen (name) + 1);
-
- if (!new)
- return;
+ if (!images)
+ return;
- strcpy (new, name);
- if (images->name)
- free (images->name);
- images->name = new;
+ for (n = 0; n < images->nimage; n++)
+ xcursor_image_destroy(images->images[n]);
+ free(images->name);
+ free(images);
}
-static XcursorBool
-_XcursorReadUInt (XcursorFile *file, XcursorUInt *u)
+static bool
+xcursor_read_uint(FILE *file, uint32_t *u)
{
- unsigned char bytes[4];
+ unsigned char bytes[4];
- if (!file || !u)
- return XcursorFalse;
+ if (!file || !u)
+ return false;
- if ((*file->read) (file, bytes, 4) != 4)
- return XcursorFalse;
+ if (fread(bytes, 1, 4, file) != 4)
+ return false;
- *u = ((XcursorUInt)(bytes[0]) << 0) |
- ((XcursorUInt)(bytes[1]) << 8) |
- ((XcursorUInt)(bytes[2]) << 16) |
- ((XcursorUInt)(bytes[3]) << 24);
- return XcursorTrue;
+ *u = ((uint32_t)(bytes[0]) << 0) |
+ ((uint32_t)(bytes[1]) << 8) |
+ ((uint32_t)(bytes[2]) << 16) |
+ ((uint32_t)(bytes[3]) << 24);
+ return true;
}
static void
-_XcursorFileHeaderDestroy (XcursorFileHeader *fileHeader)
+xcursor_file_header_destroy(struct xcursor_file_header *file_header)
{
- free (fileHeader);
+ free(file_header);
}
-static XcursorFileHeader *
-_XcursorFileHeaderCreate (int ntoc)
+static struct xcursor_file_header *
+xcursor_file_header_create(uint32_t ntoc)
{
- XcursorFileHeader *fileHeader;
-
- if (ntoc > 0x10000)
- return NULL;
- fileHeader = malloc (sizeof (XcursorFileHeader) +
- ntoc * sizeof (XcursorFileToc));
- if (!fileHeader)
- return NULL;
- fileHeader->magic = XCURSOR_MAGIC;
- fileHeader->header = XCURSOR_FILE_HEADER_LEN;
- fileHeader->version = XCURSOR_FILE_VERSION;
- fileHeader->ntoc = ntoc;
- fileHeader->tocs = (XcursorFileToc *) (fileHeader + 1);
- return fileHeader;
+ struct xcursor_file_header *file_header;
+
+ if (ntoc > 0x10000)
+ return NULL;
+ file_header = malloc(sizeof(struct xcursor_file_header) +
+ ntoc * sizeof(struct xcursor_file_toc));
+ if (!file_header)
+ return NULL;
+ file_header->magic = XCURSOR_MAGIC;
+ file_header->header = XCURSOR_FILE_HEADER_LEN;
+ file_header->version = XCURSOR_FILE_VERSION;
+ file_header->ntoc = ntoc;
+ file_header->tocs = (struct xcursor_file_toc *) (file_header + 1);
+ return file_header;
}
-static XcursorFileHeader *
-_XcursorReadFileHeader (XcursorFile *file)
+static struct xcursor_file_header *
+xcursor_read_file_header(FILE *file)
{
- XcursorFileHeader head, *fileHeader;
- XcursorUInt skip;
- unsigned int n;
-
- if (!file)
- return NULL;
-
- if (!_XcursorReadUInt (file, &head.magic))
- return NULL;
- if (head.magic != XCURSOR_MAGIC)
- return NULL;
- if (!_XcursorReadUInt (file, &head.header))
- return NULL;
- if (!_XcursorReadUInt (file, &head.version))
- return NULL;
- if (!_XcursorReadUInt (file, &head.ntoc))
- return NULL;
- skip = head.header - XCURSOR_FILE_HEADER_LEN;
- if (skip)
- if ((*file->seek) (file, skip, SEEK_CUR) == EOF)
- return NULL;
- fileHeader = _XcursorFileHeaderCreate (head.ntoc);
- if (!fileHeader)
- return NULL;
- fileHeader->magic = head.magic;
- fileHeader->header = head.header;
- fileHeader->version = head.version;
- fileHeader->ntoc = head.ntoc;
- for (n = 0; n < fileHeader->ntoc; n++)
- {
- if (!_XcursorReadUInt (file, &fileHeader->tocs[n].type))
- break;
- if (!_XcursorReadUInt (file, &fileHeader->tocs[n].subtype))
- break;
- if (!_XcursorReadUInt (file, &fileHeader->tocs[n].position))
- break;
- }
- if (n != fileHeader->ntoc)
- {
- _XcursorFileHeaderDestroy (fileHeader);
- return NULL;
- }
- return fileHeader;
+ struct xcursor_file_header head, *file_header;
+ uint32_t skip;
+ unsigned int n;
+
+ if (!file)
+ return NULL;
+
+ if (!xcursor_read_uint(file, &head.magic))
+ return NULL;
+ if (head.magic != XCURSOR_MAGIC)
+ return NULL;
+ if (!xcursor_read_uint(file, &head.header))
+ return NULL;
+ if (!xcursor_read_uint(file, &head.version))
+ return NULL;
+ if (!xcursor_read_uint(file, &head.ntoc))
+ return NULL;
+ skip = head.header - XCURSOR_FILE_HEADER_LEN;
+ if (skip)
+ if (fseek(file, skip, SEEK_CUR) == EOF)
+ return NULL;
+ file_header = xcursor_file_header_create(head.ntoc);
+ if (!file_header)
+ return NULL;
+ file_header->magic = head.magic;
+ file_header->header = head.header;
+ file_header->version = head.version;
+ file_header->ntoc = head.ntoc;
+ for (n = 0; n < file_header->ntoc; n++) {
+ if (!xcursor_read_uint(file, &file_header->tocs[n].type))
+ break;
+ if (!xcursor_read_uint(file, &file_header->tocs[n].subtype))
+ break;
+ if (!xcursor_read_uint(file, &file_header->tocs[n].position))
+ break;
+ }
+ if (n != file_header->ntoc) {
+ xcursor_file_header_destroy(file_header);
+ return NULL;
+ }
+ return file_header;
}
-static XcursorBool
-_XcursorSeekToToc (XcursorFile *file,
- XcursorFileHeader *fileHeader,
- int toc)
+static bool
+xcursor_seek_to_toc(FILE *file,
+ struct xcursor_file_header *file_header,
+ int toc)
{
- if (!file || !fileHeader || \
- (*file->seek) (file, fileHeader->tocs[toc].position, SEEK_SET) == EOF)
- return XcursorFalse;
- return XcursorTrue;
+ if (!file || !file_header ||
+ fseek(file, file_header->tocs[toc].position, SEEK_SET) == EOF)
+ return false;
+ return true;
}
-static XcursorBool
-_XcursorFileReadChunkHeader (XcursorFile *file,
- XcursorFileHeader *fileHeader,
- int toc,
- XcursorChunkHeader *chunkHeader)
+static bool
+xcursor_file_read_chunk_header(FILE *file,
+ struct xcursor_file_header *file_header,
+ int toc,
+ struct xcursor_chunk_header *chunk_header)
{
- if (!file || !fileHeader || !chunkHeader)
- return XcursorFalse;
- if (!_XcursorSeekToToc (file, fileHeader, toc))
- return XcursorFalse;
- if (!_XcursorReadUInt (file, &chunkHeader->header))
- return XcursorFalse;
- if (!_XcursorReadUInt (file, &chunkHeader->type))
- return XcursorFalse;
- if (!_XcursorReadUInt (file, &chunkHeader->subtype))
- return XcursorFalse;
- if (!_XcursorReadUInt (file, &chunkHeader->version))
- return XcursorFalse;
- /* sanity check */
- if (chunkHeader->type != fileHeader->tocs[toc].type ||
- chunkHeader->subtype != fileHeader->tocs[toc].subtype)
- return XcursorFalse;
- return XcursorTrue;
+ if (!file || !file_header || !chunk_header)
+ return false;
+ if (!xcursor_seek_to_toc(file, file_header, toc))
+ return false;
+ if (!xcursor_read_uint(file, &chunk_header->header))
+ return false;
+ if (!xcursor_read_uint(file, &chunk_header->type))
+ return false;
+ if (!xcursor_read_uint(file, &chunk_header->subtype))
+ return false;
+ if (!xcursor_read_uint(file, &chunk_header->version))
+ return false;
+ /* sanity check */
+ if (chunk_header->type != file_header->tocs[toc].type ||
+ chunk_header->subtype != file_header->tocs[toc].subtype)
+ return false;
+ return true;
}
-#define dist(a,b) ((a) > (b) ? (a) - (b) : (b) - (a))
-
-static XcursorDim
-_XcursorFindBestSize (XcursorFileHeader *fileHeader,
- XcursorDim size,
- int *nsizesp)
+static uint32_t
+dist(uint32_t a, uint32_t b)
{
- unsigned int n;
- int nsizes = 0;
- XcursorDim bestSize = 0;
- XcursorDim thisSize;
-
- if (!fileHeader || !nsizesp)
- return 0;
-
- for (n = 0; n < fileHeader->ntoc; n++)
- {
- if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE)
- continue;
- thisSize = fileHeader->tocs[n].subtype;
- if (!bestSize || dist (thisSize, size) < dist (bestSize, size))
- {
- bestSize = thisSize;
- nsizes = 1;
- }
- else if (thisSize == bestSize)
- nsizes++;
- }
- *nsizesp = nsizes;
- return bestSize;
+ return a > b ? a - b : b - a;
}
-static int
-_XcursorFindImageToc (XcursorFileHeader *fileHeader,
- XcursorDim size,
- int count)
+static uint32_t
+xcursor_file_best_size(struct xcursor_file_header *file_header,
+ uint32_t size, int *nsizesp)
{
- unsigned int toc;
- XcursorDim thisSize;
-
- if (!fileHeader)
- return 0;
-
- for (toc = 0; toc < fileHeader->ntoc; toc++)
- {
- if (fileHeader->tocs[toc].type != XCURSOR_IMAGE_TYPE)
- continue;
- thisSize = fileHeader->tocs[toc].subtype;
- if (thisSize != size)
- continue;
- if (!count)
- break;
- count--;
- }
- if (toc == fileHeader->ntoc)
- return -1;
- return toc;
-}
+ unsigned int n;
+ int nsizes = 0;
+ uint32_t best_size = 0;
+ uint32_t this_size;
-static XcursorImage *
-_XcursorReadImage (XcursorFile *file,
- XcursorFileHeader *fileHeader,
- int toc)
-{
- XcursorChunkHeader chunkHeader;
- XcursorImage head;
- XcursorImage *image;
- int n;
- XcursorPixel *p;
-
- if (!file || !fileHeader)
- return NULL;
-
- if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader))
- return NULL;
- if (!_XcursorReadUInt (file, &head.width))
- return NULL;
- if (!_XcursorReadUInt (file, &head.height))
- return NULL;
- if (!_XcursorReadUInt (file, &head.xhot))
- return NULL;
- if (!_XcursorReadUInt (file, &head.yhot))
- return NULL;
- if (!_XcursorReadUInt (file, &head.delay))
- return NULL;
- /* sanity check data */
- if (head.width > XCURSOR_IMAGE_MAX_SIZE ||
- head.height > XCURSOR_IMAGE_MAX_SIZE)
- return NULL;
- if (head.width == 0 || head.height == 0)
- return NULL;
- if (head.xhot > head.width || head.yhot > head.height)
- return NULL;
-
- /* Create the image and initialize it */
- image = XcursorImageCreate (head.width, head.height);
- if (image == NULL)
- return NULL;
- if (chunkHeader.version < image->version)
- image->version = chunkHeader.version;
- image->size = chunkHeader.subtype;
- image->xhot = head.xhot;
- image->yhot = head.yhot;
- image->delay = head.delay;
- n = image->width * image->height;
- p = image->pixels;
- while (n--)
- {
- if (!_XcursorReadUInt (file, p))
- {
- XcursorImageDestroy (image);
- return NULL;
- }
- p++;
- }
- return image;
-}
+ if (!file_header || !nsizesp)
+ return 0;
-static XcursorImages *
-XcursorXcFileLoadImages (XcursorFile *file, int size)
-{
- XcursorFileHeader *fileHeader;
- XcursorDim bestSize;
- int nsize;
- XcursorImages *images;
- int n;
- int toc;
-
- if (!file || size < 0)
- return NULL;
- fileHeader = _XcursorReadFileHeader (file);
- if (!fileHeader)
- return NULL;
- bestSize = _XcursorFindBestSize (fileHeader, (XcursorDim) size, &nsize);
- if (!bestSize)
- {
- _XcursorFileHeaderDestroy (fileHeader);
- return NULL;
- }
- images = XcursorImagesCreate (nsize);
- if (!images)
- {
- _XcursorFileHeaderDestroy (fileHeader);
- return NULL;
- }
- for (n = 0; n < nsize; n++)
- {
- toc = _XcursorFindImageToc (fileHeader, bestSize, n);
- if (toc < 0)
- break;
- images->images[images->nimage] = _XcursorReadImage (file, fileHeader,
- toc);
- if (!images->images[images->nimage])
- break;
- images->nimage++;
- }
- _XcursorFileHeaderDestroy (fileHeader);
- if (images->nimage != nsize)
- {
- XcursorImagesDestroy (images);
- images = NULL;
- }
- return images;
+ for (n = 0; n < file_header->ntoc; n++) {
+ if (file_header->tocs[n].type != XCURSOR_IMAGE_TYPE)
+ continue;
+ this_size = file_header->tocs[n].subtype;
+ if (!best_size || dist(this_size, size) < dist(best_size, size)) {
+ best_size = this_size;
+ nsizes = 1;
+ } else if (this_size == best_size) {
+ nsizes++;
+ }
+ }
+ *nsizesp = nsizes;
+ return best_size;
}
static int
-_XcursorStdioFileRead (XcursorFile *file, unsigned char *buf, int len)
+xcursor_find_image_toc(struct xcursor_file_header *file_header,
+ uint32_t size, int count)
{
- FILE *f = file->closure;
- return fread (buf, 1, len, f);
-}
+ unsigned int toc;
+ uint32_t this_size;
-static int
-_XcursorStdioFileWrite (XcursorFile *file, unsigned char *buf, int len)
-{
- FILE *f = file->closure;
- return fwrite (buf, 1, len, f);
-}
+ if (!file_header)
+ return 0;
-static int
-_XcursorStdioFileSeek (XcursorFile *file, long offset, int whence)
-{
- FILE *f = file->closure;
- return fseek (f, offset, whence);
+ for (toc = 0; toc < file_header->ntoc; toc++) {
+ if (file_header->tocs[toc].type != XCURSOR_IMAGE_TYPE)
+ continue;
+ this_size = file_header->tocs[toc].subtype;
+ if (this_size != size)
+ continue;
+ if (!count)
+ break;
+ count--;
+ }
+ if (toc == file_header->ntoc)
+ return -1;
+ return toc;
}
-static void
-_XcursorStdioFileInitialize (FILE *stdfile, XcursorFile *file)
+static struct xcursor_image *
+xcursor_read_image(FILE *file,
+ struct xcursor_file_header *file_header,
+ int toc)
{
- file->closure = stdfile;
- file->read = _XcursorStdioFileRead;
- file->write = _XcursorStdioFileWrite;
- file->seek = _XcursorStdioFileSeek;
+ struct xcursor_chunk_header chunk_header;
+ struct xcursor_image head;
+ struct xcursor_image *image;
+ int n;
+ uint32_t *p;
+
+ if (!file || !file_header)
+ return NULL;
+
+ if (!xcursor_file_read_chunk_header(file, file_header, toc, &chunk_header))
+ return NULL;
+ if (!xcursor_read_uint(file, &head.width))
+ return NULL;
+ if (!xcursor_read_uint(file, &head.height))
+ return NULL;
+ if (!xcursor_read_uint(file, &head.xhot))
+ return NULL;
+ if (!xcursor_read_uint(file, &head.yhot))
+ return NULL;
+ if (!xcursor_read_uint(file, &head.delay))
+ return NULL;
+ /* sanity check data */
+ if (head.width > XCURSOR_IMAGE_MAX_SIZE ||
+ head.height > XCURSOR_IMAGE_MAX_SIZE)
+ return NULL;
+ if (head.width == 0 || head.height == 0)
+ return NULL;
+ if (head.xhot > head.width || head.yhot > head.height)
+ return NULL;
+
+ /* Create the image and initialize it */
+ image = xcursor_image_create(head.width, head.height);
+ if (image == NULL)
+ return NULL;
+ if (chunk_header.version < image->version)
+ image->version = chunk_header.version;
+ image->size = chunk_header.subtype;
+ image->xhot = head.xhot;
+ image->yhot = head.yhot;
+ image->delay = head.delay;
+ n = image->width * image->height;
+ p = image->pixels;
+ while (n--) {
+ if (!xcursor_read_uint(file, p)) {
+ xcursor_image_destroy(image);
+ return NULL;
+ }
+ p++;
+ }
+ return image;
}
-static XcursorImages *
-XcursorFileLoadImages (FILE *file, int size)
+static struct xcursor_images *
+xcursor_xc_file_load_images(FILE *file, int size)
{
- XcursorFile f;
-
- if (!file)
- return NULL;
-
- _XcursorStdioFileInitialize (file, &f);
- return XcursorXcFileLoadImages (&f, size);
+ struct xcursor_file_header *file_header;
+ uint32_t best_size;
+ int nsize;
+ struct xcursor_images *images;
+ int n;
+ int toc;
+
+ if (!file || size < 0)
+ return NULL;
+ file_header = xcursor_read_file_header(file);
+ if (!file_header)
+ return NULL;
+ best_size = xcursor_file_best_size(file_header, (uint32_t) size, &nsize);
+ if (!best_size) {
+ xcursor_file_header_destroy(file_header);
+ return NULL;
+ }
+ images = xcursor_images_create(nsize);
+ if (!images) {
+ xcursor_file_header_destroy(file_header);
+ return NULL;
+ }
+ for (n = 0; n < nsize; n++) {
+ toc = xcursor_find_image_toc(file_header, best_size, n);
+ if (toc < 0)
+ break;
+ images->images[images->nimage] = xcursor_read_image(file, file_header,
+ toc);
+ if (!images->images[images->nimage])
+ break;
+ images->nimage++;
+ }
+ xcursor_file_header_destroy(file_header);
+ if (images->nimage != nsize) {
+ xcursor_images_destroy(images);
+ images = NULL;
+ }
+ return images;
}
/*
@@ -621,275 +491,213 @@ XcursorFileLoadImages (FILE *file, int size)
#define XCURSORPATH "~/.icons:/usr/share/icons:/usr/share/pixmaps:~/.cursors:/usr/share/cursors/xorg-x11:"ICONDIR
#endif
-static const char *
-XcursorLibraryPath (void)
+#define XDG_DATA_HOME_FALLBACK "~/.local/share"
+#define CURSORDIR "/icons"
+
+/** Get search path for cursor themes
+ *
+ * This function builds the list of directories to look for cursor
+ * themes in. The format is PATH-like: directories are separated by
+ * colons.
+ *
+ * The memory block returned by this function is allocated on the heap
+ * and must be freed by the caller.
+ */
+static char *
+xcursor_library_path(void)
{
- static const char *path;
+ const char *env_var, *suffix;
+ char *path;
+ size_t path_size;
- if (!path)
- {
- path = getenv ("XCURSOR_PATH");
- if (!path)
- path = XCURSORPATH;
- }
- return path;
-}
+ env_var = getenv("XCURSOR_PATH");
+ if (env_var)
+ return strdup(env_var);
-static void
-_XcursorAddPathElt (char *path, const char *elt, int len)
-{
- int pathlen = strlen (path);
-
- /* append / if the path doesn't currently have one */
- if (path[0] == '\0' || path[pathlen - 1] != '/')
- {
- strcat (path, "/");
- pathlen++;
- }
- if (len == -1)
- len = strlen (elt);
- /* strip leading slashes */
- while (len && elt[0] == '/')
- {
- elt++;
- len--;
- }
- strncpy (path + pathlen, elt, len);
- path[pathlen + len] = '\0';
+ env_var = getenv("XDG_DATA_HOME");
+ if (!env_var || env_var[0] != '/')
+ env_var = XDG_DATA_HOME_FALLBACK;
+
+ suffix = CURSORDIR ":" XCURSORPATH;
+ path_size = strlen(env_var) + strlen(suffix) + 1;
+ path = malloc(path_size);
+ if (!path)
+ return NULL;
+ snprintf(path, path_size, "%s%s", env_var, suffix);
+ return path;
}
static char *
-_XcursorBuildThemeDir (const char *dir, const char *theme)
+xcursor_build_theme_dir(const char *dir, const char *theme)
{
- const char *colon;
- const char *tcolon;
- char *full;
- char *home;
- int dirlen;
- int homelen;
- int themelen;
- int len;
-
- if (!dir || !theme)
- return NULL;
-
- colon = strchr (dir, ':');
- if (!colon)
- colon = dir + strlen (dir);
-
- dirlen = colon - dir;
-
- tcolon = strchr (theme, ':');
- if (!tcolon)
- tcolon = theme + strlen (theme);
-
- themelen = tcolon - theme;
-
- home = NULL;
- homelen = 0;
- if (*dir == '~')
- {
- home = getenv ("HOME");
- if (!home)
- return NULL;
- homelen = strlen (home);
- dir++;
- dirlen--;
- }
-
- /*
- * add space for any needed directory separators, one per component,
- * and one for the trailing null
- */
- len = 1 + homelen + 1 + dirlen + 1 + themelen + 1;
-
- full = malloc (len);
- if (!full)
- return NULL;
- full[0] = '\0';
-
- if (home)
- _XcursorAddPathElt (full, home, -1);
- _XcursorAddPathElt (full, dir, dirlen);
- _XcursorAddPathElt (full, theme, themelen);
- return full;
+ const char *colon;
+ const char *tcolon;
+ char *full;
+ const char *home, *homesep;
+ int dirlen;
+ int homelen;
+ int themelen;
+ size_t full_size;
+
+ if (!dir || !theme)
+ return NULL;
+
+ colon = strchr(dir, ':');
+ if (!colon)
+ colon = dir + strlen(dir);
+
+ dirlen = colon - dir;
+
+ tcolon = strchr(theme, ':');
+ if (!tcolon)
+ tcolon = theme + strlen(theme);
+
+ themelen = tcolon - theme;
+
+ home = "";
+ homelen = 0;
+ homesep = "";
+ if (*dir == '~') {
+ home = getenv("HOME");
+ if (!home)
+ return NULL;
+ homelen = strlen(home);
+ homesep = "/";
+ dir++;
+ dirlen--;
+ }
+
+ /*
+ * add space for any needed directory separators, one per component,
+ * and one for the trailing null
+ */
+ full_size = 1 + homelen + 1 + dirlen + 1 + themelen + 1;
+ full = malloc(full_size);
+ if (!full)
+ return NULL;
+ snprintf(full, full_size, "%s%s%.*s/%.*s", home, homesep,
+ dirlen, dir, themelen, theme);
+ return full;
}
static char *
-_XcursorBuildFullname (const char *dir, const char *subdir, const char *file)
+xcursor_build_fullname(const char *dir, const char *subdir, const char *file)
{
- char *full;
-
- if (!dir || !subdir || !file)
- return NULL;
-
- full = malloc (strlen (dir) + 1 + strlen (subdir) + 1 + strlen (file) + 1);
- if (!full)
- return NULL;
- full[0] = '\0';
- _XcursorAddPathElt (full, dir, -1);
- _XcursorAddPathElt (full, subdir, -1);
- _XcursorAddPathElt (full, file, -1);
- return full;
+ char *full;
+ size_t full_size;
+
+ if (!dir || !subdir || !file)
+ return NULL;
+
+ full_size = strlen(dir) + 1 + strlen(subdir) + 1 + strlen(file) + 1;
+ full = malloc(full_size);
+ if (!full)
+ return NULL;
+ snprintf(full, full_size, "%s/%s/%s", dir, subdir, file);
+ return full;
}
static const char *
-_XcursorNextPath (const char *path)
+xcursor_next_path(const char *path)
{
- char *colon = strchr (path, ':');
+ char *colon = strchr(path, ':');
- if (!colon)
- return NULL;
- return colon + 1;
+ if (!colon)
+ return NULL;
+ return colon + 1;
}
-#define XcursorWhite(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
-#define XcursorSep(c) ((c) == ';' || (c) == ',')
+static bool
+xcursor_white(char c)
+{
+ return c == ' ' || c == '\t' || c == '\n';
+}
+
+static bool
+xcursor_sep(char c)
+{
+ return c == ';' || c == ',';
+}
static char *
-_XcursorThemeInherits (const char *full)
+xcursor_theme_inherits(const char *full)
{
- char line[8192];
- char *result = NULL;
- FILE *f;
-
- if (!full)
- return NULL;
-
- f = fopen (full, "r");
- if (f)
- {
- while (fgets (line, sizeof (line), f))
- {
- if (!strncmp (line, "Inherits", 8))
- {
- char *l = line + 8;
- char *r;
- while (*l == ' ') l++;
- if (*l != '=') continue;
+ char *line = NULL;
+ size_t line_size = 0;
+ char *result = NULL;
+ FILE *f;
+
+ if (!full)
+ return NULL;
+
+ f = fopen(full, "r");
+ if (!f)
+ return NULL;
+
+ while (getline(&line, &line_size, f) >= 0) {
+ const char *l;
+ char *r;
+
+ if (strncmp(line, "Inherits", 8))
+ continue;
+
+ l = line + 8;
+ while (*l == ' ')
+ l++;
+ if (*l != '=')
+ continue;
l++;
- while (*l == ' ') l++;
- result = malloc (strlen (l) + 1);
- if (result)
- {
- r = result;
- while (*l)
- {
- while (XcursorSep(*l) || XcursorWhite (*l)) l++;
+ while (*l == ' ')
+ l++;
+ result = malloc(strlen(l) + 1);
+ if (!result)
+ break;
+
+ r = result;
+ while (*l) {
+ while (xcursor_sep(*l) || xcursor_white(*l))
+ l++;
if (!*l)
- break;
+ break;
if (r != result)
- *r++ = ':';
- while (*l && !XcursorWhite(*l) &&
- !XcursorSep(*l))
- *r++ = *l++;
- }
- *r++ = '\0';
+ *r++ = ':';
+ while (*l && !xcursor_white(*l) && !xcursor_sep(*l))
+ *r++ = *l++;
}
+ *r++ = '\0';
+
break;
- }
}
- fclose (f);
- }
- return result;
-}
-static FILE *
-XcursorScanTheme (const char *theme, const char *name)
-{
- FILE *f = NULL;
- char *full;
- char *dir;
- const char *path;
- char *inherits = NULL;
- const char *i;
-
- if (!theme || !name)
- return NULL;
-
- /*
- * Scan this theme
- */
- for (path = XcursorLibraryPath ();
- path && f == NULL;
- path = _XcursorNextPath (path))
- {
- dir = _XcursorBuildThemeDir (path, theme);
- if (dir)
- {
- full = _XcursorBuildFullname (dir, "cursors", name);
- if (full)
- {
- f = fopen (full, "r");
- free (full);
- }
- if (!f && !inherits)
- {
- full = _XcursorBuildFullname (dir, "", "index.theme");
- if (full)
- {
- inherits = _XcursorThemeInherits (full);
- free (full);
- }
- }
- free (dir);
- }
- }
- /*
- * Recurse to scan inherited themes
- */
- for (i = inherits; i && f == NULL; i = _XcursorNextPath (i))
- f = XcursorScanTheme (i, name);
- if (inherits != NULL)
- free (inherits);
- return f;
-}
+ fclose(f);
+ free(line);
-XcursorImages *
-XcursorLibraryLoadImages (const char *file, const char *theme, int size)
-{
- FILE *f = NULL;
- XcursorImages *images = NULL;
-
- if (!file)
- return NULL;
-
- if (theme)
- f = XcursorScanTheme (theme, file);
- if (!f)
- f = XcursorScanTheme ("default", file);
- if (f)
- {
- images = XcursorFileLoadImages (f, size);
- if (images)
- XcursorImagesSetName (images, file);
- fclose (f);
- }
- return images;
+ return result;
}
static void
load_all_cursors_from_dir(const char *path, int size,
- void (*load_callback)(XcursorImages *, void *),
+ void (*load_callback)(struct xcursor_images *, void *),
void *user_data)
{
FILE *f;
DIR *dir = opendir(path);
struct dirent *ent;
char *full;
- XcursorImages *images;
+ struct xcursor_images *images;
if (!dir)
return;
- for(ent = readdir(dir); ent; ent = readdir(dir)) {
+ for (ent = readdir(dir); ent; ent = readdir(dir)) {
#ifdef _DIRENT_HAVE_D_TYPE
if (ent->d_type != DT_UNKNOWN &&
- (ent->d_type != DT_REG && ent->d_type != DT_LNK))
+ ent->d_type != DT_REG &&
+ ent->d_type != DT_LNK)
continue;
#endif
- full = _XcursorBuildFullname(path, "", ent->d_name);
+ full = xcursor_build_fullname(path, "", ent->d_name);
if (!full)
continue;
@@ -899,14 +707,14 @@ load_all_cursors_from_dir(const char *path, int size,
continue;
}
- images = XcursorFileLoadImages(f, size);
+ images = xcursor_xc_file_load_images(f, size);
if (images) {
- XcursorImagesSetName(images, ent->d_name);
+ images->name = strdup(ent->d_name);
load_callback(images, user_data);
}
- fclose (f);
+ fclose(f);
free(full);
}
@@ -916,63 +724,60 @@ load_all_cursors_from_dir(const char *path, int size,
/** Load all the cursor of a theme
*
* This function loads all the cursor images of a given theme and its
- * inherited themes. Each cursor is loaded into an XcursorImages object
+ * inherited themes. Each cursor is loaded into an struct xcursor_images object
* which is passed to the caller's load callback. If a cursor appears
* more than once across all the inherited themes, the load callback
- * will be called multiple times, with possibly different XcursorImages
+ * will be called multiple times, with possibly different struct xcursor_images
* object which have the same name. The user is expected to destroy the
- * XcursorImages objects passed to the callback with
- * XcursorImagesDestroy().
+ * struct xcursor_images objects passed to the callback with
+ * xcursor_images_destroy().
*
* \param theme The name of theme that should be loaded
* \param size The desired size of the cursor images
* \param load_callback A callback function that will be called
- * for each cursor loaded. The first parameter is the XcursorImages
+ * for each cursor loaded. The first parameter is the struct xcursor_images
* object representing the loaded cursor and the second is a pointer
* to data provided by the user.
* \param user_data The data that should be passed to the load callback
*/
void
xcursor_load_theme(const char *theme, int size,
- void (*load_callback)(XcursorImages *, void *),
- void *user_data)
+ void (*load_callback)(struct xcursor_images *, void *),
+ void *user_data)
{
char *full, *dir;
char *inherits = NULL;
const char *path, *i;
+ char *xcursor_path;
if (!theme)
theme = "default";
- for (path = XcursorLibraryPath();
+ xcursor_path = xcursor_library_path();
+ for (path = xcursor_path;
path;
- path = _XcursorNextPath(path)) {
- dir = _XcursorBuildThemeDir(path, theme);
+ path = xcursor_next_path(path)) {
+ dir = xcursor_build_theme_dir(path, theme);
if (!dir)
continue;
- full = _XcursorBuildFullname(dir, "cursors", "");
-
- if (full) {
- load_all_cursors_from_dir(full, size, load_callback,
- user_data);
- free(full);
- }
+ full = xcursor_build_fullname(dir, "cursors", "");
+ load_all_cursors_from_dir(full, size, load_callback,
+ user_data);
+ free(full);
if (!inherits) {
- full = _XcursorBuildFullname(dir, "", "index.theme");
- if (full) {
- inherits = _XcursorThemeInherits(full);
- free(full);
- }
+ full = xcursor_build_fullname(dir, "", "index.theme");
+ inherits = xcursor_theme_inherits(full);
+ free(full);
}
free(dir);
}
- for (i = inherits; i; i = _XcursorNextPath(i))
+ for (i = inherits; i; i = xcursor_next_path(i))
xcursor_load_theme(i, size, load_callback, user_data);
- if (inherits)
- free(inherits);
+ free(inherits);
+ free(xcursor_path);
}
diff --git a/cursor/xcursor.h b/cursor/xcursor.h
index c1ca12c..459f816 100644
--- a/cursor/xcursor.h
+++ b/cursor/xcursor.h
@@ -28,40 +28,31 @@
#include <stdint.h>
-typedef int XcursorBool;
-typedef uint32_t XcursorUInt;
-
-typedef XcursorUInt XcursorDim;
-typedef XcursorUInt XcursorPixel;
-
-typedef struct _XcursorImage {
- XcursorUInt version; /* version of the image data */
- XcursorDim size; /* nominal size for matching */
- XcursorDim width; /* actual width */
- XcursorDim height; /* actual height */
- XcursorDim xhot; /* hot spot x (must be inside image) */
- XcursorDim yhot; /* hot spot y (must be inside image) */
- XcursorUInt delay; /* animation delay to next frame (ms) */
- XcursorPixel *pixels; /* pointer to pixels */
-} XcursorImage;
+struct xcursor_image {
+ uint32_t version; /* version of the image data */
+ uint32_t size; /* nominal size for matching */
+ uint32_t width; /* actual width */
+ uint32_t height; /* actual height */
+ uint32_t xhot; /* hot spot x (must be inside image) */
+ uint32_t yhot; /* hot spot y (must be inside image) */
+ uint32_t delay; /* animation delay to next frame (ms) */
+ uint32_t *pixels; /* pointer to pixels */
+};
/*
* Other data structures exposed by the library API
*/
-typedef struct _XcursorImages {
- int nimage; /* number of images */
- XcursorImage **images; /* array of XcursorImage pointers */
- char *name; /* name used to load images */
-} XcursorImages;
-
-XcursorImages *
-XcursorLibraryLoadImages (const char *file, const char *theme, int size);
+struct xcursor_images {
+ int nimage; /* number of images */
+ struct xcursor_image **images; /* array of XcursorImage pointers */
+ char *name; /* name used to load images */
+};
void
-XcursorImagesDestroy (XcursorImages *images);
+xcursor_images_destroy(struct xcursor_images *images);
void
xcursor_load_theme(const char *theme, int size,
- void (*load_callback)(XcursorImages *, void *),
- void *user_data);
+ void (*load_callback)(struct xcursor_images *, void *),
+ void *user_data);
#endif
diff --git a/doc/Makefile.am b/doc/Makefile.am
deleted file mode 100644
index 0b1c4f2..0000000
--- a/doc/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-SUBDIRS = doxygen publican
diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am
deleted file mode 100644
index 86fd8bf..0000000
--- a/doc/doxygen/Makefile.am
+++ /dev/null
@@ -1,113 +0,0 @@
-
-.SUFFIXES = .gv .png .map
-
-noinst_DATA = \
- xml/Client/index.xml \
- xml/Cursor/index.xml \
- xml/Server/index.xml \
- html/Client/index.html \
- html/Cursor/index.html \
- html/Server/index.html
-dist_noinst_DATA = wayland.doxygen.in
-
-scanned_src_files_shared = \
- $(top_srcdir)/src/wayland-util.h
-
-scanned_src_files_Client = \
- $(scanned_src_files_shared) \
- $(top_srcdir)/src/wayland-client.c \
- $(top_srcdir)/src/wayland-client.h \
- $(top_srcdir)/src/wayland-client-core.h
-
-scanned_src_files_Cursor = \
- $(top_srcdir)/cursor/wayland-cursor.c \
- $(top_srcdir)/cursor/wayland-cursor.h
-
-scanned_src_files_Server = \
- $(scanned_src_files_shared) \
- $(top_srcdir)/src/event-loop.c \
- $(top_srcdir)/src/wayland-server.c \
- $(top_srcdir)/src/wayland-server.h \
- $(top_srcdir)/src/wayland-server-core.h \
- $(top_srcdir)/src/wayland-shm.c
-
-scanned_src_files_man = \
- $(scanned_src_files_Server) \
- $(top_srcdir)/src/wayland-client.c \
- $(top_srcdir)/src/wayland-client.h \
- $(top_srcdir)/src/wayland-client-core.h
-
-extra_doxygen = \
- mainpage.dox
-
-extra_doxygen_Server = \
- $(top_builddir)/protocol/wayland-server-protocol.h \
- $(extra_doxygen)
-
-extra_doxygen_Client = \
- $(top_builddir)/protocol/wayland-client-protocol.h \
- $(extra_doxygen)
-
-extra_doxygen_Cursor = \
- $(extra_doxygen)
-
-diagramsdir := $(srcdir)/dot
-diagramssrc := $(wildcard $(diagramsdir)/*.gv)
-diagrams := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.png))
-diagram_maps := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.map))
-
-# find all man/man3/wl_foo.3 pages
-# for this to work, we need to create them before the man target (hence
-# all-local below)
-dist_man3_MANS = $(shell test -d man && find man/man3 -name "wl_*.3" -printf "man/man3/%P\n")
-
-# Listing various directories that might need to be created.
-alldirsrel := xml xml/Client xml/Server xml/Cursor man/man3 html/Client html/Server html/Cursor
-alldirs := $(patsubst %,$(CURDIR)/%,$(alldirsrel))
-
-$(diagrams): $(diagramssrc)
-
-$(diagram_maps): $(diagramssrc)
-
-xml/%/index.xml: $(top_srcdir)/src/scanner.c $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | $(CURDIR)/xml/%
- $(AM_V_GEN)(cat wayland.doxygen; \
- echo "GENERATE_XML=YES"; \
- echo "XML_OUTPUT=xml/$*"; \
- echo "INPUT= $(scanned_src_files_$*)"; \
- ) | $(DOXYGEN) -
-
-html/%/index.html: $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | $(CURDIR)/html/%
- $(AM_V_GEN)(cat wayland.doxygen; \
- echo "PROJECT_NAME=\"Wayland $* API\""; \
- echo "GENERATE_HTML=YES"; \
- echo "HTML_OUTPUT=html/$*"; \
- echo "INPUT= $(scanned_src_files_$*) $(extra_doxygen_$*)"; \
- ) | $(DOXYGEN) -
-
-man/man3/wl_display.3: $(top_srcdir)/src/scanner.c $(scanned_src_files_man) wayland.doxygen | $(CURDIR)/man/man3
- $(AM_V_GEN)(cat wayland.doxygen; \
- echo "GENERATE_MAN=YES"; \
- echo "MAN_OUTPUT=man"; \
- echo "JAVADOC_AUTOBRIEF=NO"; \
- echo "INPUT= $(scanned_src_files_man)"; \
- ) | $(DOXYGEN) -
-
-xml/%.png: $(diagramsdir)/%.gv | $(CURDIR)/xml
- $(AM_V_GEN)$(DOT) -Tpng -o$@ $<
-
-xml/%.map: $(diagramsdir)/%.gv | $(CURDIR)/xml
- $(AM_V_GEN)$(DOT) -Tcmapx_np -o$@ $<
-
-# general rule to create one of the listed directories.
-$(alldirs):
- $(AM_V_GEN)$(MKDIR_P) $@
-
-# there is no man-local
-all-local: man/man3/wl_display.3
-
-clean-local:
- rm -rf xml/
- rm -rf html/
- rm -rf man/
-
-EXTRA_DIST = $(diagramssrc)
diff --git a/doc/doxygen/meson.build b/doc/doxygen/meson.build
index f2bee14..6112620 100644
--- a/doc/doxygen/meson.build
+++ b/doc/doxygen/meson.build
@@ -13,7 +13,7 @@ dot_map = []
doxygen_conf = configuration_data()
doxygen_conf.set('VERSION', meson.project_version())
-doxygen_conf.set('top_builddir', meson.build_root())
+doxygen_conf.set('top_builddir', meson.project_build_root())
wayland_doxygen = configure_file(
input: 'wayland.doxygen.in',
output: 'wayland.doxygen',
@@ -76,6 +76,7 @@ foreach f_name, sections: formats
# We do not really need an output file, but Meson
# will complain if one is not set, so we use a
# dummy 'stamp' file
+ stamp = join_paths(meson.current_build_dir(), '@0@.stamp'.format(t_name))
custom_target(
t_name,
command: [
@@ -84,7 +85,7 @@ foreach f_name, sections: formats
'--builddir=@OUTDIR@',
'--section=@0@'.format(s_name),
'--output-format=@0@'.format(f_name),
- '--stamp=doc/doxygen/@0@.stamp'.format(t_name),
+ '--stamp=@0@'.format(stamp),
wayland_doxygen,
'@INPUT@',
],
@@ -97,13 +98,14 @@ foreach f_name, sections: formats
endforeach
man_files = shared_files + server_files + client_files + cursor_files
+stamp = join_paths(meson.current_build_dir(), 'man3.stamp')
custom_target(
'man-pages-3',
command: [
gen_doxygen,
'--builddir=@OUTDIR@',
'--output-format=man3',
- '--stamp=doc/doxygen/man3.stamp',
+ '--stamp=@0@'.format(stamp),
wayland_doxygen,
'@INPUT@',
],
diff --git a/doc/meson.build b/doc/meson.build
index f74b6b1..44fda2a 100644
--- a/doc/meson.build
+++ b/doc/meson.build
@@ -1,3 +1,7 @@
+if not get_option('libraries')
+ error('-Ddocumentation=true requires -Dlibraries=true')
+endif
+
dot = find_program('dot')
doxygen = find_program('doxygen')
xsltproc = find_program('xsltproc')
@@ -18,7 +22,7 @@ if vers.version_compare('< 2.26.0')
endif
manpage_xsl = 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl'
-cmd = run_command(xsltproc, '--nonet', manpage_xsl)
+cmd = run_command(xsltproc, '--nonet', manpage_xsl, check: false)
if cmd.returncode() != 0
error('The style sheet for man pages providing "@0@" was not found.'.format(manpage_xsl))
endif
diff --git a/doc/publican/Makefile.am b/doc/publican/Makefile.am
deleted file mode 100644
index e861fe6..0000000
--- a/doc/publican/Makefile.am
+++ /dev/null
@@ -1,169 +0,0 @@
-# Documentation is built with xmlto, but some of the recipes in here are
-# leftovers from building with Publican (https://fedorahosted.org/publican/)
-#
-# How this build works:
-# * the main target is Wayland, documentation ends up in $(builddir)/Wayland/
-# * hand-written chapters and CSS files are located in sources. These are
-# copied into $(builddir)/en-US/
-# * ProtocolSpec.xml is generated from $(top_srcdir)/protocol/wayland.xml,
-# changed into docbook via XSLT and saved in $(builddir)/en-US/
-# * ProtocolInterfaces.xml, same as above, uses a different XSLT
-# * *API.xml is generated from the doxygen output and saved in
-# $(builddir)/en-US
-# * run xmlto on $(builddir)/en-US, output to $(builddir)/Wayland/en-US
-
-doxydir := $(top_builddir)/doc/doxygen
-html_destdir := $(builddir)/Wayland/en-US/html
-
-publican_sources = \
- $(srcdir)/sources/Wayland.ent \
- $(srcdir)/sources/Wayland.xml \
- $(srcdir)/sources/Book_Info.xml \
- $(srcdir)/sources/Author_Group.xml \
- $(srcdir)/sources/Foreword.xml \
- $(srcdir)/sources/Preface.xml \
- $(srcdir)/sources/Revision_History.xml \
- $(srcdir)/sources/Protocol.xml \
- $(srcdir)/sources/Xwayland.xml \
- $(srcdir)/sources/Compositors.xml \
- $(srcdir)/sources/images/icon.svg \
- $(srcdir)/sources/images/wayland.png \
- $(srcdir)/sources/images/xwayland-architecture.png \
- $(srcdir)/sources/Client.xml \
- $(srcdir)/sources/Server.xml
-
-processed_sources := \
- $(srcdir)/sources/Architecture.xml \
- $(srcdir)/sources/Introduction.xml
-
-css_sources = \
- $(srcdir)/sources/css/brand.css \
- $(srcdir)/sources/css/common.css \
- $(srcdir)/sources/css/default.css \
- $(srcdir)/sources/css/epub.css \
- $(srcdir)/sources/css/print.css
-
-img_sources = \
- $(srcdir)/sources/images/icon.svg \
- $(srcdir)/sources/images/wayland.png \
- $(srcdir)/sources/images/xwayland-architecture.png
-
-doxygen_img_sources := \
- $(doxydir)/xml/wayland-architecture.png \
- $(doxydir)/xml/x-architecture.png
-
-map_sources := \
- $(doxydir)/xml/x-architecture.map \
- $(doxydir)/xml/wayland-architecture.map
-
-if HAVE_XMLTO
-if HAVE_XSLTPROC
-noinst_DATA = $(builddir)/Wayland $(publican_targets)
-XMLTO_PARAM = \
- --skip-validation \
- --stringparam chunk.section.depth=0 \
- --stringparam toc.section.depth=1 \
- --stringparam html.stylesheet=css/default.css
-
-# Listing various directories that might need to be created.
-alldirs := $(builddir)/en-US $(builddir)/en-US/images $(html_destdir) $(html_destdir)/css $(html_destdir)/images
-
-
-html_css_targets = $(addprefix $(html_destdir)/css/,$(notdir $(css_sources)))
-html_img_targets = $(addprefix $(html_destdir)/images/,$(notdir $(img_sources)))
-doxygen_img_targets := $(doxygen_img_sources:$(doxydir)/xml/%=$(html_destdir)/images/%)
-map_targets := $(map_sources:$(doxydir)/xml/%=$(builddir)/en-US/images/%)
-processed_targets := $(processed_sources:$(srcdir)/sources/%=$(builddir)/en-US/%)
-
-$(builddir)/Wayland: $(publican_targets) $(html_css_targets) $(html_img_targets) $(processed_targets) $(doxygen_img_targets) | $(builddir)/en-US
- $(AM_V_GEN)$(XMLTO) $(XMLTO_PARAM) html $(builddir)/en-US/Wayland.xml -o $(html_destdir)
- @touch $@
-
-$(html_destdir)/css/%: $(srcdir)/sources/css/% | $(html_destdir)/css
- $(AM_V_GEN)cp -f $< $@
-
-$(html_destdir)/images/%: $(srcdir)/sources/images/% | $(html_destdir)/images
- $(AM_V_GEN)cp -f $< $@
-
-$(html_destdir)/images/%: $(doxydir)/xml/% | $(html_destdir)/images
- $(AM_V_GEN)cp -f $< $@
-
-pubdir = $(docdir)/Wayland/en-US
-
-publican_targets = $(publican_sources:$(srcdir)/sources/%=$(builddir)/en-US/%) \
- $(builddir)/en-US/ProtocolSpec.xml \
- $(builddir)/en-US/ProtocolInterfaces.xml \
- $(builddir)/en-US/ClientAPI.xml \
- $(builddir)/en-US/ServerAPI.xml
-
-# The Protocol.xml is purely generated and required before running publican
-$(builddir)/en-US/ProtocolSpec.xml: $(top_srcdir)/protocol/wayland.xml $(srcdir)/protocol-to-docbook.xsl | $(builddir)/en-US
- $(AM_V_GEN)$(XSLTPROC) $(srcdir)/protocol-to-docbook.xsl \
- $(top_srcdir)/protocol/wayland.xml > $@
-
-$(builddir)/en-US/ProtocolInterfaces.xml: $(top_srcdir)/protocol/wayland.xml $(srcdir)/protocol-interfaces-to-docbook.xsl | $(builddir)/en-US
- $(AM_V_GEN)$(XSLTPROC) $(srcdir)/protocol-interfaces-to-docbook.xsl \
- $(top_srcdir)/protocol/wayland.xml > $@
-
-# * use doxygen's combine.xslt to merge the xml files into one single file
-# * pipe that through the doxygen-to-publican stylesheet
-$(builddir)/en-US/%API.xml: $(doxydir)/xml/%/index.xml $(srcdir)/doxygen-to-publican.xsl | $(builddir)/en-US
- $(AM_V_GEN)$(XSLTPROC) $(doxydir)/xml/$*/combine.xslt \
- $(doxydir)/xml/$*/index.xml | \
- $(XSLTPROC) --stringparam which $* \
- $(srcdir)/doxygen-to-publican.xsl - > $@
-
-# Copy the sources source files into en-US destination
-# This is required for out-of-source-tree build as publican does not allow us
-# to specify the location of the source code.
-$(builddir)/en-US/%: $(srcdir)/sources/% $(publican_sources) | $(builddir)/en-US/images
- $(AM_V_GEN)cp -f $< $@
- $(AM_V_at)chmod a+w $@
-
-$(builddir)/en-US/images/%: $(doxydir)/xml/% | $(builddir)/en-US/images
- $(AM_V_GEN)cp -f $< $@
- $(AM_V_at)chmod a+w $@
-
-# More specific rule to override explicitly listed targets and perform xslt
-# modifications on them.
-# Note that we can't use $< as all targets must be there
-$(processed_targets): $(processed_sources) $(map_targets) $(srcdir)/merge-mapcoords.xsl | $(builddir)/en-US/images
- $(AM_V_GEN)$(XSLTPROC) --stringparam basedir $(builddir)/en-US \
- $(srcdir)/merge-mapcoords.xsl $(addprefix $(srcdir)/sources/,$(notdir $@)) > $@
-
-# general rule to create one of the listed directories.
-$(alldirs):
- $(AM_V_GEN)$(MKDIR_P) $@
-
-CLEANFILES = $(publican_targets)
-
-clean-local:
- $(AM_V_at)rm -fr $(builddir)/en-US
- $(AM_V_at)rm -fr $(builddir)/Wayland
-
-install-data-local:
- test -z "$(pubdir)/html/css" || $(mkdir_p) "$(DESTDIR)$(pubdir)/html/css"
- test -z "$(pubdir)/html/images" || $(mkdir_p) "$(DESTDIR)$(pubdir)/html/images"
- list=`find $(builddir)/Wayland/en-US -type f`; \
- for p in $$list; do \
- echo " $(INSTALL_DATA) '$$p' '$(DESTDIR)$(docdir)/$$p'"; \
- $(INSTALL_DATA) "$$p" "$(DESTDIR)$(docdir)/$$p"; \
- done;
-
-uninstall-local:
- @if test -n $(DESTDIR)$(docdir); then \
- if test -d $(DESTDIR)$(docdir); then \
- echo " rm -fr $(DESTDIR)$(docdir)/Wayland;"; \
- rm -fr $(DESTDIR)$(docdir)/Wayland; \
- fi; \
- fi;
-
-endif
-endif
-
-EXTRA_DIST = \
- $(publican_sources) $(processed_sources) $(css_sources) $(img_sources) \
- protocol-to-docbook.xsl \
- protocol-interfaces-to-docbook.xsl \
- doxygen-to-publican.xsl \
- merge-mapcoords.xsl
diff --git a/doc/publican/meson.build b/doc/publican/meson.build
index 60305f4..eac3e9b 100644
--- a/doc/publican/meson.build
+++ b/doc/publican/meson.build
@@ -7,6 +7,7 @@ custom_target(
command: [
xmlto,
'--skip-validation',
+ '--stringparam', 'chunker.output.encoding=UTF-8',
'--stringparam', 'chunk.section.depth=0',
'--stringparam', 'toc.section.depth=1',
'--stringparam', 'generate.consistent.ids=1',
diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml
index 97e9ba2..57d8835 100644
--- a/doc/publican/sources/Protocol.xml
+++ b/doc/publican/sources/Protocol.xml
@@ -149,9 +149,10 @@
<term>string</term>
<listitem>
<para>
- Starts with an unsigned 32-bit length, followed by the
- string contents, including terminating null byte, then padding
- to a 32-bit boundary.
+ Starts with an unsigned 32-bit length (including null terminator),
+ followed by the string contents, including terminating null byte,
+ then padding to a 32-bit boundary. A null value is represented
+ with a length of 0.
</para>
</listitem>
</varlistentry>
@@ -159,7 +160,7 @@
<term>object</term>
<listitem>
<para>
- 32-bit object ID.
+ 32-bit object ID. A null value is represented with an ID of 0.
</para>
</listitem>
</varlistentry>
@@ -194,6 +195,21 @@
</varlistentry>
</variablelist>
</para>
+ <para>
+ The protocol does not specify the exact position of the ancillary data
+ in the stream, except that the order of file descriptors is the same as
+ the order of messages and <code>fd</code> arguments within messages on
+ the wire.
+ </para>
+ <para>
+ In particular, it means that any byte of the stream, even the message
+ header, may carry the ancillary data with file descriptors.
+ </para>
+ <para>
+ Clients and compositors should queue incoming data until they have
+ whole messages to process, as file descriptors may arrive earlier
+ or later than the corresponding data bytes.
+ </para>
</section>
<xi:include href="ProtocolInterfaces.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
<section id="sect-Protocol-Versioning">
diff --git a/egl/meson.build b/egl/meson.build
index dee9b1d..b3cbdf3 100644
--- a/egl/meson.build
+++ b/egl/meson.build
@@ -5,13 +5,13 @@ wayland_egl = library(
wayland_client_protocol_h
],
include_directories: src_inc,
- version: '1.0.0',
+ version: meson.project_version(),
install: true
)
executable('wayland-egl-abi-check', 'wayland-egl-abi-check.c')
-nm_path = find_program('nm').path()
+nm_path = find_program('nm').full_path()
test(
'wayland-egl symbols check',
@@ -41,3 +41,12 @@ pkgconfig.generate(
description: 'Backend wayland-egl interface',
version: '3'
)
+
+wayland_egl_dep = declare_dependency(
+ link_with: wayland_egl,
+ include_directories: [ root_inc, include_directories('.') ],
+)
+
+if meson.version().version_compare('>= 0.54.0')
+ meson.override_dependency('wayland-egl', wayland_egl_dep)
+endif
diff --git a/egl/wayland-egl-backend.h b/egl/wayland-egl-backend.h
index 869c86f..e5287b7 100644
--- a/egl/wayland-egl-backend.h
+++ b/egl/wayland-egl-backend.h
@@ -35,8 +35,8 @@ extern "C" {
#endif
/*
- * NOTE: This version must be kept in sync with the Version field in the
- * wayland-egl-backend.pc.in file.
+ * NOTE: This version must be kept in sync with the version field in the
+ * wayland-egl-backend pkgconfig file generated in meson.build.
*/
#define WL_EGL_WINDOW_VERSION 3
diff --git a/egl/wayland-egl-backend.pc.in b/egl/wayland-egl-backend.pc.in
deleted file mode 100644
index 6cf0ed4..0000000
--- a/egl/wayland-egl-backend.pc.in
+++ /dev/null
@@ -1,9 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-includedir=@includedir@
-
-Name: wayland-egl-backend
-Description: Backend wayland-egl interface
-Version: 3
-Libs:
-Cflags: -I${includedir}
diff --git a/egl/wayland-egl.c b/egl/wayland-egl.c
index a60f899..36a3471 100644
--- a/egl/wayland-egl.c
+++ b/egl/wayland-egl.c
@@ -35,6 +35,20 @@
#include "wayland-util.h"
+/** Resize the EGL window
+ *
+ * \param egl_window A pointer to a struct wl_egl_window
+ * \param width The new width
+ * \param height The new height
+ * \param dx Offset on the X axis
+ * \param dy Offset on the Y axis
+ *
+ * Note that applications should prefer using the wl_surface.offset request if
+ * the associated wl_surface has the interface version 5 or higher.
+ *
+ * If the wl_surface.offset request is used, applications MUST pass 0 to both
+ * dx and dy.
+ */
WL_EXPORT void
wl_egl_window_resize(struct wl_egl_window *egl_window,
int width, int height,
diff --git a/egl/wayland-egl.pc.in b/egl/wayland-egl.pc.in
deleted file mode 100644
index 2e2d4c4..0000000
--- a/egl/wayland-egl.pc.in
+++ /dev/null
@@ -1,11 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: wayland-egl
-Description: Frontend wayland-egl library
-Version: 18.1.0
-Requires: wayland-client
-Libs: -L${libdir} -lwayland-egl
-Cflags: -I${includedir}
diff --git a/m4/.gitignore b/m4/.gitignore
deleted file mode 100644
index 38066dd..0000000
--- a/m4/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-libtool.m4
-ltoptions.m4
-ltsugar.m4
-ltversion.m4
-lt~obsolete.m4
diff --git a/m4/weston.m4 b/m4/weston.m4
deleted file mode 100644
index 636f9fb..0000000
--- a/m4/weston.m4
+++ /dev/null
@@ -1,37 +0,0 @@
-dnl
-dnl Copyright © 2016 Quentin “Sardem FF7†Glidic
-dnl
-dnl Permission is hereby granted, free of charge, to any person obtaining a
-dnl copy of this software and associated documentation files (the "Software"),
-dnl to deal in the Software without restriction, including without limitation
-dnl the rights to use, copy, modify, merge, publish, distribute, sublicense,
-dnl and/or sell copies of the Software, and to permit persons to whom the
-dnl Software is furnished to do so, subject to the following conditions:
-dnl
-dnl The above copyright notice and this permission notice (including the next
-dnl paragraph) shall be included in all copies or substantial portions of the
-dnl Software.
-dnl
-dnl THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-dnl IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-dnl FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-dnl THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-dnl LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-dnl FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-dnl DEALINGS IN THE SOFTWARE.
-dnl
-
-dnl WESTON_SEARCH_LIBS(PREFIX, search-libs, function, [action-if-found], [action-if-not-found], [other-libraries])
-dnl WESTON_SEARCH_LIBS is a wrapper around AC_SEARCH_LIBS with a little difference:
-dnl action-if-found is called even if no library is required
-AC_DEFUN([WESTON_SEARCH_LIBS], [
- weston_save_LIBS=${LIBS}
- AC_SEARCH_LIBS([$3], [$2], [$4], [$5], [$6])
- AS_CASE([${ac_cv_search_][$3][}],
- ['none required'], [$4],
- [no], [],
- [$1][_LIBS=${ac_cv_search_][$3][}]
- )
- AC_SUBST([$1][_LIBS])
- LIBS=${weston_save_LIBS}
-])
diff --git a/meson.build b/meson.build
index 11c35fa..558c7ac 100644
--- a/meson.build
+++ b/meson.build
@@ -1,18 +1,26 @@
project(
- 'wayland', 'c', 'cpp',
- version: '1.19.0',
+ 'wayland', 'c',
+ version: '1.22.0',
license: 'MIT',
- meson_version: '>= 0.52.1',
+ meson_version: '>= 0.56.0',
default_options: [
'warning_level=2',
- 'buildtype=debugoptimized'
+ 'buildtype=debugoptimized',
+ 'c_std=c99',
]
)
+wayland_version = meson.project_version().split('.')
config_h = configuration_data()
config_h.set_quoted('PACKAGE', meson.project_name())
config_h.set_quoted('PACKAGE_VERSION', meson.project_version())
+cc_args = []
+if host_machine.system() != 'freebsd'
+ cc_args += ['-D_POSIX_C_SOURCE=200809L']
+endif
+add_project_arguments(cc_args, language: 'c')
+
compiler_flags = [
'-Wno-unused-parameter',
'-Wstrict-prototypes',
@@ -26,7 +34,7 @@ add_project_arguments(
language: 'c'
)
-foreach h: [ 'sys/prctl.h' ]
+foreach h: [ 'sys/prctl.h', 'sys/procctl.h', 'sys/ucred.h' ]
config_h.set('HAVE_' + h.underscorify().to_upper(), cc.has_header(h))
endforeach
@@ -36,13 +44,39 @@ have_funcs = [
'posix_fallocate',
'prctl',
'memfd_create',
+ 'mremap',
'strndup',
]
foreach f: have_funcs
config_h.set('HAVE_' + f.underscorify().to_upper(), cc.has_function(f))
endforeach
+config_h.set10('HAVE_XUCRED_CR_PID', cc.has_member('struct xucred', 'cr_pid', prefix : '#include <sys/ucred.h>'))
+have_broken_msg_cmsg_cloexec = false
+if host_machine.system() == 'freebsd'
+ have_broken_msg_cmsg_cloexec = not cc.compiles('''
+#include <sys/param.h> /* To get __FreeBSD_version. */
+#if __FreeBSD_version < 1300502 || \
+ (__FreeBSD_version >= 1400000 && __FreeBSD_version < 1400006)
+/*
+ * FreeBSD had a broken implementation of MSG_CMSG_CLOEXEC between 2015 and
+ * 2021. Check if we are compiling against a version that includes the fix
+ * (https://cgit.freebsd.org/src/commit/?id=6ceacebdf52211).
+ */
+#error "Broken MSG_CMSG_CLOEXEC"
+#endif
+''', name : 'MSG_CMSG_CLOEXEC works correctly')
+endif
+config_h.set10('HAVE_BROKEN_MSG_CMSG_CLOEXEC', have_broken_msg_cmsg_cloexec)
if get_option('libraries')
+ if host_machine.system() == 'freebsd'
+ # When building for FreeBSD, epoll(7) is provided by a userspace
+ # wrapper around kqueue(2).
+ epoll_dep = dependency('epoll-shim')
+ else
+ # Otherwise, assume that epoll(7) is supported natively.
+ epoll_dep = []
+ endif
ffi_dep = dependency('libffi')
decls = [
@@ -52,7 +86,7 @@ if get_option('libraries')
]
foreach d: decls
- if not cc.has_header_symbol(d['header'], d['symbol'])
+ if not cc.has_header_symbol(d['header'], d['symbol'], dependencies: epoll_dep, args: cc_args)
error('@0@ is needed to compile Wayland libraries'.format(d['symbol']))
endif
endforeach
@@ -60,19 +94,12 @@ if get_option('libraries')
rt_dep = []
if not cc.has_function('clock_gettime', prefix: '#include <time.h>')
rt_dep = cc.find_library('rt')
- if not cc.has_function('clock_gettime', prefix: '#include <time.h>', dependencies: rt_dep)
+ if not cc.has_function('clock_gettime', prefix: '#include <time.h>', dependencies: rt_dep, args: cc_args)
error('clock_gettime not found')
endif
endif
endif
-scanner_deps = [ dependency('expat') ]
-
-if get_option('dtd_validation')
- scanner_deps += dependency('libxml-2.0')
- config_h.set('HAVE_LIBXML', 1)
-endif
-
configure_file(
output: 'config.h',
configuration: config_h,
@@ -91,10 +118,12 @@ subdir('src')
if get_option('libraries')
subdir('cursor')
subdir('egl')
+endif
+if get_option('tests')
subdir('tests')
- if get_option('documentation')
- subdir('doc')
- endif
+endif
+if get_option('documentation')
+ subdir('doc')
endif
if get_option('scanner')
diff --git a/meson_options.txt b/meson_options.txt
index de588d1..b8e2ec6 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1,19 +1,23 @@
option('libraries',
description: 'Compile Wayland libraries',
type: 'boolean',
- value: 'true')
+ value: true)
option('scanner',
description: 'Compile wayland-scanner binary',
type: 'boolean',
- value: 'true')
+ value: true)
+option('tests',
+ description: 'Compile Wayland tests',
+ type: 'boolean',
+ value: true)
option('documentation',
description: 'Build the documentation (requires Doxygen, dot, xmlto, xsltproc)',
type: 'boolean',
- value: 'true')
+ value: true)
option('dtd_validation',
description: 'Validate the protocol DTD (requires libxml2)',
type: 'boolean',
- value: 'true')
+ value: true)
option('icon_directory',
description: 'Location used to look for cursors (defaults to ${datadir}/icons if unset)',
type: 'string',
diff --git a/protocol/wayland.dtd b/protocol/wayland.dtd
index 15f20ab..ee062ee 100644
--- a/protocol/wayland.dtd
+++ b/protocol/wayland.dtd
@@ -10,6 +10,7 @@
<!ATTLIST request since CDATA #IMPLIED>
<!ELEMENT event (description?,arg*)>
<!ATTLIST event name CDATA #REQUIRED>
+ <!ATTLIST event type CDATA #IMPLIED>
<!ATTLIST event since CDATA #IMPLIED>
<!ELEMENT enum (description?,entry*)>
<!ATTLIST enum name CDATA #REQUIRED>
diff --git a/protocol/wayland.xml b/protocol/wayland.xml
index 471daf6..10e039d 100644
--- a/protocol/wayland.xml
+++ b/protocol/wayland.xml
@@ -177,9 +177,12 @@
<description summary="callback object">
Clients can handle the 'done' event to get notified when
the related request is done.
+
+ Note, because wl_callback objects are created from multiple independent
+ factory interfaces, the wl_callback interface is frozen at version 1.
</description>
- <event name="done">
+ <event name="done" type="destructor">
<description summary="done event">
Notify the client when the related request is done.
</description>
@@ -187,7 +190,7 @@
</event>
</interface>
- <interface name="wl_compositor" version="4">
+ <interface name="wl_compositor" version="6">
<description summary="the compositor singleton">
A compositor. This object is a singleton global. The
compositor is in charge of combining the contents of multiple
@@ -258,6 +261,12 @@
for the pool from the file descriptor passed when the pool was
created, but using the new size. This request can only be
used to make the pool bigger.
+
+ This request only changes the amount of bytes that are mmapped
+ by the server and does not touch the file corresponding to the
+ file descriptor passed at creation time. It is the client's
+ responsibility to ensure that the file is at least as big as
+ the new pool size.
</description>
<arg name="size" type="int" summary="new size of the pool, in bytes"/>
</request>
@@ -271,8 +280,8 @@
Clients can create wl_shm_pool objects using the create_pool
request.
- At connection setup time, the wl_shm object emits one or more
- format events to inform clients about the valid pixel formats
+ On binding the wl_shm object one or more format events
+ are emitted to inform clients about the valid pixel formats
that can be used for buffers.
</description>
@@ -296,6 +305,9 @@
The drm format codes match the macros defined in drm_fourcc.h, except
argb8888 and xrgb8888. The formats actually supported by the compositor
will be reported by the format event.
+
+ For all wl_shm formats and unless specified in another protocol
+ extension, pre-multiplied alpha is used for pixel values.
</description>
<!-- Note to protocol writers: don't update this list manually, instead
run the automated script that keeps it in sync with drm_fourcc.h. -->
@@ -403,6 +415,10 @@
<entry name="nv15" value="0x3531564e" summary="2x2 subsampled Cr:Cb plane"/>
<entry name="q410" value="0x30313451"/>
<entry name="q401" value="0x31303451"/>
+ <entry name="xrgb16161616" value="0x38345258" summary="[63:0] x:R:G:B 16:16:16:16 little endian"/>
+ <entry name="xbgr16161616" value="0x38344258" summary="[63:0] x:B:G:R 16:16:16:16 little endian"/>
+ <entry name="argb16161616" value="0x38345241" summary="[63:0] A:R:G:B 16:16:16:16 little endian"/>
+ <entry name="abgr16161616" value="0x38344241" summary="[63:0] A:B:G:R 16:16:16:16 little endian"/>
</enum>
<request name="create_pool">
@@ -431,10 +447,18 @@
<interface name="wl_buffer" version="1">
<description summary="content for a wl_surface">
A buffer provides the content for a wl_surface. Buffers are
- created through factory interfaces such as wl_drm, wl_shm or
- similar. It has a width and a height and can be attached to a
- wl_surface, but the mechanism by which a client provides and
- updates the contents is defined by the buffer factory interface.
+ created through factory interfaces such as wl_shm, wp_linux_buffer_params
+ (from the linux-dmabuf protocol extension) or similar. It has a width and
+ a height and can be attached to a wl_surface, but the mechanism by which a
+ client provides and updates the contents is defined by the buffer factory
+ interface.
+
+ If the buffer uses a format that has an alpha channel, the alpha channel
+ is assumed to be premultiplied in the color channels unless otherwise
+ specified.
+
+ Note, because wl_buffer objects are created from multiple independent
+ factory interfaces, the wl_buffer interface is frozen at version 1.
</description>
<request name="destroy" type="destructor">
@@ -606,8 +630,9 @@
<event name="source_actions" since="3">
<description summary="notify the source-side available actions">
This event indicates the actions offered by the data source. It
- will be sent right after wl_data_device.enter, or anytime the source
- side changes its offered actions through wl_data_source.set_actions.
+ will be sent immediately after creating the wl_data_offer object,
+ or anytime the source side changes its offered actions through
+ wl_data_source.set_actions.
</description>
<arg name="source_actions" type="uint" summary="actions offered by the data source"
enum="wl_data_device_manager.dnd_action"/>
@@ -849,11 +874,8 @@
a drag-and-drop icon. If the icon surface already has another role,
it raises a protocol error.
- The current and pending input regions of the icon wl_surface are
- cleared, and wl_surface.set_input_region is ignored until the
- wl_surface is no longer used as the icon surface. When the use
- as an icon ends, the current and pending input regions become
- undefined, and the wl_surface is unmapped.
+ The input region is ignored for wl_surfaces with the role of a
+ drag-and-drop icon.
</description>
<arg name="source" type="object" interface="wl_data_source" allow-null="true" summary="data source for the eventual transfer"/>
<arg name="origin" type="object" interface="wl_surface" summary="surface where the drag originates"/>
@@ -878,7 +900,7 @@
which will subsequently be used in either the
data_device.enter event (for drag-and-drop) or the
data_device.selection event (for selections). Immediately
- following the data_device_data_offer event, the new data_offer
+ following the data_device.data_offer event, the new data_offer
object will send out data_offer.offer events to describe the
mime types it offers.
</description>
@@ -948,9 +970,10 @@
immediately before receiving keyboard focus and when a new
selection is set while the client has keyboard focus. The
data_offer is valid until a new data_offer or NULL is received
- or until the client loses keyboard focus. The client must
- destroy the previous selection data_offer, if any, upon receiving
- this event.
+ or until the client loses keyboard focus. Switching surface with
+ keyboard focus within the same client doesn't mean a new selection
+ will be sent. The client must destroy the previous selection
+ data_offer, if any, upon receiving this event.
</description>
<arg name="id" type="object" interface="wl_data_offer" allow-null="true"
summary="selection data_offer object"/>
@@ -1038,7 +1061,8 @@
a basic surface.
Note! This protocol is deprecated and not intended for production use.
- For desktop-style user interfaces, use xdg_shell.
+ For desktop-style user interfaces, use xdg_shell. Compositors and clients
+ should not implement this interface.
</description>
<enum name="error">
@@ -1332,7 +1356,7 @@
</event>
</interface>
- <interface name="wl_surface" version="4">
+ <interface name="wl_surface" version="6">
<description summary="an onscreen surface">
A surface is a rectangular area that may be displayed on zero
or more outputs, and shown any number of times at the compositor's
@@ -1364,8 +1388,9 @@
that this request gives a role to a wl_surface. Often, this
request also creates a new protocol object that represents the
role and adds additional functionality to wl_surface. When a
- client wants to destroy a wl_surface, they must destroy this 'role
- object' before the wl_surface.
+ client wants to destroy a wl_surface, they must destroy this role
+ object before the wl_surface, otherwise a defunct_role_object error is
+ sent.
Destroying the role object does not remove the role from the
wl_surface, but it may stop the wl_surface from "playing the role".
@@ -1384,6 +1409,9 @@
<entry name="invalid_scale" value="0" summary="buffer scale value is invalid"/>
<entry name="invalid_transform" value="1" summary="buffer transform value is invalid"/>
<entry name="invalid_size" value="2" summary="buffer size is invalid"/>
+ <entry name="invalid_offset" value="3" summary="buffer offset is invalid"/>
+ <entry name="defunct_role_object" value="4"
+ summary="surface was destroyed before its role object"/>
</enum>
<request name="destroy" type="destructor">
@@ -1406,7 +1434,15 @@
buffer's upper left corner, relative to the current buffer's upper
left corner, in surface-local coordinates. In other words, the
x and y, combined with the new surface size define in which
- directions the surface's size changes.
+ directions the surface's size changes. Setting anything other than 0
+ as x and y arguments is discouraged, and should instead be replaced
+ with using the separate wl_surface.offset request.
+
+ When the bound wl_surface version is 5 or higher, passing any
+ non-zero x or y is a protocol violation, and will result in an
+ 'invalid_offset' error being raised. The x and y arguments are ignored
+ and do not change the pending state. To achieve equivalent semantics,
+ use wl_surface.offset.
Surface contents are double-buffered state, see wl_surface.commit.
@@ -1434,9 +1470,12 @@
from the same backing storage or use wp_linux_buffer_release.
Destroying the wl_buffer after wl_buffer.release does not change
- the surface contents. However, if the client destroys the
- wl_buffer before receiving the wl_buffer.release event, the surface
- contents become undefined immediately.
+ the surface contents. Destroying the wl_buffer before wl_buffer.release
+ is allowed as long as the underlying buffer storage isn't re-used (this
+ can happen e.g. on client process termination). However, if the client
+ destroys the wl_buffer before receiving the wl_buffer.release event and
+ mutates the underlying buffer storage, the surface contents become
+ undefined immediately.
If wl_surface.attach is sent with a NULL wl_buffer, the
following wl_surface.commit will remove the surface content.
@@ -1734,9 +1773,58 @@
<arg name="width" type="int" summary="width of damage rectangle"/>
<arg name="height" type="int" summary="height of damage rectangle"/>
</request>
+
+ <!-- Version 5 additions -->
+
+ <request name="offset" since="5">
+ <description summary="set the surface contents offset">
+ The x and y arguments specify the location of the new pending
+ buffer's upper left corner, relative to the current buffer's upper
+ left corner, in surface-local coordinates. In other words, the
+ x and y, combined with the new surface size define in which
+ directions the surface's size changes.
+
+ Surface location offset is double-buffered state, see
+ wl_surface.commit.
+
+ This request is semantically equivalent to and the replaces the x and y
+ arguments in the wl_surface.attach request in wl_surface versions prior
+ to 5. See wl_surface.attach for details.
+ </description>
+ <arg name="x" type="int" summary="surface-local x coordinate"/>
+ <arg name="y" type="int" summary="surface-local y coordinate"/>
+ </request>
+
+ <!-- Version 6 additions -->
+
+ <event name="preferred_buffer_scale" since="6">
+ <description summary="preferred buffer scale for the surface">
+ This event indicates the preferred buffer scale for this surface. It is
+ sent whenever the compositor's preference changes.
+
+ It is intended that scaling aware clients use this event to scale their
+ content and use wl_surface.set_buffer_scale to indicate the scale they
+ have rendered with. This allows clients to supply a higher detail
+ buffer.
+ </description>
+ <arg name="factor" type="int" summary="preferred scaling factor"/>
+ </event>
+
+ <event name="preferred_buffer_transform" since="6">
+ <description summary="preferred buffer transform for the surface">
+ This event indicates the preferred buffer transform for this surface.
+ It is sent whenever the compositor's preference changes.
+
+ It is intended that transform aware clients use this event to apply the
+ transform to their content and use wl_surface.set_buffer_transform to
+ indicate the transform they have rendered with.
+ </description>
+ <arg name="transform" type="uint" enum="wl_output.transform"
+ summary="preferred transform"/>
+ </event>
</interface>
- <interface name="wl_seat" version="7">
+ <interface name="wl_seat" version="9">
<description summary="group of input devices">
A seat is a group of keyboards, pointer and touch devices. This
object is published as a global during start up, or when such a
@@ -1838,9 +1926,22 @@
<event name="name" since="2">
<description summary="unique identifier for this seat">
- In a multiseat configuration this can be used by the client to help
- identify which physical devices the seat represents. Based on
- the seat configuration used by the compositor.
+ In a multi-seat configuration the seat name can be used by clients to
+ help identify which physical devices the seat represents.
+
+ The seat name is a UTF-8 string with no convention defined for its
+ contents. Each name is unique among all wl_seat globals. The name is
+ only guaranteed to be unique for the current compositor instance.
+
+ The same seat names are used for all clients. Thus, the name can be
+ shared across processes to refer to a specific wl_seat global.
+
+ The name event is sent after binding to the seat global. This event is
+ only sent once per seat object, and the name does not change over the
+ lifetime of the wl_seat global.
+
+ Compositors may re-use the same seat name if the wl_seat global is
+ destroyed and re-created later.
</description>
<arg name="name" type="string" summary="seat identifier"/>
</event>
@@ -1856,7 +1957,7 @@
</interface>
- <interface name="wl_pointer" version="7">
+ <interface name="wl_pointer" version="9">
<description summary="pointer input device">
The wl_pointer interface represents one or more input devices,
such as mice, which control the pointer location and pointer_focus
@@ -1900,11 +2001,13 @@
pointer surface to this request with new values for hotspot_x
and hotspot_y.
- The current and pending input regions of the wl_surface are
- cleared, and wl_surface.set_input_region is ignored until the
- wl_surface is no longer used as the cursor. When the use as a
- cursor ends, the current and pending input regions become
- undefined, and the wl_surface is unmapped.
+ The input region is ignored for wl_surfaces with the role of
+ a cursor. When the use as a cursor ends, the wl_surface is
+ unmapped.
+
+ The serial parameter must match the latest wl_pointer.enter
+ serial number sent to the client. Otherwise the request will be
+ ignored.
</description>
<arg name="serial" type="uint" summary="serial number of the enter event"/>
<arg name="surface" type="object" interface="wl_surface" allow-null="true"
@@ -2152,6 +2255,9 @@
This event carries the axis value of the wl_pointer.axis event in
discrete steps (e.g. mouse wheel clicks).
+ This event is deprecated with wl_pointer version 8 - this event is not
+ sent to clients supporting version 8 or later.
+
This event does not occur on its own, it is coupled with a
wl_pointer.axis event that represents this axis value on a
continuous scale. The protocol guarantees that each axis_discrete
@@ -2159,7 +2265,8 @@
axis number within the same wl_pointer.frame. Note that the protocol
allows for other events to occur between the axis_discrete and
its coupled axis event, including other axis_discrete or axis
- events.
+ events. A wl_pointer.frame must not contain more than one axis_discrete
+ event per axis type.
This event is optional; continuous scrolling devices
like two-finger scrolling on touchpads do not have discrete
@@ -2177,9 +2284,93 @@
<arg name="axis" type="uint" enum="axis" summary="axis type"/>
<arg name="discrete" type="int" summary="number of steps"/>
</event>
+
+ <event name="axis_value120" since="8">
+ <description summary="axis high-resolution scroll event">
+ Discrete high-resolution scroll information.
+
+ This event carries high-resolution wheel scroll information,
+ with each multiple of 120 representing one logical scroll step
+ (a wheel detent). For example, an axis_value120 of 30 is one quarter of
+ a logical scroll step in the positive direction, a value120 of
+ -240 are two logical scroll steps in the negative direction within the
+ same hardware event.
+ Clients that rely on discrete scrolling should accumulate the
+ value120 to multiples of 120 before processing the event.
+
+ The value120 must not be zero.
+
+ This event replaces the wl_pointer.axis_discrete event in clients
+ supporting wl_pointer version 8 or later.
+
+ Where a wl_pointer.axis_source event occurs in the same
+ wl_pointer.frame, the axis source applies to this event.
+
+ The order of wl_pointer.axis_value120 and wl_pointer.axis_source is
+ not guaranteed.
+ </description>
+ <arg name="axis" type="uint" enum="axis" summary="axis type"/>
+ <arg name="value120" type="int" summary="scroll distance as fraction of 120"/>
+ </event>
+
+ <!-- Version 9 additions -->
+
+ <enum name="axis_relative_direction">
+ <description summary="axis relative direction">
+ This specifies the direction of the physical motion that caused a
+ wl_pointer.axis event, relative to the wl_pointer.axis direction.
+ </description>
+ <entry name="identical" value="0"
+ summary="physical motion matches axis direction"/>
+ <entry name="inverted" value="1"
+ summary="physical motion is the inverse of the axis direction"/>
+ </enum>
+
+ <event name="axis_relative_direction" since="9">
+ <description summary="axis relative physical direction event">
+ Relative directional information of the entity causing the axis
+ motion.
+
+ For a wl_pointer.axis event, the wl_pointer.axis_relative_direction
+ event specifies the movement direction of the entity causing the
+ wl_pointer.axis event. For example:
+ - if a user's fingers on a touchpad move down and this
+ causes a wl_pointer.axis vertical_scroll down event, the physical
+ direction is 'identical'
+ - if a user's fingers on a touchpad move down and this causes a
+ wl_pointer.axis vertical_scroll up scroll up event ('natural
+ scrolling'), the physical direction is 'inverted'.
+
+ A client may use this information to adjust scroll motion of
+ components. Specifically, enabling natural scrolling causes the
+ content to change direction compared to traditional scrolling.
+ Some widgets like volume control sliders should usually match the
+ physical direction regardless of whether natural scrolling is
+ active. This event enables clients to match the scroll direction of
+ a widget to the physical direction.
+
+ This event does not occur on its own, it is coupled with a
+ wl_pointer.axis event that represents this axis value.
+ The protocol guarantees that each axis_relative_direction event is
+ always followed by exactly one axis event with the same
+ axis number within the same wl_pointer.frame. Note that the protocol
+ allows for other events to occur between the axis_relative_direction
+ and its coupled axis event.
+
+ The axis number is identical to the axis number in the associated
+ axis event.
+
+ The order of wl_pointer.axis_relative_direction,
+ wl_pointer.axis_discrete and wl_pointer.axis_source is not
+ guaranteed.
+ </description>
+ <arg name="axis" type="uint" enum="axis" summary="axis type"/>
+ <arg name="direction" type="uint" enum="axis_relative_direction"
+ summary="physical direction relative to axis motion"/>
+ </event>
</interface>
- <interface name="wl_keyboard" version="7">
+ <interface name="wl_keyboard" version="9">
<description summary="keyboard input device">
The wl_keyboard interface represents one or more keyboards
associated with a seat.
@@ -2193,13 +2384,14 @@
<entry name="no_keymap" value="0"
summary="no keymap; client must understand how to interpret the raw keycode"/>
<entry name="xkb_v1" value="1"
- summary="libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode"/>
+ summary="libxkbcommon compatible, null-terminated string; to determine the xkb keycode, clients must add 8 to the key event keycode"/>
</enum>
<event name="keymap">
<description summary="keyboard mapping">
This event provides a file descriptor to the client which can be
- memory-mapped to provide a keyboard mapping description.
+ memory-mapped in read-only mode to provide a keyboard mapping
+ description.
From version 7 onwards, the fd must be mapped with MAP_PRIVATE by
the recipient, as MAP_SHARED may fail.
@@ -2305,7 +2497,7 @@
</event>
</interface>
- <interface name="wl_touch" version="7">
+ <interface name="wl_touch" version="9">
<description summary="touchscreen input device">
The wl_touch interface represents a touchscreen
associated with a seat.
@@ -2449,7 +2641,7 @@
</event>
</interface>
- <interface name="wl_output" version="3">
+ <interface name="wl_output" version="4">
<description summary="compositor output region">
An output describes part of the compositor geometry. The
compositor works in the 'compositor coordinate system' and an
@@ -2505,12 +2697,15 @@
The physical size can be set to zero if it doesn't make sense for this
output (e.g. for projectors or virtual outputs).
+ The geometry event will be followed by a done event (starting from
+ version 2).
+
Note: wl_output only advertises partial information about the output
position and identification. Some compositors, for instance those not
implementing a desktop-style output layout or those exposing virtual
outputs, might fake this information. Instead of using x and y, clients
should use xdg_output.logical_position. Instead of using make and model,
- clients should use xdg_output.name and xdg_output.description.
+ clients should use name and description.
</description>
<arg name="x" type="int"
summary="x position within the global compositor space"/>
@@ -2566,6 +2761,9 @@
The vertical refresh rate can be set to zero if it doesn't make
sense for this output (e.g. for virtual outputs).
+ The mode event will be followed by a done event (starting from
+ version 2).
+
Clients should not use the refresh rate to schedule frames. Instead,
they should use the wl_surface.frame event or the presentation-time
protocol.
@@ -2612,6 +2810,8 @@
the scale of the output. That way the compositor can
avoid scaling the surface, and the client can supply
a higher detail image.
+
+ The scale event will be followed by a done event.
</description>
<arg name="factor" type="int" summary="scaling factor of output"/>
</event>
@@ -2624,6 +2824,62 @@
use the output object anymore.
</description>
</request>
+
+ <!-- Version 4 additions -->
+
+ <event name="name" since="4">
+ <description summary="name of this output">
+ Many compositors will assign user-friendly names to their outputs, show
+ them to the user, allow the user to refer to an output, etc. The client
+ may wish to know this name as well to offer the user similar behaviors.
+
+ The name is a UTF-8 string with no convention defined for its contents.
+ Each name is unique among all wl_output globals. The name is only
+ guaranteed to be unique for the compositor instance.
+
+ The same output name is used for all clients for a given wl_output
+ global. Thus, the name can be shared across processes to refer to a
+ specific wl_output global.
+
+ The name is not guaranteed to be persistent across sessions, thus cannot
+ be used to reliably identify an output in e.g. configuration files.
+
+ Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do
+ not assume that the name is a reflection of an underlying DRM connector,
+ X11 connection, etc.
+
+ The name event is sent after binding the output object. This event is
+ only sent once per output object, and the name does not change over the
+ lifetime of the wl_output global.
+
+ Compositors may re-use the same output name if the wl_output global is
+ destroyed and re-created later. Compositors should avoid re-using the
+ same name if possible.
+
+ The name event will be followed by a done event.
+ </description>
+ <arg name="name" type="string" summary="output name"/>
+ </event>
+
+ <event name="description" since="4">
+ <description summary="human-readable description of this output">
+ Many compositors can produce human-readable descriptions of their
+ outputs. The client may wish to know this description as well, e.g. for
+ output selection purposes.
+
+ The description is a UTF-8 string with no convention defined for its
+ contents. The description is not guaranteed to be unique among all
+ wl_output globals. Examples might include 'Foocorp 11" Display' or
+ 'Virtual X11 output via :1'.
+
+ The description event is sent after binding the output object and
+ whenever the description changes. The description is optional, and may
+ not be sent at all.
+
+ The description event will be followed by a done event.
+ </description>
+ <arg name="description" type="string" summary="output description"/>
+ </event>
</interface>
<interface name="wl_region" version="1">
@@ -2695,6 +2951,8 @@
<enum name="error">
<entry name="bad_surface" value="0"
summary="the to-be sub-surface is invalid"/>
+ <entry name="bad_parent" value="1"
+ summary="the to-be sub-surface parent is invalid"/>
</enum>
<request name="get_subsurface">
@@ -2704,14 +2962,18 @@
plain wl_surface into a sub-surface.
The to-be sub-surface must not already have another role, and it
- must not have an existing wl_subsurface object. Otherwise a protocol
- error is raised.
+ must not have an existing wl_subsurface object. Otherwise the
+ bad_surface protocol error is raised.
Adding sub-surfaces to a parent is a double-buffered operation on the
parent (see wl_surface.commit). The effect of adding a sub-surface
becomes visible on the next time the state of the parent surface is
applied.
+ The parent surface must not be one of the child surface's descendants,
+ and the parent must be different from the child surface, otherwise the
+ bad_parent protocol error is raised.
+
This request modifies the behaviour of wl_surface.commit request on
the sub-surface, see the documentation on wl_subsurface interface.
</description>
@@ -2766,12 +3028,10 @@
synchronized mode, and then assume that all its child and grand-child
sub-surfaces are synchronized, too, without explicitly setting them.
- If the wl_surface associated with the wl_subsurface is destroyed, the
- wl_subsurface object becomes inert. Note, that destroying either object
- takes effect immediately. If you need to synchronize the removal
- of a sub-surface to the parent surface update, unmap the sub-surface
- first by attaching a NULL wl_buffer, update parent, and then destroy
- the sub-surface.
+ Destroying a sub-surface takes effect immediately. If you need to
+ synchronize the removal of a sub-surface to the parent surface update,
+ unmap the sub-surface first by attaching a NULL wl_buffer, update parent,
+ and then destroy the sub-surface.
If the parent wl_surface object is destroyed, the sub-surface is
unmapped.
@@ -2782,8 +3042,7 @@
The sub-surface interface is removed from the wl_surface object
that was turned into a sub-surface with a
wl_subcompositor.get_subsurface request. The wl_surface's association
- to the parent is deleted, and the wl_surface loses its role as
- a sub-surface. The wl_surface is unmapped immediately.
+ to the parent is deleted. The wl_surface is unmapped immediately.
</description>
</request>
diff --git a/publish-doc b/publish-doc
deleted file mode 100755
index 80fc22a..0000000
--- a/publish-doc
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-
-set -e
-
-[ -e doc ] || (echo "Run this from the project root" && exit 1)
-
-make
-
-DOC_HTML=./doc/publican/Wayland/en-US/html/
-
-[ -e "${DOC_HTML}" ] || (echo "HTML documentation failed to build at ${DOC_HTML}" && exit 1)
-
-chmod -R g+x ${DOC_HTML}
-
-rsync --delete -avz ${DOC_HTML} freedesktop.org:/srv/wayland.freedesktop.org/www/docs/html/
diff --git a/release.sh b/release.sh
new file mode 100755
index 0000000..8e843f5
--- /dev/null
+++ b/release.sh
@@ -0,0 +1,79 @@
+#!/bin/sh -eu
+
+build_dir=build-release
+
+if ! type glab >/dev/null; then
+ echo "glab is needed to create a release"
+ exit 1
+fi
+
+case "$(git rev-parse --abbrev-ref HEAD)" in
+main | [0-9]*.[0-9]*)
+ ;;
+*)
+ echo "Not on the main or a stable branch"
+ exit 1
+esac
+
+if [ -n "$(git log @{upstream}..)" ]; then
+ echo "The main branch has unpushed commits"
+ exit 1
+fi
+
+meson_options=""
+if [ -e "$build_dir" ]; then
+ meson_options="$meson_options --wipe"
+fi
+meson setup "$build_dir" $meson_options
+
+prev_version="$(git describe --tags --abbrev=0)"
+version="$(meson introspect "$build_dir" --projectinfo | jq -r .version)"
+if [ "$version" = "$prev_version" ]; then
+ echo "Version not bumped"
+ exit 1
+fi
+
+name="$(meson introspect "$build_dir" --projectinfo | jq -r .descriptive_name)"
+if [ "$name" = "" ]; then
+ echo "Cannot determine project name"
+ exit 1
+fi
+
+ninja -C "$build_dir" dist
+
+archive_name="$name-$version.tar.xz"
+archive_path="$build_dir/meson-dist/$archive_name"
+gpg --detach-sig "$archive_path"
+
+sha256="$(cd $build_dir/meson-dist && sha256sum $archive_name)"
+sha512="$(cd $build_dir/meson-dist && sha512sum $archive_name)"
+archive_url="https://gitlab.freedesktop.org/wayland/$name/-/releases/$version/downloads/$archive_name"
+announce_path="$build_dir/meson-dist/$name-$version-announce.eml"
+current_branch=$(git branch --show-current)
+remote_name=$(git config --get branch.${current_branch}.remote)
+
+cat >"$announce_path" <<EOF
+To: <wayland-devel@lists.freedesktop.org>
+Subject: [ANNOUNCE] $name $version
+
+`git shortlog --no-merges "$prev_version.."`
+
+git tag: $version
+
+$archive_url
+SHA256: $sha256
+SHA512: $sha512
+PGP: $archive_url.sig
+EOF
+
+echo "Release announcement written to $announce_path"
+
+echo -n "Release $name $version? [y/N] "
+read answer
+if [ "$answer" != "y" ]; then
+ exit 1
+fi
+
+git tag -s -m "$version" "$version"
+git push "$remote_name" "$version"
+glab release create "$version" "$archive_path"* --notes ""
diff --git a/releasing.txt b/releasing.txt
index 1481f7c..e93f53d 100644
--- a/releasing.txt
+++ b/releasing.txt
@@ -3,41 +3,25 @@ To make a release of Wayland, follow these steps.
0. Verify the test suites and codebase checks pass. All of the
tests should either pass or skip.
- $ make check
+ $ ninja -C build/ test
- 1. Update the first stanza of configure.ac to the intended version.
+ 1. Update the first stanza of meson.build to the intended version.
Then commit your changes:
$ export RELEASE_NUMBER="x.y.z"
$ export RELEASE_NAME="[alpha|beta|RC1|RC2|official|point]"
$ git status
- $ git commit configure.ac -m "configure.ac: bump to version $RELEASE_NUMBER for the $RELEASE_NAME release"
+ $ git commit meson.build -m "build: bump to version $RELEASE_NUMBER for the $RELEASE_NAME release"
$ git push
2. Run the release.sh script to generate the tarballs, sign and
upload them, and generate a release announcement template.
- This script can be obtained from X.org's modular package:
- http://cgit.freedesktop.org/xorg/util/modular/tree/release.sh
-
- The script supports a --dry-run option to test it without actually
- doing a release. If the script fails on the distcheck step due to
- a testsuite error that can't be fixed for some reason, you can
- skip testsuite by specifying the --dist argument. Pass --help to
- see other supported options.
-
- $ release.sh .
-
- For Wayland official and point releases, also publish the publican
- documentation to wayland.freedesktop.org:
-
- $ ./publish-doc
-
- 3. Compose the release announcements. The script will generate
- *.x.y.z.announce files with a list of changes and tags. Prepend
- it with a human-readable listing of the most notable changes.
- For x.y.0 releases, indicate the schedule for the x.y+1.0
+ 3. Compose the release announcements. The script will generate a
+ wayland-x.y.z-announce.eml file with a list of changes and tags.
+ Prepend it with a human-readable listing of the most notable
+ changes. For x.y.0 releases, indicate the schedule for the x.y+1.0
release.
4. PGP sign the release announcements and send them to
@@ -69,9 +53,9 @@ development early).
$ git branch x.y [sha]
$ git push origin x.y
-The master branch's configure.ac version should always be (at least)
+The master branch's meson.build version should always be (at least)
x.y.90, with x.y being the most recent stable branch. The stable
-branch's configure.ac version is just whatever was most recently
+branch's meson.build version is just whatever was most recently
released from that branch.
For stable branches, we commit fixes to master first, then cherry-pick
diff --git a/src/connection.c b/src/connection.c
index d0c7d9f..110b614 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -54,7 +54,7 @@ div_roundup(uint32_t n, size_t a)
return (uint32_t) (((uint64_t) n + (a - 1)) / a);
}
-struct wl_buffer {
+struct wl_ring_buffer {
char data[4096];
uint32_t head, tail;
};
@@ -65,14 +65,14 @@ struct wl_buffer {
#define CLEN (CMSG_LEN(MAX_FDS_OUT * sizeof(int32_t)))
struct wl_connection {
- struct wl_buffer in, out;
- struct wl_buffer fds_in, fds_out;
+ struct wl_ring_buffer in, out;
+ struct wl_ring_buffer fds_in, fds_out;
int fd;
int want_flush;
};
static int
-wl_buffer_put(struct wl_buffer *b, const void *data, size_t count)
+ring_buffer_put(struct wl_ring_buffer *b, const void *data, size_t count)
{
uint32_t head, size;
@@ -98,7 +98,7 @@ wl_buffer_put(struct wl_buffer *b, const void *data, size_t count)
}
static void
-wl_buffer_put_iov(struct wl_buffer *b, struct iovec *iov, int *count)
+ring_buffer_put_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count)
{
uint32_t head, tail;
@@ -122,7 +122,7 @@ wl_buffer_put_iov(struct wl_buffer *b, struct iovec *iov, int *count)
}
static void
-wl_buffer_get_iov(struct wl_buffer *b, struct iovec *iov, int *count)
+ring_buffer_get_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count)
{
uint32_t head, tail;
@@ -146,7 +146,7 @@ wl_buffer_get_iov(struct wl_buffer *b, struct iovec *iov, int *count)
}
static void
-wl_buffer_copy(struct wl_buffer *b, void *data, size_t count)
+ring_buffer_copy(struct wl_ring_buffer *b, void *data, size_t count)
{
uint32_t tail, size;
@@ -161,7 +161,7 @@ wl_buffer_copy(struct wl_buffer *b, void *data, size_t count)
}
static uint32_t
-wl_buffer_size(struct wl_buffer *b)
+ring_buffer_size(struct wl_ring_buffer *b)
{
return b->head - b->tail;
}
@@ -181,16 +181,16 @@ wl_connection_create(int fd)
}
static void
-close_fds(struct wl_buffer *buffer, int max)
+close_fds(struct wl_ring_buffer *buffer, int max)
{
int32_t fds[sizeof(buffer->data) / sizeof(int32_t)], i, count;
size_t size;
- size = wl_buffer_size(buffer);
+ size = ring_buffer_size(buffer);
if (size == 0)
return;
- wl_buffer_copy(buffer, fds, size);
+ ring_buffer_copy(buffer, fds, size);
count = size / sizeof fds[0];
if (max > 0 && max < count)
count = max;
@@ -221,7 +221,7 @@ wl_connection_destroy(struct wl_connection *connection)
void
wl_connection_copy(struct wl_connection *connection, void *data, size_t size)
{
- wl_buffer_copy(&connection->in, data, size);
+ ring_buffer_copy(&connection->in, data, size);
}
void
@@ -231,12 +231,12 @@ wl_connection_consume(struct wl_connection *connection, size_t size)
}
static void
-build_cmsg(struct wl_buffer *buffer, char *data, int *clen)
+build_cmsg(struct wl_ring_buffer *buffer, char *data, size_t *clen)
{
struct cmsghdr *cmsg;
size_t size;
- size = wl_buffer_size(buffer);
+ size = ring_buffer_size(buffer);
if (size > MAX_FDS_OUT * sizeof(int32_t))
size = MAX_FDS_OUT * sizeof(int32_t);
@@ -245,7 +245,7 @@ build_cmsg(struct wl_buffer *buffer, char *data, int *clen)
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(size);
- wl_buffer_copy(buffer, CMSG_DATA(cmsg), size);
+ ring_buffer_copy(buffer, CMSG_DATA(cmsg), size);
*clen = cmsg->cmsg_len;
} else {
*clen = 0;
@@ -253,7 +253,7 @@ build_cmsg(struct wl_buffer *buffer, char *data, int *clen)
}
static int
-decode_cmsg(struct wl_buffer *buffer, struct msghdr *msg)
+decode_cmsg(struct wl_ring_buffer *buffer, struct msghdr *msg)
{
struct cmsghdr *cmsg;
size_t size, max, i;
@@ -266,13 +266,13 @@ decode_cmsg(struct wl_buffer *buffer, struct msghdr *msg)
continue;
size = cmsg->cmsg_len - CMSG_LEN(0);
- max = sizeof(buffer->data) - wl_buffer_size(buffer);
+ max = sizeof(buffer->data) - ring_buffer_size(buffer);
if (size > max || overflow) {
overflow = 1;
size /= sizeof(int32_t);
for (i = 0; i < size; i++)
close(((int*)CMSG_DATA(cmsg))[i]);
- } else if (wl_buffer_put(buffer, CMSG_DATA(cmsg), size) < 0) {
+ } else if (ring_buffer_put(buffer, CMSG_DATA(cmsg), size) < 0) {
return -1;
}
}
@@ -289,9 +289,10 @@ int
wl_connection_flush(struct wl_connection *connection)
{
struct iovec iov[2];
- struct msghdr msg;
+ struct msghdr msg = {0};
char cmsg[CLEN];
- int len = 0, count, clen;
+ int len = 0, count;
+ size_t clen;
uint32_t tail;
if (!connection->want_flush)
@@ -299,17 +300,14 @@ wl_connection_flush(struct wl_connection *connection)
tail = connection->out.tail;
while (connection->out.head - connection->out.tail > 0) {
- wl_buffer_get_iov(&connection->out, iov, &count);
+ ring_buffer_get_iov(&connection->out, iov, &count);
build_cmsg(&connection->fds_out, cmsg, &clen);
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = count;
msg.msg_control = (clen > 0) ? cmsg : NULL;
msg.msg_controllen = clen;
- msg.msg_flags = 0;
do {
len = sendmsg(connection->fd, &msg,
@@ -332,7 +330,7 @@ wl_connection_flush(struct wl_connection *connection)
uint32_t
wl_connection_pending_input(struct wl_connection *connection)
{
- return wl_buffer_size(&connection->in);
+ return ring_buffer_size(&connection->in);
}
int
@@ -343,12 +341,12 @@ wl_connection_read(struct wl_connection *connection)
char cmsg[CLEN];
int len, count, ret;
- if (wl_buffer_size(&connection->in) >= sizeof(connection->in.data)) {
+ if (ring_buffer_size(&connection->in) >= sizeof(connection->in.data)) {
errno = EOVERFLOW;
return -1;
}
- wl_buffer_put_iov(&connection->in, iov, &count);
+ ring_buffer_put_iov(&connection->in, iov, &count);
msg.msg_name = NULL;
msg.msg_namelen = 0;
@@ -385,7 +383,7 @@ wl_connection_write(struct wl_connection *connection,
return -1;
}
- if (wl_buffer_put(&connection->out, data, count) < 0)
+ if (ring_buffer_put(&connection->out, data, count) < 0)
return -1;
connection->want_flush = 1;
@@ -404,7 +402,7 @@ wl_connection_queue(struct wl_connection *connection,
return -1;
}
- return wl_buffer_put(&connection->out, data, count);
+ return ring_buffer_put(&connection->out, data, count);
}
int
@@ -429,13 +427,13 @@ wl_connection_get_fd(struct wl_connection *connection)
static int
wl_connection_put_fd(struct wl_connection *connection, int32_t fd)
{
- if (wl_buffer_size(&connection->fds_out) == MAX_FDS_OUT * sizeof fd) {
+ if (ring_buffer_size(&connection->fds_out) == MAX_FDS_OUT * sizeof fd) {
connection->want_flush = 1;
if (wl_connection_flush(connection) < 0)
return -1;
}
- return wl_buffer_put(&connection->fds_out, &fd, sizeof fd);
+ return ring_buffer_put(&connection->fds_out, &fd, sizeof fd);
}
const char *
@@ -568,10 +566,10 @@ wl_closure_init(const struct wl_message *message, uint32_t size,
if (size) {
*num_arrays = wl_message_count_arrays(message);
- closure = malloc(sizeof *closure + size +
+ closure = zalloc(sizeof *closure + size +
*num_arrays * sizeof(struct wl_array));
} else {
- closure = malloc(sizeof *closure);
+ closure = zalloc(sizeof *closure);
}
if (!closure) {
@@ -632,13 +630,13 @@ wl_closure_marshal(struct wl_object *sender, uint32_t opcode,
break;
case 'n':
object = args[i].o;
- if (!arg.nullable && object == NULL)
+ if (object == NULL)
goto err_null;
closure->args[i].n = object ? object->id : 0;
break;
case 'a':
- if (!arg.nullable && args[i].a == NULL)
+ if (args[i].a == NULL)
goto err_null;
break;
case 'h':
@@ -749,6 +747,13 @@ wl_connection_demarshal(struct wl_connection *connection,
case 's':
length = *p++;
+ if (length == 0 && !arg.nullable) {
+ wl_log("NULL string received on non-nullable "
+ "type, message %s(%s)\n", message->name,
+ message->signature);
+ errno = EINVAL;
+ goto err;
+ }
if (length == 0) {
closure->args[i].s = NULL;
break;
@@ -794,7 +799,7 @@ wl_connection_demarshal(struct wl_connection *connection,
id = *p++;
closure->args[i].n = id;
- if (id == 0 && !arg.nullable) {
+ if (id == 0) {
wl_log("NULL new ID received on non-nullable "
"type, message %s(%s)\n", message->name,
message->signature);
@@ -803,10 +808,12 @@ wl_connection_demarshal(struct wl_connection *connection,
}
if (wl_map_reserve_new(objects, id) < 0) {
- wl_log("not a valid new object id (%u), "
- "message %s(%s)\n",
- id, message->name, message->signature);
- errno = EINVAL;
+ if (errno == EINVAL) {
+ wl_log("not a valid new object id (%u), "
+ "message %s(%s)\n", id,
+ message->name,
+ message->signature);
+ }
goto err;
}
@@ -842,7 +849,7 @@ wl_connection_demarshal(struct wl_connection *connection,
goto err;
}
- wl_buffer_copy(&connection->fds_in, &fd, sizeof fd);
+ ring_buffer_copy(&connection->fds_in, &fd, sizeof fd);
connection->fds_in.tail += sizeof fd;
closure->args[i].h = fd;
break;
@@ -1049,7 +1056,7 @@ copy_fds_to_connection(struct wl_closure *closure,
fd = closure->args[i].h;
if (wl_connection_put_fd(connection, fd)) {
wl_log("request could not be marshaled: "
- "can't send file descriptor");
+ "can't send file descriptor\n");
return -1;
}
closure->args[i].h = -1;
@@ -1256,19 +1263,31 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection)
}
void
-wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send)
+wl_closure_print(struct wl_closure *closure, struct wl_object *target,
+ bool send, const char *discarded_reason)
{
int i;
struct argument_details arg;
const char *signature = closure->message->signature;
struct timespec tp;
unsigned int time;
+ uint32_t nval;
+ FILE *f;
+ char *buffer;
+ size_t buffer_length;
+
+ f = open_memstream(&buffer, &buffer_length);
+ if (f == NULL)
+ return;
clock_gettime(CLOCK_REALTIME, &tp);
time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
- fprintf(stderr, "[%10.3f] %s%s@%u.%s(",
- time / 1000.0,
+ fprintf(f, "[%7u.%03u] %s%s%s%s%s@%u.%s(",
+ time / 1000, time % 1000,
+ (discarded_reason != NULL) ? "discarded[" : "",
+ (discarded_reason != NULL) ? discarded_reason : "",
+ (discarded_reason != NULL) ? "] " : "",
send ? " -> " : "",
target->interface->name, target->id,
closure->message->name);
@@ -1276,53 +1295,69 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send)
for (i = 0; i < closure->count; i++) {
signature = get_next_argument(signature, &arg);
if (i > 0)
- fprintf(stderr, ", ");
+ fprintf(f, ", ");
switch (arg.type) {
case 'u':
- fprintf(stderr, "%u", closure->args[i].u);
+ fprintf(f, "%u", closure->args[i].u);
break;
case 'i':
- fprintf(stderr, "%d", closure->args[i].i);
+ fprintf(f, "%d", closure->args[i].i);
break;
case 'f':
- fprintf(stderr, "%f",
- wl_fixed_to_double(closure->args[i].f));
+ /* The magic number 390625 is 1e8 / 256 */
+ if (closure->args[i].f >= 0) {
+ fprintf(f, "%d.%08d",
+ closure->args[i].f / 256,
+ 390625 * (closure->args[i].f % 256));
+ } else {
+
+ fprintf(f, "-%d.%08d",
+ closure->args[i].f / -256,
+ -390625 * (closure->args[i].f % 256));
+ }
break;
case 's':
if (closure->args[i].s)
- fprintf(stderr, "\"%s\"", closure->args[i].s);
+ fprintf(f, "\"%s\"", closure->args[i].s);
else
- fprintf(stderr, "nil");
+ fprintf(f, "nil");
break;
case 'o':
if (closure->args[i].o)
- fprintf(stderr, "%s@%u",
+ fprintf(f, "%s@%u",
closure->args[i].o->interface->name,
closure->args[i].o->id);
else
- fprintf(stderr, "nil");
+ fprintf(f, "nil");
break;
case 'n':
- fprintf(stderr, "new id %s@",
+ nval = closure->args[i].n;
+
+ fprintf(f, "new id %s@",
(closure->message->types[i]) ?
closure->message->types[i]->name :
"[unknown]");
- if (closure->args[i].n != 0)
- fprintf(stderr, "%u", closure->args[i].n);
+ if (nval != 0)
+ fprintf(f, "%u", nval);
else
- fprintf(stderr, "nil");
+ fprintf(f, "nil");
break;
case 'a':
- fprintf(stderr, "array");
+ fprintf(f, "array[%zu]", closure->args[i].a->size);
break;
case 'h':
- fprintf(stderr, "fd %d", closure->args[i].h);
+ fprintf(f, "fd %d", closure->args[i].h);
break;
}
}
- fprintf(stderr, ")\n");
+ fprintf(f, ")\n");
+
+ if (fclose(f) == 0) {
+ fprintf(stderr, "%s", buffer);
+ free(buffer);
+ }
}
static int
diff --git a/src/dtddata.S b/src/dtddata.S
deleted file mode 100644
index 2405066..0000000
--- a/src/dtddata.S
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright © 2015 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * Avoid executable stack.
- * from: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart
- */
-#if defined(__linux__) && defined(__ELF__)
-.section .note.GNU-stack,"",%progbits
-#endif
-
-/* from: http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967#comment-348129 */
-
-.macro binfile name file
- .p2align 2
- .globl \name\()_begin
-\name\()_begin:
- .incbin "\file"
-\name\()_end:
- .byte 0
- .p2align 2
- .globl \name\()_len
-\name\()_len:
- .int (\name\()_end - \name\()_begin)
-.endm
-
-.section .rodata
-binfile DTD_DATA src/wayland.dtd.embed
diff --git a/src/embed.py b/src/embed.py
new file mode 100644
index 0000000..abebb15
--- /dev/null
+++ b/src/embed.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+
+"""
+Simple C data embedder
+
+License: MIT
+
+Copyright (c) 2020 Simon Ser
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+"""
+
+import sys
+
+if len(sys.argv) != 3:
+ print('usage: ' + sys.argv[0] + ' <filename> <ident>', file=sys.stderr)
+ sys.exit(1)
+
+filename = sys.argv[1]
+ident = sys.argv[2]
+
+with open(filename, 'rb') as f:
+ buf = f.read()
+
+print('static const char ' + ident + '[] = {\n\t', end='')
+for i in range(len(buf)):
+ ch = buf[i:i+1]
+ print('0x' + ch.hex() + ', ', end='')
+print('\n};')
diff --git a/src/event-loop.c b/src/event-loop.c
index 339ff19..37cf95d 100644
--- a/src/event-loop.c
+++ b/src/event-loop.c
@@ -179,7 +179,7 @@ wl_event_loop_add_fd(struct wl_event_loop *loop,
{
struct wl_event_source_fd *source;
- source = malloc(sizeof *source);
+ source = zalloc(sizeof *source);
if (source == NULL)
return NULL;
@@ -340,7 +340,7 @@ wl_timer_heap_reserve(struct wl_timer_heap *timers)
new_space = timers->space >= 8 ? timers->space * 2 : 8;
n = realloc(timers->data, (size_t)new_space * sizeof(*n));
if (!n) {
- wl_log("Allocation failure when expanding timer list");
+ wl_log("Allocation failure when expanding timer list\n");
return -1;
}
timers->data = n;
@@ -361,7 +361,7 @@ wl_timer_heap_unreserve(struct wl_timer_heap *timers)
if (timers->space >= 16 && timers->space >= 4 * timers->count) {
n = realloc(timers->data, (size_t)timers->space / 2 * sizeof(*n));
if (!n) {
- wl_log("Reallocation failure when shrinking timer list");
+ wl_log("Reallocation failure when shrinking timer list\n");
return;
}
timers->data = n;
@@ -568,7 +568,7 @@ wl_event_loop_add_timer(struct wl_event_loop *loop,
if (wl_timer_heap_ensure_timerfd(&loop->timers) < 0)
return NULL;
- source = malloc(sizeof *source);
+ source = zalloc(sizeof *source);
if (source == NULL)
return NULL;
@@ -718,7 +718,7 @@ wl_event_loop_add_signal(struct wl_event_loop *loop,
struct wl_event_source_signal *source;
sigset_t mask;
- source = malloc(sizeof *source);
+ source = zalloc(sizeof *source);
if (source == NULL)
return NULL;
@@ -775,7 +775,7 @@ wl_event_loop_add_idle(struct wl_event_loop *loop,
{
struct wl_event_source_idle *source;
- source = malloc(sizeof *source);
+ source = zalloc(sizeof *source);
if (source == NULL)
return NULL;
@@ -885,7 +885,7 @@ wl_event_loop_create(void)
{
struct wl_event_loop *loop;
- loop = malloc(sizeof *loop);
+ loop = zalloc(sizeof *loop);
if (loop == NULL)
return NULL;
@@ -942,8 +942,8 @@ post_dispatch_check(struct wl_event_loop *loop)
dispatch_result = source->interface->dispatch(source, &ep);
if (dispatch_result < 0) {
- wl_log("Source dispatch function returned negative value!");
- wl_log("This would previously accidentally suppress a follow-up dispatch");
+ wl_log("Source dispatch function returned negative value!\n");
+ wl_log("This would previously accidentally suppress a follow-up dispatch\n");
}
needs_recheck |= dispatch_result != 0;
}
diff --git a/src/meson.build b/src/meson.build
index d91c503..a8a1d2b 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -1,4 +1,7 @@
-wayland_version = meson.project_version().split('.')
+if not (get_option('scanner') or get_option('libraries'))
+ error('Either -Dscanner=true or -Dlibraries=true is required')
+endif
+
wayland_version_h = configuration_data()
wayland_version_h.set('WAYLAND_VERSION', meson.project_version())
wayland_version_h.set('WAYLAND_VERSION_MAJOR', wayland_version[0].to_int())
@@ -26,19 +29,31 @@ wayland_util_dep = declare_dependency(
if get_option('scanner')
# wayland-scanner
- configure_file(
+ scanner_deps = [ dependency('expat') ]
+ scanner_args = [ '-include', 'config.h' ]
+
+ if get_option('dtd_validation')
+ scanner_deps += dependency('libxml-2.0')
+ scanner_args += '-DHAVE_LIBXML=1'
+ endif
+
+ prog_embed = find_program('embed.py', native: true)
+
+ embed_dtd = custom_target(
+ 'wayland.dtd.h',
input: '../protocol/wayland.dtd',
- output: 'wayland.dtd.embed',
- copy: true
+ output: 'wayland.dtd.h',
+ command: [ prog_embed, '@INPUT@', 'wayland_dtd' ],
+ capture: true
)
- wayland_scanner_sources = [ 'scanner.c', 'dtddata.S' ]
+ wayland_scanner_sources = [ 'scanner.c', embed_dtd ]
wayland_scanner_includes = [ root_inc, protocol_inc ]
wayland_scanner = executable(
'wayland-scanner',
wayland_scanner_sources,
- c_args: [ '-include', 'config.h' ],
+ c_args: scanner_args,
include_directories: wayland_scanner_includes,
dependencies: [ scanner_deps, wayland_util_dep, ],
install: true
@@ -56,11 +71,15 @@ if get_option('scanner')
],
filebase: 'wayland-scanner'
)
+
+ if meson.can_run_host_binaries()
+ meson.override_find_program('wayland-scanner', wayland_scanner)
+ endif
endif
if meson.is_cross_build() or not get_option('scanner')
scanner_dep = dependency('wayland-scanner', native: true, version: meson.project_version())
- wayland_scanner_for_build = find_program(scanner_dep.get_pkgconfig_variable('wayland_scanner'))
+ wayland_scanner_for_build = find_program(scanner_dep.get_variable(pkgconfig: 'wayland_scanner'))
else
wayland_scanner_for_build = wayland_scanner
endif
@@ -77,7 +96,7 @@ if get_option('libraries')
'connection.c',
'wayland-os.c'
],
- dependencies: [ ffi_dep, rt_dep ]
+ dependencies: [ epoll_dep, ffi_dep, rt_dep ]
)
wayland_private_dep = declare_dependency(
@@ -139,6 +158,15 @@ if get_option('libraries')
output: 'wayland-protocol.c'
)
+ if wayland_version[0] != '1'
+ # The versioning used for the shared libraries assumes that the major
+ # version of Wayland as a whole will increase to 2 if and only if there
+ # is an ABI break, at which point we should probably bump the SONAME of
+ # all libraries to .so.2. For more details see
+ # https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/177
+ error('We probably need to bump the SONAME of libwayland-server and -client')
+ endif
+
wayland_server = library(
'wayland-server',
sources: [
@@ -149,8 +177,11 @@ if get_option('libraries')
'wayland-shm.c',
'event-loop.c'
],
- version: '0.1.0',
+ # To avoid an unnecessary SONAME bump, wayland 1.x.y produces
+ # libwayland-server.so.0.x.y.
+ version: '.'.join(['0', wayland_version[1], wayland_version[2]]),
dependencies: [
+ epoll_dep,
ffi_dep,
wayland_private_dep,
wayland_util_dep,
@@ -165,7 +196,7 @@ if get_option('libraries')
wayland_server_dep = declare_dependency(
link_with: wayland_server,
include_directories: [ root_inc, include_directories('.') ],
- dependencies: [ ffi_dep, mathlib_dep, threads_dep ],
+ dependencies: [ epoll_dep, ffi_dep, mathlib_dep, threads_dep ],
sources: [
wayland_server_protocol_core_h,
wayland_server_protocol_h
@@ -184,6 +215,10 @@ if get_option('libraries')
]
)
+ if meson.version().version_compare('>= 0.54.0')
+ meson.override_dependency('wayland-server', wayland_server_dep)
+ endif
+
wayland_client = library(
'wayland-client',
sources: [
@@ -192,8 +227,11 @@ if get_option('libraries')
wayland_protocol_c,
'wayland-client.c'
],
- version: '0.3.0',
+ # To avoid an unnecessary SONAME bump, wayland 1.x.y produces
+ # libwayland-client.so.0.x.y.
+ version: '.'.join(['0', wayland_version[1], wayland_version[2]]),
dependencies: [
+ epoll_dep,
ffi_dep,
wayland_private_dep,
wayland_util_dep,
@@ -225,6 +263,10 @@ if get_option('libraries')
]
)
+ if meson.version().version_compare('>= 0.54.0')
+ meson.override_dependency('wayland-client', wayland_client_dep)
+ endif
+
install_headers([
'wayland-util.h',
'wayland-server.h',
diff --git a/src/scanner.c b/src/scanner.c
index 36ac905..c512d23 100644
--- a/src/scanner.c
+++ b/src/scanner.c
@@ -41,9 +41,9 @@
#if HAVE_LIBXML
#include <libxml/parser.h>
-/* Embedded wayland.dtd file, see dtddata.S */
-extern char DTD_DATA_begin;
-extern int DTD_DATA_len;
+/* Embedded wayland.dtd file */
+/* static const char wayland_dtd[]; wayland.dtd */
+#include "wayland.dtd.h"
#endif
/* Expat must be included after libxml as both want to declare XMLCALL; see
@@ -112,8 +112,8 @@ is_dtd_valid(FILE *input, const char *filename)
if (!ctx || !dtdctx)
abort();
- buffer = xmlParserInputBufferCreateMem(&DTD_DATA_begin,
- DTD_DATA_len,
+ buffer = xmlParserInputBufferCreateMem(wayland_dtd,
+ sizeof(wayland_dtd),
XML_CHAR_ENCODING_UTF8);
if (!buffer) {
fprintf(stderr, "Failed to init buffer for DTD.\n");
@@ -236,6 +236,7 @@ struct entry {
char *summary;
int since;
struct wl_list link;
+ struct description *description;
};
struct parse_context {
@@ -245,6 +246,7 @@ struct parse_context {
struct interface *interface;
struct message *message;
struct enumeration *enumeration;
+ struct entry *entry;
struct description *description;
char character_data[8192];
unsigned int character_data_length;
@@ -409,11 +411,9 @@ static bool
is_nullable_type(struct arg *arg)
{
switch (arg->type) {
- /* Strings, objects, and arrays are possibly nullable */
+ /* Strings and objects are possibly nullable */
case STRING:
case OBJECT:
- case NEW_ID:
- case ARRAY:
return true;
default:
return false;
@@ -542,6 +542,7 @@ free_entry(struct entry *entry)
free(entry->uppercase_name);
free(entry->value);
free(entry->summary);
+ free_description(entry->description);
free(entry);
}
@@ -884,6 +885,7 @@ start_element(void *data, const char *element_name, const char **atts)
entry->summary = NULL;
wl_list_insert(ctx->enumeration->entry_list.prev,
&entry->link);
+ ctx->entry = entry;
} else if (strcmp(element_name, "description") == 0) {
if (summary == NULL)
fail(&ctx->loc, "description without summary");
@@ -893,6 +895,8 @@ start_element(void *data, const char *element_name, const char **atts)
if (ctx->message)
ctx->message->description = description;
+ else if (ctx->entry)
+ ctx->entry->description = description;
else if (ctx->enumeration)
ctx->enumeration->description = description;
else if (ctx->interface)
@@ -1008,6 +1012,8 @@ end_element(void *data, const XML_Char *name)
ctx->enumeration->name);
}
ctx->enumeration = NULL;
+ } else if (strcmp(name, "entry") == 0) {
+ ctx->entry = NULL;
} else if (strcmp(name, "protocol") == 0) {
struct interface *i;
@@ -1230,38 +1236,40 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)
printf(")\n"
"{\n");
- if (ret && ret->interface_name == NULL) {
- /* an arg has type ="new_id" but interface is not
- * provided, such as in wl_registry.bind */
- printf("\tstruct wl_proxy *%s;\n\n"
- "\t%s = wl_proxy_marshal_constructor_versioned("
- "(struct wl_proxy *) %s,\n"
- "\t\t\t %s_%s, interface, version",
- ret->name, ret->name,
- interface->name,
- interface->uppercase_name,
- m->uppercase_name);
- } else if (ret) {
- /* Normal factory case, an arg has type="new_id" and
- * an interface is provided */
- printf("\tstruct wl_proxy *%s;\n\n"
- "\t%s = wl_proxy_marshal_constructor("
- "(struct wl_proxy *) %s,\n"
- "\t\t\t %s_%s, &%s_interface",
- ret->name, ret->name,
- interface->name,
- interface->uppercase_name,
- m->uppercase_name,
- ret->interface_name);
+ printf("\t");
+ if (ret) {
+ printf("struct wl_proxy *%s;\n\n"
+ "\t%s = ", ret->name, ret->name);
+ }
+ printf("wl_proxy_marshal_flags("
+ "(struct wl_proxy *) %s,\n"
+ "\t\t\t %s_%s",
+ interface->name,
+ interface->uppercase_name,
+ m->uppercase_name);
+
+ if (ret) {
+ if (ret->interface_name) {
+ /* Normal factory case, an arg has type="new_id" and
+ * an interface is provided */
+ printf(", &%s_interface", ret->interface_name);
+ } else {
+ /* an arg has type ="new_id" but interface is not
+ * provided, such as in wl_registry.bind */
+ printf(", interface");
+ }
} else {
/* No args have type="new_id" */
- printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
- "\t\t\t %s_%s",
- interface->name,
- interface->uppercase_name,
- m->uppercase_name);
+ printf(", NULL");
}
+ if (ret && ret->interface_name == NULL)
+ printf(", version");
+ else
+ printf(", wl_proxy_get_version((struct wl_proxy *) %s)",
+ interface->name);
+ printf(", %s", m->destructor ? "WL_MARSHAL_FLAG_DESTROY" : "0");
+
wl_list_for_each(a, &m->arg_list, link) {
if (a->type == NEW_ID) {
if (a->interface_name == NULL)
@@ -1273,11 +1281,6 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)
}
printf(");\n");
- if (m->destructor)
- printf("\n\twl_proxy_destroy("
- "(struct wl_proxy *) %s);\n",
- interface->name);
-
if (ret && ret->interface_name == NULL)
printf("\n\treturn (void *) %s;\n", ret->name);
else if (ret)
@@ -1364,10 +1367,17 @@ emit_enumerations(struct interface *interface)
}
printf("enum %s_%s {\n", interface->name, e->name);
wl_list_for_each(entry, &e->entry_list, link) {
- if (entry->summary || entry->since > 1) {
+ desc = entry->description;
+ if (entry->summary || entry->since > 1 || desc) {
printf("\t/**\n");
if (entry->summary)
printf("\t * %s\n", entry->summary);
+ if (desc) {
+ printf("\t * %s\n", desc->summary);
+ printf("\t *\n");
+ if (desc->text)
+ desc_dump(desc->text, "\t * ");
+ }
if (entry->since > 1)
printf("\t * @since %d\n", entry->since);
printf("\t */\n");
@@ -1624,7 +1634,9 @@ emit_header(struct protocol *protocol, enum side side)
*p = i->name;
}
- qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names);
+ if (types.size > 0)
+ qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names);
+
prev = NULL;
wl_array_for_each(p, &types) {
if (prev && strcmp(*p, prev) == 0)
@@ -1834,7 +1846,10 @@ emit_code(struct protocol *protocol, enum visibility vis)
emit_types_forward_declarations(protocol, &i->request_list, &types);
emit_types_forward_declarations(protocol, &i->event_list, &types);
}
- qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names);
+
+ if (types.size > 0)
+ qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names);
+
prev = NULL;
wl_array_for_each(p, &types) {
if (prev && strcmp(*p, prev) == 0)
diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h
index 94c25e3..af7c184 100644
--- a/src/wayland-client-core.h
+++ b/src/wayland-client-core.h
@@ -119,9 +119,27 @@ struct wl_display;
*/
struct wl_event_queue;
+/** Destroy proxy after marshalling
+ * @ingroup wl_proxy
+ */
+#define WL_MARSHAL_FLAG_DESTROY (1 << 0)
+
void
wl_event_queue_destroy(struct wl_event_queue *queue);
+struct wl_proxy *
+wl_proxy_marshal_flags(struct wl_proxy *proxy, uint32_t opcode,
+ const struct wl_interface *interface,
+ uint32_t version,
+ uint32_t flags, ...);
+
+struct wl_proxy *
+wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode,
+ const struct wl_interface *interface,
+ uint32_t version,
+ uint32_t flags,
+ union wl_argument *args);
+
void
wl_proxy_marshal(struct wl_proxy *p, uint32_t opcode, ...);
@@ -270,31 +288,106 @@ wl_display_read_events(struct wl_display *display);
void
wl_log_set_handler_client(wl_log_func_t handler);
-enum wl_protocol_logger_client_type {
- WL_PROTOCOL_LOGGER_CLIENT_REQUEST,
- WL_PROTOCOL_LOGGER_CLIENT_EVENT,
+/**
+ * The message type.
+ */
+enum wl_client_message_type {
+ /** The message is a request */
+ WL_CLIENT_MESSAGE_REQUEST,
+
+ /** The message is an event */
+ WL_CLIENT_MESSAGE_EVENT,
+};
+
+/**
+ * The message discard reason codes.
+ */
+enum wl_client_message_discarded_reason {
+ /** The message was handled normally, and not discarded. */
+ WL_CLIENT_MESSAGE_NOT_DISCARDED = 0,
+
+ /** The target was not alive at dispatch time */
+ WL_CLIENT_MESSAGE_DISCARD_DEAD_PROXY_ON_DISPATCH,
+
+ /** The target had no listener or dispatcher */
+ WL_CLIENT_MESSAGE_DISCARD_NO_LISTENER_ON_DISPATCH,
+
+ /** The target was not valid when the event was demarshalled */
+ WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL,
};
-struct wl_protocol_logger_client_message {
+/**
+ * The structure used to communicate details about an observed message to the
+ * registered observers.
+ */
+struct wl_client_observed_message {
+ /** The target for the message */
struct wl_proxy *proxy;
+
+ /** The message opcode */
int message_opcode;
+
+ /** The protocol message structure */
const struct wl_message *message;
+
+ /** The count of arguments to the message */
int arguments_count;
+
+ /** The argument array for the messagge */
const union wl_argument *arguments;
+
+ /** The discard reason code */
+ enum wl_client_message_discarded_reason discarded_reason;
+
+ /**
+ * The discard reason string, or NULL if the event was not discarded.
+ *
+ * This string is only for convenience for a observer that does
+ * logging. The string values should not be considered stable, and
+ * are not localized.
+ */
+ const char *discarded_reason_str;
};
-typedef void (*wl_protocol_logger_client_func_t)(
- void *user_data,
- enum wl_protocol_logger_client_type direction,
- const struct wl_protocol_logger_client_message *message);
+/**
+ * The signature for a client message observer function, as registered with
+ * wl_display_add_client_observer().
+ *
+ * \param user_data \c user_data pointer given when the observer was
+ * registered with \c wl_display_create_client_observer
+ * \param type type of message
+ * \param message details for the message
+ */
+typedef void (*wl_client_message_observer_func_t)(
+ void *user_data, enum wl_client_message_type type,
+ const struct wl_client_observed_message *message);
+
+/** \class wl_client_observer
+ *
+ * \brief Represents a client message observer
+ *
+ * A client observer allows the client to observe all request and event
+ * message traffic to and from the client. For events, the observer is
+ * also given a discard reason if the event wasn't handled.
+ *
+ * The typical use for the observer is to allow the client implementation to
+ * do its own debug logging, as the default when setting WAYLAND_DEBUG is to
+ * log to stderr.
+ *
+ * With this runtime call, the client can also enable and disable the observer
+ * at any time.
+ *
+ * The protocol-logger-test.c file has an example of a logger implementation.
+ */
+struct wl_client_observer;
-struct wl_protocol_logger_client *
-wl_display_add_protocol_logger_client(struct wl_display *display,
- wl_protocol_logger_client_func_t,
- void *user_data);
+struct wl_client_observer *
+wl_display_create_client_observer(struct wl_display *display,
+ wl_client_message_observer_func_t observer,
+ void *user_data);
void
-wl_protocol_logger_client_destroy(struct wl_protocol_logger_client *logger);
+wl_client_observer_destroy(struct wl_client_observer *observer);
#ifdef __cplusplus
}
diff --git a/src/wayland-client-uninstalled.pc.in b/src/wayland-client-uninstalled.pc.in
deleted file mode 100644
index 6fd0ce6..0000000
--- a/src/wayland-client-uninstalled.pc.in
+++ /dev/null
@@ -1,9 +0,0 @@
-libdir=@abs_builddir@/.libs
-includedir=@abs_srcdir@
-protocoldir=@abs_top_builddir@/protocol
-
-Name: Wayland Client
-Description: Wayland client side library (not installed)
-Version: @PACKAGE_VERSION@
-Cflags: -I${includedir} -I${protocoldir}
-Libs: -L${libdir} -lwayland-client
diff --git a/src/wayland-client.c b/src/wayland-client.c
index 74d4861..d54e715 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -70,10 +70,12 @@ struct wl_proxy {
wl_dispatcher_func_t dispatcher;
uint32_t version;
const char * const *tag;
+ struct wl_list queue_link; /**< in struct wl_event_queue::proxy_list */
};
struct wl_event_queue {
struct wl_list event_list;
+ struct wl_list proxy_list; /**< struct wl_proxy::queue_link */
struct wl_display *display;
};
@@ -108,47 +110,183 @@ struct wl_display {
uint32_t read_serial;
pthread_cond_t reader_cond;
- struct wl_list protocol_loggers;
+ struct wl_list observers;
};
/** \endcond */
-struct wl_protocol_logger_client {
+struct wl_client_observer {
struct wl_list link;
- wl_protocol_logger_client_func_t func;
+ struct wl_display *display;
+ wl_client_message_observer_func_t func;
void *user_data;
};
static int debug_client = 0;
+/**
+ * This helper function adjusts the closure arguments before they are logged.
+ * On the client, after the call to create_proxies(), NEW_ID arguments will
+ * point to a wl_proxy accessible via arg.o instead of being an int32
+ * accessible by arg.n, which is what wl_closure_print() attempts to print.
+ * This helper transforms the argument back into an id, so wl_closure_print()
+ * doesn't need to handle that as a special case.
+ *
+ * \param closure closure to adjust
+ * \param send if this is closure is for a request
+ *
+ */
static void
-log_closure(struct wl_closure *closure, struct wl_proxy* proxy, int send)
+adjust_closure_args_for_logging(struct wl_closure *closure, bool send)
+{
+ int i;
+ struct argument_details arg;
+ const struct wl_proxy *proxy;
+ const char *signature = closure->message->signature;
+
+ // No adjustment needed for a send.
+ if (send)
+ return;
+
+ for (i = 0; i < closure->count; i++) {
+ signature = get_next_argument(signature, &arg);
+
+ switch (arg.type) {
+ case 'n':
+ proxy = (struct wl_proxy *)closure->args[i].o;
+ closure->args[i].n = proxy ? proxy->object.id : 0;
+ break;
+ }
+ }
+}
+
+/**
+ * Maps the \c discard_reason to a string suitable for logging.
+ *
+ * \param discarded_reason reason for discard
+ * \return A string describing the reason, or NULL.
+ *
+ */
+static const char *
+get_discarded_reason_str(
+ enum wl_client_message_discarded_reason discarded_reason)
+{
+ switch (discarded_reason) {
+ case WL_CLIENT_MESSAGE_NOT_DISCARDED:
+ return NULL;
+ case WL_CLIENT_MESSAGE_DISCARD_DEAD_PROXY_ON_DISPATCH:
+ return "dead proxy on dispatch";
+ case WL_CLIENT_MESSAGE_DISCARD_NO_LISTENER_ON_DISPATCH:
+ return "no listener on dispatch";
+ case WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL:
+ return "unknown id on demarshal";
+ }
+ return NULL;
+}
+
+/**
+ * This function helps log closures from the client, assuming logging is
+ * enabled.
+ *
+ * \param closure closure for the message
+ * \param proxy proxy for the message
+ * \param send true if this is closure is for a request
+ * \param discarded_reason reason if the message is being discarded, or
+ * WL_CLIENT_MESSAGE_NOT_DISCARDED
+ */
+static void
+closure_log(struct wl_closure *closure, struct wl_proxy *proxy, bool send,
+ enum wl_client_message_discarded_reason discarded_reason)
{
struct wl_display *display = proxy->display;
- struct wl_protocol_logger_client *protocol_logger;
- struct wl_protocol_logger_client_message message;
+ const char *discarded_reason_str;
+ struct wl_closure adjusted_closure = { 0 };
+
+ if (!debug_client && wl_list_empty(&display->observers))
+ return;
+
+ // Note: The real closure has extra data (referenced by its args
+ // immediately following the structure in memory, but we don't
+ // need to duplicate that.
+ memcpy(&adjusted_closure, closure, sizeof(struct wl_closure));
+
+ // Adjust the closure arguments.
+ adjust_closure_args_for_logging(&adjusted_closure, send);
+
+ discarded_reason_str = get_discarded_reason_str(discarded_reason);
if (debug_client)
- wl_closure_print(closure, &proxy->object, send);
+ wl_closure_print(&adjusted_closure, &proxy->object, send,
+ discarded_reason_str);
+
+ if (!wl_list_empty(&display->observers)) {
+ enum wl_client_message_type type =
+ send ? WL_CLIENT_MESSAGE_REQUEST
+ : WL_CLIENT_MESSAGE_EVENT;
+ struct wl_client_observer *observer;
+ struct wl_client_observed_message message;
- if (!wl_list_empty(&display->protocol_loggers)) {
message.proxy = proxy;
- message.message_opcode = closure->opcode;
- message.message = closure->message;
- message.arguments_count = closure->count;
- message.arguments = closure->args;
- wl_list_for_each(protocol_logger, &display->protocol_loggers,
- link) {
- protocol_logger->func(
- protocol_logger->user_data,
- send ? WL_PROTOCOL_LOGGER_CLIENT_REQUEST :
- WL_PROTOCOL_LOGGER_CLIENT_EVENT,
- &message);
+ message.message_opcode = adjusted_closure.opcode;
+ message.message = adjusted_closure.message;
+ message.arguments_count = adjusted_closure.count;
+ message.arguments = adjusted_closure.args;
+ message.discarded_reason = discarded_reason;
+ message.discarded_reason_str = discarded_reason_str;
+ wl_list_for_each(observer, &display->observers, link) {
+ observer->func(observer->user_data, type, &message);
}
}
}
/**
+ * This function helps log unknown messages on the client, when logging is
+ * enabled.
+ *
+ * \param display current display
+ * \param zombie true if there was a zombie for the message target
+ * \param id id of the proxy this message was meant for
+ * \param opcode opcode from the message
+ * \param num_fds number of fd arguments for this message
+ * \param num_bytes byte size of this message
+ */
+static void
+log_unknown_message(struct wl_display *display, bool zombie, uint32_t id,
+ int opcode, int num_fds, int num_bytes)
+{
+ char event_detail[100];
+ struct wl_interface unknown_interface = { 0 };
+ struct wl_proxy unknown_proxy = { 0 };
+ struct wl_message unknown_message = { 0 };
+ struct wl_closure unknown_closure = { 0 };
+
+ if (!debug_client && wl_list_empty(&display->observers))
+ return;
+
+ snprintf(event_detail, sizeof event_detail,
+ "[event %d, %d fds, %d bytes]", opcode, num_fds, num_bytes);
+
+ unknown_interface.name = zombie ? "[zombie]" : "[unknown]";
+
+ unknown_proxy.object.interface = &unknown_interface;
+ unknown_proxy.object.id = id;
+ unknown_proxy.display = display;
+ unknown_proxy.refcount = -1;
+ unknown_proxy.flags = WL_PROXY_FLAG_WRAPPER;
+
+ unknown_message.name = event_detail;
+ unknown_message.signature = "";
+ unknown_message.types = NULL;
+
+ unknown_closure.message = &unknown_message;
+ unknown_closure.opcode = opcode;
+ unknown_closure.proxy = &unknown_proxy;
+
+ closure_log(&unknown_closure, &unknown_proxy, false,
+ WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL);
+}
+
+/**
* This helper function wakes up all threads that are
* waiting for display->reader_cond (i. e. when reading is done,
* canceled, or an error occurred)
@@ -256,6 +394,7 @@ static void
wl_event_queue_init(struct wl_event_queue *queue, struct wl_display *display)
{
wl_list_init(&queue->event_list);
+ wl_list_init(&queue->proxy_list);
queue->display = display;
}
@@ -333,6 +472,27 @@ wl_event_queue_release(struct wl_event_queue *queue)
{
struct wl_closure *closure;
+ if (!wl_list_empty(&queue->proxy_list)) {
+ struct wl_proxy *proxy, *tmp;
+
+ if (queue != &queue->display->default_queue) {
+ wl_log("warning: queue %p destroyed while proxies "
+ "still attached:\n", queue);
+ }
+
+ wl_list_for_each_safe(proxy, tmp, &queue->proxy_list,
+ queue_link) {
+ if (queue != &queue->display->default_queue) {
+ wl_log(" %s@%u still attached\n",
+ proxy->object.interface->name,
+ proxy->object.id);
+ }
+ proxy->queue = NULL;
+ wl_list_remove(&proxy->queue_link);
+ wl_list_init(&proxy->queue_link);
+ }
+ }
+
while (!wl_list_empty(&queue->event_list)) {
closure = wl_container_of(queue->event_list.next,
closure, link);
@@ -378,7 +538,7 @@ wl_display_create_queue(struct wl_display *display)
{
struct wl_event_queue *queue;
- queue = malloc(sizeof *queue);
+ queue = zalloc(sizeof *queue);
if (queue == NULL)
return NULL;
@@ -465,6 +625,12 @@ proxy_create(struct wl_proxy *factory, const struct wl_interface *interface,
proxy->version = version;
proxy->object.id = wl_map_insert_new(&display->objects, 0, proxy);
+ if (proxy->object.id == 0) {
+ free(proxy);
+ return NULL;
+ }
+
+ wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link);
return proxy;
}
@@ -520,7 +686,12 @@ wl_proxy_create_for_id(struct wl_proxy *factory,
proxy->refcount = 1;
proxy->version = factory->version;
- wl_map_insert_at(&display->objects, 0, id, proxy);
+ if (wl_map_insert_at(&display->objects, 0, id, proxy) == -1) {
+ free(proxy);
+ return NULL;
+ }
+
+ wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link);
return proxy;
}
@@ -546,15 +717,33 @@ proxy_destroy(struct wl_proxy *proxy)
proxy->flags |= WL_PROXY_FLAG_DESTROYED;
+ proxy->queue = NULL;
+ wl_list_remove(&proxy->queue_link);
+ wl_list_init(&proxy->queue_link);
+
wl_proxy_unref(proxy);
}
+static void
+wl_proxy_destroy_caller_locks(struct wl_proxy *proxy)
+{
+ if (proxy->flags & WL_PROXY_FLAG_WRAPPER)
+ wl_abort("Tried to destroy wrapper with wl_proxy_destroy()\n");
+
+ proxy_destroy(proxy);
+}
+
/** Destroy a proxy object
*
* \param proxy The proxy to be destroyed
*
* \c proxy must not be a proxy wrapper.
*
+ * \note This function will abort in response to egregious
+ * errors, and will do so with the display lock held. This means
+ * SIGABRT handlers must not perform any actions that would
+ * attempt to take that lock, or a deadlock would occur.
+ *
* \memberof wl_proxy
*/
WL_EXPORT void
@@ -562,11 +751,10 @@ wl_proxy_destroy(struct wl_proxy *proxy)
{
struct wl_display *display = proxy->display;
- if (proxy->flags & WL_PROXY_FLAG_WRAPPER)
- wl_abort("Tried to destroy wrapper with wl_proxy_destroy()\n");
-
pthread_mutex_lock(&display->mutex);
- proxy_destroy(proxy);
+
+ wl_proxy_destroy_caller_locks(proxy);
+
pthread_mutex_unlock(&display->mutex);
}
@@ -760,11 +948,93 @@ wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy,
const struct wl_interface *interface,
uint32_t version)
{
+ return wl_proxy_marshal_array_flags(proxy, opcode, interface, version, 0, args);
+}
+
+/** Prepare a request to be sent to the compositor
+ *
+ * \param proxy The proxy object
+ * \param opcode Opcode of the request to be sent
+ * \param interface The interface to use for the new proxy
+ * \param version The protocol object version of the new proxy
+ * \param flags Flags that modify marshalling behaviour
+ * \param ... Extra arguments for the given request
+ * \return A new wl_proxy for the new_id argument or NULL on error
+ *
+ * Translates the request given by opcode and the extra arguments into the
+ * wire format and write it to the connection buffer.
+ *
+ * For new-id arguments, this function will allocate a new wl_proxy
+ * and send the ID to the server. The new wl_proxy will be returned
+ * on success or NULL on error with errno set accordingly. The newly
+ * created proxy will have the version specified.
+ *
+ * The flag WL_MARSHAL_FLAG_DESTROY may be passed to ensure the proxy
+ * is destroyed atomically with the marshalling in order to prevent
+ * races that can occur if the display lock is dropped between the
+ * marshal and destroy operations.
+ *
+ * \note This should not normally be used by non-generated code.
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT struct wl_proxy *
+wl_proxy_marshal_flags(struct wl_proxy *proxy, uint32_t opcode,
+ const struct wl_interface *interface, uint32_t version,
+ uint32_t flags, ...)
+{
+ union wl_argument args[WL_CLOSURE_MAX_ARGS];
+ va_list ap;
+
+ va_start(ap, flags);
+ wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature,
+ args, WL_CLOSURE_MAX_ARGS, ap);
+ va_end(ap);
+
+ return wl_proxy_marshal_array_flags(proxy, opcode, interface, version, flags, args);
+}
+
+/** Prepare a request to be sent to the compositor
+ *
+ * \param proxy The proxy object
+ * \param opcode Opcode of the request to be sent
+ * \param interface The interface to use for the new proxy
+ * \param version The protocol object version for the new proxy
+ * \param flags Flags that modify marshalling behaviour
+ * \param args Extra arguments for the given request
+ *
+ * Translates the request given by opcode and the extra arguments into the
+ * wire format and write it to the connection buffer. This version takes an
+ * array of the union type wl_argument.
+ *
+ * For new-id arguments, this function will allocate a new wl_proxy
+ * and send the ID to the server. The new wl_proxy will be returned
+ * on success or NULL on error with errno set accordingly. The newly
+ * created proxy will have the version specified.
+ *
+ * The flag WL_MARSHAL_FLAG_DESTROY may be passed to ensure the proxy
+ * is destroyed atomically with the marshalling in order to prevent
+ * races that can occur if the display lock is dropped between the
+ * marshal and destroy operations.
+ *
+ * \note This is intended to be used by language bindings and not in
+ * non-generated code.
+ *
+ * \sa wl_proxy_marshal_flags()
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT struct wl_proxy *
+wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode,
+ const struct wl_interface *interface, uint32_t version,
+ uint32_t flags, union wl_argument *args)
+{
struct wl_closure *closure;
struct wl_proxy *new_proxy = NULL;
const struct wl_message *message;
+ struct wl_display *disp = proxy->display;
- pthread_mutex_lock(&proxy->display->mutex);
+ pthread_mutex_lock(&disp->mutex);
message = &proxy->object.interface->methods[opcode];
if (interface) {
@@ -786,7 +1056,7 @@ wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy,
goto err_unlock;
}
- log_closure(closure, proxy, true);
+ closure_log(closure, proxy, true, WL_CLIENT_MESSAGE_NOT_DISCARDED);
if (wl_closure_send(closure, proxy->display->connection)) {
wl_log("Error sending request: %s\n", strerror(errno));
@@ -796,7 +1066,10 @@ wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy,
wl_closure_destroy(closure);
err_unlock:
- pthread_mutex_unlock(&proxy->display->mutex);
+ if (flags & WL_MARSHAL_FLAG_DESTROY)
+ wl_proxy_destroy_caller_locks(proxy);
+
+ pthread_mutex_unlock(&disp->mutex);
return new_proxy;
}
@@ -1005,8 +1278,8 @@ connect_to_socket(const char *name)
path_is_absolute = name[0] == '/';
runtime_dir = getenv("XDG_RUNTIME_DIR");
- if (!runtime_dir && !path_is_absolute) {
- wl_log("error: XDG_RUNTIME_DIR not set in the environment.\n");
+ if (((!runtime_dir || runtime_dir[0] != '/') && !path_is_absolute)) {
+ wl_log("error: XDG_RUNTIME_DIR is invalid or not set in the environment.\n");
/* to prevent programs reporting
* "failed to create display: Success" */
errno = ENOENT;
@@ -1090,13 +1363,18 @@ wl_display_connect_to_fd(int fd)
pthread_mutex_init(&display->mutex, NULL);
pthread_cond_init(&display->reader_cond, NULL);
display->reader_count = 0;
- wl_list_init(&display->protocol_loggers);
+ wl_list_init(&display->observers);
- wl_map_insert_new(&display->objects, 0, NULL);
+ if (wl_map_insert_at(&display->objects, 0, 0, NULL) == -1)
+ goto err_connection;
- display->proxy.object.interface = &wl_display_interface;
display->proxy.object.id =
wl_map_insert_new(&display->objects, 0, display);
+
+ if (display->proxy.object.id == 0)
+ goto err_connection;
+
+ display->proxy.object.interface = &wl_display_interface;
display->proxy.display = display;
display->proxy.object.implementation = (void(**)(void)) &display_listener;
display->proxy.user_data = display;
@@ -1183,7 +1461,9 @@ wl_display_connect(const char *name)
errno = prev_errno;
flags = fcntl(fd, F_GETFD);
- if (flags != -1)
+ if (flags == -1 && errno == EBADF)
+ return NULL;
+ else if (flags != -1)
fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
unsetenv("WAYLAND_SOCKET");
} else {
@@ -1199,8 +1479,9 @@ wl_display_connect(const char *name)
*
* \param display The display context object
*
- * Close the connection to \c display and free all resources associated
- * with it.
+ * Close the connection to \c display. The \ref wl_proxy and
+ * \ref wl_event_queue objects need to be manually destroyed by the caller
+ * before disconnecting.
*
* \memberof wl_display
*/
@@ -1212,7 +1493,7 @@ wl_display_disconnect(struct wl_display *display)
wl_map_release(&display->objects);
wl_event_queue_release(&display->default_queue);
wl_event_queue_release(&display->display_queue);
- wl_list_remove(&display->protocol_loggers);
+ wl_list_remove(&display->observers);
pthread_mutex_destroy(&display->mutex);
pthread_cond_destroy(&display->reader_cond);
close(display->fd);
@@ -1394,6 +1675,7 @@ queue_event(struct wl_display *display, int len)
struct wl_closure *closure;
const struct wl_message *message;
struct wl_event_queue *queue;
+ int num_zombie_fds;
wl_connection_copy(display->connection, p, sizeof p);
id = p[0];
@@ -1407,10 +1689,15 @@ queue_event(struct wl_display *display, int len)
proxy = wl_map_lookup(&display->objects, id);
if (!proxy || wl_object_is_zombie(&display->objects, id)) {
struct wl_zombie *zombie = wl_map_lookup(&display->objects, id);
+ num_zombie_fds = (zombie && opcode < zombie->event_count) ?
+ zombie->fd_count[opcode] : 0;
+
+ log_unknown_message(display, !!zombie, id, opcode,
+ num_zombie_fds, size);
- if (zombie && zombie->fd_count[opcode])
+ if (num_zombie_fds > 0)
wl_connection_close_fds_in(display->connection,
- zombie->fd_count[opcode]);
+ num_zombie_fds);
wl_connection_consume(display->connection, size);
return size;
@@ -1446,6 +1733,9 @@ queue_event(struct wl_display *display, int len)
else
queue = proxy->queue;
+ if (!queue)
+ wl_abort("Tried to add event to destroyed queue\n");
+
wl_list_insert(queue->event_list.prev, &closure->link);
return size;
@@ -1469,24 +1759,29 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
proxy = closure->proxy;
proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED);
if (proxy_destroyed) {
- destroy_queued_closure(closure);
- return;
- }
-
- pthread_mutex_unlock(&display->mutex);
+ closure_log(closure, proxy, false,
+ WL_CLIENT_MESSAGE_DISCARD_DEAD_PROXY_ON_DISPATCH);
+ } else if (proxy->dispatcher) {
+ closure_log(closure, proxy, false,
+ WL_CLIENT_MESSAGE_NOT_DISCARDED);
- log_closure(closure, proxy, false);
-
- if (proxy->dispatcher) {
+ pthread_mutex_unlock(&display->mutex);
wl_closure_dispatch(closure, proxy->dispatcher,
&proxy->object, opcode);
+ pthread_mutex_lock(&display->mutex);
} else if (proxy->object.implementation) {
+ closure_log(closure, proxy, false,
+ WL_CLIENT_MESSAGE_NOT_DISCARDED);
+
+ pthread_mutex_unlock(&display->mutex);
wl_closure_invoke(closure, WL_CLOSURE_INVOKE_CLIENT,
&proxy->object, opcode, proxy->user_data);
+ pthread_mutex_lock(&display->mutex);
+ } else {
+ closure_log(closure, proxy, false,
+ WL_CLIENT_MESSAGE_DISCARD_NO_LISTENER_ON_DISPATCH);
}
- pthread_mutex_lock(&display->mutex);
-
destroy_queued_closure(closure);
}
@@ -2200,6 +2495,19 @@ wl_proxy_get_class(struct wl_proxy *proxy)
* queued in \c queue from now. If queue is NULL, then the display's
* default queue is set to the proxy.
*
+ * In order to guarantee proper handing of all events which were queued
+ * before the queue change takes effect, it is required to dispatch the
+ * proxy's old event queue after setting a new event queue.
+ *
+ * This is particularly important for multi-threaded setups, where it is
+ * possible for events to be queued to the proxy's old queue from a
+ * different thread during the invocation of this function.
+ *
+ * To ensure that all events for a newly created proxy are dispatched
+ * on a particular queue, it is necessary to use a proxy wrapper if
+ * events are read and dispatched on more than one thread. See
+ * wl_proxy_create_wrapper() for more details.
+ *
* \note By default, the queue set in proxy is the one inherited from parent.
*
* \sa wl_display_dispatch_queue()
@@ -2209,10 +2517,20 @@ wl_proxy_get_class(struct wl_proxy *proxy)
WL_EXPORT void
wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue)
{
- if (queue)
+ pthread_mutex_lock(&proxy->display->mutex);
+
+ wl_list_remove(&proxy->queue_link);
+
+ if (queue) {
+ assert(proxy->display == queue->display);
proxy->queue = queue;
- else
+ } else {
proxy->queue = &proxy->display->default_queue;
+ }
+
+ wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link);
+
+ pthread_mutex_unlock(&proxy->display->mutex);
}
/** Create a proxy wrapper for making queue assignments thread-safe
@@ -2283,6 +2601,8 @@ wl_proxy_create_wrapper(void *proxy)
wrapper->flags = WL_PROXY_FLAG_WRAPPER;
wrapper->refcount = 1;
+ wl_list_insert(&wrapper->queue->proxy_list, &wrapper->queue_link);
+
pthread_mutex_unlock(&wrapped_proxy->display->mutex);
return wrapper;
@@ -2304,13 +2624,19 @@ wl_proxy_wrapper_destroy(void *proxy_wrapper)
assert(wrapper->refcount == 1);
+ pthread_mutex_lock(&wrapper->display->mutex);
+
+ wl_list_remove(&wrapper->queue_link);
+
+ pthread_mutex_unlock(&wrapper->display->mutex);
+
free(wrapper);
}
/** Safely converts an object into its corresponding proxy
*
- * \param object The object to convert
- * \return A corresponding proxy, or NULL on failure
+ * \param object object to get the proxy for
+ * \return A corresponding proxy, or NULL on failure.
*
* Safely converts an object into its corresponding proxy.
*
@@ -2335,59 +2661,63 @@ wl_log_set_handler_client(wl_log_func_t handler)
wl_log_handler = handler;
}
-/** Adds a new protocol client logger.
- *
- * When a new protocol message arrives or is sent from the client
- * all the protocol logger functions will be called, carrying the
- * \a user_data pointer, the type of the message (request or
- * event) and the actual message.
- * The lifetime of the messages passed to the logger function ends
- * when they return so the messages cannot be stored and accessed
- * later.
+/** Creates an client message observer.
*
- * \a errno is set on error.
+ * Note that the observer can potentially start receiving traffic immediately
+ * after being created, and even before this call returns.
*
- * \param display The display object
- * \param func The function to call to log a new protocol message
- * \param user_data The user data pointer to pass to \a func
+ * \param display client display to register with
+ * \param func function to call when client messages are observed
+ * \param user_data \c user_data pointer to pass to the observer
*
- * \return The protocol logger object on success, NULL on failure.
+ * \return The created observer, or NULL.
*
- * \sa wl_protocol_logger_client_destroy
+ * \sa wl_client_observer_destroy
*
* \memberof wl_display
*/
-WL_EXPORT struct wl_protocol_logger_client *
-wl_display_add_protocol_logger_client(struct wl_display *display,
- wl_protocol_logger_client_func_t func,
- void *user_data)
+
+WL_EXPORT struct wl_client_observer *
+wl_display_create_client_observer(struct wl_display *display,
+ wl_client_message_observer_func_t func,
+ void *user_data)
{
- struct wl_protocol_logger_client *logger;
+ struct wl_client_observer *observer;
- logger = malloc(sizeof *logger);
- if (!logger)
+ observer = malloc(sizeof *observer);
+ if (!observer)
return NULL;
- logger->func = func;
- logger->user_data = user_data;
- wl_list_insert(&display->protocol_loggers, &logger->link);
+ observer->display = display;
+ observer->func = func;
+ observer->user_data = user_data;
+
+ pthread_mutex_lock(&display->mutex);
+
+ wl_list_insert(&display->observers, &observer->link);
+
+ pthread_mutex_unlock(&display->mutex);
- return logger;
+ return observer;
}
-/** Destroys a protocol client logger.
+/** Destroys a client message obsever.
*
- * This function destroys a protocol client logger and removes it from the
- * display it was added to with \a wl_display_add_protocol_logger_client.
- * The \a logger object becomes invalid after calling this function.
+ * This function destroys a client message observer, and removes it from the
+ * display it was added to with \c wl_display_create_client_observer.
*
- * \sa wl_display_add_protocol_logger_client
+ * \param observer observer to destroy.
*
- * \memberof wl_protocol_logger_client
+ * \memberof wl_client_observer
*/
WL_EXPORT void
-wl_protocol_logger_client_destroy(struct wl_protocol_logger_client *logger)
+wl_client_observer_destroy(struct wl_client_observer *observer)
{
- wl_list_remove(&logger->link);
- free(logger);
+ pthread_mutex_lock(&observer->display->mutex);
+
+ wl_list_remove(&observer->link);
+
+ pthread_mutex_unlock(&observer->display->mutex);
+
+ free(observer);
}
diff --git a/src/wayland-client.pc.in b/src/wayland-client.pc.in
deleted file mode 100644
index eef61da..0000000
--- a/src/wayland-client.pc.in
+++ /dev/null
@@ -1,12 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-datarootdir=@datarootdir@
-pkgdatadir=@datadir@/@PACKAGE@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: Wayland Client
-Description: Wayland client side library
-Version: @WAYLAND_VERSION@
-Cflags: -I${includedir}
-Libs: -L${libdir} -lwayland-client
diff --git a/src/wayland-os.c b/src/wayland-os.c
index 93b6f5f..a9066ca 100644
--- a/src/wayland-os.c
+++ b/src/wayland-os.c
@@ -25,14 +25,21 @@
#define _GNU_SOURCE
+#include "../config.h"
+
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
+#include <string.h>
#include <sys/epoll.h>
+#include <sys/mman.h>
+#include <sys/un.h>
+#ifdef HAVE_SYS_UCRED_H
+#include <sys/ucred.h>
+#endif
-#include "../config.h"
#include "wayland-os.h"
static int
@@ -72,8 +79,48 @@ wl_os_socket_cloexec(int domain, int type, int protocol)
return set_cloexec_or_close(fd);
}
+#if defined(__FreeBSD__)
+int
+wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid)
+{
+ socklen_t len;
+ struct xucred ucred;
+
+ len = sizeof(ucred);
+ if (getsockopt(sockfd, SOL_LOCAL, LOCAL_PEERCRED, &ucred, &len) < 0 ||
+ ucred.cr_version != XUCRED_VERSION)
+ return -1;
+ *uid = ucred.cr_uid;
+ *gid = ucred.cr_gid;
+#if HAVE_XUCRED_CR_PID
+ /* Since https://cgit.freebsd.org/src/commit/?id=c5afec6e895a */
+ *pid = ucred.cr_pid;
+#else
+ *pid = 0;
+#endif
+ return 0;
+}
+#elif defined(SO_PEERCRED)
+int
+wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid)
+{
+ socklen_t len;
+ struct ucred ucred;
+
+ len = sizeof(ucred);
+ if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0)
+ return -1;
+ *uid = ucred.uid;
+ *gid = ucred.gid;
+ *pid = ucred.pid;
+ return 0;
+}
+#else
+#error "Don't know how to read ucred on this platform"
+#endif
+
int
-wl_os_dupfd_cloexec(int fd, long minfd)
+wl_os_dupfd_cloexec(int fd, int minfd)
{
int newfd;
@@ -121,6 +168,15 @@ recvmsg_cloexec_fallback(int sockfd, struct msghdr *msg, int flags)
ssize_t
wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags)
{
+#if HAVE_BROKEN_MSG_CMSG_CLOEXEC
+ /*
+ * FreeBSD had a broken implementation of MSG_CMSG_CLOEXEC between 2015
+ * and 2021, so we have to use the non-MSG_CMSG_CLOEXEC fallback
+ * directly when compiling against a version that does not include the
+ * fix (https://cgit.freebsd.org/src/commit/?id=6ceacebdf52211).
+ */
+#pragma message("Using fallback directly since MSG_CMSG_CLOEXEC is broken.")
+#else
ssize_t len;
len = recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC);
@@ -128,7 +184,7 @@ wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags)
return len;
if (errno != EINVAL)
return -1;
-
+#endif
return recvmsg_cloexec_fallback(sockfd, msg, flags);
}
@@ -165,3 +221,32 @@ wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
fd = accept(sockfd, addr, addrlen);
return set_cloexec_or_close(fd);
}
+
+/*
+ * Fallback function for operating systems that don't implement
+ * mremap(MREMAP_MAYMOVE).
+ */
+void *
+wl_os_mremap_maymove(int fd, void *old_data, ssize_t *old_size,
+ ssize_t new_size, int prot, int flags)
+{
+ void *result;
+
+ /* Make sure any pending write is flushed. */
+ if (msync(old_data, *old_size, MS_SYNC) != 0)
+ return MAP_FAILED;
+
+ /* We could try mapping a new block immediately after the current one
+ * with MAP_FIXED, however that is not guaranteed to work and breaks
+ * on CHERI-enabled architectures since the data pointer will still
+ * have the bounds of the previous allocation.
+ */
+ result = mmap(NULL, new_size, prot, flags, fd, 0);
+ if (result == MAP_FAILED)
+ return MAP_FAILED;
+
+ if (munmap(old_data, *old_size) == 0)
+ *old_size = 0;
+
+ return result;
+}
diff --git a/src/wayland-os.h b/src/wayland-os.h
index f51efaa..068fd2f 100644
--- a/src/wayland-os.h
+++ b/src/wayland-os.h
@@ -26,11 +26,17 @@
#ifndef WAYLAND_OS_H
#define WAYLAND_OS_H
+#include <sys/types.h>
+#include <sys/socket.h>
+
int
wl_os_socket_cloexec(int domain, int type, int protocol);
int
-wl_os_dupfd_cloexec(int fd, long minfd);
+wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid);
+
+int
+wl_os_dupfd_cloexec(int fd, int minfd);
ssize_t
wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags);
@@ -41,6 +47,10 @@ wl_os_epoll_create_cloexec(void);
int
wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+void *
+wl_os_mremap_maymove(int fd, void *old_data, ssize_t *old_size,
+ ssize_t new_size, int prot, int flags);
+
/*
* The following are for wayland-os.c and the unit tests.
diff --git a/src/wayland-private.h b/src/wayland-private.h
index 9bf8cb7..66fc78f 100644
--- a/src/wayland-private.h
+++ b/src/wayland-private.h
@@ -45,6 +45,7 @@
#define WL_MAP_SERVER_SIDE 0
#define WL_MAP_CLIENT_SIDE 1
#define WL_SERVER_ID_START 0xff000000
+#define WL_MAP_MAX_OBJECTS 0x00f00000
#define WL_CLOSURE_MAX_ARGS 20
struct wl_object {
@@ -210,8 +211,8 @@ int
wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection);
void
-wl_closure_print(struct wl_closure *closure,
- struct wl_object *target, int send);
+wl_closure_print(struct wl_closure *closure, struct wl_object *target,
+ bool send, const char *discarded_reason);
void
wl_closure_destroy(struct wl_closure *closure);
diff --git a/src/wayland-scanner-uninstalled.pc.in b/src/wayland-scanner-uninstalled.pc.in
deleted file mode 100644
index 4559799..0000000
--- a/src/wayland-scanner-uninstalled.pc.in
+++ /dev/null
@@ -1,6 +0,0 @@
-pkgdatadir=@abs_top_srcdir@
-wayland_scanner=@abs_top_builddir@/wayland-scanner
-
-Name: Wayland Scanner
-Description: Wayland scanner (not installed)
-Version: @PACKAGE_VERSION@
diff --git a/src/wayland-scanner.pc.in b/src/wayland-scanner.pc.in
deleted file mode 100644
index 7b2a4c9..0000000
--- a/src/wayland-scanner.pc.in
+++ /dev/null
@@ -1,9 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-datarootdir=@datarootdir@
-pkgdatadir=@datadir@/@PACKAGE@
-wayland_scanner=@bindir@/wayland-scanner
-
-Name: Wayland Scanner
-Description: Wayland scanner
-Version: @WAYLAND_VERSION@
diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h
index e5f4e43..63c6a62 100644
--- a/src/wayland-server-core.h
+++ b/src/wayland-server-core.h
@@ -279,6 +279,16 @@ wl_display_set_global_filter(struct wl_display *display,
const struct wl_interface *
wl_global_get_interface(const struct wl_global *global);
+uint32_t
+wl_global_get_name(const struct wl_global *global,
+ const struct wl_client *client);
+
+uint32_t
+wl_global_get_version(const struct wl_global *global);
+
+struct wl_display *
+wl_global_get_display(const struct wl_global *global);
+
void *
wl_global_get_user_data(const struct wl_global *global);
@@ -324,6 +334,14 @@ struct wl_listener *
wl_client_get_destroy_listener(struct wl_client *client,
wl_notify_func_t notify);
+void
+wl_client_add_destroy_late_listener(struct wl_client *client,
+ struct wl_listener *listener);
+
+struct wl_listener *
+wl_client_get_destroy_late_listener(struct wl_client *client,
+ wl_notify_func_t notify);
+
struct wl_resource *
wl_client_get_object(struct wl_client *client, uint32_t id);
@@ -478,6 +496,9 @@ wl_signal_emit(struct wl_signal *signal, void *data)
l->notify(l, data);
}
+void
+wl_signal_emit_mutable(struct wl_signal *signal, void *data);
+
typedef void (*wl_resource_destroy_func_t)(struct wl_resource *resource);
/*
diff --git a/src/wayland-server-uninstalled.pc.in b/src/wayland-server-uninstalled.pc.in
deleted file mode 100644
index 6b6e603..0000000
--- a/src/wayland-server-uninstalled.pc.in
+++ /dev/null
@@ -1,9 +0,0 @@
-libdir=@abs_builddir@/.libs
-includedir=@abs_srcdir@
-protocoldir=@abs_top_builddir@/protocol
-
-Name: Wayland Server
-Description: Server side implementation of the Wayland protocol (not installed)
-Version: @PACKAGE_VERSION@
-Cflags: -I${includedir} -I${protocoldir}
-Libs: -L${libdir} -lwayland-server
diff --git a/src/wayland-server.c b/src/wayland-server.c
index ca0d98d..468322d 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -31,7 +31,6 @@
#include <stddef.h>
#include <stdio.h>
#include <stdarg.h>
-#include <stdbool.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
@@ -41,6 +40,7 @@
#include <assert.h>
#include <sys/time.h>
#include <fcntl.h>
+#include <sys/eventfd.h>
#include <sys/file.h>
#include <sys/stat.h>
@@ -79,7 +79,10 @@ struct wl_client {
struct wl_list link;
struct wl_map objects;
struct wl_priv_signal destroy_signal;
- struct ucred ucred;
+ struct wl_priv_signal destroy_late_signal;
+ pid_t pid;
+ uid_t uid;
+ gid_t gid;
int error;
struct wl_priv_signal resource_created_signal;
};
@@ -88,7 +91,7 @@ struct wl_display {
struct wl_event_loop *loop;
int run;
- uint32_t id;
+ uint32_t next_global_name;
uint32_t serial;
struct wl_list registry_resource_list;
@@ -104,6 +107,9 @@ struct wl_display {
wl_display_global_filter_func_t global_filter;
void *global_filter_data;
+
+ int terminate_efd;
+ struct wl_event_source *term_source;
};
struct wl_global {
@@ -151,7 +157,7 @@ log_closure(struct wl_resource *resource,
struct wl_protocol_logger_message message;
if (debug_server)
- wl_closure_print(closure, object, send);
+ wl_closure_print(closure, object, send, NULL);
if (!wl_list_empty(&display->protocol_loggers)) {
message.resource = resource;
@@ -315,7 +321,7 @@ wl_resource_post_error(struct wl_resource *resource,
static void
destroy_client_with_error(struct wl_client *client, const char *reason)
{
- wl_log("%s (pid %u)\n", reason, client->ucred.pid);
+ wl_log("%s (pid %u)\n", reason, client->pid);
wl_client_destroy(client);
}
@@ -514,7 +520,6 @@ WL_EXPORT struct wl_client *
wl_client_create(struct wl_display *display, int fd)
{
struct wl_client *client;
- socklen_t len;
client = zalloc(sizeof *client);
if (client == NULL)
@@ -529,9 +534,8 @@ wl_client_create(struct wl_display *display, int fd)
if (!client->source)
goto err_client;
- len = sizeof client->ucred;
- if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED,
- &client->ucred, &len) < 0)
+ if (wl_os_socket_peercred(fd, &client->uid, &client->gid,
+ &client->pid) != 0)
goto err_source;
client->connection = wl_connection_create(fd);
@@ -544,6 +548,7 @@ wl_client_create(struct wl_display *display, int fd)
goto err_map;
wl_priv_signal_init(&client->destroy_signal);
+ wl_priv_signal_init(&client->destroy_late_signal);
if (bind_display(client, display) < 0)
goto err_map;
@@ -575,6 +580,9 @@ err_client:
* SO_PEERCRED, on the client socket fd. All the pointers can be
* NULL, if the caller is not interested in a particular ID.
*
+ * Note, process IDs are subject to race conditions and are not a reliable way
+ * to identify a client.
+ *
* Be aware that for clients that a compositor forks and execs and
* then connects using socketpair(), this function will return the
* credentials for the compositor. The credentials for the socketpair
@@ -587,11 +595,11 @@ wl_client_get_credentials(struct wl_client *client,
pid_t *pid, uid_t *uid, gid_t *gid)
{
if (pid)
- *pid = client->ucred.pid;
+ *pid = client->pid;
if (uid)
- *uid = client->ucred.uid;
+ *uid = client->uid;
if (gid)
- *gid = client->ucred.gid;
+ *gid = client->gid;
}
/** Get the file descriptor for the client
@@ -860,7 +868,7 @@ wl_resource_get_class(struct wl_resource *resource)
/** Safely converts an object into its corresponding resource
*
- * \param object The object to convert
+ * \param object object to get the resource for
* \return A corresponding resource, or NULL on failure
*
* Safely converts an object into its corresponding resource.
@@ -880,6 +888,17 @@ wl_resource_from_object(struct wl_object *object)
return wl_container_of(object, resource, object);
}
+/**
+ * Add a listener to be called at the beginning of wl_client destruction
+ *
+ * The listener provided will be called when wl_client destroy has begun,
+ * before any of that client's resources have been destroyed.
+ *
+ * There is no requirement to remove the link of the wl_listener when the
+ * signal is emitted.
+ *
+ * \memberof wl_client
+ */
WL_EXPORT void
wl_client_add_destroy_listener(struct wl_client *client,
struct wl_listener *listener)
@@ -894,6 +913,32 @@ wl_client_get_destroy_listener(struct wl_client *client,
return wl_priv_signal_get(&client->destroy_signal, notify);
}
+/**
+ * Add a listener to be called at the end of wl_client destruction
+ *
+ * The listener provided will be called when wl_client destroy is nearly
+ * complete, after all of that client's resources have been destroyed.
+ *
+ * There is no requirement to remove the link of the wl_listener when the
+ * signal is emitted.
+ *
+ * \memberof wl_client
+ * \since 1.22.0
+ */
+WL_EXPORT void
+wl_client_add_destroy_late_listener(struct wl_client *client,
+ struct wl_listener *listener)
+{
+ wl_priv_signal_add(&client->destroy_late_signal, listener);
+}
+
+WL_EXPORT struct wl_listener *
+wl_client_get_destroy_late_listener(struct wl_client *client,
+ wl_notify_func_t notify)
+{
+ return wl_priv_signal_get(&client->destroy_late_signal, notify);
+}
+
WL_EXPORT void
wl_client_destroy(struct wl_client *client)
{
@@ -906,6 +951,9 @@ wl_client_destroy(struct wl_client *client)
wl_map_release(&client->objects);
wl_event_source_remove(client->source);
close(wl_connection_destroy(client->connection));
+
+ wl_priv_signal_final_emit(&client->destroy_late_signal, client);
+
wl_list_remove(&client->link);
wl_list_remove(&client->resource_created_signal.listener_list);
free(client);
@@ -1053,6 +1101,16 @@ bind_display(struct wl_client *client, struct wl_display *display)
return 0;
}
+static int
+handle_display_terminate(int fd, uint32_t mask, void *data) {
+ uint64_t term_event;
+
+ if (read(fd, &term_event, sizeof(term_event)) < 0 && errno != EAGAIN)
+ return -1;
+
+ return 0;
+}
+
/** Create Wayland display object.
*
* \return The Wayland display object. Null if failed to create
@@ -1071,7 +1129,7 @@ wl_display_create(void)
if (debug && (strstr(debug, "server") || strstr(debug, "1")))
debug_server = 1;
- display = malloc(sizeof *display);
+ display = zalloc(sizeof *display);
if (display == NULL)
return NULL;
@@ -1081,6 +1139,19 @@ wl_display_create(void)
return NULL;
}
+ display->terminate_efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
+ if (display->terminate_efd < 0)
+ goto err_eventfd;
+
+ display->term_source = wl_event_loop_add_fd(display->loop,
+ display->terminate_efd,
+ WL_EVENT_READABLE,
+ handle_display_terminate,
+ NULL);
+
+ if (display->term_source == NULL)
+ goto err_term_source;
+
wl_list_init(&display->global_list);
wl_list_init(&display->socket_list);
wl_list_init(&display->client_list);
@@ -1090,7 +1161,7 @@ wl_display_create(void)
wl_priv_signal_init(&display->destroy_signal);
wl_priv_signal_init(&display->create_client_signal);
- display->id = 1;
+ display->next_global_name = 1;
display->serial = 0;
display->global_filter = NULL;
@@ -1099,6 +1170,13 @@ wl_display_create(void)
wl_array_init(&display->additional_shm_formats);
return display;
+
+err_term_source:
+ close(display->terminate_efd);
+err_eventfd:
+ wl_event_loop_destroy(display->loop);
+ free(display);
+ return NULL;
}
static void
@@ -1136,7 +1214,6 @@ wl_socket_alloc(void)
/** Destroy Wayland display object.
*
* \param display The Wayland display object which should be destroyed.
- * \return None.
*
* This function emits the wl_display destroy signal, releases
* all the sockets added to this display, free's all the globals associated
@@ -1158,6 +1235,10 @@ wl_display_destroy(struct wl_display *display)
wl_list_for_each_safe(s, next, &display->socket_list, link) {
wl_socket_destroy(s);
}
+
+ close(display->terminate_efd);
+ wl_event_source_remove(display->term_source);
+
wl_event_loop_destroy(display->loop);
wl_list_for_each_safe(global, gnext, &display->global_list, link)
@@ -1175,7 +1256,6 @@ wl_display_destroy(struct wl_display *display)
* \param display The Wayland display object.
* \param filter The global filter function.
* \param data User data to be associated with the global filter.
- * \return None.
*
* Set a filter for the wl_display to advertise or hide global objects
* to clients.
@@ -1190,6 +1270,10 @@ wl_display_destroy(struct wl_display *display)
* Setting the filter NULL will result in all globals being
* advertised to all clients. The default is no filter.
*
+ * The filter should be installed before any client connects and should always
+ * take the same decision given a client and a global. Not doing so will result
+ * in inconsistent filtering and broken wl_registry event sequences.
+ *
* \memberof wl_display
*/
WL_EXPORT void
@@ -1223,12 +1307,17 @@ wl_global_create(struct wl_display *display,
return NULL;
}
- global = malloc(sizeof *global);
+ if (display->next_global_name >= UINT32_MAX) {
+ wl_log("wl_global_create: ran out of global names\n");
+ return NULL;
+ }
+
+ global = zalloc(sizeof *global);
if (global == NULL)
return NULL;
global->display = display;
- global->name = display->id++;
+ global->name = display->next_global_name++;
global->interface = interface;
global->version = version;
global->data = data;
@@ -1237,11 +1326,12 @@ wl_global_create(struct wl_display *display,
wl_list_insert(display->global_list.prev, &global->link);
wl_list_for_each(resource, &display->registry_resource_list, link)
- wl_resource_post_event(resource,
- WL_REGISTRY_GLOBAL,
- global->name,
- global->interface->name,
- global->version);
+ if (wl_global_is_visible(resource->client, global))
+ wl_resource_post_event(resource,
+ WL_REGISTRY_GLOBAL,
+ global->name,
+ global->interface->name,
+ global->version);
return global;
}
@@ -1279,8 +1369,9 @@ wl_global_remove(struct wl_global *global)
global->name);
wl_list_for_each(resource, &display->registry_resource_list, link)
- wl_resource_post_event(resource, WL_REGISTRY_GLOBAL_REMOVE,
- global->name);
+ if (wl_global_is_visible(resource->client, global))
+ wl_resource_post_event(resource, WL_REGISTRY_GLOBAL_REMOVE,
+ global->name);
global->removed = true;
}
@@ -1300,6 +1391,51 @@ wl_global_get_interface(const struct wl_global *global)
return global->interface;
}
+/** Get the name of the global.
+ *
+ * \param global The global object.
+ * \param client Client for which to look up the global.
+ * \return The name of the global, or 0 if the global is not visible to the
+ * client.
+ *
+ * \memberof wl_global
+ * \since 1.22
+ */
+WL_EXPORT uint32_t
+wl_global_get_name(const struct wl_global *global,
+ const struct wl_client *client)
+{
+ return wl_global_is_visible(client, global) ? global->name : 0;
+}
+
+/** Get the version of the given global.
+ *
+ * \param global The global object.
+ * \return The version advertised by the global.
+ *
+ * \memberof wl_global
+ * \since 1.21
+ */
+WL_EXPORT uint32_t
+wl_global_get_version(const struct wl_global *global)
+{
+ return global->version;
+}
+
+/** Get the display object for the given global
+ *
+ * \param global The global object
+ * \return The display object the global is associated with.
+ *
+ * \memberof wl_global
+ * \since 1.20
+ */
+WL_EXPORT struct wl_display *
+wl_global_get_display(const struct wl_global *global)
+{
+ return global->display;
+}
+
WL_EXPORT void *
wl_global_get_user_data(const struct wl_global *global)
{
@@ -1360,7 +1496,13 @@ wl_display_get_event_loop(struct wl_display *display)
WL_EXPORT void
wl_display_terminate(struct wl_display *display)
{
+ int ret;
+ uint64_t terminate = 1;
+
display->run = 0;
+
+ ret = write(display->terminate_efd, &terminate, sizeof(terminate));
+ assert (ret >= 0 || errno == EAGAIN);
}
WL_EXPORT void
@@ -1508,8 +1650,9 @@ wl_socket_init_for_display_name(struct wl_socket *s, const char *name)
if (name[0] != '/') {
runtime_dir = getenv("XDG_RUNTIME_DIR");
- if (!runtime_dir) {
- wl_log("error: XDG_RUNTIME_DIR not set in the environment\n");
+ if (!runtime_dir || runtime_dir[0] != '/') {
+ wl_log("error: XDG_RUNTIME_DIR is invalid or not set in"
+ " the environment\n");
/* to prevent programs reporting
* "failed to add socket: Success" */
@@ -1523,8 +1666,6 @@ wl_socket_init_for_display_name(struct wl_socket *s, const char *name)
name_size = snprintf(s->addr.sun_path, sizeof s->addr.sun_path,
"%s%s%s", runtime_dir, separator, name) + 1;
- s->display_name = (s->addr.sun_path + name_size - 1) - strlen(name);
-
assert(name_size > 0);
if (name_size > (int)sizeof s->addr.sun_path) {
wl_log("error: socket path \"%s%s%s\" plus null terminator"
@@ -1536,6 +1677,8 @@ wl_socket_init_for_display_name(struct wl_socket *s, const char *name)
return -1;
}
+ s->display_name = (s->addr.sun_path + name_size - 1) - strlen(name);
+
return 0;
}
@@ -1576,7 +1719,7 @@ wl_display_add_socket_auto(struct wl_display *display)
{
struct wl_socket *s;
int displayno = 0;
- char display_name[16] = "";
+ char display_name[20] = "";
/* A reasonable number of maximum default sockets. If
* you need more than this, use the explicit add_socket API. */
@@ -1669,7 +1812,7 @@ wl_display_add_socket_fd(struct wl_display *display, int sock_fd)
*
* If the socket name is a relative path, the Unix socket will be created in
* the directory pointed to by environment variable XDG_RUNTIME_DIR. If
- * XDG_RUNTIME_DIR is not set, then this function fails and returns -1.
+ * XDG_RUNTIME_DIR is invalid or not set, then this function fails and returns -1.
*
* If the socket name is an absolute path, then it is used as-is for the
* the Unix socket.
@@ -1787,12 +1930,17 @@ wl_resource_create(struct wl_client *client,
{
struct wl_resource *resource;
- resource = malloc(sizeof *resource);
+ resource = zalloc(sizeof *resource);
if (resource == NULL)
return NULL;
- if (id == 0)
+ if (id == 0) {
id = wl_map_insert_new(&client->objects, 0, NULL);
+ if (id == 0) {
+ free(resource);
+ return NULL;
+ }
+ }
resource->object.id = id;
resource->object.interface = interface;
@@ -1808,9 +1956,11 @@ wl_resource_create(struct wl_client *client,
resource->dispatcher = NULL;
if (wl_map_insert_at(&client->objects, 0, id, resource) < 0) {
- wl_resource_post_error(client->display_resource,
- WL_DISPLAY_ERROR_INVALID_OBJECT,
- "invalid new id %d", id);
+ if (errno == EINVAL) {
+ wl_resource_post_error(client->display_resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "invalid new id %d", id);
+ }
free(resource);
return NULL;
}
@@ -1853,7 +2003,7 @@ wl_display_add_protocol_logger(struct wl_display *display,
{
struct wl_protocol_logger *logger;
- logger = malloc(sizeof *logger);
+ logger = zalloc(sizeof *logger);
if (!logger)
return NULL;
@@ -2054,6 +2204,69 @@ wl_client_for_each_resource(struct wl_client *client,
wl_map_for_each(&client->objects, resource_iterator_helper, &context);
}
+static void
+handle_noop(struct wl_listener *listener, void *data)
+{
+ /* Do nothing */
+}
+
+/** Emits this signal, notifying all registered listeners.
+ *
+ * A safer version of wl_signal_emit() which can gracefully handle additions
+ * and deletions of any signal listener from within listener notification
+ * callbacks.
+ *
+ * Listeners deleted during a signal emission and which have not already been
+ * notified at the time of deletion are not notified by that emission.
+ *
+ * Listeners added (or readded) during signal emission are ignored by that
+ * emission.
+ *
+ * Note that repurposing a listener without explicitly removing it and readding
+ * it is not supported and can lead to unexpected behavior.
+ *
+ * \param signal The signal object that will emit the signal
+ * \param data The data that will be emitted with the signal
+ *
+ * \memberof wl_signal
+ * \since 1.20.90
+ */
+WL_EXPORT void
+wl_signal_emit_mutable(struct wl_signal *signal, void *data)
+{
+ struct wl_listener cursor;
+ struct wl_listener end;
+
+ /* Add two special markers: one cursor and one end marker. This way, we
+ * know that we've already called listeners on the left of the cursor
+ * and that we don't want to call listeners on the right of the end
+ * marker. The 'it' function can remove any element it wants from the
+ * list without troubles.
+ *
+ * There was a previous attempt that used to steal the whole list of
+ * listeners but then that broke wl_signal_get().
+ *
+ * wl_list_for_each_safe tries to be safe but it fails: it works fine
+ * if the current item is removed, but not if the next one is. */
+ wl_list_insert(&signal->listener_list, &cursor.link);
+ cursor.notify = handle_noop;
+ wl_list_insert(signal->listener_list.prev, &end.link);
+ end.notify = handle_noop;
+
+ while (cursor.link.next != &end.link) {
+ struct wl_list *pos = cursor.link.next;
+ struct wl_listener *l = wl_container_of(pos, l, link);
+
+ wl_list_remove(&cursor.link);
+ wl_list_insert(pos, &cursor.link);
+
+ l->notify(l, data);
+ }
+
+ wl_list_remove(&cursor.link);
+ wl_list_remove(&end.link);
+}
+
/** \cond INTERNAL */
/** Initialize a wl_priv_signal object
@@ -2203,12 +2416,16 @@ wl_client_add_resource(struct wl_client *client,
resource->object.id =
wl_map_insert_new(&client->objects,
WL_MAP_ENTRY_LEGACY, resource);
+ if (resource->object.id == 0)
+ return 0;
} else if (wl_map_insert_at(&client->objects, WL_MAP_ENTRY_LEGACY,
resource->object.id, resource) < 0) {
- wl_resource_post_error(client->display_resource,
- WL_DISPLAY_ERROR_INVALID_OBJECT,
- "invalid new id %d",
- resource->object.id);
+ if (errno == EINVAL) {
+ wl_resource_post_error(client->display_resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "invalid new id %d",
+ resource->object.id);
+ }
return 0;
}
diff --git a/src/wayland-server.pc.in b/src/wayland-server.pc.in
deleted file mode 100644
index 50dff53..0000000
--- a/src/wayland-server.pc.in
+++ /dev/null
@@ -1,12 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-datarootdir=@datarootdir@
-pkgdatadir=@datadir@/@PACKAGE@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: Wayland Server
-Description: Server side implementation of the Wayland protocol
-Version: @WAYLAND_VERSION@
-Cflags: -I${includedir}
-Libs: -L${libdir} -lwayland-server
diff --git a/src/wayland-shm.c b/src/wayland-shm.c
index b85e5a7..8fb657a 100644
--- a/src/wayland-shm.c
+++ b/src/wayland-shm.c
@@ -38,6 +38,7 @@
#include <stdint.h>
#include <string.h>
#include <sys/mman.h>
+#include <sys/stat.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
@@ -45,6 +46,7 @@
#include <errno.h>
#include <fcntl.h>
+#include "wayland-os.h"
#include "wayland-util.h"
#include "wayland-private.h"
#include "wayland-server.h"
@@ -61,11 +63,26 @@ struct wl_shm_pool {
int internal_refcount;
int external_refcount;
char *data;
- int32_t size;
- int32_t new_size;
+ ssize_t size;
+ ssize_t new_size;
+#ifndef MREMAP_MAYMOVE
+ /* The following three fields are needed for mremap() emulation. */
+ int mmap_fd;
+ int mmap_flags;
+ int mmap_prot;
+#endif
bool sigbus_is_impossible;
};
+/** \class wl_shm_buffer
+ *
+ * \brief A SHM buffer
+ *
+ * wl_shm_buffer provides a helper for accessing the contents of a wl_buffer
+ * resource created via the wl_shm interface.
+ *
+ * A wl_shm_buffer becomes invalid as soon as its #wl_resource is destroyed.
+ */
struct wl_shm_buffer {
struct wl_resource *resource;
int32_t width, height;
@@ -81,6 +98,26 @@ struct wl_shm_sigbus_data {
int fallback_mapping_used;
};
+static void *
+shm_pool_grow_mapping(struct wl_shm_pool *pool)
+{
+ void *data;
+
+#ifdef MREMAP_MAYMOVE
+ data = mremap(pool->data, pool->size, pool->new_size, MREMAP_MAYMOVE);
+#else
+ data = wl_os_mremap_maymove(pool->mmap_fd, pool->data, &pool->size,
+ pool->new_size, pool->mmap_prot,
+ pool->mmap_flags);
+ if (pool->size != 0 && pool->resource != NULL) {
+ wl_resource_post_error(pool->resource,
+ WL_SHM_ERROR_INVALID_FD,
+ "leaked old mapping");
+ }
+#endif
+ return data;
+}
+
static void
shm_pool_finish_resize(struct wl_shm_pool *pool)
{
@@ -89,11 +126,12 @@ shm_pool_finish_resize(struct wl_shm_pool *pool)
if (pool->size == pool->new_size)
return;
- data = mremap(pool->data, pool->size, pool->new_size, MREMAP_MAYMOVE);
+ data = shm_pool_grow_mapping(pool);
if (data == MAP_FAILED) {
- wl_resource_post_error(pool->resource,
- WL_SHM_ERROR_INVALID_FD,
- "failed mremap");
+ if (pool->resource != NULL)
+ wl_resource_post_error(pool->resource,
+ WL_SHM_ERROR_INVALID_FD,
+ "failed mremap");
return;
}
@@ -106,16 +144,21 @@ shm_pool_unref(struct wl_shm_pool *pool, bool external)
{
if (external) {
pool->external_refcount--;
+ assert(pool->external_refcount >= 0);
if (pool->external_refcount == 0)
shm_pool_finish_resize(pool);
} else {
pool->internal_refcount--;
+ assert(pool->internal_refcount >= 0);
}
- if (pool->internal_refcount + pool->external_refcount)
+ if (pool->internal_refcount + pool->external_refcount > 0)
return;
munmap(pool->data, pool->size);
+#ifndef MREMAP_MAYMOVE
+ close(pool->mmap_fd);
+#endif
free(pool);
}
@@ -124,8 +167,7 @@ destroy_buffer(struct wl_resource *resource)
{
struct wl_shm_buffer *buffer = wl_resource_get_user_data(resource);
- if (buffer->pool)
- shm_pool_unref(buffer->pool, false);
+ shm_pool_unref(buffer->pool, false);
free(buffer);
}
@@ -177,7 +219,7 @@ shm_pool_create_buffer(struct wl_client *client, struct wl_resource *resource,
}
if (offset < 0 || width <= 0 || height <= 0 || stride < width ||
- INT32_MAX / stride <= height ||
+ INT32_MAX / stride < height ||
offset > pool->size - stride * height) {
wl_resource_post_error(resource,
WL_SHM_ERROR_INVALID_STRIDE,
@@ -186,7 +228,7 @@ shm_pool_create_buffer(struct wl_client *client, struct wl_resource *resource,
return;
}
- buffer = malloc(sizeof *buffer);
+ buffer = zalloc(sizeof *buffer);
if (buffer == NULL) {
wl_client_post_no_memory(client);
return;
@@ -219,6 +261,7 @@ destroy_pool(struct wl_resource *resource)
{
struct wl_shm_pool *pool = wl_resource_get_user_data(resource);
+ pool->resource = NULL;
shm_pool_unref(pool, false);
}
@@ -263,7 +306,10 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource,
uint32_t id, int fd, int32_t size)
{
struct wl_shm_pool *pool;
+ struct stat statbuf;
int seals;
+ int prot;
+ int flags;
if (size <= 0) {
wl_resource_post_error(resource,
@@ -272,7 +318,7 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource,
goto err_close;
}
- pool = malloc(sizeof *pool);
+ pool = zalloc(sizeof *pool);
if (pool == NULL) {
wl_client_post_no_memory(client);
goto err_close;
@@ -282,7 +328,11 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource,
seals = fcntl(fd, F_GET_SEALS);
if (seals == -1)
seals = 0;
- pool->sigbus_is_impossible = (seals & F_SEAL_SHRINK) ? true : false;
+
+ if ((seals & F_SEAL_SHRINK) && fstat(fd, &statbuf) >= 0)
+ pool->sigbus_is_impossible = statbuf.st_size >= size;
+ else
+ pool->sigbus_is_impossible = false;
#else
pool->sigbus_is_impossible = false;
#endif
@@ -291,17 +341,23 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource,
pool->external_refcount = 0;
pool->size = size;
pool->new_size = size;
- pool->data = mmap(NULL, size,
- PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ prot = PROT_READ | PROT_WRITE;
+ flags = MAP_SHARED;
+ pool->data = mmap(NULL, size, prot, flags, fd, 0);
if (pool->data == MAP_FAILED) {
- wl_resource_post_error(resource,
- WL_SHM_ERROR_INVALID_FD,
+ wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FD,
"failed mmap fd %d: %s", fd,
strerror(errno));
goto err_free;
}
+#ifndef MREMAP_MAYMOVE
+ /* We may need to keep the fd, prot and flags to emulate mremap(). */
+ pool->mmap_fd = fd;
+ pool->mmap_prot = prot;
+ pool->mmap_flags = flags;
+#else
close(fd);
-
+#endif
pool->resource =
wl_resource_create(client, &wl_shm_pool_interface, 1, id);
if (!pool->resource) {
@@ -400,11 +456,6 @@ wl_shm_buffer_get_stride(struct wl_shm_buffer *buffer)
WL_EXPORT void *
wl_shm_buffer_get_data(struct wl_shm_buffer *buffer)
{
- assert(buffer->pool);
-
- if (!buffer->pool)
- return NULL;
-
if (buffer->pool->external_refcount &&
(buffer->pool->size != buffer->pool->new_size))
wl_log("Buffer address requested when its parent pool "
@@ -511,10 +562,8 @@ sigbus_handler(int signum, siginfo_t *info, void *context)
sigbus_data->fallback_mapping_used = 1;
/* This should replace the previous mapping */
- if (mmap(pool->data, pool->size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,
- 0, 0) == (void *) -1) {
+ if (mmap(pool->data, pool->size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0, 0) == MAP_FAILED) {
reraise_sigbus();
return;
}
diff --git a/src/wayland-util.c b/src/wayland-util.c
index d5973bf..bb2a183 100644
--- a/src/wayland-util.c
+++ b/src/wayland-util.c
@@ -24,6 +24,7 @@
* SOFTWARE.
*/
+#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
@@ -147,7 +148,9 @@ wl_array_copy(struct wl_array *array, struct wl_array *source)
array->size = source->size;
}
- memcpy(array->data, source->data, source->size);
+ if (source->size > 0)
+ memcpy(array->data, source->data, source->size);
+
return 0;
}
@@ -195,6 +198,7 @@ wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data)
union map_entry *start, *entry;
struct wl_array *entries;
uint32_t base;
+ uint32_t count;
if (map->side == WL_MAP_CLIENT_SIDE) {
entries = &map->client_entries;
@@ -215,10 +219,26 @@ wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data)
start = entries->data;
}
+ /* wl_array only grows, so if we have too many objects at
+ * this point there's no way to clean up. We could be more
+ * pro-active about trying to avoid this allocation, but
+ * it doesn't really matter because at this point there is
+ * nothing to be done but disconnect the client and delete
+ * the whole array either way.
+ */
+ count = entry - start;
+ if (count > WL_MAP_MAX_OBJECTS) {
+ /* entry->data is freshly malloced garbage, so we'd
+ * better make it a NULL so wl_map_for_each doesn't
+ * dereference it later. */
+ entry->data = NULL;
+ errno = ENOSPC;
+ return 0;
+ }
entry->data = data;
entry->next |= (flags & 0x1) << 1;
- return (entry - start) + base;
+ return count + base;
}
int
@@ -235,12 +255,21 @@ wl_map_insert_at(struct wl_map *map, uint32_t flags, uint32_t i, void *data)
i -= WL_SERVER_ID_START;
}
+ if (i > WL_MAP_MAX_OBJECTS) {
+ errno = ENOSPC;
+ return -1;
+ }
+
count = entries->size / sizeof *start;
- if (count < i)
+ if (count < i) {
+ errno = EINVAL;
return -1;
+ }
- if (count == i)
- wl_array_add(entries, sizeof *start);
+ if (count == i) {
+ if (!wl_array_add(entries, sizeof *start))
+ return -1;
+ }
start = entries->data;
start[i].data = data;
@@ -257,30 +286,43 @@ wl_map_reserve_new(struct wl_map *map, uint32_t i)
struct wl_array *entries;
if (i < WL_SERVER_ID_START) {
- if (map->side == WL_MAP_CLIENT_SIDE)
+ if (map->side == WL_MAP_CLIENT_SIDE) {
+ errno = EINVAL;
return -1;
+ }
entries = &map->client_entries;
} else {
- if (map->side == WL_MAP_SERVER_SIDE)
+ if (map->side == WL_MAP_SERVER_SIDE) {
+ errno = EINVAL;
return -1;
+ }
entries = &map->server_entries;
i -= WL_SERVER_ID_START;
}
- count = entries->size / sizeof *start;
+ if (i > WL_MAP_MAX_OBJECTS) {
+ errno = ENOSPC;
+ return -1;
+ }
- if (count < i)
+ count = entries->size / sizeof *start;
+ if (count < i) {
+ errno = EINVAL;
return -1;
+ }
if (count == i) {
- wl_array_add(entries, sizeof *start);
+ if (!wl_array_add(entries, sizeof *start))
+ return -1;
+
start = entries->data;
start[i].data = NULL;
} else {
start = entries->data;
if (start[i].data != NULL) {
+ errno = EINVAL;
return -1;
}
}
@@ -361,18 +403,21 @@ wl_map_lookup_flags(struct wl_map *map, uint32_t i)
static enum wl_iterator_result
for_each_helper(struct wl_array *entries, wl_iterator_func_t func, void *data)
{
- union map_entry *start, *end, *p;
enum wl_iterator_result ret = WL_ITERATOR_CONTINUE;
+ union map_entry entry, *start;
+ size_t count;
- start = entries->data;
- end = (union map_entry *) ((char *) entries->data + entries->size);
+ start = (union map_entry *) entries->data;
+ count = entries->size / sizeof(union map_entry);
- for (p = start; p < end; p++)
- if (p->data && !map_entry_is_free(*p)) {
- ret = func(map_entry_get_data(*p), data, map_entry_get_flags(*p));
+ for (size_t idx = 0; idx < count; idx++) {
+ entry = start[idx];
+ if (entry.data && !map_entry_is_free(entry)) {
+ ret = func(map_entry_get_data(entry), data, map_entry_get_flags(entry));
if (ret != WL_ITERATOR_CONTINUE)
break;
}
+ }
return ret;
}
diff --git a/src/wayland-util.h b/src/wayland-util.h
index 7997778..b4cdcfa 100644
--- a/src/wayland-util.h
+++ b/src/wayland-util.h
@@ -118,7 +118,7 @@ struct wl_object;
* * `n`: new_id
* * `a`: array
* * `h`: fd
- * * `?`: following argument is nullable
+ * * `?`: following argument (`o` or `s`) is nullable
*
* While demarshaling primitive arguments is straightforward, when demarshaling
* messages containing `object` or `new_id` arguments, the protocol
@@ -182,7 +182,7 @@ struct wl_message {
* For example, consider a protocol interface `foo`, marked as version `1`, with
* two requests and one event.
*
- * \code
+ * \code{.xml}
* <interface name="foo" version="1">
* <request name="a"></request>
* <request name="b"></request>
@@ -707,17 +707,17 @@ union wl_argument {
* corresponding to the callback. The final argument is an array of arguments
* received from the other process via the wire protocol.
*
- * \param "const void *" Dispatcher-specific implementation data
- * \param "void *" Callback invocation target (wl_proxy or `wl_resource`)
- * \param uint32_t Callback opcode
- * \param "const struct wl_message *" Callback message signature
- * \param "union wl_argument *" Array of received arguments
+ * \param user_data Dispatcher-specific implementation data
+ * \param target Callback invocation target (wl_proxy or `wl_resource`)
+ * \param opcode Callback opcode
+ * \param msg Callback message signature
+ * \param args Array of received arguments
*
* \return 0 on success, or -1 on failure
*/
-typedef int (*wl_dispatcher_func_t)(const void *, void *, uint32_t,
- const struct wl_message *,
- union wl_argument *);
+typedef int (*wl_dispatcher_func_t)(const void *user_data, void *target,
+ uint32_t opcode, const struct wl_message *msg,
+ union wl_argument *args);
/**
* Log function type alias
@@ -736,14 +736,14 @@ typedef int (*wl_dispatcher_func_t)(const void *, void *, uint32_t,
* \note Take care to not confuse this with `wl_protocol_logger_func_t`, which
* is a specific server-side logger for requests and events.
*
- * \param "const char *" String to write to the log, containing optional format
- * specifiers
- * \param "va_list" Variable argument list
+ * \param fmt String to write to the log, containing optional format
+ * specifiers
+ * \param args Variable argument list
*
* \sa wl_log_set_handler_client
* \sa wl_log_set_handler_server
*/
-typedef void (*wl_log_func_t)(const char *, va_list) WL_PRINTF(1, 0);
+typedef void (*wl_log_func_t)(const char *fmt, va_list args) WL_PRINTF(1, 0);
/**
* Return value of an iterator function
diff --git a/src/wayland-version.h b/src/wayland-version.h
index eb33462..34e860e 100644
--- a/src/wayland-version.h
+++ b/src/wayland-version.h
@@ -27,8 +27,8 @@
#define WAYLAND_VERSION_H
#define WAYLAND_VERSION_MAJOR 1
-#define WAYLAND_VERSION_MINOR 19
+#define WAYLAND_VERSION_MINOR 22
#define WAYLAND_VERSION_MICRO 0
-#define WAYLAND_VERSION "1.19.0"
+#define WAYLAND_VERSION "1.22.0"
#endif
diff --git a/tests/client-test.c b/tests/client-test.c
index 960cfa9..47be83f 100644
--- a/tests/client-test.c
+++ b/tests/client-test.c
@@ -40,7 +40,11 @@
struct client_destroy_listener {
struct wl_listener listener;
- int done;
+ bool done;
+ struct wl_listener late_listener;
+ bool late_done;
+ struct wl_listener resource_listener;
+ bool resource_done;
};
static void
@@ -49,13 +53,38 @@ client_destroy_notify(struct wl_listener *l, void *data)
struct client_destroy_listener *listener =
wl_container_of(l, listener, listener);
- listener->done = 1;
+ listener->done = true;
+ assert(!listener->resource_done);
+ assert(!listener->late_done);
+}
+
+static void
+client_resource_destroy_notify(struct wl_listener *l, void *data)
+{
+ struct client_destroy_listener *listener =
+ wl_container_of(l, listener, resource_listener);
+
+ assert(listener->done);
+ listener->resource_done = true;
+ assert(!listener->late_done);
+}
+
+static void
+client_late_destroy_notify(struct wl_listener *l, void *data)
+{
+ struct client_destroy_listener *listener =
+ wl_container_of(l, listener, late_listener);
+
+ assert(listener->done);
+ assert(listener->resource_done);
+ listener->late_done = true;
}
TEST(client_destroy_listener)
{
struct wl_display *display;
struct wl_client *client;
+ struct wl_resource *resource;
struct client_destroy_listener a, b;
int s[2];
@@ -65,23 +94,48 @@ TEST(client_destroy_listener)
client = wl_client_create(display, s[0]);
assert(client);
+ resource = wl_resource_create(client, &wl_callback_interface, 1, 0);
+ assert(resource);
+
a.listener.notify = client_destroy_notify;
- a.done = 0;
+ a.done = false;
+ a.resource_listener.notify = client_resource_destroy_notify;
+ a.resource_done = false;
+ a.late_listener.notify = client_late_destroy_notify;
+ a.late_done = false;
wl_client_add_destroy_listener(client, &a.listener);
+ wl_resource_add_destroy_listener(resource, &a.resource_listener);
+ wl_client_add_destroy_late_listener(client, &a.late_listener);
assert(wl_client_get_destroy_listener(client, client_destroy_notify) ==
&a.listener);
+ assert(wl_resource_get_destroy_listener(resource, client_resource_destroy_notify) ==
+ &a.resource_listener);
+ assert(wl_client_get_destroy_late_listener(client, client_late_destroy_notify) ==
+ &a.late_listener);
b.listener.notify = client_destroy_notify;
- b.done = 0;
+ b.done = false;
+ b.resource_listener.notify = client_resource_destroy_notify;
+ b.resource_done = false;
+ b.late_listener.notify = client_late_destroy_notify;
+ b.late_done = false;
wl_client_add_destroy_listener(client, &b.listener);
+ wl_resource_add_destroy_listener(resource, &b.resource_listener);
+ wl_client_add_destroy_late_listener(client, &b.late_listener);
wl_list_remove(&a.listener.link);
+ wl_list_remove(&a.resource_listener.link);
+ wl_list_remove(&a.late_listener.link);
wl_client_destroy(client);
assert(!a.done);
+ assert(!a.resource_done);
+ assert(!a.late_done);
assert(b.done);
+ assert(b.resource_done);
+ assert(b.late_done);
close(s[0]);
close(s[1]);
diff --git a/tests/compositor-introspection-test.c b/tests/compositor-introspection-test.c
index 83194ce..064d253 100644
--- a/tests/compositor-introspection-test.c
+++ b/tests/compositor-introspection-test.c
@@ -40,7 +40,7 @@ static const char *
require_xdg_runtime_dir(void)
{
char *val = getenv("XDG_RUNTIME_DIR");
- assert(val && "set $XDG_RUNTIME_DIR to run this test");
+ assert(val && val[0] == '/' && "set $XDG_RUNTIME_DIR to run this test");
return val;
}
diff --git a/tests/connection-test.c b/tests/connection-test.c
index c04845b..9762e0d 100644
--- a/tests/connection-test.c
+++ b/tests/connection-test.c
@@ -245,9 +245,6 @@ TEST(connection_marshal)
marshal(&data, "n", 12, &object);
assert(data.buffer[2] == object.id);
- marshal(&data, "?n", 12, NULL);
- assert(data.buffer[2] == 0);
-
array.data = (void *) text;
array.size = sizeof text;
marshal(&data, "a", 20, &array);
@@ -305,7 +302,6 @@ TEST(connection_marshal_nullables)
{
struct marshal_data data;
struct wl_object object;
- struct wl_array array;
const char text[] = "curry";
setup_marshal_data(&data);
@@ -317,9 +313,6 @@ TEST(connection_marshal_nullables)
marshal(&data, "?o", 12, NULL);
assert(data.buffer[2] == 0);
- marshal(&data, "?a", 12, NULL);
- assert(data.buffer[2] == 0);
-
marshal(&data, "?s", 12, NULL);
assert(data.buffer[2] == 0);
@@ -327,12 +320,6 @@ TEST(connection_marshal_nullables)
marshal(&data, "?o", 12, &object);
assert(data.buffer[2] == object.id);
- array.data = (void *) text;
- array.size = sizeof text;
- marshal(&data, "?a", 20, &array);
- assert(data.buffer[2] == array.size);
- assert(memcmp(&data.buffer[3], text, array.size) == 0);
-
marshal(&data, "?s", 20, text);
assert(data.buffer[2] == sizeof text);
assert(strcmp((char *) &data.buffer[3], text) == 0);
@@ -394,7 +381,7 @@ demarshal(struct marshal_data *data, const char *format,
struct wl_closure *closure;
struct wl_map objects;
struct wl_object object = { NULL, &func, 0 };
- int size = msg[1];
+ int size = msg[1] >> 16;
assert(write(data->s[1], msg, size) == size);
assert(wl_connection_read(data->read_connection) == size);
@@ -417,39 +404,41 @@ TEST(connection_demarshal)
data.value.u = 8000;
msg[0] = 400200; /* object id */
- msg[1] = 12; /* size = 12, opcode = 0 */
+ msg[1] = 12 << 16; /* size = 12, opcode = 0 */
msg[2] = data.value.u;
demarshal(&data, "u", msg, (void *) validate_demarshal_u);
data.value.i = -557799;
msg[0] = 400200;
- msg[1] = 12;
+ msg[1] = 12 << 16;
msg[2] = data.value.i;
demarshal(&data, "i", msg, (void *) validate_demarshal_i);
data.value.s = "superdude";
msg[0] = 400200;
- msg[1] = 24;
+ msg[1] = 24 << 16;
msg[2] = 10;
+ msg[3 + msg[2]/4] = 0;
memcpy(&msg[3], data.value.s, msg[2]);
demarshal(&data, "s", msg, (void *) validate_demarshal_s);
data.value.s = "superdude";
msg[0] = 400200;
- msg[1] = 24;
+ msg[1] = 24 << 16;
msg[2] = 10;
+ msg[3 + msg[2]/4] = 0;
memcpy(&msg[3], data.value.s, msg[2]);
demarshal(&data, "?s", msg, (void *) validate_demarshal_s);
data.value.i = wl_fixed_from_double(-90000.2390);
msg[0] = 400200;
- msg[1] = 12;
+ msg[1] = 12 << 16;
msg[2] = data.value.i;
demarshal(&data, "f", msg, (void *) validate_demarshal_f);
data.value.s = NULL;
msg[0] = 400200;
- msg[1] = 12;
+ msg[1] = 12 << 16;
msg[2] = 0;
demarshal(&data, "?s", msg, (void *) validate_demarshal_s);
@@ -553,6 +542,24 @@ expected_fail_demarshal(struct marshal_data *data, const char *format,
assert(errno == expected_error);
}
+TEST(connection_demarshal_null_strings)
+{
+ struct marshal_data data;
+ uint32_t msg[3];
+
+ setup_marshal_data(&data);
+
+ data.value.s = NULL;
+ msg[0] = 400200; /* object id */
+ msg[1] = 12 << 16; /* size = 12, opcode = 0 */
+ msg[2] = 0; /* string length = 0 */
+ demarshal(&data, "?s", msg, (void *) validate_demarshal_s);
+
+ expected_fail_demarshal(&data, "s", msg, EINVAL);
+
+ release_marshal_data(&data);
+}
+
/* These tests are verifying that the demarshaling code will gracefully handle
* clients lying about string and array lengths and giving values near
* UINT32_MAX. Before fixes f7fdface and f5b9e3b9 this test would crash on
diff --git a/tests/data/example-client.h b/tests/data/example-client.h
index d421af9..a14b5e0 100644
--- a/tests/data/example-client.h
+++ b/tests/data/example-client.h
@@ -1011,8 +1011,8 @@ wl_display_sync(struct wl_display *wl_display)
{
struct wl_proxy *callback;
- callback = wl_proxy_marshal_constructor((struct wl_proxy *) wl_display,
- WL_DISPLAY_SYNC, &wl_callback_interface, NULL);
+ callback = wl_proxy_marshal_flags((struct wl_proxy *) wl_display,
+ WL_DISPLAY_SYNC, &wl_callback_interface, wl_proxy_get_version((struct wl_proxy *) wl_display), 0, NULL);
return (struct wl_callback *) callback;
}
@@ -1029,8 +1029,8 @@ wl_display_get_registry(struct wl_display *wl_display)
{
struct wl_proxy *registry;
- registry = wl_proxy_marshal_constructor((struct wl_proxy *) wl_display,
- WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, NULL);
+ registry = wl_proxy_marshal_flags((struct wl_proxy *) wl_display,
+ WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, wl_proxy_get_version((struct wl_proxy *) wl_display), 0, NULL);
return (struct wl_registry *) registry;
}
@@ -1142,8 +1142,8 @@ wl_registry_bind(struct wl_registry *wl_registry, uint32_t name, const struct wl
{
struct wl_proxy *id;
- id = wl_proxy_marshal_constructor_versioned((struct wl_proxy *) wl_registry,
- WL_REGISTRY_BIND, interface, version, name, interface->name, version, NULL);
+ id = wl_proxy_marshal_flags((struct wl_proxy *) wl_registry,
+ WL_REGISTRY_BIND, interface, version, 0, name, interface->name, version, NULL);
return (void *) id;
}
@@ -1258,8 +1258,8 @@ wl_compositor_create_surface(struct wl_compositor *wl_compositor)
{
struct wl_proxy *id;
- id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_compositor,
- WL_COMPOSITOR_CREATE_SURFACE, &wl_surface_interface, NULL);
+ id = wl_proxy_marshal_flags((struct wl_proxy *) wl_compositor,
+ WL_COMPOSITOR_CREATE_SURFACE, &wl_surface_interface, wl_proxy_get_version((struct wl_proxy *) wl_compositor), 0, NULL);
return (struct wl_surface *) id;
}
@@ -1274,8 +1274,8 @@ wl_compositor_create_region(struct wl_compositor *wl_compositor)
{
struct wl_proxy *id;
- id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_compositor,
- WL_COMPOSITOR_CREATE_REGION, &wl_region_interface, NULL);
+ id = wl_proxy_marshal_flags((struct wl_proxy *) wl_compositor,
+ WL_COMPOSITOR_CREATE_REGION, &wl_region_interface, wl_proxy_get_version((struct wl_proxy *) wl_compositor), 0, NULL);
return (struct wl_region *) id;
}
@@ -1338,8 +1338,8 @@ wl_shm_pool_create_buffer(struct wl_shm_pool *wl_shm_pool, int32_t offset, int32
{
struct wl_proxy *id;
- id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_shm_pool,
- WL_SHM_POOL_CREATE_BUFFER, &wl_buffer_interface, NULL, offset, width, height, stride, format);
+ id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool,
+ WL_SHM_POOL_CREATE_BUFFER, &wl_buffer_interface, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), 0, NULL, offset, width, height, stride, format);
return (struct wl_buffer *) id;
}
@@ -1356,10 +1356,8 @@ wl_shm_pool_create_buffer(struct wl_shm_pool *wl_shm_pool, int32_t offset, int32
static inline void
wl_shm_pool_destroy(struct wl_shm_pool *wl_shm_pool)
{
- wl_proxy_marshal((struct wl_proxy *) wl_shm_pool,
- WL_SHM_POOL_DESTROY);
-
- wl_proxy_destroy((struct wl_proxy *) wl_shm_pool);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool,
+ WL_SHM_POOL_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), WL_MARSHAL_FLAG_DESTROY);
}
/**
@@ -1373,8 +1371,8 @@ wl_shm_pool_destroy(struct wl_shm_pool *wl_shm_pool)
static inline void
wl_shm_pool_resize(struct wl_shm_pool *wl_shm_pool, int32_t size)
{
- wl_proxy_marshal((struct wl_proxy *) wl_shm_pool,
- WL_SHM_POOL_RESIZE, size);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool,
+ WL_SHM_POOL_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), 0, size);
}
#ifndef WL_SHM_ERROR_ENUM
@@ -1734,8 +1732,8 @@ wl_shm_create_pool(struct wl_shm *wl_shm, int32_t fd, int32_t size)
{
struct wl_proxy *id;
- id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_shm,
- WL_SHM_CREATE_POOL, &wl_shm_pool_interface, NULL, fd, size);
+ id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shm,
+ WL_SHM_CREATE_POOL, &wl_shm_pool_interface, wl_proxy_get_version((struct wl_proxy *) wl_shm), 0, NULL, fd, size);
return (struct wl_shm_pool *) id;
}
@@ -1819,10 +1817,8 @@ wl_buffer_get_version(struct wl_buffer *wl_buffer)
static inline void
wl_buffer_destroy(struct wl_buffer *wl_buffer)
{
- wl_proxy_marshal((struct wl_proxy *) wl_buffer,
- WL_BUFFER_DESTROY);
-
- wl_proxy_destroy((struct wl_proxy *) wl_buffer);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_buffer,
+ WL_BUFFER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_buffer), WL_MARSHAL_FLAG_DESTROY);
}
#ifndef WL_DATA_OFFER_ERROR_ENUM
@@ -2015,8 +2011,8 @@ wl_data_offer_get_version(struct wl_data_offer *wl_data_offer)
static inline void
wl_data_offer_accept(struct wl_data_offer *wl_data_offer, uint32_t serial, const char *mime_type)
{
- wl_proxy_marshal((struct wl_proxy *) wl_data_offer,
- WL_DATA_OFFER_ACCEPT, serial, mime_type);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer,
+ WL_DATA_OFFER_ACCEPT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, serial, mime_type);
}
/**
@@ -2041,8 +2037,8 @@ wl_data_offer_accept(struct wl_data_offer *wl_data_offer, uint32_t serial, const
static inline void
wl_data_offer_receive(struct wl_data_offer *wl_data_offer, const char *mime_type, int32_t fd)
{
- wl_proxy_marshal((struct wl_proxy *) wl_data_offer,
- WL_DATA_OFFER_RECEIVE, mime_type, fd);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer,
+ WL_DATA_OFFER_RECEIVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, mime_type, fd);
}
/**
@@ -2053,10 +2049,8 @@ wl_data_offer_receive(struct wl_data_offer *wl_data_offer, const char *mime_type
static inline void
wl_data_offer_destroy(struct wl_data_offer *wl_data_offer)
{
- wl_proxy_marshal((struct wl_proxy *) wl_data_offer,
- WL_DATA_OFFER_DESTROY);
-
- wl_proxy_destroy((struct wl_proxy *) wl_data_offer);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer,
+ WL_DATA_OFFER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), WL_MARSHAL_FLAG_DESTROY);
}
/**
@@ -2077,8 +2071,8 @@ wl_data_offer_destroy(struct wl_data_offer *wl_data_offer)
static inline void
wl_data_offer_finish(struct wl_data_offer *wl_data_offer)
{
- wl_proxy_marshal((struct wl_proxy *) wl_data_offer,
- WL_DATA_OFFER_FINISH);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer,
+ WL_DATA_OFFER_FINISH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0);
}
/**
@@ -2119,8 +2113,8 @@ wl_data_offer_finish(struct wl_data_offer *wl_data_offer)
static inline void
wl_data_offer_set_actions(struct wl_data_offer *wl_data_offer, uint32_t dnd_actions, uint32_t preferred_action)
{
- wl_proxy_marshal((struct wl_proxy *) wl_data_offer,
- WL_DATA_OFFER_SET_ACTIONS, dnd_actions, preferred_action);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer,
+ WL_DATA_OFFER_SET_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, dnd_actions, preferred_action);
}
#ifndef WL_DATA_SOURCE_ERROR_ENUM
@@ -2344,8 +2338,8 @@ wl_data_source_get_version(struct wl_data_source *wl_data_source)
static inline void
wl_data_source_offer(struct wl_data_source *wl_data_source, const char *mime_type)
{
- wl_proxy_marshal((struct wl_proxy *) wl_data_source,
- WL_DATA_SOURCE_OFFER, mime_type);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source,
+ WL_DATA_SOURCE_OFFER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), 0, mime_type);
}
/**
@@ -2356,10 +2350,8 @@ wl_data_source_offer(struct wl_data_source *wl_data_source, const char *mime_typ
static inline void
wl_data_source_destroy(struct wl_data_source *wl_data_source)
{
- wl_proxy_marshal((struct wl_proxy *) wl_data_source,
- WL_DATA_SOURCE_DESTROY);
-
- wl_proxy_destroy((struct wl_proxy *) wl_data_source);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source,
+ WL_DATA_SOURCE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), WL_MARSHAL_FLAG_DESTROY);
}
/**
@@ -2382,8 +2374,8 @@ wl_data_source_destroy(struct wl_data_source *wl_data_source)
static inline void
wl_data_source_set_actions(struct wl_data_source *wl_data_source, uint32_t dnd_actions)
{
- wl_proxy_marshal((struct wl_proxy *) wl_data_source,
- WL_DATA_SOURCE_SET_ACTIONS, dnd_actions);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source,
+ WL_DATA_SOURCE_SET_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), 0, dnd_actions);
}
#ifndef WL_DATA_DEVICE_ERROR_ENUM
@@ -2408,7 +2400,7 @@ struct wl_data_device_listener {
* which will subsequently be used in either the data_device.enter
* event (for drag-and-drop) or the data_device.selection event
* (for selections). Immediately following the
- * data_device_data_offer event, the new data_offer object will
+ * data_device.data_offer event, the new data_offer object will
* send out data_offer.offer events to describe the mime types it
* offers.
* @param id the new data_offer object
@@ -2614,8 +2606,8 @@ wl_data_device_destroy(struct wl_data_device *wl_data_device)
static inline void
wl_data_device_start_drag(struct wl_data_device *wl_data_device, struct wl_data_source *source, struct wl_surface *origin, struct wl_surface *icon, uint32_t serial)
{
- wl_proxy_marshal((struct wl_proxy *) wl_data_device,
- WL_DATA_DEVICE_START_DRAG, source, origin, icon, serial);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device,
+ WL_DATA_DEVICE_START_DRAG, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), 0, source, origin, icon, serial);
}
/**
@@ -2629,8 +2621,8 @@ wl_data_device_start_drag(struct wl_data_device *wl_data_device, struct wl_data_
static inline void
wl_data_device_set_selection(struct wl_data_device *wl_data_device, struct wl_data_source *source, uint32_t serial)
{
- wl_proxy_marshal((struct wl_proxy *) wl_data_device,
- WL_DATA_DEVICE_SET_SELECTION, source, serial);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device,
+ WL_DATA_DEVICE_SET_SELECTION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), 0, source, serial);
}
/**
@@ -2641,10 +2633,8 @@ wl_data_device_set_selection(struct wl_data_device *wl_data_device, struct wl_da
static inline void
wl_data_device_release(struct wl_data_device *wl_data_device)
{
- wl_proxy_marshal((struct wl_proxy *) wl_data_device,
- WL_DATA_DEVICE_RELEASE);
-
- wl_proxy_destroy((struct wl_proxy *) wl_data_device);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device,
+ WL_DATA_DEVICE_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), WL_MARSHAL_FLAG_DESTROY);
}
#ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM
@@ -2747,8 +2737,8 @@ wl_data_device_manager_create_data_source(struct wl_data_device_manager *wl_data
{
struct wl_proxy *id;
- id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_data_device_manager,
- WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE, &wl_data_source_interface, NULL);
+ id = wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device_manager,
+ WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE, &wl_data_source_interface, wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager), 0, NULL);
return (struct wl_data_source *) id;
}
@@ -2763,8 +2753,8 @@ wl_data_device_manager_get_data_device(struct wl_data_device_manager *wl_data_de
{
struct wl_proxy *id;
- id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_data_device_manager,
- WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE, &wl_data_device_interface, NULL, seat);
+ id = wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device_manager,
+ WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE, &wl_data_device_interface, wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager), 0, NULL, seat);
return (struct wl_data_device *) id;
}
@@ -2828,8 +2818,8 @@ wl_shell_get_shell_surface(struct wl_shell *wl_shell, struct wl_surface *surface
{
struct wl_proxy *id;
- id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_shell,
- WL_SHELL_GET_SHELL_SURFACE, &wl_shell_surface_interface, NULL, surface);
+ id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shell,
+ WL_SHELL_GET_SHELL_SURFACE, &wl_shell_surface_interface, wl_proxy_get_version((struct wl_proxy *) wl_shell), 0, NULL, surface);
return (struct wl_shell_surface *) id;
}
@@ -3099,8 +3089,8 @@ wl_shell_surface_destroy(struct wl_shell_surface *wl_shell_surface)
static inline void
wl_shell_surface_pong(struct wl_shell_surface *wl_shell_surface, uint32_t serial)
{
- wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_PONG, serial);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+ WL_SHELL_SURFACE_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, serial);
}
/**
@@ -3115,8 +3105,8 @@ wl_shell_surface_pong(struct wl_shell_surface *wl_shell_surface, uint32_t serial
static inline void
wl_shell_surface_move(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial)
{
- wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_MOVE, seat, serial);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+ WL_SHELL_SURFACE_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial);
}
/**
@@ -3131,8 +3121,8 @@ wl_shell_surface_move(struct wl_shell_surface *wl_shell_surface, struct wl_seat
static inline void
wl_shell_surface_resize(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, uint32_t edges)
{
- wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_RESIZE, seat, serial, edges);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+ WL_SHELL_SURFACE_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial, edges);
}
/**
@@ -3145,8 +3135,8 @@ wl_shell_surface_resize(struct wl_shell_surface *wl_shell_surface, struct wl_sea
static inline void
wl_shell_surface_set_toplevel(struct wl_shell_surface *wl_shell_surface)
{
- wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_SET_TOPLEVEL);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+ WL_SHELL_SURFACE_SET_TOPLEVEL, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0);
}
/**
@@ -3163,8 +3153,8 @@ wl_shell_surface_set_toplevel(struct wl_shell_surface *wl_shell_surface)
static inline void
wl_shell_surface_set_transient(struct wl_shell_surface *wl_shell_surface, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags)
{
- wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_SET_TRANSIENT, parent, x, y, flags);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+ WL_SHELL_SURFACE_SET_TRANSIENT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, parent, x, y, flags);
}
/**
@@ -3207,8 +3197,8 @@ wl_shell_surface_set_transient(struct wl_shell_surface *wl_shell_surface, struct
static inline void
wl_shell_surface_set_fullscreen(struct wl_shell_surface *wl_shell_surface, uint32_t method, uint32_t framerate, struct wl_output *output)
{
- wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_SET_FULLSCREEN, method, framerate, output);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+ WL_SHELL_SURFACE_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, method, framerate, output);
}
/**
@@ -3237,8 +3227,8 @@ wl_shell_surface_set_fullscreen(struct wl_shell_surface *wl_shell_surface, uint3
static inline void
wl_shell_surface_set_popup(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags)
{
- wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_SET_POPUP, seat, serial, parent, x, y, flags);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+ WL_SHELL_SURFACE_SET_POPUP, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial, parent, x, y, flags);
}
/**
@@ -3266,8 +3256,8 @@ wl_shell_surface_set_popup(struct wl_shell_surface *wl_shell_surface, struct wl_
static inline void
wl_shell_surface_set_maximized(struct wl_shell_surface *wl_shell_surface, struct wl_output *output)
{
- wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_SET_MAXIMIZED, output);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+ WL_SHELL_SURFACE_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, output);
}
/**
@@ -3284,8 +3274,8 @@ wl_shell_surface_set_maximized(struct wl_shell_surface *wl_shell_surface, struct
static inline void
wl_shell_surface_set_title(struct wl_shell_surface *wl_shell_surface, const char *title)
{
- wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_SET_TITLE, title);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+ WL_SHELL_SURFACE_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, title);
}
/**
@@ -3301,8 +3291,8 @@ wl_shell_surface_set_title(struct wl_shell_surface *wl_shell_surface, const char
static inline void
wl_shell_surface_set_class(struct wl_shell_surface *wl_shell_surface, const char *class_)
{
- wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
- WL_SHELL_SURFACE_SET_CLASS, class_);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+ WL_SHELL_SURFACE_SET_CLASS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, class_);
}
#ifndef WL_SURFACE_ERROR_ENUM
@@ -3457,10 +3447,8 @@ wl_surface_get_version(struct wl_surface *wl_surface)
static inline void
wl_surface_destroy(struct wl_surface *wl_surface)
{
- wl_proxy_marshal((struct wl_proxy *) wl_surface,
- WL_SURFACE_DESTROY);
-
- wl_proxy_destroy((struct wl_proxy *) wl_surface);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+ WL_SURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), WL_MARSHAL_FLAG_DESTROY);
}
/**
@@ -3509,8 +3497,8 @@ wl_surface_destroy(struct wl_surface *wl_surface)
static inline void
wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32_t x, int32_t y)
{
- wl_proxy_marshal((struct wl_proxy *) wl_surface,
- WL_SURFACE_ATTACH, buffer, x, y);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+ WL_SURFACE_ATTACH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, buffer, x, y);
}
/**
@@ -3541,8 +3529,8 @@ wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32
static inline void
wl_surface_damage(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height)
{
- wl_proxy_marshal((struct wl_proxy *) wl_surface,
- WL_SURFACE_DAMAGE, x, y, width, height);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+ WL_SURFACE_DAMAGE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y, width, height);
}
/**
@@ -3586,8 +3574,8 @@ wl_surface_frame(struct wl_surface *wl_surface)
{
struct wl_proxy *callback;
- callback = wl_proxy_marshal_constructor((struct wl_proxy *) wl_surface,
- WL_SURFACE_FRAME, &wl_callback_interface, NULL);
+ callback = wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+ WL_SURFACE_FRAME, &wl_callback_interface, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, NULL);
return (struct wl_callback *) callback;
}
@@ -3623,8 +3611,8 @@ wl_surface_frame(struct wl_surface *wl_surface)
static inline void
wl_surface_set_opaque_region(struct wl_surface *wl_surface, struct wl_region *region)
{
- wl_proxy_marshal((struct wl_proxy *) wl_surface,
- WL_SURFACE_SET_OPAQUE_REGION, region);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+ WL_SURFACE_SET_OPAQUE_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, region);
}
/**
@@ -3656,8 +3644,8 @@ wl_surface_set_opaque_region(struct wl_surface *wl_surface, struct wl_region *re
static inline void
wl_surface_set_input_region(struct wl_surface *wl_surface, struct wl_region *region)
{
- wl_proxy_marshal((struct wl_proxy *) wl_surface,
- WL_SURFACE_SET_INPUT_REGION, region);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+ WL_SURFACE_SET_INPUT_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, region);
}
/**
@@ -3684,8 +3672,8 @@ wl_surface_set_input_region(struct wl_surface *wl_surface, struct wl_region *reg
static inline void
wl_surface_commit(struct wl_surface *wl_surface)
{
- wl_proxy_marshal((struct wl_proxy *) wl_surface,
- WL_SURFACE_COMMIT);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+ WL_SURFACE_COMMIT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0);
}
/**
@@ -3724,8 +3712,8 @@ wl_surface_commit(struct wl_surface *wl_surface)
static inline void
wl_surface_set_buffer_transform(struct wl_surface *wl_surface, int32_t transform)
{
- wl_proxy_marshal((struct wl_proxy *) wl_surface,
- WL_SURFACE_SET_BUFFER_TRANSFORM, transform);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+ WL_SURFACE_SET_BUFFER_TRANSFORM, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, transform);
}
/**
@@ -3758,8 +3746,8 @@ wl_surface_set_buffer_transform(struct wl_surface *wl_surface, int32_t transform
static inline void
wl_surface_set_buffer_scale(struct wl_surface *wl_surface, int32_t scale)
{
- wl_proxy_marshal((struct wl_proxy *) wl_surface,
- WL_SURFACE_SET_BUFFER_SCALE, scale);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+ WL_SURFACE_SET_BUFFER_SCALE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, scale);
}
/**
@@ -3801,8 +3789,8 @@ wl_surface_set_buffer_scale(struct wl_surface *wl_surface, int32_t scale)
static inline void
wl_surface_damage_buffer(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height)
{
- wl_proxy_marshal((struct wl_proxy *) wl_surface,
- WL_SURFACE_DAMAGE_BUFFER, x, y, width, height);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+ WL_SURFACE_DAMAGE_BUFFER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y, width, height);
}
#ifndef WL_SEAT_CAPABILITY_ENUM
@@ -3967,8 +3955,8 @@ wl_seat_get_pointer(struct wl_seat *wl_seat)
{
struct wl_proxy *id;
- id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_seat,
- WL_SEAT_GET_POINTER, &wl_pointer_interface, NULL);
+ id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat,
+ WL_SEAT_GET_POINTER, &wl_pointer_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL);
return (struct wl_pointer *) id;
}
@@ -3989,8 +3977,8 @@ wl_seat_get_keyboard(struct wl_seat *wl_seat)
{
struct wl_proxy *id;
- id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_seat,
- WL_SEAT_GET_KEYBOARD, &wl_keyboard_interface, NULL);
+ id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat,
+ WL_SEAT_GET_KEYBOARD, &wl_keyboard_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL);
return (struct wl_keyboard *) id;
}
@@ -4011,8 +3999,8 @@ wl_seat_get_touch(struct wl_seat *wl_seat)
{
struct wl_proxy *id;
- id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_seat,
- WL_SEAT_GET_TOUCH, &wl_touch_interface, NULL);
+ id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat,
+ WL_SEAT_GET_TOUCH, &wl_touch_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL);
return (struct wl_touch *) id;
}
@@ -4026,10 +4014,8 @@ wl_seat_get_touch(struct wl_seat *wl_seat)
static inline void
wl_seat_release(struct wl_seat *wl_seat)
{
- wl_proxy_marshal((struct wl_proxy *) wl_seat,
- WL_SEAT_RELEASE);
-
- wl_proxy_destroy((struct wl_proxy *) wl_seat);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_seat,
+ WL_SEAT_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_seat), WL_MARSHAL_FLAG_DESTROY);
}
#ifndef WL_POINTER_ERROR_ENUM
@@ -4095,16 +4081,6 @@ enum wl_pointer_axis {
* from a "finger" source may be in a smooth coordinate space with
* kinetic scrolling whereas a "wheel" source may be in discrete steps
* of a number of lines.
- *
- * The "continuous" axis source is a device generating events in a
- * continuous coordinate space, but using something other than a
- * finger. One example for this source is button-based scrolling where
- * the vertical motion of a device is converted to scroll events while
- * a button is held down.
- *
- * The "wheel tilt" axis source indicates that the actual device is a
- * wheel but the scroll event is not caused by a rotation but a
- * (usually sideways) tilt of the wheel.
*/
enum wl_pointer_axis_source {
/**
@@ -4117,10 +4093,20 @@ enum wl_pointer_axis_source {
WL_POINTER_AXIS_SOURCE_FINGER = 1,
/**
* continuous coordinate space
+ *
+ * A device generating events in a continuous coordinate space,
+ * but using something other than a finger. One example for this
+ * source is button-based scrolling where the vertical motion of a
+ * device is converted to scroll events while a button is held
+ * down.
*/
WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2,
/**
* a physical wheel tilt
+ *
+ * Indicates that the actual device is a wheel but the scroll
+ * event is not caused by a rotation but a (usually sideways) tilt
+ * of the wheel.
* @since 6
*/
WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3,
@@ -4506,8 +4492,8 @@ wl_pointer_destroy(struct wl_pointer *wl_pointer)
static inline void
wl_pointer_set_cursor(struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, int32_t hotspot_x, int32_t hotspot_y)
{
- wl_proxy_marshal((struct wl_proxy *) wl_pointer,
- WL_POINTER_SET_CURSOR, serial, surface, hotspot_x, hotspot_y);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_pointer,
+ WL_POINTER_SET_CURSOR, NULL, wl_proxy_get_version((struct wl_proxy *) wl_pointer), 0, serial, surface, hotspot_x, hotspot_y);
}
/**
@@ -4522,10 +4508,8 @@ wl_pointer_set_cursor(struct wl_pointer *wl_pointer, uint32_t serial, struct wl_
static inline void
wl_pointer_release(struct wl_pointer *wl_pointer)
{
- wl_proxy_marshal((struct wl_proxy *) wl_pointer,
- WL_POINTER_RELEASE);
-
- wl_proxy_destroy((struct wl_proxy *) wl_pointer);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_pointer,
+ WL_POINTER_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_pointer), WL_MARSHAL_FLAG_DESTROY);
}
#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM
@@ -4753,10 +4737,8 @@ wl_keyboard_destroy(struct wl_keyboard *wl_keyboard)
static inline void
wl_keyboard_release(struct wl_keyboard *wl_keyboard)
{
- wl_proxy_marshal((struct wl_proxy *) wl_keyboard,
- WL_KEYBOARD_RELEASE);
-
- wl_proxy_destroy((struct wl_proxy *) wl_keyboard);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_keyboard,
+ WL_KEYBOARD_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_keyboard), WL_MARSHAL_FLAG_DESTROY);
}
/**
@@ -4997,10 +4979,8 @@ wl_touch_destroy(struct wl_touch *wl_touch)
static inline void
wl_touch_release(struct wl_touch *wl_touch)
{
- wl_proxy_marshal((struct wl_proxy *) wl_touch,
- WL_TOUCH_RELEASE);
-
- wl_proxy_destroy((struct wl_proxy *) wl_touch);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_touch,
+ WL_TOUCH_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_touch), WL_MARSHAL_FLAG_DESTROY);
}
#ifndef WL_OUTPUT_SUBPIXEL_ENUM
@@ -5282,10 +5262,8 @@ wl_output_destroy(struct wl_output *wl_output)
static inline void
wl_output_release(struct wl_output *wl_output)
{
- wl_proxy_marshal((struct wl_proxy *) wl_output,
- WL_OUTPUT_RELEASE);
-
- wl_proxy_destroy((struct wl_proxy *) wl_output);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_output,
+ WL_OUTPUT_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_output), WL_MARSHAL_FLAG_DESTROY);
}
#define WL_REGION_DESTROY 0
@@ -5334,10 +5312,8 @@ wl_region_get_version(struct wl_region *wl_region)
static inline void
wl_region_destroy(struct wl_region *wl_region)
{
- wl_proxy_marshal((struct wl_proxy *) wl_region,
- WL_REGION_DESTROY);
-
- wl_proxy_destroy((struct wl_proxy *) wl_region);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_region,
+ WL_REGION_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), WL_MARSHAL_FLAG_DESTROY);
}
/**
@@ -5348,8 +5324,8 @@ wl_region_destroy(struct wl_region *wl_region)
static inline void
wl_region_add(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height)
{
- wl_proxy_marshal((struct wl_proxy *) wl_region,
- WL_REGION_ADD, x, y, width, height);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_region,
+ WL_REGION_ADD, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), 0, x, y, width, height);
}
/**
@@ -5360,8 +5336,8 @@ wl_region_add(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width,
static inline void
wl_region_subtract(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height)
{
- wl_proxy_marshal((struct wl_proxy *) wl_region,
- WL_REGION_SUBTRACT, x, y, width, height);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_region,
+ WL_REGION_SUBTRACT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), 0, x, y, width, height);
}
#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM
@@ -5417,10 +5393,8 @@ wl_subcompositor_get_version(struct wl_subcompositor *wl_subcompositor)
static inline void
wl_subcompositor_destroy(struct wl_subcompositor *wl_subcompositor)
{
- wl_proxy_marshal((struct wl_proxy *) wl_subcompositor,
- WL_SUBCOMPOSITOR_DESTROY);
-
- wl_proxy_destroy((struct wl_proxy *) wl_subcompositor);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_subcompositor,
+ WL_SUBCOMPOSITOR_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subcompositor), WL_MARSHAL_FLAG_DESTROY);
}
/**
@@ -5439,8 +5413,8 @@ wl_subcompositor_get_subsurface(struct wl_subcompositor *wl_subcompositor, struc
{
struct wl_proxy *id;
- id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_subcompositor,
- WL_SUBCOMPOSITOR_GET_SUBSURFACE, &wl_subsurface_interface, NULL, surface, parent);
+ id = wl_proxy_marshal_flags((struct wl_proxy *) wl_subcompositor,
+ WL_SUBCOMPOSITOR_GET_SUBSURFACE, &wl_subsurface_interface, wl_proxy_get_version((struct wl_proxy *) wl_subcompositor), 0, NULL, surface, parent);
return (struct wl_subsurface *) id;
}
@@ -5520,10 +5494,8 @@ wl_subsurface_get_version(struct wl_subsurface *wl_subsurface)
static inline void
wl_subsurface_destroy(struct wl_subsurface *wl_subsurface)
{
- wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
- WL_SUBSURFACE_DESTROY);
-
- wl_proxy_destroy((struct wl_proxy *) wl_subsurface);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
+ WL_SUBSURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), WL_MARSHAL_FLAG_DESTROY);
}
/**
@@ -5549,8 +5521,8 @@ wl_subsurface_destroy(struct wl_subsurface *wl_subsurface)
static inline void
wl_subsurface_set_position(struct wl_subsurface *wl_subsurface, int32_t x, int32_t y)
{
- wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
- WL_SUBSURFACE_SET_POSITION, x, y);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
+ WL_SUBSURFACE_SET_POSITION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, x, y);
}
/**
@@ -5575,8 +5547,8 @@ wl_subsurface_set_position(struct wl_subsurface *wl_subsurface, int32_t x, int32
static inline void
wl_subsurface_place_above(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling)
{
- wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
- WL_SUBSURFACE_PLACE_ABOVE, sibling);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
+ WL_SUBSURFACE_PLACE_ABOVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, sibling);
}
/**
@@ -5588,8 +5560,8 @@ wl_subsurface_place_above(struct wl_subsurface *wl_subsurface, struct wl_surface
static inline void
wl_subsurface_place_below(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling)
{
- wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
- WL_SUBSURFACE_PLACE_BELOW, sibling);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
+ WL_SUBSURFACE_PLACE_BELOW, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, sibling);
}
/**
@@ -5612,8 +5584,8 @@ wl_subsurface_place_below(struct wl_subsurface *wl_subsurface, struct wl_surface
static inline void
wl_subsurface_set_sync(struct wl_subsurface *wl_subsurface)
{
- wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
- WL_SUBSURFACE_SET_SYNC);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
+ WL_SUBSURFACE_SET_SYNC, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0);
}
/**
@@ -5642,8 +5614,8 @@ wl_subsurface_set_sync(struct wl_subsurface *wl_subsurface)
static inline void
wl_subsurface_set_desync(struct wl_subsurface *wl_subsurface)
{
- wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
- WL_SUBSURFACE_SET_DESYNC);
+ wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
+ WL_SUBSURFACE_SET_DESYNC, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0);
}
#ifdef __cplusplus
diff --git a/tests/data/example-server.h b/tests/data/example-server.h
index 3311c5d..7cfa4e7 100644
--- a/tests/data/example-server.h
+++ b/tests/data/example-server.h
@@ -3304,16 +3304,6 @@ enum wl_pointer_axis {
* from a "finger" source may be in a smooth coordinate space with
* kinetic scrolling whereas a "wheel" source may be in discrete steps
* of a number of lines.
- *
- * The "continuous" axis source is a device generating events in a
- * continuous coordinate space, but using something other than a
- * finger. One example for this source is button-based scrolling where
- * the vertical motion of a device is converted to scroll events while
- * a button is held down.
- *
- * The "wheel tilt" axis source indicates that the actual device is a
- * wheel but the scroll event is not caused by a rotation but a
- * (usually sideways) tilt of the wheel.
*/
enum wl_pointer_axis_source {
/**
@@ -3326,10 +3316,20 @@ enum wl_pointer_axis_source {
WL_POINTER_AXIS_SOURCE_FINGER = 1,
/**
* continuous coordinate space
+ *
+ * A device generating events in a continuous coordinate space,
+ * but using something other than a finger. One example for this
+ * source is button-based scrolling where the vertical motion of a
+ * device is converted to scroll events while a button is held
+ * down.
*/
WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2,
/**
* a physical wheel tilt
+ *
+ * Indicates that the actual device is a wheel but the scroll
+ * event is not caused by a rotation but a (usually sideways) tilt
+ * of the wheel.
* @since 6
*/
WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3,
diff --git a/tests/data/example.xml b/tests/data/example.xml
index 29b63be..2d76940 100644
--- a/tests/data/example.xml
+++ b/tests/data/example.xml
@@ -812,7 +812,7 @@
which will subsequently be used in either the
data_device.enter event (for drag-and-drop) or the
data_device.selection event (for selections). Immediately
- following the data_device_data_offer event, the new data_offer
+ following the data_device.data_offer event, the new data_offer
object will send out data_offer.offer events to describe the
mime types it offers.
</description>
@@ -1980,21 +1980,23 @@
from a "finger" source may be in a smooth coordinate space with
kinetic scrolling whereas a "wheel" source may be in discrete steps
of a number of lines.
-
- The "continuous" axis source is a device generating events in a
- continuous coordinate space, but using something other than a
- finger. One example for this source is button-based scrolling where
- the vertical motion of a device is converted to scroll events while
- a button is held down.
-
- The "wheel tilt" axis source indicates that the actual device is a
- wheel but the scroll event is not caused by a rotation but a
- (usually sideways) tilt of the wheel.
</description>
<entry name="wheel" value="0" summary="a physical wheel rotation" />
<entry name="finger" value="1" summary="finger on a touch surface" />
- <entry name="continuous" value="2" summary="continuous coordinate space"/>
- <entry name="wheel_tilt" value="3" summary="a physical wheel tilt" since="6"/>
+ <entry name="continuous" value="2">
+ <description summary="continuous coordinate space">
+ A device generating events in a continuous coordinate space, but
+ using something other than a finger. One example for this source
+ is button-based scrolling where the vertical motion of a device
+ is converted to scroll events while a button is held down.
+ </description>
+ </entry>
+ <entry name="wheel_tilt" value="3" since="6">
+ <description summary="a physical wheel tilt">
+ Indicates that the actual device is a wheel but the scroll event is
+ not caused by a rotation but a (usually sideways) tilt of the wheel.
+ </description>
+ </entry>
</enum>
<event name="axis_source" since="5">
diff --git a/tests/data/small-client-core.h b/tests/data/small-client-core.h
index d424757..348d2dc 100644
--- a/tests/data/small-client-core.h
+++ b/tests/data/small-client-core.h
@@ -159,8 +159,8 @@ intf_A_rq1(struct intf_A *intf_A, const struct wl_interface *interface, uint32_t
{
struct wl_proxy *untyped_new;
- untyped_new = wl_proxy_marshal_constructor_versioned((struct wl_proxy *) intf_A,
- INTF_A_RQ1, interface, version, interface->name, version, NULL);
+ untyped_new = wl_proxy_marshal_flags((struct wl_proxy *) intf_A,
+ INTF_A_RQ1, interface, version, 0, interface->name, version, NULL);
return (void *) untyped_new;
}
@@ -173,8 +173,8 @@ intf_A_rq2(struct intf_A *intf_A, const char *str, int32_t i, uint32_t u, wl_fix
{
struct wl_proxy *typed_new;
- typed_new = wl_proxy_marshal_constructor((struct wl_proxy *) intf_A,
- INTF_A_RQ2, &intf_not_here_interface, NULL, str, i, u, f, fd, obj);
+ typed_new = wl_proxy_marshal_flags((struct wl_proxy *) intf_A,
+ INTF_A_RQ2, &intf_not_here_interface, wl_proxy_get_version((struct wl_proxy *) intf_A), 0, NULL, str, i, u, f, fd, obj);
return (struct intf_not_here *) typed_new;
}
@@ -185,10 +185,8 @@ intf_A_rq2(struct intf_A *intf_A, const char *str, int32_t i, uint32_t u, wl_fix
static inline void
intf_A_destroy(struct intf_A *intf_A)
{
- wl_proxy_marshal((struct wl_proxy *) intf_A,
- INTF_A_DESTROY);
-
- wl_proxy_destroy((struct wl_proxy *) intf_A);
+ wl_proxy_marshal_flags((struct wl_proxy *) intf_A,
+ INTF_A_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) intf_A), WL_MARSHAL_FLAG_DESTROY);
}
#ifdef __cplusplus
diff --git a/tests/data/small-client.h b/tests/data/small-client.h
index 2a1f961..8c6abc5 100644
--- a/tests/data/small-client.h
+++ b/tests/data/small-client.h
@@ -159,8 +159,8 @@ intf_A_rq1(struct intf_A *intf_A, const struct wl_interface *interface, uint32_t
{
struct wl_proxy *untyped_new;
- untyped_new = wl_proxy_marshal_constructor_versioned((struct wl_proxy *) intf_A,
- INTF_A_RQ1, interface, version, interface->name, version, NULL);
+ untyped_new = wl_proxy_marshal_flags((struct wl_proxy *) intf_A,
+ INTF_A_RQ1, interface, version, 0, interface->name, version, NULL);
return (void *) untyped_new;
}
@@ -173,8 +173,8 @@ intf_A_rq2(struct intf_A *intf_A, const char *str, int32_t i, uint32_t u, wl_fix
{
struct wl_proxy *typed_new;
- typed_new = wl_proxy_marshal_constructor((struct wl_proxy *) intf_A,
- INTF_A_RQ2, &intf_not_here_interface, NULL, str, i, u, f, fd, obj);
+ typed_new = wl_proxy_marshal_flags((struct wl_proxy *) intf_A,
+ INTF_A_RQ2, &intf_not_here_interface, wl_proxy_get_version((struct wl_proxy *) intf_A), 0, NULL, str, i, u, f, fd, obj);
return (struct intf_not_here *) typed_new;
}
@@ -185,10 +185,8 @@ intf_A_rq2(struct intf_A *intf_A, const char *str, int32_t i, uint32_t u, wl_fix
static inline void
intf_A_destroy(struct intf_A *intf_A)
{
- wl_proxy_marshal((struct wl_proxy *) intf_A,
- INTF_A_DESTROY);
-
- wl_proxy_destroy((struct wl_proxy *) intf_A);
+ wl_proxy_marshal_flags((struct wl_proxy *) intf_A,
+ INTF_A_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) intf_A), WL_MARSHAL_FLAG_DESTROY);
}
#ifdef __cplusplus
diff --git a/tests/display-test.c b/tests/display-test.c
index 3db7c95..bcb3267 100644
--- a/tests/display-test.c
+++ b/tests/display-test.c
@@ -24,6 +24,7 @@
* SOFTWARE.
*/
+#define _GNU_SOURCE
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -1005,9 +1006,16 @@ registry_handle_filtered(void *data, struct wl_registry *registry,
}
}
+static void
+registry_handle_remove_filtered(void *data, struct wl_registry *registry,
+ uint32_t id)
+{
+ assert(false);
+}
+
static const struct wl_registry_listener registry_listener_filtered = {
registry_handle_filtered,
- NULL
+ registry_handle_remove_filtered,
};
static void
@@ -1044,6 +1052,58 @@ TEST(filtered_global_is_hidden)
}
static void
+get_dynamic_globals(void *data)
+{
+ struct client *c = client_connect();
+ struct wl_registry *registry;
+
+ registry = wl_display_get_registry(c->wl_display);
+ wl_registry_add_listener(registry, &registry_listener_filtered, data);
+ wl_display_roundtrip(c->wl_display);
+
+ /* Wait for the server to create a new global */
+ assert(stop_display(c, 1) >= 0);
+
+ /* Check that we don't see it */
+ wl_display_roundtrip(c->wl_display);
+
+ /* Wait for the server to remove that global */
+ assert(stop_display(c, 1) >= 0);
+
+ /* Check that we don't get a global_remove event */
+ wl_display_roundtrip(c->wl_display);
+
+ wl_registry_destroy(registry);
+ client_disconnect_nocheck(c);
+}
+
+TEST(filtered_dynamic_global_is_hidden)
+{
+ struct display *d;
+ struct wl_global *g;
+
+ d = display_create();
+ wl_display_set_global_filter(d->wl_display, global_filter, NULL);
+
+ /* Create a client and let it enumerate the globals */
+ client_create_noarg(d, get_dynamic_globals);
+ display_run(d);
+
+ /* Dynamically create a new global */
+ g = wl_global_create(d->wl_display, &wl_data_offer_interface,
+ 1, d, bind_data_offer);
+
+ display_resume(d);
+
+ /* Dynamically remove the global */
+ wl_global_destroy(g);
+
+ display_resume(d);
+
+ display_destroy(d);
+}
+
+static void
check_bind_error(struct client *c)
{
uint32_t errorcode, id;
@@ -1629,3 +1689,24 @@ TEST(global_remove)
display_destroy(d);
}
+
+static void
+terminate_display(void *arg)
+{
+ struct wl_display *wl_display = arg;
+ wl_display_terminate(wl_display);
+}
+
+TEST(no_source_terminate)
+{
+ struct display *d;
+ struct wl_event_loop *loop;
+
+ d = display_create();
+ loop = wl_display_get_event_loop(d->wl_display);
+
+ wl_event_loop_add_idle(loop, terminate_display, d->wl_display);
+
+ display_run(d);
+ display_destroy(d);
+}
diff --git a/tests/event-loop-test.c b/tests/event-loop-test.c
index cbeaf8e..a51ba8f 100644
--- a/tests/event-loop-test.c
+++ b/tests/event-loop-test.c
@@ -24,6 +24,7 @@
* SOFTWARE.
*/
+#define _GNU_SOURCE
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
@@ -168,10 +169,22 @@ TEST(event_loop_signal)
signal_callback, &got_it);
assert(source);
- wl_event_loop_dispatch(loop, 0);
+ assert(wl_event_loop_dispatch(loop, 0) == 0);
assert(!got_it);
- kill(getpid(), SIGUSR1);
- wl_event_loop_dispatch(loop, 0);
+ assert(kill(getpid(), SIGUSR1) == 0);
+ /*
+ * On Linux the signal will be immediately visible in the epoll_wait()
+ * call. However, on FreeBSD we may need a small delay between kill()
+ * call and the signal being visible to the kevent() call. This
+ * sometimes happens when the signal processing and kevent processing
+ * runs on different CPUs, so becomes more likely when the system is
+ * under load (e.g. running all tests in parallel).
+ * See https://github.com/jiixyj/epoll-shim/pull/32
+ * Passing 1ms as the timeout appears to avoid this race condition in
+ * all cases tested so far, but to be safe we use 1000ms which should
+ * be enough time even on a really slow (or emulated) system.
+ */
+ assert(wl_event_loop_dispatch(loop, 1000) == 0);
assert(got_it == 1);
wl_event_source_remove(source);
@@ -199,8 +212,12 @@ TEST(event_loop_multiple_same_signals)
/* Try it more times */
for (i = 0; i < 5; ++i) {
calls_no = 0;
- kill(getpid(), SIGUSR1);
- assert(wl_event_loop_dispatch(loop, 0) == 0);
+ assert(kill(getpid(), SIGUSR1) == 0);
+ /*
+ * We need a non-zero timeout here to allow the test to pass
+ * on non-Linux systems (see comment in event_loop_signal).
+ */
+ assert(wl_event_loop_dispatch(loop, 1000) == 0);
assert(calls_no == 2);
}
@@ -208,8 +225,12 @@ TEST(event_loop_multiple_same_signals)
/* Try it again with one source */
calls_no = 0;
- kill(getpid(), SIGUSR1);
- assert(wl_event_loop_dispatch(loop, 0) == 0);
+ assert(kill(getpid(), SIGUSR1) == 0);
+ /*
+ * We need a non-zero timeout here to allow the test to pass
+ * on non-Linux systems (see comment in event_loop_signal).
+ */
+ assert(wl_event_loop_dispatch(loop, 1000) == 0);
assert(calls_no == 1);
wl_event_source_remove(s2);
diff --git a/tests/fixed-test.c b/tests/fixed-test.c
index 47a4dae..0b58797 100644
--- a/tests/fixed-test.c
+++ b/tests/fixed-test.c
@@ -23,6 +23,7 @@
* SOFTWARE.
*/
+#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
diff --git a/tests/map-test.c b/tests/map-test.c
index 8ecc1aa..03568ea 100644
--- a/tests/map-test.c
+++ b/tests/map-test.c
@@ -119,3 +119,19 @@ TEST(map_flags)
wl_map_release(&map);
}
+
+static enum wl_iterator_result never_run(void *element, void *data, uint32_t flags)
+{
+ assert(0);
+}
+
+TEST(map_iter_empty)
+{
+ struct wl_map map;
+
+ wl_map_init(&map, WL_MAP_SERVER_SIDE);
+
+ wl_map_for_each(&map, never_run, NULL);
+
+ wl_map_release(&map);
+}
diff --git a/tests/meson.build b/tests/meson.build
index a32ac50..5efd6f7 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -1,3 +1,7 @@
+if not get_option('libraries')
+ error('-Dtests=true requires -Dlibraries=true')
+endif
+
test_runner = static_library(
'test-runner',
sources: [
@@ -9,6 +13,7 @@ test_runner = static_library(
dependencies: [
cc.find_library('dl', required: false),
dependency('threads'),
+ epoll_dep,
ffi_dep,
wayland_util_dep,
wayland_private_dep,
@@ -64,17 +69,19 @@ executable(
dependencies: test_runner_dep
)
-test(
- 'cpp-compile-test',
- executable(
+if add_languages('cpp', native: false)
+ test(
'cpp-compile-test',
- 'cpp-compile-test.cpp',
- wayland_server_protocol_h,
- include_directories: src_inc
+ executable(
+ 'cpp-compile-test',
+ 'cpp-compile-test.cpp',
+ wayland_server_protocol_h,
+ include_directories: src_inc
+ )
)
-)
+endif
-sed_path = find_program('sed').path()
+sed_path = find_program('sed').full_path()
if get_option('scanner')
test(
@@ -152,7 +159,7 @@ tests = {
foreach test_name, test_extra_sources: tests
test_sources = [ test_name + '.c' ] + test_extra_sources
- test_deps = [test_runner_dep]
+ test_deps = [test_runner_dep, epoll_dep]
bin = executable(test_name, test_sources, dependencies: test_deps)
test(
test_name,
diff --git a/tests/message-test.c b/tests/message-test.c
index 4e69392..86f387a 100644
--- a/tests/message-test.c
+++ b/tests/message-test.c
@@ -63,9 +63,8 @@ TEST(message_count_arrays)
{ "middle", "iufasonh", NULL },
{ "multiple", "aaiufaasonhaa", NULL },
{ "leading_version", "2aaiufaasonhaa", NULL },
- { "among_nullables", "iufsa?oa?nah", NULL },
- { "nullable", "?aiufs?a?onh?a", NULL },
- { "all_mixed", "2?aiufas?oa?na", NULL },
+ { "among_nullables", "iufsa?oa?sah", NULL },
+ { "all_mixed", "2aiufas?oa?sa", NULL },
};
const struct {
const struct wl_message *message;
@@ -81,8 +80,7 @@ TEST(message_count_arrays)
{ &fake_messages[5], 6 },
{ &fake_messages[6], 6 },
{ &fake_messages[7], 3 },
- { &fake_messages[8], 3 },
- { &fake_messages[9], 4 },
+ { &fake_messages[8], 4 },
};
for (i = 0; i < ARRAY_LENGTH(messages); ++i) {
diff --git a/tests/os-wrappers-test.c b/tests/os-wrappers-test.c
index 102622c..8d8c3ab 100644
--- a/tests/os-wrappers-test.c
+++ b/tests/os-wrappers-test.c
@@ -23,6 +23,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#include "../config.h"
#define _GNU_SOURCE
@@ -46,26 +47,44 @@
static int fall_back;
-static int (*real_socket)(int, int, int);
-static int wrapped_calls_socket;
+/* Play nice with sanitizers
+ *
+ * Sanitizers need to intercept syscalls in the compiler run-time library. As
+ * this isn't a separate ELF object, the usual dlsym(RTLD_NEXT) approach won't
+ * work: there can only be one function named "socket" etc. To support this, the
+ * sanitizer library names its interceptors with the prefix __interceptor_ ("__"
+ * being reserved for the implementation) and then weakly aliases it to the real
+ * function. The functions we define below will override the weak alias, and we
+ * can call them by the __interceptor_ name directly. This allows the sanitizer
+ * to do its work before calling the next version of the function via dlsym.
+ *
+ * However! We also don't know which of these functions the sanitizer actually
+ * wants to override, so we have to declare our own weak symbols for
+ * __interceptor_ and check at run time if they linked to anything or not.
+*/
-static int (*real_fcntl)(int, int, ...);
-static int wrapped_calls_fcntl;
+#define DECL(ret_type, func, ...) \
+ ret_type __interceptor_ ## func(__VA_ARGS__) __attribute__((weak)); \
+ static ret_type (*real_ ## func)(__VA_ARGS__); \
+ static int wrapped_calls_ ## func;
-static ssize_t (*real_recvmsg)(int, struct msghdr *, int);
-static int wrapped_calls_recvmsg;
+#define REAL(func) (__interceptor_ ## func) ? \
+ __interceptor_ ## func : \
+ (__typeof__(&__interceptor_ ## func))dlsym(RTLD_NEXT, #func)
-static int (*real_epoll_create1)(int);
-static int wrapped_calls_epoll_create1;
+DECL(int, socket, int, int, int);
+DECL(int, fcntl, int, int, ...);
+DECL(ssize_t, recvmsg, int, struct msghdr *, int);
+DECL(int, epoll_create1, int);
static void
init_fallbacks(int do_fallbacks)
{
fall_back = do_fallbacks;
- real_socket = dlsym(RTLD_NEXT, "socket");
- real_fcntl = dlsym(RTLD_NEXT, "fcntl");
- real_recvmsg = dlsym(RTLD_NEXT, "recvmsg");
- real_epoll_create1 = dlsym(RTLD_NEXT, "epoll_create1");
+ real_socket = REAL(socket);
+ real_fcntl = REAL(fcntl);
+ real_recvmsg = REAL(recvmsg);
+ real_epoll_create1 = REAL(epoll_create1);
}
__attribute__ ((visibility("default"))) int
@@ -82,10 +101,11 @@ socket(int domain, int type, int protocol)
}
__attribute__ ((visibility("default"))) int
-fcntl(int fd, int cmd, ...)
+(fcntl)(int fd, int cmd, ...)
{
va_list ap;
- void *arg;
+ int arg;
+ int has_arg;
wrapped_calls_fcntl++;
@@ -93,12 +113,27 @@ fcntl(int fd, int cmd, ...)
errno = EINVAL;
return -1;
}
+ switch (cmd) {
+ case F_DUPFD_CLOEXEC:
+ case F_DUPFD:
+ case F_SETFD:
+ va_start(ap, cmd);
+ arg = va_arg(ap, int);
+ has_arg = 1;
+ va_end(ap);
+ break;
+ case F_GETFD:
+ has_arg = 0;
+ break;
+ default:
+ fprintf(stderr, "Unexpected fctnl cmd %d\n", cmd);
+ abort();
+ }
- va_start(ap, cmd);
- arg = va_arg(ap, void*);
- va_end(ap);
-
- return real_fcntl(fd, cmd, arg);
+ if (has_arg) {
+ return real_fcntl(fd, cmd, arg);
+ }
+ return real_fcntl(fd, cmd);
}
__attribute__ ((visibility("default"))) ssize_t
@@ -307,7 +342,13 @@ do_os_wrappers_recvmsg_cloexec(int n)
struct marshal_data data;
data.nr_fds_begin = count_open_fds();
+#if HAVE_BROKEN_MSG_CMSG_CLOEXEC
+ /* We call the fallback directly on FreeBSD versions with a broken
+ * MSG_CMSG_CLOEXEC, so we don't call the local recvmsg() wrapper. */
+ data.wrapped_calls = 0;
+#else
data.wrapped_calls = n;
+#endif
setup_marshal_data(&data);
data.nr_fds_conn = count_open_fds();
diff --git a/tests/protocol-logger-test.c b/tests/protocol-logger-test.c
index b66e761..94e437d 100644
--- a/tests/protocol-logger-test.c
+++ b/tests/protocol-logger-test.c
@@ -34,125 +34,166 @@
#include "wayland-client.h"
#include "wayland-server.h"
-#include "wayland-util.h"
#include "test-runner.h"
+#define ARRAY_LENGTH(a) (sizeof(a) / sizeof(a)[0])
+
/* Ensure the connection doesn't fail due to lack of XDG_RUNTIME_DIR. */
static const char *
require_xdg_runtime_dir(void)
{
char *val = getenv("XDG_RUNTIME_DIR");
- assert(val && "set $XDG_RUNTIME_DIR to run this test");
+ assert(val && val[0] == '/' && "set $XDG_RUNTIME_DIR to run this test");
return val;
}
+struct expected_compositor_message {
+ enum wl_protocol_logger_type type;
+ const char *class;
+ int opcode;
+ const char *message_name;
+ int args_count;
+};
+
struct compositor {
struct wl_display *display;
struct wl_event_loop *loop;
- int message;
- struct wl_client *client;
-};
+ struct wl_protocol_logger *logger;
-struct client {
- struct wl_display *display;
- struct wl_callback *cb;
- int message;
+ struct expected_compositor_message *expected_msg;
+ int expected_msg_count;
+ int actual_msg_count;
+ struct wl_client *client;
};
-struct message {
- enum wl_protocol_logger_type type;
+struct expected_client_message {
+ enum wl_client_message_type type;
+ enum wl_client_message_discarded_reason discarded_reason;
const char *class;
int opcode;
const char *message_name;
int args_count;
-} messages[] = {
- {
- .type = WL_PROTOCOL_LOGGER_REQUEST,
- .class = "wl_display",
- .opcode = 0,
- .message_name = "sync",
- .args_count = 1,
- },
- {
- .type = WL_PROTOCOL_LOGGER_EVENT,
- .class = "wl_callback",
- .opcode = 0,
- .message_name = "done",
- .args_count = 1,
- },
- {
- .type = WL_PROTOCOL_LOGGER_EVENT,
- .class = "wl_display",
- .opcode = 1,
- .message_name = "delete_id",
- .args_count = 1,
- },
};
-struct client_message {
- enum wl_protocol_logger_client_type type;
- const char *class;
- int opcode;
- const char *message_name;
- int args_count;
-} client_messages[] = {
- {
- .type = WL_PROTOCOL_LOGGER_CLIENT_REQUEST,
- .class = "wl_display",
- .opcode = 0,
- .message_name = "sync",
- .args_count = 1,
- },
- {
- .type = WL_PROTOCOL_LOGGER_CLIENT_EVENT,
- .class = "wl_display",
- .opcode = 1,
- .message_name = "delete_id",
- .args_count = 1,
- },
- {
- .type = WL_PROTOCOL_LOGGER_CLIENT_EVENT,
- .class = "wl_callback",
- .opcode = 0,
- .message_name = "done",
- .args_count = 1,
- },
+struct client {
+ struct wl_display *display;
+ struct wl_callback *cb;
+ struct wl_client_observer *sequence_observer;
+ struct wl_client_observer *stderr_logger;
+
+ struct expected_client_message *expected_msg;
+ int expected_msg_count;
+ int actual_msg_count;
};
+#define ASSERT_LT(arg1, arg2, ...) \
+ if (arg1 >= arg2) \
+ fprintf(stderr, __VA_ARGS__); \
+ assert(arg1 < arg2)
+
+#define ASSERT_EQ(arg1, arg2, ...) \
+ if (arg1 != arg2) \
+ fprintf(stderr, __VA_ARGS__); \
+ assert(arg1 == arg2)
+
+#define ASSERT_STR_EQ(arg1, arg2, ...) \
+ if (strcmp(arg1, arg2) != 0) \
+ fprintf(stderr, __VA_ARGS__); \
+ assert(strcmp(arg1, arg2) == 0)
+
static void
-logger_func(void *user_data, enum wl_protocol_logger_type type,
- const struct wl_protocol_logger_message *message)
+compositor_sequence_observer_func(
+ void *user_data, enum wl_protocol_logger_type actual_type,
+ const struct wl_protocol_logger_message *actual_msg)
{
struct compositor *c = user_data;
- struct message *msg = &messages[c->message++];
-
- assert(msg->type == type);
- assert(strcmp(msg->class, wl_resource_get_class(message->resource)) == 0);
- assert(msg->opcode == message->message_opcode);
- assert(strcmp(msg->message_name, message->message->name) == 0);
- assert(msg->args_count == message->arguments_count);
-
- c->client = wl_resource_get_client(message->resource);
+ struct expected_compositor_message *expected_msg;
+ int actual_msg_count = c->actual_msg_count++;
+ char details_msg[256];
+
+ c->client = wl_resource_get_client(actual_msg->resource);
+
+ if (!c->expected_msg)
+ return;
+
+ ASSERT_LT(actual_msg_count, c->expected_msg_count,
+ "actual count %d exceeds expected count %d\n",
+ actual_msg_count, c->expected_msg_count);
+
+ expected_msg = &c->expected_msg[actual_msg_count];
+
+ snprintf(details_msg, sizeof details_msg,
+ "compositor msg %d of %d actual [%d, '%s', %d, '%s', %d] vs "
+ "expected [%d, '%s', %d, '%s', %d]\n",
+ c->actual_msg_count, c->expected_msg_count, actual_type,
+ wl_resource_get_class(actual_msg->resource),
+ actual_msg->message_opcode, actual_msg->message->name,
+ actual_msg->arguments_count, expected_msg->type,
+ expected_msg->class, expected_msg->opcode,
+ expected_msg->message_name, expected_msg->args_count);
+
+ ASSERT_EQ(expected_msg->type, actual_type, "type mismatch: %s",
+ details_msg);
+ ASSERT_STR_EQ(expected_msg->class,
+ wl_resource_get_class(actual_msg->resource),
+ "class mismatch: %s", details_msg);
+ ASSERT_EQ(expected_msg->opcode, actual_msg->message_opcode,
+ "opcode mismatch: %s", details_msg);
+ ASSERT_STR_EQ(expected_msg->message_name, actual_msg->message->name,
+ "message name mismatch: %s", details_msg);
+ ASSERT_EQ(expected_msg->args_count, actual_msg->arguments_count,
+ "arg count mismatch: %s", details_msg);
}
static void
-client_logger_func(void *user_data, enum wl_protocol_logger_client_type type,
- const struct wl_protocol_logger_client_message *message)
+client_sequence_observer_func(
+ void *user_data, enum wl_client_message_type actual_type,
+ const struct wl_client_observed_message *actual_msg)
{
struct client *c = user_data;
- struct client_message *msg = &client_messages[c->message++];
-
- assert(msg->type == type);
- assert(strcmp(msg->class, wl_proxy_get_class(message->proxy)) == 0);
- assert(msg->opcode == message->message_opcode);
- assert(strcmp(msg->message_name, message->message->name) == 0);
- assert(msg->args_count == message->arguments_count);
+ struct expected_client_message *expected_msg;
+ int actual_msg_count = c->actual_msg_count++;
+ char details_msg[256];
+
+ if (!c->expected_msg)
+ return;
+
+ ASSERT_LT(actual_msg_count, c->expected_msg_count,
+ "actual count %d exceeds expected count %d\n",
+ actual_msg_count, c->expected_msg_count);
+ expected_msg = &c->expected_msg[actual_msg_count];
+
+ snprintf(details_msg, sizeof details_msg,
+ "client msg %d of %d actual [%d, %d, '%s', %d, '%s', %d] vs "
+ "expected [%d, %d, '%s', %d, '%s', %d]\n",
+ c->actual_msg_count, c->expected_msg_count, actual_type,
+ actual_msg->discarded_reason,
+ wl_proxy_get_class(actual_msg->proxy),
+ actual_msg->message_opcode, actual_msg->message->name,
+ actual_msg->arguments_count, expected_msg->type,
+ expected_msg->discarded_reason, expected_msg->class,
+ expected_msg->opcode, expected_msg->message_name,
+ expected_msg->args_count);
+
+ ASSERT_EQ(expected_msg->type, actual_type, "type mismatch: %s",
+ details_msg);
+ ASSERT_EQ(expected_msg->discarded_reason, actual_msg->discarded_reason,
+ "discarded reason mismatch: %s", details_msg);
+ ASSERT_STR_EQ(expected_msg->class,
+ wl_proxy_get_class(actual_msg->proxy),
+ "class mismatch: %s", details_msg);
+ ASSERT_EQ(expected_msg->opcode, actual_msg->message_opcode,
+ "opcode mismatch: %s", details_msg);
+ ASSERT_STR_EQ(expected_msg->message_name, actual_msg->message->name,
+ "message name mismatch: %s", details_msg);
+ ASSERT_EQ(expected_msg->args_count, actual_msg->arguments_count,
+ "arg count mismatch: %s", details_msg);
}
-// A slightly simplified version of get_next_argument() from src/connection.c
-static const char*
-get_next_argument_type(const char *signature, char* type)
+// A slightly simplified version of get_next_argument() from src/connection.c
+static const char *
+get_next_argument_type(const char *signature, char *type)
{
for (; *signature; ++signature) {
assert(strchr("iufsonah?", *signature) != NULL);
@@ -169,7 +210,6 @@ get_next_argument_type(const char *signature, char* type)
return signature + 1;
case '?':
break;
-
}
}
*type = 0;
@@ -179,85 +219,101 @@ get_next_argument_type(const char *signature, char* type)
// This duplicates what the internal wl_closure_print function does, and can be
// used as a starting point for a client or server that wants to log messages.
static void
-client_log_to_stderr_demo(void *user_data,
- enum wl_protocol_logger_client_type type,
- const struct wl_protocol_logger_client_message *message) {
+client_log_to_stderr_demo(void *user_data, enum wl_client_message_type type,
+ const struct wl_client_observed_message *message)
+{
int i;
char arg_type;
const char *signature = message->message->signature;
- const union wl_argument* args = message->arguments;
- struct wl_proxy* arg_proxy;
- const char* arg_class;
+ const union wl_argument *args = message->arguments;
+ struct wl_proxy *arg_proxy;
+ const char *arg_class;
struct timespec tp;
- unsigned int time;
+ unsigned long long time;
+ FILE *f;
+ char *buffer;
+ size_t buffer_length;
+
+ f = open_memstream(&buffer, &buffer_length);
+ if (f == NULL)
+ return;
clock_gettime(CLOCK_REALTIME, &tp);
- time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
+ time = (tp.tv_sec * 1000000LL) + (tp.tv_nsec / 1000);
// Note: server logger will be given message->resource, and should
// use wl_resource_get_class and wl_resolurce_get_id.
- fprintf(stderr, "[%10.3f] %s%s@%u.%s(",
- time / 1000.0,
- (type == WL_PROTOCOL_LOGGER_CLIENT_REQUEST) ? " -> " : "",
- wl_proxy_get_class(message->proxy), wl_proxy_get_id(message->proxy),
- message->message->name);
+ fprintf(f, "[%7llu.%03llu] %s%s%s%s%s@%u.%s(", time / 1000, time % 1000,
+ (message->discarded_reason_str ? "discarded[" : ""),
+ (message->discarded_reason_str ? message->discarded_reason_str
+ : ""),
+ (message->discarded_reason_str ? "] " : ""),
+ (type == WL_CLIENT_MESSAGE_REQUEST) ? " -> " : "",
+ wl_proxy_get_class(message->proxy),
+ wl_proxy_get_id(message->proxy), message->message->name);
for (i = 0; i < message->arguments_count; i++) {
signature = get_next_argument_type(signature, &arg_type);
if (i > 0)
- fprintf(stderr, ", ");
+ fprintf(f, ", ");
switch (arg_type) {
case 'u':
- fprintf(stderr, "%u", args[i].u);
+ fprintf(f, "%u", args[i].u);
break;
case 'i':
- fprintf(stderr, "%d", args[i].i);
+ fprintf(f, "%d", args[i].i);
break;
case 'f':
- fprintf(stderr, "%f", wl_fixed_to_double(args[i].f));
+ fprintf(f, "%f", wl_fixed_to_double(args[i].f));
break;
case 's':
if (args[i].s)
- fprintf(stderr, "\"%s\"", args[i].s);
+ fprintf(f, "\"%s\"", args[i].s);
else
- fprintf(stderr, "nil");
+ fprintf(f, "nil");
break;
case 'o':
if (args[i].o) {
// Note: server logger should instead use
// wl_resource_from_object, and then
- // wl_resource_get_class and wl_resource_get_id.
+ // wl_resource_get_class and
+ // wl_resource_get_id.
arg_proxy = wl_proxy_from_object(args[i].o);
arg_class = wl_proxy_get_class(arg_proxy);
- fprintf(stderr, "%s@%u",
+ fprintf(f, "%s@%u",
arg_class ? arg_class : "[unknown]",
wl_proxy_get_id(arg_proxy));
} else {
- fprintf(stderr, "nil");
+ fprintf(f, "nil");
}
break;
case 'n':
- fprintf(stderr, "new id %s@",
- (message->message->types[i]) ?
- message->message->types[i]->name :
- "[unknown]");
+ fprintf(f, "new id %s@",
+ (message->message->types[i])
+ ? message->message->types[i]->name
+ : "[unknown]");
if (args[i].n != 0)
- fprintf(stderr, "%u", args[i].n);
+ fprintf(f, "%u", args[i].n);
else
- fprintf(stderr, "nil");
+ fprintf(f, "nil");
break;
case 'a':
- fprintf(stderr, "array");
+ fprintf(f, "array");
break;
case 'h':
- fprintf(stderr, "fd %d", args[i].h);
+ fprintf(f, "fd %d", args[i].h);
break;
}
}
- fprintf(stderr, ")\n");
+ fprintf(f, ")\n");
+
+ if (fclose(f) == 0) {
+ fprintf(stderr, "%s", buffer);
+ free(buffer);
+ }
}
static void
@@ -270,46 +326,486 @@ static const struct wl_callback_listener callback_listener = {
callback_done,
};
+static void
+logger_setup(struct compositor *compositor, struct client *client)
+{
+ const char *socket;
+
+ require_xdg_runtime_dir();
+
+ compositor->display = wl_display_create();
+ compositor->loop = wl_display_get_event_loop(compositor->display);
+ socket = wl_display_add_socket_auto(compositor->display);
+
+ compositor->logger = wl_display_add_protocol_logger(
+ compositor->display, compositor_sequence_observer_func,
+ compositor);
+
+ client->display = wl_display_connect(socket);
+ client->sequence_observer = wl_display_create_client_observer(
+ client->display, client_sequence_observer_func, client);
+ client->stderr_logger = wl_display_create_client_observer(
+ client->display, client_log_to_stderr_demo, client);
+}
+
+static void
+logger_teardown(struct compositor *compositor, struct client *client)
+{
+ wl_client_observer_destroy(client->sequence_observer);
+ wl_client_observer_destroy(client->stderr_logger);
+ wl_display_disconnect(client->display);
+
+ wl_client_destroy(compositor->client);
+ wl_protocol_logger_destroy(compositor->logger);
+ wl_display_destroy(compositor->display);
+}
+
TEST(logger)
{
test_set_timeout(1);
- const char *socket;
+ struct expected_compositor_message compositor_messages[] = {
+ {
+ .type = WL_PROTOCOL_LOGGER_REQUEST,
+ .class = "wl_display",
+ .opcode = 0,
+ .message_name = "sync",
+ .args_count = 1,
+ },
+ {
+ .type = WL_PROTOCOL_LOGGER_EVENT,
+ .class = "wl_callback",
+ .opcode = 0,
+ .message_name = "done",
+ .args_count = 1,
+ },
+ {
+ .type = WL_PROTOCOL_LOGGER_EVENT,
+ .class = "wl_display",
+ .opcode = 1,
+ .message_name = "delete_id",
+ .args_count = 1,
+ },
+ };
+ struct expected_client_message client_messages[] = {
+ {
+ .type = WL_CLIENT_MESSAGE_REQUEST,
+ .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
+ .class = "wl_display",
+ .opcode = 0,
+ .message_name = "sync",
+ .args_count = 1,
+ },
+ {
+ .type = WL_CLIENT_MESSAGE_EVENT,
+ .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
+ .class = "wl_display",
+ .opcode = 1,
+ .message_name = "delete_id",
+ .args_count = 1,
+ },
+ {
+ .type = WL_CLIENT_MESSAGE_EVENT,
+ .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
+ .class = "wl_callback",
+ .opcode = 0,
+ .message_name = "done",
+ .args_count = 1,
+ },
+ };
struct compositor compositor = { 0 };
struct client client = { 0 };
- struct wl_protocol_logger *logger;
- struct wl_protocol_logger_client *logger_client;
- struct wl_protocol_logger_client *logger_client_demo;
- require_xdg_runtime_dir();
+ logger_setup(&compositor, &client);
+
+ compositor.expected_msg = &compositor_messages[0];
+ compositor.expected_msg_count = ARRAY_LENGTH(compositor_messages);
+
+ client.expected_msg = &client_messages[0];
+ client.expected_msg_count = ARRAY_LENGTH(client_messages);
+
+ client.cb = wl_display_sync(client.display);
+ wl_callback_add_listener(client.cb, &callback_listener, NULL);
+ wl_display_flush(client.display);
+
+ while (compositor.actual_msg_count < compositor.expected_msg_count) {
+ wl_event_loop_dispatch(compositor.loop, -1);
+ wl_display_flush_clients(compositor.display);
+ }
+
+ while (client.actual_msg_count < client.expected_msg_count) {
+ wl_display_dispatch(client.display);
+ }
+
+ logger_teardown(&compositor, &client);
+}
+
+TEST(client_discards_if_dead_on_dispatch)
+{
+ test_set_timeout(1);
+
+ struct expected_client_message client_messages[] = {
+ {
+ .type = WL_CLIENT_MESSAGE_REQUEST,
+ .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
+ .class = "wl_display",
+ .opcode = 0,
+ .message_name = "sync",
+ .args_count = 1,
+ },
+ {
+ .type = WL_CLIENT_MESSAGE_EVENT,
+ .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
+ .class = "wl_display",
+ .opcode = 1,
+ .message_name = "delete_id",
+ .args_count = 1,
+ },
+ {
+ .type = WL_CLIENT_MESSAGE_EVENT,
+ .discarded_reason =
+ WL_CLIENT_MESSAGE_DISCARD_DEAD_PROXY_ON_DISPATCH,
+ .class = "wl_callback",
+ .opcode = 0,
+ .message_name = "done",
+ .args_count = 1,
+ },
+ };
+ struct compositor compositor = { 0 };
+ struct client client = { 0 };
+
+ logger_setup(&compositor, &client);
- compositor.display = wl_display_create();
- compositor.loop = wl_display_get_event_loop(compositor.display);
- socket = wl_display_add_socket_auto(compositor.display);
+ compositor.expected_msg_count = 3;
- logger = wl_display_add_protocol_logger(compositor.display,
- logger_func, &compositor);
+ client.expected_msg = &client_messages[0];
+ client.expected_msg_count = ARRAY_LENGTH(client_messages);
- client.display = wl_display_connect(socket);
- logger_client = wl_display_add_protocol_logger_client(
- client.display, client_logger_func, &client);
- logger_client_demo = wl_display_add_protocol_logger_client(
- client.display, client_log_to_stderr_demo, &client);
client.cb = wl_display_sync(client.display);
wl_callback_add_listener(client.cb, &callback_listener, NULL);
wl_display_flush(client.display);
- while (compositor.message < 3) {
+ while (compositor.actual_msg_count < compositor.expected_msg_count) {
+ wl_event_loop_dispatch(compositor.loop, -1);
+ wl_display_flush_clients(compositor.display);
+ }
+
+ wl_display_prepare_read(client.display);
+ wl_display_read_events(client.display);
+
+ // To get a WL_CLIENT_MESSAGE_DISCARD_DEAD_PROXY_ON_DISPATCH, we
+ // destroy the callback after reading client events, but before
+ // dispatching them.
+ wl_callback_destroy(client.cb);
+
+ while (client.actual_msg_count < client.expected_msg_count) {
+ wl_display_dispatch(client.display);
+ }
+
+ logger_teardown(&compositor, &client);
+}
+
+TEST(client_discards_if_no_listener_on_dispatch)
+{
+ test_set_timeout(1);
+
+ struct expected_client_message client_messages[] = {
+ {
+ .type = WL_CLIENT_MESSAGE_REQUEST,
+ .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
+ .class = "wl_display",
+ .opcode = 0,
+ .message_name = "sync",
+ .args_count = 1,
+ },
+ {
+ .type = WL_CLIENT_MESSAGE_EVENT,
+ .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
+ .class = "wl_display",
+ .opcode = 1,
+ .message_name = "delete_id",
+ .args_count = 1,
+ },
+ {
+ .type = WL_CLIENT_MESSAGE_EVENT,
+ .discarded_reason =
+ WL_CLIENT_MESSAGE_DISCARD_NO_LISTENER_ON_DISPATCH,
+ .class = "wl_callback",
+ .opcode = 0,
+ .message_name = "done",
+ .args_count = 1,
+ },
+ };
+ struct compositor compositor = { 0 };
+ struct client client = { 0 };
+
+ logger_setup(&compositor, &client);
+
+ compositor.expected_msg_count = 3;
+
+ client.expected_msg = &client_messages[0];
+ client.expected_msg_count = ARRAY_LENGTH(client_messages);
+
+ client.cb = wl_display_sync(client.display);
+ wl_display_flush(client.display);
+
+ while (compositor.actual_msg_count < compositor.expected_msg_count) {
+ wl_event_loop_dispatch(compositor.loop, -1);
+ wl_display_flush_clients(compositor.display);
+ }
+
+ while (client.actual_msg_count < client.expected_msg_count) {
+ wl_display_dispatch(client.display);
+ }
+
+ wl_callback_destroy(client.cb);
+
+ logger_teardown(&compositor, &client);
+}
+
+TEST(client_discards_if_invalid_id_on_demarshal)
+{
+ test_set_timeout(1);
+
+ struct expected_client_message client_messages[] = {
+ {
+ .type = WL_CLIENT_MESSAGE_REQUEST,
+ .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
+ .class = "wl_display",
+ .opcode = 0,
+ .message_name = "sync",
+ .args_count = 1,
+ },
+ {
+ .type = WL_CLIENT_MESSAGE_EVENT,
+ .discarded_reason =
+ WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL,
+ .class = "[unknown]",
+ .opcode = 0,
+ .message_name = "[event 0, 0 fds, 12 bytes]",
+ .args_count = 0,
+ },
+ {
+ .type = WL_CLIENT_MESSAGE_EVENT,
+ .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
+ .class = "wl_display",
+ .opcode = 1,
+ .message_name = "delete_id",
+ .args_count = 1,
+ },
+ };
+ struct compositor compositor = { 0 };
+ struct client client = { 0 };
+
+ logger_setup(&compositor, &client);
+
+ compositor.expected_msg_count = 3;
+
+ client.expected_msg = &client_messages[0];
+ client.expected_msg_count = ARRAY_LENGTH(client_messages);
+
+ client.cb = wl_display_sync(client.display);
+ wl_display_flush(client.display);
+
+ while (compositor.actual_msg_count < compositor.expected_msg_count) {
+ wl_event_loop_dispatch(compositor.loop, -1);
+ wl_display_flush_clients(compositor.display);
+ }
+
+ // To get a WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL, we
+ // destroy the callback before reading and dispatching client events.
+ wl_callback_destroy(client.cb);
+
+ while (client.actual_msg_count < client.expected_msg_count) {
+ wl_display_dispatch(client.display);
+ }
+
+ logger_teardown(&compositor, &client);
+}
+
+static const struct wl_keyboard_interface keyboard_interface = { 0 };
+
+static void
+seat_get_pointer(struct wl_client *client, struct wl_resource *resource,
+ uint32_t id)
+{
+ assert(false && "Not expected to be called by client.");
+}
+
+static void
+seat_get_keyboard(struct wl_client *client, struct wl_resource *resource,
+ uint32_t id)
+{
+ struct wl_resource *keyboard_res;
+
+ keyboard_res =
+ wl_resource_create(client, &wl_keyboard_interface,
+ wl_resource_get_version(resource), id);
+ wl_resource_set_implementation(keyboard_res, &keyboard_interface, NULL,
+ NULL);
+
+ wl_keyboard_send_key(keyboard_res, 0, 0, 0, 0);
+}
+
+static void
+seat_get_touch(struct wl_client *client, struct wl_resource *resource,
+ uint32_t id)
+{
+ assert(false && "Not expected to be called by client.");
+}
+
+static void
+seat_release(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_seat_interface seat_interface = {
+ &seat_get_pointer,
+ &seat_get_keyboard,
+ &seat_get_touch,
+ &seat_release,
+};
+
+static void
+bind_seat(struct wl_client *client, void *data, uint32_t vers, uint32_t id)
+{
+ struct wl_resource *seat_res;
+
+ seat_res = wl_resource_create(client, &wl_seat_interface, vers, id);
+ wl_resource_set_implementation(seat_res, &seat_interface, NULL, NULL);
+}
+
+static void
+registry_seat_listener_handle_global(void *data, struct wl_registry *registry,
+ uint32_t id, const char *intf,
+ uint32_t ver)
+{
+ uint32_t *seat_id_ptr = data;
+
+ if (strcmp(intf, wl_seat_interface.name) == 0) {
+ *seat_id_ptr = id;
+ }
+}
+
+static const struct wl_registry_listener registry_seat_listener = {
+ registry_seat_listener_handle_global, NULL
+};
+
+TEST(client_discards_if_zombie_on_demarshal)
+{
+ test_set_timeout(1);
+
+ struct expected_client_message client_messages[] = {
+ {
+ .type = WL_CLIENT_MESSAGE_REQUEST,
+ .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
+ .class = "wl_display",
+ .opcode = 1,
+ .message_name = "get_registry",
+ .args_count = 1,
+ },
+ {
+ .type = WL_CLIENT_MESSAGE_EVENT,
+ .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
+ .class = "wl_registry",
+ .opcode = 0,
+ .message_name = "global",
+ .args_count = 3,
+ },
+ {
+ .type = WL_CLIENT_MESSAGE_REQUEST,
+ .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
+ .class = "wl_registry",
+ .opcode = 0,
+ .message_name = "bind",
+ .args_count = 4,
+ },
+ {
+ .type = WL_CLIENT_MESSAGE_REQUEST,
+ .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
+ .class = "wl_seat",
+ .opcode = 1,
+ .message_name = "get_keyboard",
+ .args_count = 1,
+ },
+ {
+ .type = WL_CLIENT_MESSAGE_REQUEST,
+ .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
+ .class = "wl_keyboard",
+ .opcode = 0,
+ .message_name = "release",
+ .args_count = 0,
+ },
+ {
+ .type = WL_CLIENT_MESSAGE_REQUEST,
+ .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
+ .class = "wl_seat",
+ .opcode = 3,
+ .message_name = "release",
+ .args_count = 0,
+ },
+ {
+ .type = WL_CLIENT_MESSAGE_EVENT,
+ .discarded_reason =
+ WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL,
+ .class = "[zombie]",
+ .opcode = 3,
+ .message_name = "[event 3, 0 fds, 24 bytes]",
+ .args_count = 0,
+ },
+ };
+
+ struct compositor compositor = { 0 };
+ struct client client = { 0 };
+ struct wl_global *g_keyboard;
+ struct wl_registry *registry;
+ struct wl_seat *seat;
+ struct wl_keyboard *keyboard;
+ int32_t seat_id;
+
+ logger_setup(&compositor, &client);
+
+ client.expected_msg = &client_messages[0];
+ client.expected_msg_count = ARRAY_LENGTH(client_messages);
+
+ g_keyboard = wl_global_create(compositor.display, &wl_seat_interface,
+ 5, &compositor.display, bind_seat);
+
+ registry = wl_display_get_registry(client.display);
+ wl_registry_add_listener(registry, &registry_seat_listener, &seat_id);
+ wl_display_flush(client.display);
+
+ compositor.actual_msg_count = 0;
+ compositor.expected_msg_count = 2;
+
+ while (compositor.actual_msg_count < compositor.expected_msg_count) {
wl_event_loop_dispatch(compositor.loop, -1);
wl_display_flush_clients(compositor.display);
}
wl_display_dispatch(client.display);
- wl_display_disconnect(client.display);
- wl_protocol_logger_client_destroy(logger_client);
- wl_protocol_logger_client_destroy(logger_client_demo);
- wl_client_destroy(compositor.client);
- wl_protocol_logger_destroy(logger);
- wl_display_destroy(compositor.display);
+ seat = wl_registry_bind(registry, seat_id, &wl_seat_interface, 5);
+ keyboard = wl_seat_get_keyboard(seat);
+ wl_display_flush(client.display);
+
+ compositor.actual_msg_count = 0;
+ compositor.expected_msg_count = 3;
+
+ while (compositor.actual_msg_count < compositor.expected_msg_count) {
+ wl_event_loop_dispatch(compositor.loop, -1);
+ wl_display_flush_clients(compositor.display);
+ }
+
+ wl_keyboard_release(keyboard);
+ wl_seat_release(seat);
+
+ wl_display_dispatch(client.display);
+
+ wl_registry_destroy(registry);
+
+ wl_global_destroy(g_keyboard);
+
+ logger_teardown(&compositor, &client);
}
diff --git a/tests/queue-test.c b/tests/queue-test.c
index 86a3602..4129310 100644
--- a/tests/queue-test.c
+++ b/tests/queue-test.c
@@ -23,14 +23,18 @@
* SOFTWARE.
*/
+#define _GNU_SOURCE /* For memrchr */
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
+#include <string.h>
#include <unistd.h>
+#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>
+#include <signal.h>
#include "wayland-client.h"
#include "wayland-server.h"
@@ -303,6 +307,170 @@ client_test_queue_set_queue_race(void)
wl_display_disconnect(display);
}
+static char *
+maybe_map_file(int fd, size_t *len)
+{
+ char *data;
+
+ *len = lseek(fd, 0, SEEK_END);
+ data = mmap(0, *len, PROT_READ, MAP_PRIVATE, fd, 0);
+
+ return data;
+}
+
+static char *
+map_file(int fd, size_t *len)
+{
+ char *data;
+
+ data = maybe_map_file(fd, len);
+ assert(data != MAP_FAILED && "Failed to mmap file");
+
+ return data;
+}
+
+static char *
+last_line_of(char *s)
+{
+ size_t len = strlen(s);
+ char *last;
+
+ last = memrchr(s, '\n', len);
+ /* If we found a newline at end of string, find the previous one. */
+ if (last && last[1] == 0)
+ last = memrchr(s, '\n', len - 1);
+ /* If we have a newline, the last line starts after the newline.
+ * Otherwise, the whole string is the last line. */
+ if (last)
+ last += 1;
+ else
+ last = s;
+
+ return last;
+}
+
+static void
+client_test_queue_destroy_with_attached_proxies(void)
+{
+ struct wl_event_queue *queue;
+ struct wl_display *display;
+ struct wl_display *display_wrapper;
+ struct wl_callback *callback;
+ char *log;
+ size_t log_len;
+ char callback_name[24];
+ int ret;
+
+ display = wl_display_connect(NULL);
+ assert(display);
+
+ /* Pretend we are in a separate thread where a thread-local queue is
+ * used. */
+ queue = wl_display_create_queue(display);
+ assert(queue);
+
+ /* Create a sync dispatching events on the thread-local queue. */
+ display_wrapper = wl_proxy_create_wrapper(display);
+ assert(display_wrapper);
+ wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue);
+ callback = wl_display_sync(display_wrapper);
+ wl_proxy_wrapper_destroy(display_wrapper);
+ assert(callback != NULL);
+
+ /* Destroy the queue before the attached object. */
+ wl_event_queue_destroy(queue);
+
+ /* Check that the log contains some information about the attached
+ * wl_callback proxy. */
+ log = map_file(client_log_fd, &log_len);
+ ret = snprintf(callback_name, sizeof(callback_name), "wl_callback@%u",
+ wl_proxy_get_id((struct wl_proxy *) callback));
+ assert(ret > 0 && ret < (int)sizeof(callback_name) &&
+ "callback name creation failed (possibly truncated)");
+ assert(strstr(last_line_of(log), callback_name));
+ munmap(log, log_len);
+
+ wl_callback_destroy(callback);
+
+ wl_display_disconnect(display);
+}
+
+static void
+client_test_queue_proxy_event_to_destroyed_queue(void)
+{
+ struct wl_event_queue *queue;
+ struct wl_display *display;
+ struct wl_display *display_wrapper;
+ struct wl_callback *callback;
+
+ display = wl_display_connect(NULL);
+ assert(display);
+
+ /* Pretend we are in a separate thread where a thread-local queue is
+ * used. */
+ queue = wl_display_create_queue(display);
+ assert(queue);
+
+ /* Create a sync dispatching events on the thread-local queue. */
+ display_wrapper = wl_proxy_create_wrapper(display);
+ assert(display_wrapper);
+ wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue);
+ callback = wl_display_sync(display_wrapper);
+ wl_proxy_wrapper_destroy(display_wrapper);
+ assert(callback != NULL);
+ wl_display_flush(display);
+
+ /* Destroy the queue before the attached object. */
+ wl_event_queue_destroy(queue);
+
+ /* During this roundtrip we should receive the done event on 'callback',
+ * try to queue it to the destroyed queue, and abort. */
+ wl_display_roundtrip(display);
+
+ wl_callback_destroy(callback);
+
+ wl_display_disconnect(display);
+}
+
+static void
+client_test_queue_destroy_default_with_attached_proxies(void)
+{
+ struct wl_display *display;
+ struct wl_callback *callback;
+ char *log;
+ size_t log_len;
+ char callback_name[24];
+ int ret;
+
+ display = wl_display_connect(NULL);
+ assert(display);
+
+ /* Create a sync dispatching events on the default queue. */
+ callback = wl_display_sync(display);
+ assert(callback != NULL);
+
+ /* Destroy the default queue (by disconnecting) before the attached
+ * object. */
+ wl_display_disconnect(display);
+
+ /* Check that the log does not contain any warning about the attached
+ * wl_callback proxy. */
+ log = maybe_map_file(client_log_fd, &log_len);
+ ret = snprintf(callback_name, sizeof(callback_name), "wl_callback@%u",
+ wl_proxy_get_id((struct wl_proxy *) callback));
+ assert(ret > 0 && ret < (int)sizeof(callback_name) &&
+ "callback name creation failed (possibly truncated)");
+ assert(log == MAP_FAILED || strstr(log, callback_name) == NULL);
+ if (log != MAP_FAILED)
+ munmap(log, log_len);
+
+ /* HACK: Directly free the memory of the wl_callback proxy to appease
+ * ASan. We would normally use wl_callback_destroy(), but since we have
+ * destroyed the associated wl_display, using this function would lead
+ * to memory errors. */
+ free(callback);
+}
+
static void
dummy_bind(struct wl_client *client,
void *data, uint32_t version, uint32_t id)
@@ -382,3 +550,50 @@ TEST(queue_set_queue_race)
display_destroy(d);
}
+
+TEST(queue_destroy_with_attached_proxies)
+{
+ struct display *d = display_create();
+
+ test_set_timeout(2);
+
+ client_create_noarg(d, client_test_queue_destroy_with_attached_proxies);
+ display_run(d);
+
+ display_destroy(d);
+}
+
+TEST(queue_proxy_event_to_destroyed_queue)
+{
+ struct display *d = display_create();
+ struct client_info *ci;
+ char *client_log;
+ size_t client_log_len;
+
+ test_set_timeout(2);
+
+ ci = client_create_noarg(d, client_test_queue_proxy_event_to_destroyed_queue);
+ display_run(d);
+
+ /* Check that the final line in the log mentions the expected reason
+ * for the abort. */
+ client_log = map_file(ci->log_fd, &client_log_len);
+ assert(!strcmp(last_line_of(client_log),
+ "Tried to add event to destroyed queue\n"));
+ munmap(client_log, client_log_len);
+
+ /* Check that the client aborted. */
+ display_destroy_expect_signal(d, SIGABRT);
+}
+
+TEST(queue_destroy_default_with_attached_proxies)
+{
+ struct display *d = display_create();
+
+ test_set_timeout(2);
+
+ client_create_noarg(d, client_test_queue_destroy_default_with_attached_proxies);
+ display_run(d);
+
+ display_destroy(d);
+}
diff --git a/tests/sanity-test.c b/tests/sanity-test.c
index 98beca8..e614cfb 100644
--- a/tests/sanity-test.c
+++ b/tests/sanity-test.c
@@ -25,7 +25,9 @@
#include <stdlib.h>
#include <assert.h>
+#include <string.h>
#include <sys/types.h>
+#include <sys/mman.h>
#include <signal.h>
#include <unistd.h>
@@ -174,13 +176,72 @@ FAIL_TEST(tc_client_fd_leaks_exec)
{
struct display *d = display_create();
- client_create_noarg(d, sanity_fd_leak);
+ client_create_noarg(d, sanity_fd_leak_exec);
display_run(d);
test_disable_coredumps();
display_destroy(d);
}
+static char *
+map_file(int fd, size_t *len)
+{
+ char *data;
+
+ *len = lseek(fd, 0, SEEK_END);
+ data = mmap(0, *len, PROT_READ, MAP_PRIVATE, fd, 0);
+ assert(data != MAP_FAILED && "Failed to mmap file");
+
+ return data;
+}
+
+static void
+sanity_client_log(void)
+{
+ char *log;
+ size_t log_len;
+ char *wayland_socket = strdup(getenv("WAYLAND_SOCKET"));
+ char *xdg_runtime_dir = strdup(getenv("XDG_RUNTIME_DIR"));
+
+ unsetenv("WAYLAND_SOCKET");
+ unsetenv("XDG_RUNTIME_DIR");
+
+ /* Try to connect to the default wayland display, which should fail since
+ * we have neither WAYLAND_SOCKET nor XDG_RUNTIME_DIR. */
+ assert(!wl_display_connect(NULL));
+
+ /* Check that the client log contains some mention of XDG_RUNTIME_DIR. */
+ log = map_file(client_log_fd, &log_len);
+ assert(strstr(log, "XDG_RUNTIME_DIR"));
+ munmap(log, log_len);
+
+ /* Reset the environment variables we unset for the test. The test harness
+ * leak checker cares about the value of WAYLAND_SOCKET during teardown for
+ * correct fd accounting. */
+ setenv("XDG_RUNTIME_DIR", xdg_runtime_dir, 0);
+ setenv("WAYLAND_SOCKET", wayland_socket, 0);
+ free(xdg_runtime_dir);
+ free(wayland_socket);
+}
+
+TEST(tc_client_log)
+{
+ struct display *d = display_create();
+ struct client_info *ci;
+ char *log;
+ size_t log_len;
+
+ ci = client_create_noarg(d, sanity_client_log);
+ display_run(d);
+
+ /* Check that the client log contains some mention of XDG_RUNTIME_DIR. */
+ log = map_file(ci->log_fd, &log_len);
+ assert(strstr(log, "XDG_RUNTIME_DIR"));
+ munmap(log, log_len);
+
+ display_destroy(d);
+}
+
FAIL_TEST(timeout_tst)
{
test_set_timeout(1);
diff --git a/tests/signal-test.c b/tests/signal-test.c
index 7bbaa9f..f7e1bd6 100644
--- a/tests/signal-test.c
+++ b/tests/signal-test.c
@@ -115,3 +115,44 @@ TEST(signal_emit_to_more_listeners)
assert(3 * counter == count);
}
+
+struct signal_emit_mutable_data {
+ int count;
+ struct wl_listener *remove_listener;
+};
+
+static void
+signal_notify_mutable(struct wl_listener *listener, void *data)
+{
+ struct signal_emit_mutable_data *test_data = data;
+ test_data->count++;
+}
+
+static void
+signal_notify_and_remove_mutable(struct wl_listener *listener, void *data)
+{
+ struct signal_emit_mutable_data *test_data = data;
+ signal_notify_mutable(listener, test_data);
+ wl_list_remove(&test_data->remove_listener->link);
+}
+
+TEST(signal_emit_mutable)
+{
+ struct signal_emit_mutable_data data = {0};
+
+ /* l2 will remove l3 before l3 is notified */
+ struct wl_signal signal;
+ struct wl_listener l1 = {.notify = signal_notify_mutable};
+ struct wl_listener l2 = {.notify = signal_notify_and_remove_mutable};
+ struct wl_listener l3 = {.notify = signal_notify_mutable};
+
+ wl_signal_init(&signal);
+ wl_signal_add(&signal, &l1);
+ wl_signal_add(&signal, &l2);
+ wl_signal_add(&signal, &l3);
+
+ data.remove_listener = &l3;
+ wl_signal_emit_mutable(&signal, &data);
+
+ assert(data.count == 2);
+}
diff --git a/tests/socket-test.c b/tests/socket-test.c
index 8d39edc..78743dc 100644
--- a/tests/socket-test.c
+++ b/tests/socket-test.c
@@ -51,7 +51,7 @@ static const char *
require_xdg_runtime_dir(void)
{
char *val = getenv("XDG_RUNTIME_DIR");
- assert(val && "set $XDG_RUNTIME_DIR to run this test");
+ assert(val && val[0] == '/' && "set $XDG_RUNTIME_DIR to run this test");
return val;
}
diff --git a/tests/test-compositor.c b/tests/test-compositor.c
index 468ee56..49d76d6 100644
--- a/tests/test-compositor.c
+++ b/tests/test-compositor.c
@@ -40,6 +40,8 @@
#include "test-runner.h"
#include "test-compositor.h"
+int client_log_fd = -1;
+
/* --- Protocol --- */
struct test_compositor;
@@ -112,7 +114,7 @@ handle_client_destroy(void *data)
case CLD_DUMPED:
fprintf(stderr, "Client '%s' was killed by signal %d\n",
ci->name, status.si_status);
- ci->exit_code = status.si_status;
+ ci->kill_code = status.si_status;
break;
case CLD_EXITED:
if (status.si_status != EXIT_SUCCESS)
@@ -156,8 +158,20 @@ client_destroyed(struct wl_listener *listener, void *data)
}
static void
+client_log_handler(const char *fmt, va_list arg)
+{
+ va_list arg_copy;
+
+ va_copy(arg_copy, arg);
+ vdprintf(client_log_fd, fmt, arg_copy);
+ va_end(arg_copy);
+
+ vfprintf(stderr, fmt, arg);
+}
+
+static void
run_client(void (*client_main)(void *data), void *data,
- int wayland_sock, int client_pipe)
+ int wayland_sock, int client_pipe, int log_fd)
{
char s[8];
int cur_fds;
@@ -173,6 +187,10 @@ run_client(void (*client_main)(void *data), void *data,
snprintf(s, sizeof s, "%d", wayland_sock);
setenv("WAYLAND_SOCKET", s, 0);
+ /* Capture the log to the specified file descriptor. */
+ client_log_fd = log_fd;
+ wl_log_set_handler_client(client_log_handler);
+
cur_fds = count_open_fds();
client_main(data);
@@ -188,6 +206,18 @@ run_client(void (*client_main)(void *data), void *data,
check_fd_leaks(cur_fds);
}
+static int
+create_log_fd(void)
+{
+ char logname[] = "/tmp/wayland-tests-log-XXXXXX";
+ int log_fd = mkstemp(logname);
+
+ if (log_fd >= 0)
+ unlink(logname);
+
+ return log_fd;
+}
+
static struct client_info *
display_create_client(struct display *d,
void (*client_main)(void *data),
@@ -199,11 +229,15 @@ display_create_client(struct display *d,
pid_t pid;
int can_continue = 0;
struct client_info *cl;
+ int log_fd;
assert(pipe(pipe_cli) == 0 && "Failed creating pipe");
assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_wayl) == 0
&& "Failed creating socket pair");
+ log_fd = create_log_fd();
+ assert(log_fd >= 0 && "Failed to create log fd");
+
pid = fork();
assert(pid != -1 && "Fork failed");
@@ -211,10 +245,11 @@ display_create_client(struct display *d,
close(sock_wayl[1]);
close(pipe_cli[1]);
- run_client(client_main, data, sock_wayl[0], pipe_cli[0]);
+ run_client(client_main, data, sock_wayl[0], pipe_cli[0], log_fd);
close(sock_wayl[0]);
close(pipe_cli[0]);
+ close(log_fd);
exit(0);
}
@@ -231,6 +266,7 @@ display_create_client(struct display *d,
cl->name = name;
cl->pid = pid;
cl->pipe = pipe_cli[1];
+ cl->log_fd = log_fd;
cl->destroy_listener.notify = &client_destroyed;
cl->wl_client = wl_client_create(d->wl_display, sock_wayl[1]);
@@ -329,7 +365,6 @@ struct display *
display_create(void)
{
struct display *d = NULL;
- struct wl_global *g;
const char *socket_name;
int stat = 0;
@@ -350,9 +385,10 @@ display_create(void)
wl_list_init(&d->waiting_for_resume);
d->wfr_num = 0;
- g = wl_global_create(d->wl_display, &test_compositor_interface,
- 1, d, tc_bind);
- assert(g && "Creating test global failed");
+ d->test_global = wl_global_create(d->wl_display,
+ &test_compositor_interface,
+ 1, d, tc_bind);
+ assert(d->test_global && "Creating test global failed");
return d;
}
@@ -389,8 +425,10 @@ display_resume(struct display *d)
wl_display_run(d->wl_display);
}
+/* If signum is 0, expect a successful client exit, otherwise
+ * expect the client to have been killed by that signal. */
void
-display_destroy(struct display *d)
+display_destroy_expect_signal(struct display *d, int signum)
{
struct client_info *cl, *next;
int failed = 0;
@@ -401,15 +439,25 @@ display_destroy(struct display *d)
wl_list_for_each_safe(cl, next, &d->clients, link) {
assert(cl->wl_client == NULL);
- if (cl->exit_code != 0) {
+ if (signum != 0 && cl->kill_code != signum) {
+ ++failed;
+ fprintf(stderr,
+ "Client '%s' failed, expecting signal %d, "
+ "got %d\n",
+ cl->name, signum, cl->kill_code);
+ }
+ else if (signum == 0 &&
+ (cl->kill_code != 0 || cl->exit_code != 0)) {
++failed;
fprintf(stderr, "Client '%s' failed\n", cl->name);
}
close(cl->pipe);
+ close(cl->log_fd);
free(cl);
}
+ wl_global_destroy(d->test_global);
wl_display_destroy(d->wl_display);
free(d);
@@ -419,6 +467,12 @@ display_destroy(struct display *d)
}
}
+void
+display_destroy(struct display *d)
+{
+ display_destroy_expect_signal(d, 0);
+}
+
/*
* --- Client helper functions ---
*/
diff --git a/tests/test-compositor.h b/tests/test-compositor.h
index 180dad2..3fb390c 100644
--- a/tests/test-compositor.h
+++ b/tests/test-compositor.h
@@ -25,6 +25,7 @@
#include <stdint.h>
#include <unistd.h>
+#include <stdatomic.h>
#include "wayland-server.h"
#include "wayland-client.h"
@@ -39,13 +40,16 @@ struct client_info {
int pipe;
pid_t pid;
int exit_code;
+ int kill_code;
struct wl_list link;
void *data; /* for arbitrary use */
+ int log_fd;
};
struct display {
struct wl_display *wl_display;
+ struct wl_global *test_global;
struct wl_list clients;
uint32_t clients_no;
@@ -64,7 +68,7 @@ struct client {
struct wl_display *wl_display;
struct test_compositor *tc;
- int display_stopped;
+ atomic_bool display_stopped;
};
struct client *client_connect(void);
@@ -88,6 +92,7 @@ void noop_request(struct client *);
*/
struct display *display_create(void);
void display_destroy(struct display *d);
+void display_destroy_expect_signal(struct display *d, int signum);
void display_run(struct display *d);
/* This function posts the display_resumed event to all waiting clients,
@@ -104,6 +109,9 @@ void display_post_resume_events(struct display *d);
* it then reruns the display. */
void display_resume(struct display *d);
+/* The file descriptor containing the client log. This is only valid in the
+ * test client processes. */
+extern int client_log_fd;
struct client_info *client_create_with_name(struct display *d,
void (*client_main)(void *data),
diff --git a/tests/test-helpers.c b/tests/test-helpers.c
index 20b6690..3535744 100644
--- a/tests/test-helpers.c
+++ b/tests/test-helpers.c
@@ -41,6 +41,27 @@
#include "test-runner.h"
+#if defined(__FreeBSD__)
+#include <sys/sysctl.h>
+
+/*
+ * On FreeBSD, get file descriptor information using sysctl() since that does
+ * not depend on a mounted fdescfs (which provides /dev/fd/N for N > 2).
+ */
+int
+count_open_fds(void)
+{
+ int error;
+ int nfds;
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_NFDS, 0 };
+ size_t len;
+
+ len = sizeof(nfds);
+ error = sysctl(mib, 4, &nfds, &len, NULL, 0);
+ assert(error == 0 && "sysctl KERN_PROC_NFDS failed.");
+ return nfds;
+}
+#else
int
count_open_fds(void)
{
@@ -48,8 +69,12 @@ count_open_fds(void)
struct dirent *ent;
int count = 0;
- dir = opendir("/proc/self/fd");
- assert(dir && "opening /proc/self/fd failed.");
+ /*
+ * Using /dev/fd instead of /proc/self/fd should allow this code to
+ * work on non-Linux operating systems.
+ */
+ dir = opendir("/dev/fd");
+ assert(dir && "opening /dev/fd failed.");
errno = 0;
while ((ent = readdir(dir))) {
@@ -58,12 +83,13 @@ count_open_fds(void)
continue;
count++;
}
- assert(errno == 0 && "reading /proc/self/fd failed.");
+ assert(errno == 0 && "reading /dev/fd failed.");
closedir(dir);
return count;
}
+#endif
void
exec_fd_leak_check(int nr_expected_fds)
diff --git a/tests/test-runner.c b/tests/test-runner.c
index 8f08445..d07dab1 100644
--- a/tests/test-runner.c
+++ b/tests/test-runner.c
@@ -22,6 +22,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#include "../config.h"
#define _GNU_SOURCE
@@ -36,11 +37,16 @@
#include <dlfcn.h>
#include <errno.h>
#include <limits.h>
+#include <signal.h>
#include <sys/ptrace.h>
+#ifdef HAVE_SYS_PROCCTL_H
+#include <sys/procctl.h>
+#elif defined(HAVE_SYS_PRCTL_H)
#include <sys/prctl.h>
#ifndef PR_SET_PTRACER
# define PR_SET_PTRACER 0x59616d61
#endif
+#endif
#include "test-runner.h"
@@ -174,7 +180,7 @@ set_xdg_runtime_dir(void)
xrd_env = getenv("XDG_RUNTIME_DIR");
/* if XDG_RUNTIME_DIR is not set in environ, fallback to /tmp */
assert((snprintf(xdg_runtime_dir, PATH_MAX, "%s/wayland-tests-XXXXXX",
- xrd_env ? xrd_env : "/tmp") < PATH_MAX)
+ (xrd_env && xrd_env[0] == '/') ? xrd_env : "/tmp") < PATH_MAX)
&& "test error: XDG_RUNTIME_DIR too long");
assert(mkdtemp(xdg_runtime_dir) && "test error: mkdtemp failed");
@@ -194,7 +200,7 @@ static void
rmdir_xdg_runtime_dir(void)
{
const char *xrd_env = getenv("XDG_RUNTIME_DIR");
- assert(xrd_env && "No XDG_RUNTIME_DIR set");
+ assert(xrd_env && xrd_env[0] == '/' && "No XDG_RUNTIME_DIR set");
/* rmdir may fail if some test didn't do clean up */
if (rmdir(xrd_env) == -1)
@@ -226,6 +232,21 @@ stderr_reset_color(void)
* Returns: 1 if a debugger is confirmed present; 0 if no debugger is
* present or if it can't be determined.
*/
+#if defined(HAVE_SYS_PROCCTL_H) && defined(PROC_TRACE_STATUS)
+static int
+is_debugger_attached(void)
+{
+ int rc;
+ int status;
+ rc = procctl(P_PID, getpid(), PROC_TRACE_STATUS, &status);
+ if (rc == -1) {
+ perror("procctl");
+ return 0;
+ }
+ /* -1=tracing disabled, 0=no debugger attached, >0=pid of debugger. */
+ return status > 0;
+}
+#elif defined(HAVE_SYS_PRCTL_H)
static int
is_debugger_attached(void)
{
@@ -287,6 +308,7 @@ is_debugger_attached(void)
return rc;
}
+#endif
int main(int argc, char *argv[])
{