Compare commits

..

No commits in common. "main" and "5.0.92" have entirely different histories.
main ... 5.0.92

725 changed files with 64266 additions and 152435 deletions

102
.gitignore vendored
View file

@ -1,13 +1,113 @@
*.announce
*.deps
*.jpg
*.la
*.lo
*.log
*.o
*.pc
*.sig
*.so
*.swp *.swp
.*.sw? .*.sw?
.sw? .sw?
*.sublime-project *.sublime-project
*.sublime-workspace *.sublime-workspace
*.tar.xz
*.trs
*~ *~
ctags ctags
cscope.out cscope.out
.libs
.dirstamp
/aclocal.m4
/autom4te.cache
/build-aux/
/config.guess
/config.h
/config.h.in
/config.log
/config.mk
/config.status
/config.sub
/configure
/depcomp
/doc/doxygen/*.doxygen
/docs/developer
/docs/tools
/install-sh
/libtool
/ltmain.sh
/logs
/missing
/stamp-h1
/test-driver
/weston.ini
Makefile
Makefile.in
TAGS TAGS
protocol/.*.valid
protocol/*.[ch]
00*.patch 00*.patch
build/ weston-calibrator
weston-clickdot
weston-cliptest
weston-confine
weston-dnd
weston-editor
weston-eventdemo
weston-flower
weston-fullscreen
weston-gears
weston-image
weston-nested
weston-nested-client
weston-presentation-shm
weston-resizor
weston-scaler
weston-simple-dmabuf-drm
weston-simple-dmabuf-v4l
weston-simple-egl
weston-simple-shm
weston-simple-touch
weston-simple-damage
weston-smoke
weston-stacking
weston-subsurfaces
weston-touch-calibrator
weston-transformed
weston-view
weston-keyboard
libtoytoolkit.a
weston-desktop-shell
weston-ivi-shell-user-interface
weston-info
weston-screenshooter
weston-tablet-shell
weston-terminal
weston-multi-resource
weston-simple-im
weston
weston-launch
spring-tool
*.weston
*.test
*.ivi
wcap-decode
matrix-test
setbacklight
weston.1
weston-drm.7
weston.ini.5
/libweston/git-version.h
/libweston/version.h
/tests/weston-ivi.ini
internal-screenshot-00.png
/zuctest

View file

@ -1,656 +1,84 @@
# vim: set expandtab shiftwidth=2 tabstop=8 textwidth=0: image: debian:stretch
.templates_sha: &template_sha 32afe5644697e503af18a736587c8619fa036a72 # see https://docs.gitlab.com/ee/ci/yaml/#includefile
# This file uses the freedesktop ci-templates to build Weston 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/
variables:
FDO_UPSTREAM_REPO: wayland/weston
FDO_REPO_SUFFIX: "$BUILD_OS-$FDO_DISTRIBUTION_VERSION/$BUILD_ARCH"
FDO_DISTRIBUTION_TAG: '2026-04-01-mesa-26.0.4'
include:
# 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.
- project: 'freedesktop/ci-templates'
ref: *template_sha
file: '/templates/debian.yml'
- project: 'freedesktop/ci-templates'
ref: *template_sha
file: '/templates/ci-fairy.yml'
.default-rules:
rules:
# do not duplicate pipelines on merge pipelines
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
when: never
# we need a default case though, so all the rest still run
- when: on_success
default:
retry:
max: 2
when: runner_system_failure
.merge-rules:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: always
- when: never
# Define the build stages. These are used for UI grouping as well as
# dependencies.
stages: stages:
- "Merge request checks" - build
- "Pre Base container"
- "Base container"
- "Full build and test"
- "No-GL/Vulkan build and test"
- "Other builds"
- pages
before_script:
- echo 'path-exclude=/usr/share/doc/*' > /etc/dpkg/dpkg.cfg.d/99-exclude-cruft
- echo 'path-exclude=/usr/share/man/*' >> /etc/dpkg/dpkg.cfg.d/99-exclude-cruft
- echo '#!/bin/sh' > /usr/sbin/policy-rc.d
- echo 'exit 101' >> /usr/sbin/policy-rc.d
- chmod +x /usr/sbin/policy-rc.d
- echo 'deb http://deb.debian.org/debian stretch-backports main' >> /etc/apt/sources.list
- apt-get update
- apt-get -y --no-install-recommends install build-essential automake autoconf libtool pkg-config libexpat1-dev libffi-dev libxml2-dev libpixman-1-dev libpng-dev libjpeg-dev libcolord-dev mesa-common-dev libglu1-mesa-dev libegl1-mesa-dev libgles2-mesa-dev libwayland-dev libxcb1-dev libxcb-composite0-dev libxcb-xfixes0-dev libxcb-xkb-dev libx11-xcb-dev libx11-dev libudev-dev libgbm-dev libxkbcommon-dev libcairo2-dev libpango1.0-dev libgdk-pixbuf2.0-dev libxcursor-dev libmtdev-dev libpam0g-dev libvpx-dev libsystemd-dev libevdev-dev libinput-dev libwebp-dev libjpeg-dev libva-dev liblcms2-dev git libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev freerdp2-dev curl python3-pip python3-setuptools ninja-build
- pip3 install --user git+https://github.com/mesonbuild/meson.git@0.49
- mkdir -p /tmp/.X11-unix
- chmod 777 /tmp/.X11-unix
# Base variables used for anything using a Debian environment build-native-autotools:
.os-debian-lts: stage: build
variables:
BUILD_OS: debian
LLVM_VERSION: 15
USE_DEBIAN_BACKPORTS: y
PACKAGES_SPECIFIC: vulkan-validationlayers-dev
FREERDP_VERSION: 2
FDO_DISTRIBUTION_VERSION: bookworm
FDO_DISTRIBUTION_EXEC: 'env FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} BUILD_ARCH=${BUILD_ARCH} KERNEL_IMAGE=${KERNEL_IMAGE} KERNEL_DEFCONFIG=${KERNEL_DEFCONFIG} LLVM_VERSION=${LLVM_VERSION} FDO_DISTRIBUTION_VERSION=${FDO_DISTRIBUTION_VERSION} PACKAGES_SPECIFIC="${PACKAGES_SPECIFIC}" bash .gitlab-ci/debian-install.sh'
.os-debian:
variables:
BUILD_OS: debian
LLVM_VERSION: 19
FREERDP_VERSION: 3
USE_DEBIAN_BACKPORTS: y
PACKAGES_SPECIFIC: vulkan-utility-libraries-dev libpolly-19-dev libclang-rt-19-dev python3-standard-imghdr
# If you upgrade from trixie, see the use_tls=0 notes in tests/meson.build.
FDO_DISTRIBUTION_VERSION: trixie
FDO_DISTRIBUTION_EXEC: 'env FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} BUILD_ARCH=${BUILD_ARCH} KERNEL_IMAGE=${KERNEL_IMAGE} KERNEL_DEFCONFIG=${KERNEL_DEFCONFIG} LLVM_VERSION=${LLVM_VERSION} FDO_DISTRIBUTION_VERSION=${FDO_DISTRIBUTION_VERSION} PACKAGES_SPECIFIC="${PACKAGES_SPECIFIC}" bash .gitlab-ci/debian-install.sh'
# Does not inherit .default-rules as we only want it to run in MR context.
check-commit:
extends:
- .fdo.ci-fairy
- .merge-rules
stage: "Merge request checks"
script: script:
- ci-fairy check-commits --signed-off-by --junit-xml=results.xml - git clone --depth=1 git://anongit.freedesktop.org/git/wayland/wayland-protocols
variables: - export WAYLAND_PROTOCOLS_DIR="$(pwd)/prefix-wayland-protocols"
GIT_DEPTH: 100 - export PKG_CONFIG_PATH="$WAYLAND_PROTOCOLS_DIR/share/pkgconfig:$PKG_CONFIG_PATH"
artifacts: - export MAKEFLAGS="-j4"
reports: - cd wayland-protocols
junit: results.xml - git show -s HEAD
- mkdir build
.debian-lts-x86_64: - cd build
extends: - ../autogen.sh --prefix="$WAYLAND_PROTOCOLS_DIR"
- .os-debian-lts - make install
variables: - cd ../../
BUILD_ARCH: "x86-64"
KERNEL_IMAGE: "bzImage"
KERNEL_DEFCONFIG: "x86_64_defconfig"
.debian-x86_64:
extends:
- .os-debian
variables:
BUILD_ARCH: "x86-64"
KERNEL_IMAGE: "bzImage"
KERNEL_DEFCONFIG: "x86_64_defconfig"
.debian-lts-armv7:
extends:
- .os-debian-lts
variables:
BUILD_ARCH: "armv7"
FDO_DISTRIBUTION_PLATFORM: "linux/arm/v7"
.debian-armv7:
extends:
- .os-debian
variables:
BUILD_ARCH: "armv7"
FDO_DISTRIBUTION_PLATFORM: "linux/arm/v7"
# Armv7 doesn't have freerdp3 in bookworm-backports so we don't build FreeRDP
MESON_DIST_OPTIONS: "-Dbackend-rdp=false"
# Inhibit installation of freerdp-dev
FREERDP_VERSION: 0
.debian-lts-aarch64:
extends:
- .os-debian-lts
variables:
BUILD_ARCH: "aarch64"
KERNEL_IMAGE: "Image"
KERNEL_DEFCONFIG: "defconfig"
QEMU_SMP: 8 # built-in QEmu limit
.debian-aarch64:
extends:
- .os-debian
variables:
BUILD_ARCH: "aarch64"
KERNEL_IMAGE: "Image"
KERNEL_DEFCONFIG: "defconfig"
QEMU_SMP: 8 # built-in QEmu limit
base-container-pre:
rules:
# this run always in merge request
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: always
# run always on main to allow docs to publish
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_PATH == "wayland/weston" && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
when: always
# allow to run manually in a branch
- when: manual
stage: "Pre Base container"
script: echo "exit 0"
# 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-lts-container_prep:
extends:
- .default-rules
- .debian-lts-x86_64
- .fdo.container-build@debian
timeout: 30m
needs:
- job: base-container-pre
stage: "Base container"
x86_64-debian-container_prep:
extends:
- .default-rules
- .debian-x86_64
- .fdo.container-build@debian
needs:
- job: base-container-pre
timeout: 30m
stage: "Base container"
armv7-debian-lts-container_prep:
extends:
- .default-rules
- .debian-lts-armv7
- .fdo.container-build@debian
tags:
- aarch64
needs:
- job: base-container-pre
timeout: 30m
stage: "Base container"
armv7-debian-container_prep:
extends:
- .default-rules
- .debian-armv7
- .fdo.container-build@debian
tags:
- aarch64
needs:
- job: base-container-pre
timeout: 30m
stage: "Base container"
aarch64-debian-lts-container_prep:
extends:
- .default-rules
- .debian-lts-aarch64
- .fdo.container-build@debian
tags:
- aarch64
needs:
- job: base-container-pre
timeout: 30m
stage: "Base container"
aarch64-debian-container_prep:
extends:
- .default-rules
- .debian-aarch64
- .fdo.container-build@debian
tags:
- aarch64
needs:
- job: base-container-pre
timeout: 30m
stage: "Base container"
# Core templates for all of our build steps. These are reused by all build jobs
# through the `extends` keyword.
.build-env:
timeout: 15m
variables:
BUILDDIR: $CI_PROJECT_DIR/build-weston-$CI_JOB_NAME
BUILDDIR_WESTINY: $CI_PROJECT_DIR/build-westiny-$CI_JOB_NAME
PREFIX: $CI_PROJECT_DIR/prefix-weston-$CI_JOB_NAME
PREFIX_WESTINY: $CI_PROJECT_DIR/prefix-westiny-$CI_JOB_NAME
before_script:
- export PATH=~/.local/bin:$PATH
- export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)" - export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
- export TESTS_RES_PATH="$BUILDDIR/tests-res.txt" - export BUILD_ID="weston-$CI_JOB_NAME_$CI_COMMIT_SHA-$CI_JOB_ID"
- export VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation - export PREFIX="$(pwd)/prefix-$BUILD_ID"
- export BUILDDIR="$(pwd)/build-$BUILD_ID"
- mkdir "$BUILDDIR" "$PREFIX" - mkdir "$BUILDDIR" "$PREFIX"
- mkdir "$BUILDDIR_WESTINY" "$PREFIX_WESTINY" - cd "$BUILDDIR"
- ../autogen.sh --prefix="$PREFIX" --disable-setuid-install --enable-xwayland --enable-x11-compositor --enable-drm-compositor --enable-wayland-compositor --enable-headless-compositor --enable-fbdev-compositor --enable-rdp-compositor --enable-screen-sharing --enable-vaapi-recorder --enable-simple-clients --enable-simple-egl-clients --enable-simple-dmabuf-drm-client --enable-simple-dmabuf-v4l-client --enable-clients --enable-resize-optimization --enable-weston-launch --enable-fullscreen-shell --enable-colord --enable-dbus --enable-systemd-login --enable-junit-xml --enable-ivi-shell --enable-wcap-tools --disable-libunwind --enable-demo-clients-install --enable-lcms --with-cairo=image --enable-remoting --enable-autotools
.build-with-clang: - make all
variables: - make check
CC: clang-$LLVM_VERSION - make install
CC_LD: lld-$LLVM_VERSION - make distcheck
CXX: clang++-$LLVM_VERSION
CXX_LD: lld-$LLVM_VERSION
MESON_TOOLCHAIN_OPTIONS: "$MESON_OPTIONS -Db_lundef=false" # clang+ASan+undef=boom
# Extends the core build templates to also provide for running our testing. We
# run this inside a virtme (qemu wrapper) VM environment so we can test the DRM
# backend using the 'vkms' virtual driver under Linux.
.build-and-test:
extends:
- .default-rules
variables:
SANITIZE: "-Db_sanitize=address"
script:
- "${CI_PROJECT_DIR}/.gitlab-ci/build.sh"
- "${CI_PROJECT_DIR}/.gitlab-ci/test.sh"
artifacts: artifacts:
name: weston-$CI_COMMIT_SHA name: weston-$CI_COMMIT_SHA-$CI_JOB_ID
when: always when: always
paths: paths:
- $BUILDDIR/*.png - build-*/weston-*.tar.xz
- $BUILDDIR/meson-logs - build-*/*.log
- $BUILDDIR/dmesg.log - build-*/logs
- $BUILDDIR/weston-virtme - prefix-*
- $PREFIX
reports:
junit: $BUILDDIR/meson-logs/testlog.junit.xml
# Same as above, but without running any tests. build-native-meson:
.build-no-test: stage: build
extends:
- .default-rules
script: script:
- "${CI_PROJECT_DIR}/.gitlab-ci/build.sh" - git clone --depth=1 git://anongit.freedesktop.org/git/wayland/wayland-protocols
- export WAYLAND_PROTOCOLS_DIR="$(pwd)/prefix-wayland-protocols"
- export PKG_CONFIG_PATH="$WAYLAND_PROTOCOLS_DIR/share/pkgconfig:$PKG_CONFIG_PATH"
- export MAKEFLAGS="-j4"
- cd wayland-protocols
- git show -s HEAD
- mkdir build
- cd build
- ../autogen.sh --prefix="$WAYLAND_PROTOCOLS_DIR"
- make install
- cd ../../
- export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
- export BUILD_ID="weston-$CI_JOB_NAME_$CI_COMMIT_SHA-$CI_JOB_ID"
- export PREFIX="$(pwd)/prefix-$BUILD_ID"
- export BUILDDIR="$(pwd)/build-$BUILD_ID"
- export PATH=~/.local/bin:$PATH
- mkdir "$BUILDDIR" "$PREFIX"
- cd "$BUILDDIR"
- meson --prefix="$PREFIX" -Dsimple-dmabuf-drm=intel ..
- ninja -k0
- ninja install
- ninja test
- ninja clean
artifacts: artifacts:
name: weston-$CI_COMMIT_SHA name: weston-$CI_COMMIT_SHA-$CI_JOB_ID
when: always when: always
paths: paths:
- $BUILDDIR/meson-logs - build-*/meson-logs
- $PREFIX - prefix-*
# OS/architecture-specific variants
.build-env-debian-lts-x86_64:
extends:
- .debian-lts-x86_64
- .fdo.suffixed-image@debian
- .build-env
needs:
- job: x86_64-debian-lts-container_prep
artifacts: false
.build-env-debian-x86_64:
extends:
- .debian-x86_64
- .fdo.suffixed-image@debian
- .build-env
needs:
- job: x86_64-debian-container_prep
artifacts: false
.build-env-debian-lts-armv7:
tags:
- aarch64
extends:
- .debian-lts-armv7
- .fdo.suffixed-image@debian
- .build-env
needs:
- job: armv7-debian-lts-container_prep
artifacts: false
.build-env-debian-armv7:
tags:
- aarch64
extends:
- .debian-armv7
- .fdo.suffixed-image@debian
- .build-env
needs:
- job: armv7-debian-container_prep
artifacts: false
.build-env-debian-lts-aarch64:
tags:
- aarch64
extends:
- .debian-lts-aarch64
- .fdo.suffixed-image@debian
- .build-env
needs:
- job: aarch64-debian-lts-container_prep
artifacts: false
.build-env-debian-aarch64:
tags:
- aarch64
extends:
- .debian-aarch64
- .fdo.suffixed-image@debian
- .build-env
needs:
- job: aarch64-debian-container_prep
artifacts: false
.test-env-debian-lts-x86_64:
tags:
- kvm
extends:
- .build-env-debian-lts-x86_64
- .build-and-test
needs:
- job: x86_64-debian-lts-container_prep
artifacts: false
.test-env-debian-x86_64:
tags:
- kvm
extends:
- .build-env-debian-x86_64
- .build-and-test
needs:
- job: x86_64-debian-container_prep
artifacts: false
.test-env-debian-lts-aarch64:
tags:
- kvm-aarch64
extends:
- .build-env-debian-lts-aarch64
- .build-and-test
needs:
- job: aarch64-debian-lts-container_prep
artifacts: false
.test-env-debian-aarch64:
tags:
- kvm-aarch64
extends:
- .build-env-debian-aarch64
- .build-and-test
needs:
- job: aarch64-debian-container_prep
artifacts: false
# Full build (gcov + perfetto) used for testing under KVM.
.build-options-full:
stage: "Full build and test"
variables:
MESON_OPTIONS: >
-Doptimization=0
-Db_coverage=true
--force-fallback-for=perfetto
-Dperfetto=true
-Dperfetto:werror=false
-Dwerror=true
-Dtest-skip-is-failure=true
-Ddeprecated-remoting=true
-Ddeprecated-pipewire=true
after_script:
- ninja -C "$BUILDDIR" coverage-html > "$BUILDDIR/meson-logs/ninja-coverage-html.txt"
- ninja -C "$BUILDDIR" coverage-xml
# Full build, (without gcov and perfetto)
.build-options-full-v2:
stage: "Full build and test"
variables:
MESON_OPTIONS: >
-Doptimization=0
-Dwerror=true
-Dtest-skip-is-failure=true
x86_64-debian-lts-full-build:
extends:
- .test-env-debian-lts-x86_64
- .build-options-full
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: $BUILDDIR/meson-logs/coverage.xml
x86_64-debian-full-build:
extends:
- .test-env-debian-x86_64
- .build-options-full-v2
aarch64-debian-lts-full-build:
extends:
- .test-env-debian-lts-aarch64
- .build-options-full-v2
aarch64-debian-full-build:
extends:
- .test-env-debian-aarch64
- .build-options-full-v2
x86_64-clang-debian-lts-full-build:
extends:
- .test-env-debian-lts-x86_64
- .build-with-clang
- .build-options-full-v2
x86_64-clang-debian-full-build:
extends:
- .test-env-debian-x86_64
- .build-with-clang
- .build-options-full-v2
aarch64-clang-debian-lts-full-build:
extends:
- .test-env-debian-lts-aarch64
- .build-with-clang
- .build-options-full-v2
aarch64-clang-debian-full-build:
extends:
- .test-env-debian-aarch64
- .build-with-clang
- .build-options-full-v2
# Docs should be invariant on all architectures, so we only do it on Debian
# x86-64.
docs-build:
stage: "Other builds"
variables:
MESON_OPTIONS: >
-Dwerror=true
-Ddoc=true
extends:
- .build-env-debian-x86_64
- .build-no-test
# Building without gl-renderer and/or vulkan-renderer, to make sure this keeps working.
.build-options-no-gl-no-vulkan:
stage: "No-GL/Vulkan build and test"
variables:
MESON_OPTIONS: >
-Dsimple-clients=damage,im,shm,touch,dmabuf-v4l
-Drenderer-gl=false
-Drenderer-vulkan=false
-Dwerror=true
.build-options-no-gl:
stage: "No-GL/Vulkan build and test"
variables:
MESON_OPTIONS: >
-Dsimple-clients=damage,im,shm,touch,dmabuf-v4l
-Drenderer-gl=false
-Dwerror=true
.build-options-no-vulkan:
stage: "No-GL/Vulkan build and test"
variables:
MESON_OPTIONS: >
-Dsimple-clients=damage,im,shm,touch,dmabuf-v4l
-Drenderer-vulkan=false
-Dwerror=true
x86_64-debian-lts-no-gl-no-vulkan-build:
extends:
- .test-env-debian-lts-x86_64
- .build-options-no-gl-no-vulkan
x86_64-debian-no-gl-no-vulkan-build:
extends:
- .test-env-debian-x86_64
- .build-options-no-gl-no-vulkan
armv7-debian-lts-no-gl-no-vulkan-build:
extends:
- .build-env-debian-lts-armv7
- .build-no-test
- .build-options-no-gl-no-vulkan
armv7-debian-no-gl-no-vulkan-build:
extends:
- .build-env-debian-armv7
- .build-no-test
- .build-options-no-gl-no-vulkan
armv7-clang-debian-lts-no-gl-no-vulkan-build:
extends:
- .build-env-debian-lts-armv7
- .build-with-clang
- .build-no-test
- .build-options-no-gl-no-vulkan
armv7-clang-debian-no-gl-no-vulkan-build:
extends:
- .build-env-debian-armv7
- .build-with-clang
- .build-no-test
- .build-options-no-gl-no-vulkan
aarch64-debian-lts-no-gl-no-vulkan-build:
extends:
- .test-env-debian-lts-aarch64
- .build-options-no-gl-no-vulkan
aarch64-debian-no-gl-no-vulkan-build:
extends:
- .test-env-debian-aarch64
- .build-options-no-gl-no-vulkan
x86_64-debian-no-gl-build:
extends:
- .test-env-debian-x86_64
- .build-options-no-gl
x86_64-debian-no-vulkan-build:
extends:
- .test-env-debian-x86_64
- .build-options-no-vulkan
# Expose docs and coverage reports, so we can show users any changes to these
# inside their merge requests, letting us check them before merge.
#
# This does not build the docs or coverage information itself, but just reuses
# the docs and coverage information from the x86-64 Debian builds as the
# canonical sources of coverage information; the docs themselves should be
# invariant across any architecture or OS.
docs-and-coverage:
extends:
- .default-rules
- .debian-lts-x86_64
- .fdo.suffixed-image@debian
stage: pages
needs:
- job: docs-build
artifacts: true
- job: x86_64-debian-lts-full-build
artifacts: true
timeout: 5m
script:
- mv prefix-weston-docs-build/share/doc/weston Documentation
- mv build-weston-x86_64-debian-lts-full-build/meson-logs/coveragereport Test_Coverage
- rm Test_Coverage/gcov.css
- cp doc/style/lcov-style.css Test_Coverage/gcov.css
- cp doc/style/*.png Test_Coverage/
- rm -rf build-* prefix-*
artifacts:
expose_as: 'Documentation preview and test coverage report'
paths:
- Documentation/
- Test_Coverage/
# Generate the documentation for https://wayland.pages.freedesktop.org/weston/
# Anything under public/ is published to this URL.
#
# Does not inherit .default-rules as it should only run in our default branch for
# the upstream repo.
pages:
extends:
- .debian-x86_64
- .fdo.suffixed-image@debian
stage: pages
timeout: 5m
needs:
- job: docs-build
artifacts: true
script:
- export PREFIX=$(pwd)/prefix-weston-docs-build
- mkdir public
- cp -R $PREFIX/share/doc/weston/* public/
artifacts:
paths:
- public
rules:
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_PATH == "wayland/weston" && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
when: on_success
- when: never

View file

@ -1,244 +0,0 @@
#!/bin/bash
#
# Builds the dependencies required for any OS/architecture combination. See
# .gitlab-ci.yml for more information. This script is called from an
# OS-specific build scripts like debian-install.sh.
source "${FDO_CI_BASH_HELPERS}"
set -o xtrace -o errexit
# Set concurrency to an appropriate level for our shared runners, falling back
# to the conservative default form before we had this variable.
export MAKEFLAGS="-j${FDO_CI_CONCURRENT:-4}"
export NINJAFLAGS="-j${FDO_CI_CONCURRENT:-4}"
# When calling pip in newer versions, we're required to pass
# --break-system-packages so it knows that we did really want to call pip and
# aren't just doing it by accident.
PIP_ARGS="--user"
case "$FDO_DISTRIBUTION_VERSION" in
bullseye)
;;
*)
PIP_ARGS="$PIP_ARGS --break-system-packages"
;;
esac
# Build and install Meson. Generally we want to keep this in sync with what
# we require inside meson.build.
fdo_log_section_start_collapsed install_meson "install_meson"
pip3 install $PIP_ARGS git+https://github.com/mesonbuild/meson.git@1.4.2
export PATH=$HOME/.local/bin:$PATH
# Our docs are built using Sphinx (top-level organisation and final HTML/CSS
# generation), Doxygen (parse structures/functions/comments from source code),
# Breathe (a bridge between Doxygen and Sphinx), and we use the Read the Docs
# theme for the final presentation.
pip3 install $PIP_ARGS sphinx==4.2.0
pip3 install $PIP_ARGS sphinxcontrib-applehelp==1.0.4
pip3 install $PIP_ARGS sphinxcontrib-devhelp==1.0.2
pip3 install $PIP_ARGS sphinxcontrib-htmlhelp==2.0.0
pip3 install $PIP_ARGS sphinxcontrib-jsmath==1.0.1
pip3 install $PIP_ARGS sphinxcontrib-qthelp==1.0.3
pip3 install $PIP_ARGS sphinxcontrib-serializinghtml==1.1.5
pip3 install $PIP_ARGS breathe==4.31.0
pip3 install $PIP_ARGS sphinx_rtd_theme==1.0.0
fdo_log_section_end install_meson
# Build a Linux kernel for use in testing. We enable the VKMS module so we can
# predictably test the DRM backend in the absence of real hardware. We lock the
# version here so we see predictable results.
#
# To run this we use virtme-ng, a QEMU wrapper. It is a fork from virtme, whose
# development stalled.
#
# virtme-ng makes our lives easier by abstracting handling of the console,
# filesystem, etc, so we can pretend that the VM we execute in is actually
# just a regular container.
fdo_log_section_start_collapsed install_kernel "install_kernel"
if [[ -n "$KERNEL_DEFCONFIG" ]]; then
git clone --depth=1 --branch drm-misc-next-2026-03-20 https://gitlab.freedesktop.org/drm/misc/kernel.git linux
cd linux
if [[ "${BUILD_ARCH}" = "x86-64" ]]; then
LINUX_ARCH=x86
elif [[ "$BUILD_ARCH" = "aarch64" ]]; then
LINUX_ARCH=arm64
else
echo "Invalid or missing \$BUILD_ARCH"
exit 1
fi
if [[ -z "${KERNEL_DEFCONFIG}" ]]; then
echo "Invalid or missing \$KERNEL_DEFCONFIG"
exit
fi
if [[ -z "${KERNEL_IMAGE}" ]]; then
echo "Invalid or missing \$KERNEL_IMAGE"
exit
fi
make ARCH=${LINUX_ARCH} ${KERNEL_DEFCONFIG}
make ARCH=${LINUX_ARCH} kvm_guest.config
./scripts/config \
--enable CONFIG_DRM \
--enable CONFIG_DRM_KMS_HELPER \
--enable CONFIG_DRM_VKMS \
--enable CONFIG_UDMABUF
make ARCH=${LINUX_ARCH} oldconfig
make ARCH=${LINUX_ARCH}
cd ..
mkdir /weston-virtme
mv linux/arch/${LINUX_ARCH}/boot/${KERNEL_IMAGE} /weston-virtme/
mv linux/.config /weston-virtme/.config
rm -rf linux
git clone --depth=1 --branch=v1.25 --recurse-submodules https://github.com/arighi/virtme-ng.git virtme
cd virtme
./setup.py install
cd ..
fi
fdo_log_section_end install_kernel
# Build and install Wayland; keep this version in sync with our dependency
# in meson.build.
fdo_log_section_start_collapsed install_wayland "install_wayland"
git clone --branch 1.22.0 --depth=1 https://gitlab.freedesktop.org/wayland/wayland
cd wayland
git show -s HEAD
meson setup build --wrap-mode=nofallback -Ddocumentation=false
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf wayland
# Keep this version in sync with our dependency in meson.build. If you wish to
# raise a MR against custom protocol, please change this reference to clone
# your relevant tree, and make sure you bump $FDO_DISTRIBUTION_TAG.
git clone --branch 1.46 --depth=1 https://gitlab.freedesktop.org/wayland/wayland-protocols
cd wayland-protocols
git show -s HEAD
meson setup build --wrap-mode=nofallback -Dtests=false
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf wayland-protocols
fdo_log_section_end install_wayland
# Build and install our own version of libdrm. Debian 11 (bullseye) provides
# libdrm 2.4.104 which doesn't have the IN_FORMATS iterator api, and Mesa
# depends on 2.4.109 as well.
# Bump to 2.4.118 to include DRM_FORMAT_NV{15,20,30}
fdo_log_section_start_collapsed install_libdrm "install_libdrm"
git clone --branch libdrm-2.4.118 --depth=1 https://gitlab.freedesktop.org/mesa/drm.git
cd drm
meson setup build --wrap-mode=nofallback -Dauto_features=disabled \
-Dvc4=disabled -Dfreedreno=disabled -Detnaviv=disabled
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf drm
fdo_log_section_end install_libdrm
# Build and install Vulkan-Headers with a defined version, mostly because
# the version in Debian 11 (bullseye) is too old to build vulkan-renderer.
fdo_log_section_start_collapsed install_vulkan_headers "install_vulkan_headers"
git clone --branch sdk-1.3.239.0 --depth=1 https://github.com/KhronosGroup/Vulkan-Headers
cd Vulkan-Headers
cmake -G Ninja -B build
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf Vulkan-Headers
fdo_log_section_end install_vulkan_headers
# Build and install our own version of Mesa. Debian provides a perfectly usable
# Mesa, however llvmpipe's rendering behaviour can change subtly over time.
# This doesn't work for our tests which expect pixel-precise reproduction, so
# we lock it to a set version for more predictability. If you need newer
# features from Mesa then bump this version and $FDO_DISTRIBUTION_TAG, however
# please be prepared for some of the tests to change output, which will need to
# be manually inspected for correctness.
fdo_log_section_start_collapsed install_mesa "install_mesa"
# Needed for Mesa >= 25.3
git clone --branch 12.2.0 --depth=1 https://github.com/KhronosGroup/glslang
cd glslang
cmake -G Ninja -B build
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf glslang
git clone --branch mesa-26.0.4 --depth=1 https://gitlab.freedesktop.org/mesa/mesa.git
cd mesa
meson setup build --wrap-mode=nofallback -Dauto_features=disabled \
-Dgallium-drivers=llvmpipe -Dvulkan-drivers=swrast -Dvideo-codecs= \
-Degl=enabled -Dgbm=enabled -Dgles2=enabled -Dllvm=enabled \
-Dshared-glapi=enabled -Dglx=disabled
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf mesa
fdo_log_section_end install_mesa
# PipeWire is used for remoting support. Unlike our other dependencies its
# behaviour will be stable, however as a pre-1.0 project its API is not yet
# stable, so again we lock it to a fixed version.
#
# ... the version chosen is 0.3.32 with a small Clang-specific build fix.
fdo_log_section_start_collapsed install_pipewire "install_pipewire"
git clone --single-branch --branch master https://gitlab.freedesktop.org/pipewire/pipewire.git pipewire-src
cd pipewire-src
git checkout -b snapshot bf112940d0bf8f526dd6229a619c1283835b49c2
meson setup build --wrap-mode=nofallback
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf pipewire-src
fdo_log_section_end install_pipewire
# seatd lets us avoid the pain of open-coding TTY assignment within Weston.
# We use this for our tests using the DRM backend.
fdo_log_section_start_collapsed install_seatd "install_seatd"
git clone --depth=1 --branch 0.6.1 https://git.sr.ht/~kennylevinsen/seatd
cd seatd
meson setup build --wrap-mode=nofallback -Dauto_features=disabled \
-Dlibseat-seatd=enabled -Dlibseat-logind=systemd -Dserver=enabled
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf seatd
fdo_log_section_end install_seatd
# Build and install aml and neatvnc, which are required for the VNC backend
fdo_log_section_start_collapsed install_aml_neatvnc "install_aml_neatvnc"
git clone --branch v0.3.0 --depth=1 https://github.com/any1/aml.git
cd aml
meson setup build --wrap-mode=nofallback
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf aml
git clone --branch v0.7.0 --depth=1 https://github.com/any1/neatvnc.git
cd neatvnc
meson setup build --wrap-mode=nofallback -Dauto_features=disabled
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf neatvnc
fdo_log_section_end install_aml_neatvnc
# Build and install libdisplay-info, used by drm-backend
fdo_log_section_start_collapsed install_libdisplay-info "install_libdisplay-info"
git clone --branch 0.2.0 --depth=1 https://gitlab.freedesktop.org/emersion/libdisplay-info.git
cd libdisplay-info
meson setup build --wrap-mode=nofallback
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf libdisplay-info
fdo_log_section_end install_libdisplay-info
# Build and install lcms2, which we use to support color-management.
fdo_log_section_start_collapsed install_lcms2 "install_lcms2"
git clone --branch master https://github.com/mm2/Little-CMS.git lcms2
cd lcms2
git checkout -b snapshot lcms2.16
meson setup build --wrap-mode=nofallback
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf lcms2
fdo_log_section_end install_lcms2

View file

@ -1,22 +0,0 @@
#!/bin/bash
set -xe
source "${FDO_CI_BASH_HELPERS}"
fdo_log_section_start_collapsed build_weston "build_weston"
cd "$BUILDDIR"
meson --prefix="$PREFIX" --wrap-mode=nofallback $SANITIZE ${MESON_OPTIONS} ${MESON_TOOLCHAIN_OPTIONS} ${MESON_DIST_OPTIONS} ..
ninja -k0 -j${FDO_CI_CONCURRENT:-4}
ninja install
if [ "$CI_JOB_NAME" == "x86_64-debian-full-build" ]; then
cd "$BUILDDIR_WESTINY"
export NPREFIX=$CI_PROJECT_DIR/prefix-weston-$CI_JOB_NAME
export PKG_CONFIG_PATH=$NPREFIX/lib/pkgconfig/:$NPREFIX/share/pkgconfig/:$NPREFIX/lib/x86_64-linux-gnu/pkgconfig:$PKG_CONFIG_PATH
meson setup --prefix="$PREFIX_WESTINY" --wrap-mode=nofallback ../westinyplus/
ninja -k0 -j${FDO_CI_CONCURRENT:-4}
ninja install
ninja clean
cd -
fi
fdo_log_section_end build_weston

View file

@ -1,150 +0,0 @@
#!/bin/bash
#
# Constructs the base container image used to build Weston within CI. Per the
# comment at the top of .gitlab-ci.yml, any changes in this file must bump the
# $FDO_DISTRIBUTION_TAG variable so we know the container has to be rebuilt.
set -o xtrace -o errexit
# These get temporary installed for building Linux and then force-removed.
LINUX_DEV_PKGS="
bc
bison
flex
"
# These get temporary installed for building Mesa and then force-removed.
MESA_DEV_PKGS="
bison
flex
gettext
libwayland-egl-backend-dev
libxrandr-dev
libxshmfence-dev
libxrandr-dev
llvm-${LLVM_VERSION}-dev
python3-mako
"
# These get temporarily installed for other build dependencies and then
# force-removed.
# cmake is used by Vulkan-Headers
BUILD_DEV_PKGS="
cmake
"
# Needed for running the custom-built mesa
MESA_RUNTIME_PKGS="
libllvm${LLVM_VERSION}
"
if [ x"$USE_DEBIAN_BACKPORTS" = "xy" ] ; then
echo 'deb http://deb.debian.org/debian '${FDO_DISTRIBUTION_VERSION}'-backports main' >> /etc/apt/sources.list
fi
apt-get update
apt-get -y --no-install-recommends install \
autoconf \
automake \
build-essential \
clang-${LLVM_VERSION} \
curl \
doxygen \
graphviz \
gcovr \
git \
glslang-tools \
hwdata \
lcov \
libasound2-dev \
libbluetooth-dev \
libcairo2-dev \
libcolord-dev \
libdbus-1-dev \
libdrm-dev \
libegl1-mesa-dev \
libelf-dev \
libevdev-dev \
libexpat1-dev \
libffi-dev \
libgbm-dev \
libgdk-pixbuf-xlib-2.0-dev \
libgles2-mesa-dev \
libglu1-mesa-dev \
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev \
libinput-dev \
libjack-jackd2-dev \
libjpeg-dev \
libjpeg-dev \
liblua5.4-dev \
libmtdev-dev \
libpam0g-dev \
libpango1.0-dev \
libpciaccess-dev \
libpixman-1-dev \
libpng-dev \
libpulse-dev \
libsbc-dev \
libsystemd-dev \
libtool \
libudev-dev \
libva-dev \
libvpx-dev \
libvulkan-dev \
libwebp-dev \
libx11-dev \
libx11-xcb-dev \
libxcb1-dev \
libxcb-composite0-dev \
libxcb-dri2-0-dev \
libxcb-dri3-dev \
libxcb-glx0-dev \
libxcb-present-dev \
libxcb-randr0-dev \
libxcb-shm0-dev \
libxcb-sync-dev \
libxcb-xfixes0-dev \
libxcb-xkb-dev \
libxcursor-dev \
libxcb-cursor-dev \
libxdamage-dev \
libxext-dev \
libxfixes-dev \
libxkbcommon-dev \
libxml2-dev \
libxxf86vm-dev \
lld-${LLVM_VERSION} \
llvm-${LLVM_VERSION} \
llvm-${LLVM_VERSION}-dev \
mesa-common-dev \
ninja-build \
pkg-config \
python3-pip \
python3-pygments \
python3-setuptools \
qemu-system \
sysvinit-core \
x11proto-dev \
xwayland \
python3-argcomplete \
flake8 pylint \
cargo rustc \
iproute2 udev \
$MESA_DEV_PKGS \
$BUILD_DEV_PKGS \
$MESA_RUNTIME_PKGS \
$PACKAGES_SPECIFIC \
$LINUX_DEV_PKGS \
if [ "$FREERDP_VERSION" -ne 0 ] ; then
apt-get -y --no-install-recommends install freerdp${FREERDP_VERSION}-dev
fi
# Actually build our dependencies ...
./.gitlab-ci/build-deps.sh
# And remove packages which are only required for our build dependencies,
# which we don't need bloating the image whilst we build and run Weston.
apt-get -y --autoremove purge $LINUX_DEV_PKGS $MESA_DEV_PKGS $BUILD_DEV_PKGS

View file

@ -1,26 +0,0 @@
# AddressSanitizer memory leak suppressions
# This leaks in Debian's fontconfig/Xwayland setup. We add the entire
# fontconfig library because turning off fast unwind -- required to catch other
# originating leaks from fontconfig; would stall our tests timing them out.
leak:libfontconfig
# Workarounds for the LeakSanitizer use_tls=0 workaround,
# see tests/meson.build
leak:wl_shm_buffer_begin_access
leak:g_malloc0
leak:sysprof_collector_get
leak:/ld-*.so*
# Add all of perfetto, since it's not easy to clean up after it
leak:perfetto
# lavapipe inexplicably leaks when Vulkan physical devices are enumerated,
# despite us a) not using that device and b) freeing the instance. This is
# apparently a known issue. (Also when ASan creates threads ...)
leak:vkEnumeratePhysicalDevices
leak:asan_thread_start
# glib/pangoft for Trixie update
leak:libpangoft2
leak:libglib

View file

@ -1,13 +0,0 @@
#!/bin/bash
set -xe
source "${FDO_CI_BASH_HELPERS}"
cd "$BUILDDIR"
test -n "${QEMU_SMP}" || QEMU_SMP=${FDO_CI_CONCURRENT:-4}
virtme-run --rw --pwd --kimg /weston-virtme/${KERNEL_IMAGE} --kopt quiet --kopt log_buf_len=2M --script-sh ../.gitlab-ci/virtme-scripts/run-weston-tests.sh --qemu-opts -m 4096 -smp ${QEMU_SMP}
TEST_RES=$(cat $TESTS_RES_PATH)
rm $TESTS_RES_PATH
cp -R /weston-virtme ./
rm weston-virtme/${KERNEL_IMAGE}
exit $TEST_RES

View file

@ -1,46 +0,0 @@
#!/bin/bash
# folders that are necessary to run Weston tests
mkdir -p /tmp/tests
mkdir -p /tmp/.X11-unix
chmod -R 0700 /tmp
# set environment variables to run Weston tests
export XDG_RUNTIME_DIR=/tmp/tests
export LIBSEAT_BACKEND=seatd
# In our test suite, we use VKMS to run DRM-backend tests. The order in which
# devices are loaded is not predictable, so the DRM node that VKMS takes can
# change across each boot. That's why we have this one-liner shell script to get
# the appropriate node for VKMS.
export WESTON_TEST_SUITE_DRM_DEVICE=$(basename /sys/bus/faux/devices/vkms/drm/card*)
# ninja test depends on meson, and meson itself looks for its modules on folder
# $HOME/.local/lib/pythonX.Y/site-packages (the Python version may differ).
# build-deps.sh installs dependencies to /usr/local.
# virtme starts with HOME=/tmp/roothome, but as we installed meson on user root,
# meson can not find its modules. So we change the HOME env var to fix that.
export HOME=/root
export PATH=$HOME/.local/bin:$PATH
export PATH=/usr/local/bin:$PATH
# Terrible hack, per comment in weston-test-runner.c's main(): find Mesa's
# llvmpipe/lavapipe driver module location
export WESTON_CI_LEAK_DL_HANDLES=$(find /usr/local -name swrast_dri.so -print 2>/dev/null || true):
export WESTON_CI_LEAK_DL_HANDLES=$WESTON_CI_LEAK_DL_HANDLES:$(find /usr/local -name libvulkan_lvp.so -print 2>/dev/null || true)
export WESTON_CI_LEAK_DL_HANDLES=$WESTON_CI_LEAK_DL_HANDLES:$(find /usr/local -name libgallium\*.so -print 2>/dev/null || true)
# run the tests and save the exit status
# we give ourselves a very generous timeout multiplier due to ASan overhead
echo 0x1f > /sys/module/drm/parameters/debug
seatd-launch -- meson test --no-rebuild --timeout-multiplier 4
# note that we need to store the return value from the tests in order to
# determine if the test suite ran successfully or not.
TEST_RES=$?
dmesg &> dmesg.log
echo 0x00 > /sys/module/drm/parameters/debug
# create a file to keep the result of this script:
# - 0 means the script succeeded
# - 1 means the tests failed, so the job itself should fail
TESTS_RES_PATH=$(pwd)/tests-res.txt
echo $TEST_RES > $TESTS_RES_PATH

View file

@ -1,3 +0,0 @@
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>

View file

@ -1,31 +1,6 @@
Contributing to Weston Contributing to Weston
======================= =======================
Sending patches
---------------
Patches should be sent via
[GitLab merge requests](https://docs.gitlab.com/ce/gitlab-basics/add-merge-request.html).
Weston is
[hosted on freedesktop.org's GitLab](https://gitlab.freedesktop.org/wayland/weston/):
in order to submit code, you should create an account on this GitLab instance,
fork the core Weston repository, push your changes to a branch in your new
repository, and then submit these patches for review through a merge request.
### Forking & Permissions for new users
Due to huge amounts of spam, freedesktop.org has disabled forking of existing
projects for new users. Please head to
[How can I contribute](https://gitlab.freedesktop.org/freedesktop/freedesktop/-/wikis/home#how-can-i-contribute-to-an-existing-project-or-create-a-new-one)
and verify whether you need to perform additional steps.
### Do not send patches over email
Weston formerly accepted patches via `git-send-email`, sent to
**wayland-devel\@lists.freedesktop.org**; these were
[tracked using Patchwork](https://patchwork.freedesktop.org/project/wayland/).
New email patches are no longer accepted.
Finding something to work on Finding something to work on
---------------------------- ----------------------------
@ -43,13 +18,31 @@ If you have picked an issue you would like to work on, you may want to mention
in the issue tracker that you would like to pick it up. You can also discuss in the issue tracker that you would like to pick it up. You can also discuss
it with the developers in the issue tracker, or on the it with the developers in the issue tracker, or on the
[mailing list](https://lists.freedesktop.org/mailman/listinfo/wayland-devel). [mailing list](https://lists.freedesktop.org/mailman/listinfo/wayland-devel).
Many developers also use IRC through [OFTC](https://www.oftc.net/)'s Many developers also use IRC through [Freenode](https://freenode.net)'s
`#wayland` channel; however you may need to wait some time for a response on `#wayland` channel; however you may need to wait some time for a response on
IRC, which requires keeping your client connected. If you cannot stay for a IRC, which requires keeping your client connected. If you cannot stay for a
long time (potentially some hours due to timezone differences), then you long time (potentially some hours due to timezone differences), then you
may want to send your question to the list or issue tracker instead. may want to send your question to the list or issue tracker instead.
Sending patches
---------------
Patches should be sent via
[GitLab merge requests](https://docs.gitlab.com/ce/gitlab-basics/add-merge-request.html).
Weston is
[hosted on freedesktop.org's GitLab](https://gitlab.freedesktop.org/wayland/weston/):
in order to submit code, you should create an account on this GitLab instance,
fork the core Weston repository, push your changes to a branch in your new
repository, and then submit these patches for review through a merge request.
Weston formerly accepted patches via `git-send-email`, sent to
**wayland-devel@lists.freedesktop.org**; these were
[tracked using Patchwork](https://patchwork.freedesktop.org/projects/wayland/).
Some old patches continue to be sent this way, and we may accept small new
patches sent to the list, but please send all new patches through GitLab merge
requests.
Formatting and separating commits Formatting and separating commits
--------------------------------- ---------------------------------
@ -104,20 +97,15 @@ cope with the way git log presents them.
See [notes on commit messages] for a recommended reading on writing commit See [notes on commit messages] for a recommended reading on writing commit
messages. messages.
Your patches must also include a Signed-off-by line with your name Your patches should also include a Signed-off-by line with your name and
(or pseudonym) and email address which indicates that you agree to the email address. If you're not the patch's original author, you should
[Developer's Certificate of Origin 1.1](DCO-1.1.txt). also gather S-o-b's by them (and/or whomever gave the patch to you.) The
If you're not the patch's original author, you should
also gather S-o-b's from them (and/or whomever gave the patch to you) in
addition to your own S-o-b. The
significance of this is that it certifies that you created the patch, significance of this is that it certifies that you created the patch,
that it was created under an appropriate open source license, or that it was created under an appropriate open source license, or
provided to you under those terms. This lets us indicate a chain of provided to you under those terms. This lets us indicate a chain of
responsibility for the copyright status of the code. responsibility for the copyright status of the code.
**Agreeing to DCO 1.1 is mandatory.** Patches without a Signed-off-by cannot We won't reject patches that lack S-o-b, but it is strongly recommended.
be accepted, but using a pseudonym is fine as long as the email address is
yours personally.
When you re-send patches, revised or not, it would be very good to document the When you re-send patches, revised or not, it would be very good to document the
changes compared to the previous revision in the commit message and/or the changes compared to the previous revision in the commit message and/or the
@ -216,10 +204,6 @@ my_function(void)
parameter3, parameter4); parameter3, parameter4);
``` ```
- do not write fallback paths for failed simple memory allocations, use the
`x*alloc()` wrappers from `shared/xalloc.h` instead or use
`abort_oom_if_null()`
Conduct Conduct
======= =======

View file

@ -1,37 +0,0 @@
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
1 Letterman Drive
Suite D4700
San Francisco, CA, 94129
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.

1766
Makefile.am Normal file

File diff suppressed because it is too large Load diff

318
README.md
View file

@ -3,17 +3,38 @@ Weston
![screenshot of skeletal Weston desktop](doc/wayland-screenshot.jpg) ![screenshot of skeletal Weston desktop](doc/wayland-screenshot.jpg)
Weston is a Wayland compositor designed for correctness, reliability, Weston is the reference implementation of a Wayland compositor, as well as a
predictability, and performance. useful environment in and of itself.
Out of the box, Weston provides a very basic desktop, or a full-featured Out of the box, Weston provides a very basic desktop, or a full-featured
environment for non-desktop uses such as automotive, embedded, in-flight, environment for non-desktop uses such as automotive, embedded, in-flight,
industrial, kiosks, set-top boxes and TVs. industrial, kiosks, set-top boxes and TVs. It also provides a library allowing
other projects to build their own full-featured environments on top of Weston's
core.
It also provides a library called [libweston](#libweston) which allows The core focus of Weston is correctness and reliability. Weston aims to be lean
users to build their own custom full-featured environments on top of and fast, but more importantly, to be predictable. Whilst Weston does have known
Weston's core. bugs and shortcomings, we avoid unknown or variable behaviour as much as
possible, including variable performance such as occasional spikes in frame
display time.
A small suite of example or demo clients are also provided: though they can be
useful in themselves, their main purpose is to be an example or test case for
others building compositors or clients.
If you are after a more mainline desktop experience, the
[GNOME](https://www.gnome.org) and [KDE](https://www.kde.org) projects provide
full-featured desktop environments built on the Wayland protocol. Many other
projects also exist providing Wayland clients and desktop environments: you are
not limited to just what you can find in Weston.
Reporting issues and contributing
=================================
Weston's development is
[hosted on freedesktop.org GitLab](https://gitlab.freedesktop.org/wayland/weston/).
Please also see [the contributing document](CONTRIBUTING.md), which details how
to make code or non-technical contributions to Weston.
Building Weston Building Weston
=============== ===============
@ -21,7 +42,7 @@ Building Weston
Weston is built using [Meson](https://mesonbuild.com/). Weston often depends Weston is built using [Meson](https://mesonbuild.com/). Weston often depends
on the current release versions of on the current release versions of
[Wayland](https://gitlab.freedesktop.org/wayland/wayland) and [Wayland](https://gitlab.freedesktop.org/wayland/wayland) and
[wayland-protocols](https://gitlab.freedesktop.org/wayland/wayland-protocols). [wayland-protocols](https://cgit.freedesktop.org/wayland/wayland-protocols).
If necessary, the latest Meson can be installed as a user with: If necessary, the latest Meson can be installed as a user with:
@ -41,12 +62,14 @@ several features if you want to avoid certain dependencies.
The `meson` command populates the build directory. This step can The `meson` command populates the build directory. This step can
fail due to missing dependencies. Any build options you want can be added on fail due to missing dependencies. Any build options you want can be added on
that line, e.g. `meson build/ --prefix=... -Ddemo-clients=false`. All the build that line, e.g. `meson build/ --prefix=... -Dsimple-dmabuf-drm=intel`.
options can be found in the file [meson_options.txt](meson_options.txt). All the build options can be found in the file
[meson_options.txt](meson_options.txt).
Once the build directory has been successfully populated, you can inspect the Once the build directory has been successfully populated, you can inspect the
configuration with `meson configure build/`. If you need to change an configuration with `meson configure build/`. If you need to change an
option, you can do e.g. `meson configure build/ -Ddemo-clients=false`. option, you can do e.g.
`meson configure build/ -Dsimple-dmabuf-drm=intel`.
Every push to the Weston master repository and its forks is built using GitLab Every push to the Weston master repository and its forks is built using GitLab
CI. [Reading the configuration](.gitlab-ci.yml) may provide a useful example of CI. [Reading the configuration](.gitlab-ci.yml) may provide a useful example of
@ -56,9 +79,6 @@ More [detailed documentation on building Weston](https://wayland.freedesktop.org
is available on the Wayland site. There are also more details on is available on the Wayland site. There are also more details on
[how to run and write tests](https://wayland.freedesktop.org/testing.html). [how to run and write tests](https://wayland.freedesktop.org/testing.html).
For building the documentation see [documentation](#documentation).
Running Weston Running Weston
============== ==============
@ -68,92 +88,234 @@ from a text console, it will take over that console. When launched from inside
an existing Wayland or X11 session, it will start a 'nested' instance of Weston an existing Wayland or X11 session, it will start a 'nested' instance of Weston
inside a window in that session. inside a window in that session.
By default, Weston will start with a skeletal desktop-like environment called
`desktop-shell`. Other shells are available; for example, to load the `kiosk`
shell designed for single-application environments, you can start with:
$ weston --shell=kiosk
Help is available by running `weston --help`, or `man weston`, which will list Help is available by running `weston --help`, or `man weston`, which will list
the available configuration options and display backends. It can also be the available configuration options and display backends. It can also be
configured through a file on disk; more information on this can be found through configured through a file on disk; more information on this can be found through
`man weston.ini`. `man weston.ini`.
A small suite of example or demo clients are also provided: though they can be In some special cases, such as when running remotely or without logind's session
useful in themselves, their main purpose is to be an example or test case for control, Weston may not be able to run directly from a text console. In these
others building compositors or clients. situations, you can instead execute the `weston-launch` helper, which will gain
privileged access to input and output devices by running as root, then granting
access to the main Weston binary running as your user. Running Weston this way
is not recommended unless necessary.
Using libweston Libweston
=============== =========
libweston is designed to allow users to use Weston's core - its client support, Libweston is an effort to separate the re-usable parts of Weston into
backends and renderers - whilst implementing their own user interface, policy, a library. Libweston provides most of the boring and tedious bits of
configuration, and lifecycle. If you would like to implement your own window correctly implementing core Wayland protocols and interfacing with
manager or desktop environment, we recommend building your project using the input and output systems, so that people who just want to write a new
libweston API. "Wayland window manager" (WM) or a small desktop environment (DE) can
focus on the WM part.
Building and installing Weston will also install libweston's shared library Libweston was first introduced in Weston 1.12, and is expected to
and development headers. libweston is both API-compatible and ABI-compatible continue evolving through many Weston releases before it achieves a
within a single stable release. It is parallel-installable, so multiple stable stable API and feature completeness.
releases can be installed and used side by side.
Documentation for libweston's API can be found within the source (see the Libweston's primary purpose is exporting an API for creating Wayland
[documentation](#documentation) section), and also on compositors. Libweston's secondary purpose is to export the weston_config API
[Weston's online documentation](https://wayland.pages.freedesktop.org/weston/) so that third party plugins and helper programs can read `weston.ini` if they
for the current stable release. want to. However, these two scopes are orthogonal and independent. At no point
will the compositor functionality use or depend on the weston_config
functionality.
Reporting issues and contributing API/ABI (in)stability and parallel installability
================================= -------------------------------------------------
Weston's development is As libweston's API surface is huge, it is impossible to get it right
[hosted on freedesktop.org GitLab](https://gitlab.freedesktop.org/wayland/weston/). in one go. Therefore developers reserve the right to break the API/ABI and bump
Please also see [the contributing document](CONTRIBUTING.md), which details how the major version to signify that. For git snapshots of the master branch, the
to make code or non-technical contributions to Weston. API/ABI can break any time without warning.
Weston and libweston are not suitable for severely memory-constrained environments Libweston major can be bumped only once during a development cycle. This should
where the compositor is expected to continue running even in the face of happen on the first patch that breaks the API or ABI. Further breaks before the
trivial memory allocations failing. If standard functions like `malloc()` next Weston major.0.0 release do not cause a bump. This means that libweston
fail for small allocations, API and ABI are allowed to break also after an alpha release, up to the final
[you can expect libweston to abort](https://gitlab.freedesktop.org/wayland/weston/-/issues/631). release. However, breaks after alpha should be judged by the usual practices
This is only likely to occur if you have disabled your OS's 'overcommit' for allowing minor features, fixes only, or critical fixes only.
functionality, and not in common cases.
To make things tolerable for libweston users despite API/ABI breakages,
different libweston major versions are designed to be perfectly
parallel-installable. This way external projects can easily depend on a
particular API/ABI-version. Thus they do not have to fight over which
ABI-version is installed in a user's system. This allows a user to install many
different compositors each requiring a different libweston ABI-version without
tricks or conflicts.
Note, that versions of Weston itself will not be parallel-installable,
only libweston is.
For more information about parallel installability, see
http://ometer.com/parallel.html
Documentation Versioning scheme
============= -----------------
To read the Weston documentation online, head over to In order to provide consistent, easy to use versioning, libweston
[the Weston website](https://wayland.pages.freedesktop.org/weston/). follows the rules in the Apache Portable Runtime Project
http://apr.apache.org/versioning.html.
For documenting weston we use [sphinx](http://www.sphinx-doc.org/en/master/) The document provides the full details, with the gist summed below:
together with [breathe](https://breathe.readthedocs.io/en/latest/) to process - Major - backward incompatible changes.
and augment code documentation from Doxygen. You should be able to install - Minor - new backward compatible features.
both sphinx and the breathe extension using pip3 command, or your package - Patch - internal (implementation specific) fixes.
manager. Doxygen should be available using your distribution package manager.
Once those are set up, run `meson` with `-Ddoc=true` option in order to enable Weston and libweston have separate version numbers in configure.ac. All
building the documentation. Installation will place the documentation in the releases are made by the Weston version number. Libweston version number
prefix's path under datadir (i.e., `share/doc`). matches the Weston version number in all releases except maybe pre-releases.
Pre-releases have the Weston micro version 91 or greater.
Adding and improving documentation A pre-release is allowed to install a libweston version greater than the Weston
---------------------------------- version in case libweston major was bumped. In that case, the libweston version
must be Weston major + 1 and with minor and patch versions zero.
For re-generating the documentation a special `docs` target has been added. Pkg-config files are named after libweston major, but carry the Weston version
Although first time you build (and subsequently install) weston, you'll see the number. This means that Weston pre-release 2.1.91 may install libweston-3.pc
documentation being built, updates to the spinx documentation files or to the for the future libweston 3.0.0, but the .pc file says the version is still
source files will only be updated when using `docs` target! 2.1.91. When a libweston user wants to depend on the fully stable API and ABI
of a libweston major, he should use (e.g. for major 3):
Example: PKG_CHECK_MODULES(LIBWESTON, [libweston-3 >= 3.0.0])
~~~~ Depending only on libweston-3 without a specific version number still allows
$ ninja install # generates and installs the documentation pre-releases which might have different API or ABI.
# time passes, hack hack, add doc in sources or rST files
$ ninja install # not sufficient, docs will not be updated
$ ninja docs && ninja install # run 'docs' then install
~~~~
Improving/adding documentation can be done by modifying rST files under
`doc/sphinx/` directory or by modifying the source code using doxygen Forward compatibility
directives. ---------------------
Inspired by ATK, Qt and KDE programs/libraries, libjpeg-turbo, GDK,
NetworkManager, js17, lz4 and many others, libweston uses a macro to restrict
the API visible to the developer - REQUIRE_LIBWESTON_API_VERSION.
Note that different projects focus on different aspects - upper and/or lower
version check, default to visible/hidden old/new symbols and so on.
libweston aims to guard all newly introduced API, in order to prevent subtle
breaks that a simple recompile (against a newer version) might cause.
The macro is of the format 0x$MAJOR$MINOR and does not include PATCH version.
As mentioned in the Versioning scheme section, the latter does not reflect any
user visible API changes, thus should be not considered part of the API version.
All new symbols should be guarded by the macro like the example given below:
#if REQUIRE_LIBWESTON_API_VERSION >= 0x0101
bool
weston_ham_sandwich(void);
#endif
In order to use the said symbol, the one will have a similar code in their
configure.ac:
PKG_CHECK_MODULES(LIBWESTON, [libweston-1 >= 1.1])
AC_DEFINE(REQUIRE_LIBWESTON_API_VERSION, [0x0101])
If the user is _not_ interested in forward compatibility, they can use 0xffff
or similar high value. Yet doing so is not recommended.
Libweston design goals
----------------------
The high-level goal of libweston is to decouple the compositor from
the shell implementation (what used to be shell plugins).
Thus, instead of launching 'weston' with various arguments to choose the
shell, one would launch the shell itself, e.g. 'weston-desktop',
'weston-ivi', 'orbital', etc. The main executable (the hosting program)
will implement the shell, while libweston will be used for a fundamental
compositor implementation.
Libweston is also intended for use by other project developers who want
to create new "Wayland WMs".
Details:
- All configuration and user interfaces will be outside of libweston.
This includes command line parsing, configuration files, and runtime
(graphical) UI.
- The hosting program (main executable) will be in full control of all
libweston options. Libweston should not have user settable options
that would work behind the hosting program's back, except perhaps
debugging features and such.
- Signal handling will be outside of libweston.
- Child process execution and management will be outside of libweston.
- The different backends (drm, fbdev, x11, etc) will be an internal
detail of libweston. Libweston will not support third party
backends. However, hosting programs need to handle
backend-specific configuration due to differences in behaviour and
available features.
- Renderers will be libweston internal details too, though again the
hosting program may affect the choice of renderer if the backend
allows, and maybe set renderer-specific options.
- plugin design ???
- xwayland ???
- weston-launch is still with libweston even though it can only launch
Weston and nothing else. We would like to allow it to launch any compositor,
but since it gives by design root access to input devices and DRM, how can
we restrict it to intended programs?
There are still many more details to be decided.
For packagers
-------------
Always build Weston with --with-cairo=image.
The Weston project is (will be) intended to be split into several
binary packages, each with its own dependencies. The maximal split
would be roughly like this:
- libweston (minimal dependencies):
+ headless backend
+ wayland backend
- gl-renderer (depends on GL libs etc.)
- drm-backend (depends on libdrm, libgbm, libudev, libinput, ...)
- x11-backend (depends of X11/xcb libs)
- xwayland (depends on X11/xcb libs)
- fbdev-backend (depends on libudev...)
- rdp-backend (depends on freerdp)
- weston (the executable, not parallel-installable):
+ desktop shell
+ ivi-shell
+ fullscreen shell
+ weston-info, weston-terminal, etc. we install by default
+ screen-share
- weston demos (not parallel-installable)
+ weston-simple-* programs
+ possibly all the programs we build but do not install by
default
- and possibly more...
Everything should be parallel-installable across libweston major
ABI-versions (libweston-1.so, libweston-2.so, etc.), except those
explicitly mentioned.
Weston's build may not sanely allow this yet, but this is the
intention.

View file

@ -1,76 +0,0 @@
# Releasing
To make a release of Weston, follow these steps.
0. Verify the test suites and codebase checks pass. All of the tests should
either pass or skip.
ninja -C build/ test
1. Verify that the wayland and wayland-protocols version dependencies are
correct, and that wayland-protocols has had a release with any needed
protocol updates.
2. Update the first stanza of `meson.build` to the intended version.
If the ABI has been broken, make sure `libweston_major` has been bumped since
the last release.
Then commit your changes:
RELEASE_NUMBER="x.y.z"
RELEASE_NAME="[alpha|beta|RC1|RC2|official|point]"
git status
git commit meson.build -m "build: bump to version $RELEASE_NUMBER for the $RELEASE_NAME release"
git push
3. Ensure that you have glab client installed locally and are authenticated to
freedesktop.org Gitlab instance. You can do that using the following:
glab auth login
Use gitlab web interface to generate a token either on Weston project or
on your profile (preferably) and use the token to authenticate. gitlab cli
client can be downloaded directly from Gitlab.com or it might be provided
directly by the distribution you're currently using to do the release.
4. 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 the Wayland repository:
https://gitlab.freedesktop.org/wayland/wayland/-/blob/main/release.sh
5. Compose the release announcements. The script will generate a
weston-x.y.z.announce file with a list of changes and tags. Prepend these
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.
6. PGP sign the release announcement and send it to
<wayland-devel@lists.freedesktop.org>.
7. Update `releases.html` in wayland.freedesktop.org with links to tarballs and
the release email URL.
Once satisfied:
git add releases.html releases/weston-${RELEASE_NUMBER}.tar.xz*
git commit -m "releases: add weston ${RELEASE_NUMBER} release"
git push
For x.y.0 releases, also create the release series x.y branch. The x.y branch
is for bug fixes and conservative changes to the x.y.0 release, and is where we
create x.y.z releases from. Creating the x.y branch opens up master for new
development and lets new development move on. We've done this both after the
x.y.0 release (to focus development on bug fixing for the x.y.1 release for a
little longer) or before the x.y.0 release (like we did with the 1.5.0 release,
to unblock master development early).
git branch x.y [sha]
git push origin x.y
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 `meson.build`
version is just whatever was most recently released from that branch.
For stable branches, we commit fixes to master first, then `git cherry-pick -x`
them back to the stable branch.

9
autogen.sh Executable file
View file

@ -0,0 +1,9 @@
#! /bin/sh
test -n "$srcdir" || srcdir=`dirname "$0"`
test -n "$srcdir" || srcdir=.
(
cd "$srcdir" &&
autoreconf --force -v --install
) || exit
test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"

View file

@ -32,14 +32,13 @@
#include <math.h> #include <math.h>
#include <assert.h> #include <assert.h>
#include <getopt.h> #include <getopt.h>
#include <errno.h>
#include <linux/input.h> #include <linux/input.h>
#include <wayland-client.h> #include <wayland-client.h>
#include "window.h" #include "window.h"
#include "shared/helpers.h" #include "shared/helpers.h"
#include <libweston/matrix.h> #include "shared/matrix.h"
/* Our points for the calibration must be not be on a line */ /* Our points for the calibration must be not be on a line */
static const struct { static const struct {
@ -117,11 +116,11 @@ finish_calibration (struct calibrator *calibrator)
*/ */
memset(&m, 0, sizeof(m)); memset(&m, 0, sizeof(m));
for (i = 0; i < (int)ARRAY_LENGTH(test_ratios); i++) { for (i = 0; i < (int)ARRAY_LENGTH(test_ratios); i++) {
m.M.col[0].el[i] = calibrator->tests[i].clicked_x; m.d[i] = calibrator->tests[i].clicked_x;
m.M.col[1].el[i] = calibrator->tests[i].clicked_y; m.d[i + 4] = calibrator->tests[i].clicked_y;
m.M.col[2].el[i] = 1; m.d[i + 8] = 1;
} }
m.M.col[3].el[3] = 1; m.d[15] = 1;
weston_matrix_invert(&inverse, &m); weston_matrix_invert(&inverse, &m);
@ -129,8 +128,8 @@ finish_calibration (struct calibrator *calibrator)
memset(&y_calib, 0, sizeof(y_calib)); memset(&y_calib, 0, sizeof(y_calib));
for (i = 0; i < (int)ARRAY_LENGTH(test_ratios); i++) { for (i = 0; i < (int)ARRAY_LENGTH(test_ratios); i++) {
x_calib.v.el[i] = calibrator->tests[i].drawn_x; x_calib.f[i] = calibrator->tests[i].drawn_x;
y_calib.v.el[i] = calibrator->tests[i].drawn_y; y_calib.f[i] = calibrator->tests[i].drawn_y;
} }
/* Multiples into the vector */ /* Multiples into the vector */
@ -138,8 +137,8 @@ finish_calibration (struct calibrator *calibrator)
weston_matrix_transform(&inverse, &y_calib); weston_matrix_transform(&inverse, &y_calib);
printf ("Calibration values: %f %f %f %f %f %f\n", printf ("Calibration values: %f %f %f %f %f %f\n",
x_calib.v.el[0], x_calib.v.el[1], x_calib.v.el[2], x_calib.f[0], x_calib.f[1], x_calib.f[2],
y_calib.v.el[0], y_calib.v.el[1], y_calib.v.el[2]); y_calib.f[0], y_calib.f[1], y_calib.f[2]);
exit(0); exit(0);
} }
@ -232,8 +231,6 @@ calibrator_create(struct display *display, bool enable_button)
calibrator->window = window_create(display); calibrator->window = window_create(display);
calibrator->widget = window_add_widget(calibrator->window, calibrator); calibrator->widget = window_add_widget(calibrator->window, calibrator);
window_set_title(calibrator->window, "Wayland calibrator"); window_set_title(calibrator->window, "Wayland calibrator");
window_set_appid(calibrator->window,
"org.freedesktop.weston.wayland-calibrator");
calibrator->display = display; calibrator->display = display;
calibrator->current_test = ARRAY_LENGTH(test_ratios) - 1; calibrator->current_test = ARRAY_LENGTH(test_ratios) - 1;
@ -293,8 +290,7 @@ main(int argc, char *argv[])
display = display_create(&argc, argv); display = display_create(&argc, argv);
if (display == NULL) { if (display == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }

View file

@ -34,7 +34,6 @@
#include <assert.h> #include <assert.h>
#include <unistd.h> #include <unistd.h>
#include <time.h> #include <time.h>
#include <errno.h>
#include <linux/input.h> #include <linux/input.h>
#include <wayland-client.h> #include <wayland-client.h>
@ -281,8 +280,6 @@ clickdot_create(struct display *display)
clickdot->window = window_create(display); clickdot->window = window_create(display);
clickdot->widget = window_frame_create(clickdot->window, clickdot); clickdot->widget = window_frame_create(clickdot->window, clickdot);
window_set_title(clickdot->window, "Wayland ClickDot"); window_set_title(clickdot->window, "Wayland ClickDot");
window_set_appid(clickdot->window,
"org.freedesktop.weston.wayland-clickdot");
clickdot->display = display; clickdot->display = display;
clickdot->buffer = NULL; clickdot->buffer = NULL;
@ -331,8 +328,7 @@ main(int argc, char *argv[])
display = display_create(&argc, argv); display = display_create(&argc, argv);
if (display == NULL) { if (display == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }

View file

@ -22,16 +22,12 @@
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
*/ */
/* cliptest: /* cliptest: for debugging calculate_edges() function.
* For debugging the quad clipper. An arbitrary quad (red) is transformed
* from global coordinate space to surface coordinate space and clipped to
* an axis-aligned rect (blue).
*
* controls: * controls:
* surface rect position: mouse left drag, keys: w a s d * clip box position: mouse left drag, keys: w a s d
* surface rect size: mouse right drag, keys: i j k l * clip box size: mouse right drag, keys: i j k l
* quad orientation: mouse wheel, keys: n m * surface orientation: mouse wheel, keys: n m
* quad transform disable: key: r * surface transform disable key: r
*/ */
#include "config.h" #include "config.h"
@ -49,108 +45,145 @@
#include <cairo.h> #include <cairo.h>
#include <float.h> #include <float.h>
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <linux/input.h> #include <linux/input.h>
#include <wayland-client.h> #include <wayland-client.h>
#include "libweston/matrix.h"
#include "libweston/vertex-clipping.h" #include "libweston/vertex-clipping.h"
#include "shared/helpers.h"
#include "shared/xalloc.h" #include "shared/xalloc.h"
#include "window.h" #include "window.h"
typedef float GLfloat; typedef float GLfloat;
struct geometry { struct geometry {
pixman_box32_t surf; pixman_box32_t clip;
pixman_box32_t quad; pixman_box32_t surf;
float s; /* sin phi */ float s; /* sin phi */
float c; /* cos phi */ float c; /* cos phi */
float phi; float phi;
bool axis_aligned;
};
struct weston_surface {
}; };
struct weston_view { struct weston_view {
struct weston_surface *surface; struct {
int enabled;
} transform;
struct geometry *geometry; struct geometry *geometry;
}; };
static void static void
weston_view_from_global_float(struct weston_view *view, weston_view_to_global_float(struct weston_view *view,
float x, float y, float *sx, float *sy) float sx, float sy, float *x, float *y)
{ {
struct geometry *g = view->geometry; struct geometry *g = view->geometry;
/* pure rotation around origin by sine and cosine */ /* pure rotation around origin by sine and cosine */
*sx = g->c * x + g->s * y; *x = g->c * sx + g->s * sy;
*sy = -g->s * x + g->c * y; *y = -g->s * sx + g->c * sy;
}
static struct weston_coord_surface
weston_coord_global_to_surface(struct weston_view *view, struct weston_coord_global g_pos)
{
float sx, sy;
struct weston_coord_surface pos;
weston_view_from_global_float(view, g_pos.c.x, g_pos.c.y, &sx, &sy);
pos.c = weston_coord(sx, sy);
return pos;
} }
/* ---------------------- copied begins -----------------------*/ /* ---------------------- copied begins -----------------------*/
/* Keep this in sync with what is in gl-renderer.c! */ /* Keep this in sync with what is in gl-renderer.c! */
static void #define max(a, b) (((a) > (b)) ? (a) : (b))
global_to_surface(pixman_box32_t *rect, struct weston_view *ev, #define min(a, b) (((a) > (b)) ? (b) : (a))
struct clipper_vertex polygon[4])
{
struct weston_coord_global rect_g[4] = {
{ .c = weston_coord(rect->x1, rect->y1) },
{ .c = weston_coord(rect->x2, rect->y1) },
{ .c = weston_coord(rect->x2, rect->y2) },
{ .c = weston_coord(rect->x1, rect->y2) },
};
struct weston_coord rect_s;
int i;
for (i = 0; i < 4; i++) { /*
rect_s = weston_coord_global_to_surface(ev, rect_g[i]).c; * Compute the boundary vertices of the intersection of the global coordinate
polygon[i].x = (float)rect_s.x; * aligned rectangle 'rect', and an arbitrary quadrilateral produced from
polygon[i].y = (float)rect_s.y; * 'surf_rect' when transformed from surface coordinates into global coordinates.
* The vertices are written to 'ex' and 'ey', and the return value is the
* number of vertices. Vertices are produced in clockwise winding order.
* Guarantees to produce either zero vertices, or 3-8 vertices with non-zero
* polygon area.
*/
static int
calculate_edges(struct weston_view *ev, pixman_box32_t *rect,
pixman_box32_t *surf_rect, GLfloat *ex, GLfloat *ey)
{
struct clip_context ctx;
int i, n;
GLfloat min_x, max_x, min_y, max_y;
struct polygon8 surf = {
{ surf_rect->x1, surf_rect->x2, surf_rect->x2, surf_rect->x1 },
{ surf_rect->y1, surf_rect->y1, surf_rect->y2, surf_rect->y2 },
4
};
ctx.clip.x1 = rect->x1;
ctx.clip.y1 = rect->y1;
ctx.clip.x2 = rect->x2;
ctx.clip.y2 = rect->y2;
/* transform surface to screen space: */
for (i = 0; i < surf.n; i++)
weston_view_to_global_float(ev, surf.x[i], surf.y[i],
&surf.x[i], &surf.y[i]);
/* find bounding box: */
min_x = max_x = surf.x[0];
min_y = max_y = surf.y[0];
for (i = 1; i < surf.n; i++) {
min_x = min(min_x, surf.x[i]);
max_x = max(max_x, surf.x[i]);
min_y = min(min_y, surf.y[i]);
max_y = max(max_y, surf.y[i]);
} }
/* First, simple bounding box check to discard early transformed
* surface rects that do not intersect with the clip region:
*/
if ((min_x >= ctx.clip.x2) || (max_x <= ctx.clip.x1) ||
(min_y >= ctx.clip.y2) || (max_y <= ctx.clip.y1))
return 0;
/* Simple case, bounding box edges are parallel to surface edges,
* there will be only four edges. We just need to clip the surface
* vertices to the clip rect bounds:
*/
if (!ev->transform.enabled)
return clip_simple(&ctx, &surf, ex, ey);
/* Transformed case: use a general polygon clipping algorithm to
* clip the surface rectangle with each side of 'rect'.
* The algorithm is Sutherland-Hodgman, as explained in
* http://www.codeguru.com/cpp/misc/misc/graphics/article.php/c8965/Polygon-Clipping.htm
* but without looking at any of that code.
*/
n = clip_transformed(&ctx, &surf, ex, ey);
if (n < 3)
return 0;
return n;
} }
/* ---------------------- copied ends -----------------------*/ /* ---------------------- copied ends -----------------------*/
static void static void
geometry_set_phi(struct geometry *g, float phi) geometry_set_phi(struct geometry *g, float phi)
{ {
float integer;
g->phi = phi; g->phi = phi;
g->s = sin(phi); g->s = sin(phi);
g->c = cos(phi); g->c = cos(phi);
g->axis_aligned = fabs(modff(g->c, &integer)) < 0.0001f;
} }
static void static void
geometry_init(struct geometry *g) geometry_init(struct geometry *g)
{ {
g->surf.x1 = -50; g->clip.x1 = -50;
g->surf.y1 = -50; g->clip.y1 = -50;
g->surf.x2 = -10; g->clip.x2 = -10;
g->surf.y2 = -10; g->clip.y2 = -10;
g->quad.x1 = -20; g->surf.x1 = -20;
g->quad.y1 = -20; g->surf.y1 = -20;
g->quad.x2 = 20; g->surf.x2 = 20;
g->quad.y2 = 20; g->surf.y2 = 20;
geometry_set_phi(g, 0.0); geometry_set_phi(g, 0.0);
} }
@ -172,36 +205,35 @@ struct cliptest {
struct ui_state ui; struct ui_state ui;
struct geometry geometry; struct geometry geometry;
struct weston_surface surface;
struct weston_view view; struct weston_view view;
}; };
static void static void
draw_polygon_closed(cairo_t *cr, struct clipper_vertex *pos, int n) draw_polygon_closed(cairo_t *cr, GLfloat *x, GLfloat *y, int n)
{ {
int i; int i;
cairo_move_to(cr, pos[0].x, pos[0].y); cairo_move_to(cr, x[0], y[0]);
for (i = 1; i < n; i++) for (i = 1; i < n; i++)
cairo_line_to(cr, pos[i].x, pos[i].y); cairo_line_to(cr, x[i], y[i]);
cairo_line_to(cr, pos[0].x, pos[0].y); cairo_line_to(cr, x[0], y[0]);
} }
static void static void
draw_polygon_labels(cairo_t *cr, struct clipper_vertex *pos, int n) draw_polygon_labels(cairo_t *cr, GLfloat *x, GLfloat *y, int n)
{ {
char str[16]; char str[16];
int i; int i;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
snprintf(str, 16, "%d", i); snprintf(str, 16, "%d", i);
cairo_move_to(cr, pos[i].x, pos[i].y); cairo_move_to(cr, x[i], y[i]);
cairo_show_text(cr, str); cairo_show_text(cr, str);
} }
} }
static void static void
draw_coordinates(cairo_t *cr, double ox, double oy, struct clipper_vertex *pos, int n) draw_coordinates(cairo_t *cr, double ox, double oy, GLfloat *x, GLfloat *y, int n)
{ {
char str[64]; char str[64];
int i; int i;
@ -209,7 +241,7 @@ draw_coordinates(cairo_t *cr, double ox, double oy, struct clipper_vertex *pos,
cairo_font_extents(cr, &ext); cairo_font_extents(cr, &ext);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
snprintf(str, 64, "%d: %14.9f, %14.9f", i, pos[i].x, pos[i].y); snprintf(str, 64, "%d: %14.9f, %14.9f", i, x[i], y[i]);
cairo_move_to(cr, ox, oy + ext.height * (i + 1)); cairo_move_to(cr, ox, oy + ext.height * (i + 1));
cairo_show_text(cr, str); cairo_show_text(cr, str);
} }
@ -218,50 +250,50 @@ draw_coordinates(cairo_t *cr, double ox, double oy, struct clipper_vertex *pos,
static void static void
draw_box(cairo_t *cr, pixman_box32_t *box, struct weston_view *view) draw_box(cairo_t *cr, pixman_box32_t *box, struct weston_view *view)
{ {
struct clipper_vertex pos[4]; GLfloat x[4], y[4];
if (view) { if (view) {
weston_view_from_global_float(view, box->x1, box->y1, &pos[0].x, &pos[0].y); weston_view_to_global_float(view, box->x1, box->y1, &x[0], &y[0]);
weston_view_from_global_float(view, box->x2, box->y1, &pos[1].x, &pos[1].y); weston_view_to_global_float(view, box->x2, box->y1, &x[1], &y[1]);
weston_view_from_global_float(view, box->x2, box->y2, &pos[2].x, &pos[2].y); weston_view_to_global_float(view, box->x2, box->y2, &x[2], &y[2]);
weston_view_from_global_float(view, box->x1, box->y2, &pos[3].x, &pos[3].y); weston_view_to_global_float(view, box->x1, box->y2, &x[3], &y[3]);
} else { } else {
pos[0].x = box->x1; pos[0].y = box->y1; x[0] = box->x1; y[0] = box->y1;
pos[1].x = box->x2; pos[1].y = box->y1; x[1] = box->x2; y[1] = box->y1;
pos[2].x = box->x2; pos[2].y = box->y2; x[2] = box->x2; y[2] = box->y2;
pos[3].x = box->x1; pos[3].y = box->y2; x[3] = box->x1; y[3] = box->y2;
} }
draw_polygon_closed(cr, pos, 4); draw_polygon_closed(cr, x, y, 4);
} }
static void static void
draw_geometry(cairo_t *cr, struct weston_view *view, draw_geometry(cairo_t *cr, struct weston_view *view,
struct clipper_vertex *v, int n, struct clipper_quad *quad) GLfloat *ex, GLfloat *ey, int n)
{ {
struct geometry *g = view->geometry; struct geometry *g = view->geometry;
float cx, cy; float cx, cy;
draw_box(cr, &g->quad, view); draw_box(cr, &g->surf, view);
cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.4); cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.4);
cairo_fill(cr); cairo_fill(cr);
weston_view_from_global_float(view, g->quad.x1 - 4, g->quad.y1 - 4, &cx, &cy); weston_view_to_global_float(view, g->surf.x1 - 4, g->surf.y1 - 4, &cx, &cy);
cairo_arc(cr, cx, cy, 1.5, 0.0, 2.0 * M_PI); cairo_arc(cr, cx, cy, 1.5, 0.0, 2.0 * M_PI);
if (!quad->axis_aligned) if (view->transform.enabled == 0)
cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.8); cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.8);
cairo_fill(cr); cairo_fill(cr);
draw_box(cr, &g->surf, NULL); draw_box(cr, &g->clip, NULL);
cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 0.4); cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 0.4);
cairo_fill(cr); cairo_fill(cr);
if (n) { if (n) {
draw_polygon_closed(cr, v, n); draw_polygon_closed(cr, ex, ey, n);
cairo_set_source_rgb(cr, 0.0, 1.0, 0.0); cairo_set_source_rgb(cr, 0.0, 1.0, 0.0);
cairo_stroke(cr); cairo_stroke(cr);
cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 0.5); cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 0.5);
draw_polygon_labels(cr, v, n); draw_polygon_labels(cr, ex, ey, n);
} }
} }
@ -273,13 +305,11 @@ redraw_handler(struct widget *widget, void *data)
struct rectangle allocation; struct rectangle allocation;
cairo_t *cr; cairo_t *cr;
cairo_surface_t *surface; cairo_surface_t *surface;
struct clipper_quad quad; GLfloat ex[8];
struct clipper_vertex transformed_v[4], v[8]; GLfloat ey[8];
int n; int n;
global_to_surface(&g->quad, &cliptest->view, transformed_v); n = calculate_edges(&cliptest->view, &g->clip, &g->surf, ex, ey);
clipper_quad_init(&quad, transformed_v, g->axis_aligned);
n = clipper_quad_clip_box32(&quad, &g->surf, v);
widget_get_allocation(cliptest->widget, &allocation); widget_get_allocation(cliptest->widget, &allocation);
@ -310,10 +340,10 @@ redraw_handler(struct widget *widget, void *data)
cairo_scale(cr, 4.0, 4.0); cairo_scale(cr, 4.0, 4.0);
cairo_set_line_width(cr, 0.5); cairo_set_line_width(cr, 0.5);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_BEVEL); cairo_set_line_join(cr, CAIRO_LINE_JOIN_BEVEL);
cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD); CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 5.0); cairo_set_font_size(cr, 5.0);
draw_geometry(cr, &cliptest->view, v, n, &quad); draw_geometry(cr, &cliptest->view, ex, ey, n);
cairo_pop_group_to_source(cr); cairo_pop_group_to_source(cr);
cairo_paint(cr); cairo_paint(cr);
@ -321,7 +351,7 @@ redraw_handler(struct widget *widget, void *data)
cairo_select_font_face(cr, "monospace", CAIRO_FONT_SLANT_NORMAL, cairo_select_font_face(cr, "monospace", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL); CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cr, 12.0); cairo_set_font_size(cr, 12.0);
draw_coordinates(cr, 10.0, 10.0, v, n); draw_coordinates(cr, 10.0, 10.0, ex, ey, n);
cairo_destroy(cr); cairo_destroy(cr);
@ -346,12 +376,12 @@ motion_handler(struct widget *widget, struct input *input,
switch (ui->button) { switch (ui->button) {
case BTN_LEFT: case BTN_LEFT:
geom->surf.x1 = ref->surf.x1 + dx; geom->clip.x1 = ref->clip.x1 + dx;
geom->surf.y1 = ref->surf.y1 + dy; geom->clip.y1 = ref->clip.y1 + dy;
/* fall through */ /* fall through */
case BTN_RIGHT: case BTN_RIGHT:
geom->surf.x2 = ref->surf.x2 + dx; geom->clip.x2 = ref->clip.x2 + dx;
geom->surf.y2 = ref->surf.y2 + dy; geom->clip.y2 = ref->clip.y2 + dy;
break; break;
default: default:
return CURSOR_LEFT_PTR; return CURSOR_LEFT_PTR;
@ -392,6 +422,7 @@ axis_handler(struct widget *widget, struct input *input, uint32_t time,
geometry_set_phi(geom, geom->phi + geometry_set_phi(geom, geom->phi +
(M_PI / 12.0) * wl_fixed_to_double(value)); (M_PI / 12.0) * wl_fixed_to_double(value));
cliptest->view.transform.enabled = 1;
widget_schedule_redraw(cliptest->widget); widget_schedule_redraw(cliptest->widget);
} }
@ -412,41 +443,44 @@ key_handler(struct window *window, struct input *input, uint32_t time,
display_exit(cliptest->display); display_exit(cliptest->display);
return; return;
case XKB_KEY_w: case XKB_KEY_w:
g->surf.y1 -= 1; g->clip.y1 -= 1;
g->surf.y2 -= 1; g->clip.y2 -= 1;
break; break;
case XKB_KEY_a: case XKB_KEY_a:
g->surf.x1 -= 1; g->clip.x1 -= 1;
g->surf.x2 -= 1; g->clip.x2 -= 1;
break; break;
case XKB_KEY_s: case XKB_KEY_s:
g->surf.y1 += 1; g->clip.y1 += 1;
g->surf.y2 += 1; g->clip.y2 += 1;
break; break;
case XKB_KEY_d: case XKB_KEY_d:
g->surf.x1 += 1; g->clip.x1 += 1;
g->surf.x2 += 1; g->clip.x2 += 1;
break; break;
case XKB_KEY_i: case XKB_KEY_i:
g->surf.y2 -= 1; g->clip.y2 -= 1;
break; break;
case XKB_KEY_j: case XKB_KEY_j:
g->surf.x2 -= 1; g->clip.x2 -= 1;
break; break;
case XKB_KEY_k: case XKB_KEY_k:
g->surf.y2 += 1; g->clip.y2 += 1;
break; break;
case XKB_KEY_l: case XKB_KEY_l:
g->surf.x2 += 1; g->clip.x2 += 1;
break; break;
case XKB_KEY_n: case XKB_KEY_n:
geometry_set_phi(g, g->phi + (M_PI / 24.0)); geometry_set_phi(g, g->phi + (M_PI / 24.0));
cliptest->view.transform.enabled = 1;
break; break;
case XKB_KEY_m: case XKB_KEY_m:
geometry_set_phi(g, g->phi - (M_PI / 24.0)); geometry_set_phi(g, g->phi - (M_PI / 24.0));
cliptest->view.transform.enabled = 1;
break; break;
case XKB_KEY_r: case XKB_KEY_r:
geometry_set_phi(g, 0.0); geometry_set_phi(g, 0.0);
cliptest->view.transform.enabled = 0;
break; break;
default: default:
return; return;
@ -479,15 +513,14 @@ cliptest_create(struct display *display)
struct cliptest *cliptest; struct cliptest *cliptest;
cliptest = xzalloc(sizeof *cliptest); cliptest = xzalloc(sizeof *cliptest);
cliptest->view.surface = &cliptest->surface;
cliptest->view.geometry = &cliptest->geometry; cliptest->view.geometry = &cliptest->geometry;
cliptest->view.transform.enabled = 0;
geometry_init(&cliptest->geometry); geometry_init(&cliptest->geometry);
geometry_init(&cliptest->ui.geometry); geometry_init(&cliptest->ui.geometry);
cliptest->window = window_create(display); cliptest->window = window_create(display);
cliptest->widget = window_frame_create(cliptest->window, cliptest); cliptest->widget = window_frame_create(cliptest->window, cliptest);
window_set_title(cliptest->window, "cliptest"); window_set_title(cliptest->window, "cliptest");
window_set_appid(cliptest->window, "org.freedesktop.weston.cliptest");
cliptest->display = display; cliptest->display = display;
window_set_user_data(cliptest->window, cliptest); window_set_user_data(cliptest->window, cliptest);
@ -531,36 +564,32 @@ read_timer(void)
static int static int
benchmark(void) benchmark(void)
{ {
struct weston_surface surface;
struct weston_view view; struct weston_view view;
struct geometry geom; struct geometry geom;
struct clipper_quad quad; GLfloat ex[8], ey[8];
struct clipper_vertex transformed_v[4], v[8];
int i; int i;
double t; double t;
const int N = 1000000; const int N = 1000000;
geom.surf.x1 = -19; geom.clip.x1 = -19;
geom.surf.y1 = -19; geom.clip.y1 = -19;
geom.surf.x2 = 19; geom.clip.x2 = 19;
geom.surf.y2 = 19; geom.clip.y2 = 19;
geom.quad.x1 = -20; geom.surf.x1 = -20;
geom.quad.y1 = -20; geom.surf.y1 = -20;
geom.quad.x2 = 20; geom.surf.x2 = 20;
geom.quad.y2 = 20; geom.surf.y2 = 20;
geometry_set_phi(&geom, 0.0); geometry_set_phi(&geom, 0.0);
view.surface = &surface; view.transform.enabled = 1;
view.geometry = &geom; view.geometry = &geom;
reset_timer(); reset_timer();
for (i = 0; i < N; i++) { for (i = 0; i < N; i++) {
geometry_set_phi(&geom, (float)i / 360.0f); geometry_set_phi(&geom, (float)i / 360.0f);
global_to_surface(&geom.quad, &view, transformed_v); calculate_edges(&view, &geom.clip, &geom.surf, ex, ey);
clipper_quad_init(&quad, transformed_v, geom.axis_aligned);
clipper_quad_clip_box32(&quad, &geom.surf, v);
} }
t = read_timer(); t = read_timer();
@ -592,8 +621,7 @@ main(int argc, char *argv[])
d = display_create(&argc, argv); d = display_create(&argc, argv);
if (d == NULL) { if (d == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }

View file

@ -1,610 +0,0 @@
/*
* Copyright (C) 2024 SUSE Software Solutions Germany GmbH
*
* 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.
*/
#include "config.h"
#include <assert.h>
#include <errno.h>
#include "color-management-v1-client-protocol.h"
#include "shared/helpers.h"
#include "shared/xalloc.h"
#include "single-pixel-buffer-v1-client-protocol.h"
#include "viewporter-client-protocol.h"
#include "window.h"
enum image_description_status {
IMAGE_DESCRIPTION_NOT_CREATED = 0,
IMAGE_DESCRIPTION_READY,
IMAGE_DESCRIPTION_FAILED,
};
struct pixel_color {
uint32_t r;
uint32_t g;
uint32_t b;
uint32_t a;
};
struct color {
struct display *display;
struct window *window;
struct widget *parent_widget;
struct widget *widget;
struct wp_color_manager_v1 *color_manager;
struct wp_color_management_surface_v1 *color_surface;
struct wp_single_pixel_buffer_manager_v1 *single_pixel_manager;
struct wp_viewporter *viewporter;
struct wp_viewport *viewport;
struct pixel_color pixel_color;
bool unmanaged;
enum wp_color_manager_v1_primaries primaries;
enum wp_color_manager_v1_transfer_function transfer_function;
float min_lum;
float max_lum;
float ref_lum;
uint32_t supported_color_features;
uint32_t supported_rendering_intents;
uint32_t supported_primaries_named;
uint32_t supported_tf_named;
};
struct valid_enum {
const char *name;
uint32_t value;
};
static bool opt_help = false;
static uint32_t opt_width = 250;
static uint32_t opt_height = 250;
static const char *opt_r = NULL;
static const char *opt_g = NULL;
static const char *opt_b = NULL;
static const char *opt_a = NULL;
static bool opt_unmanaged = false;
static const char *opt_primaries = NULL;
static const char *opt_transfer_function = NULL;
static const char *opt_min_lum = NULL;
static const char *opt_max_lum = NULL;
static const char *opt_ref_lum = NULL;
static const struct weston_option cli_options[] = {
{ WESTON_OPTION_BOOLEAN, "help", 0, &opt_help },
{ WESTON_OPTION_UNSIGNED_INTEGER, "width", 'w', &opt_width },
{ WESTON_OPTION_UNSIGNED_INTEGER, "height", 'h', &opt_height },
{ WESTON_OPTION_STRING, 0, 'R', &opt_r },
{ WESTON_OPTION_STRING, 0, 'G', &opt_g },
{ WESTON_OPTION_STRING, 0, 'B', &opt_b },
{ WESTON_OPTION_STRING, 0, 'A', &opt_a },
{ WESTON_OPTION_BOOLEAN, "unmanaged", 'u', &opt_unmanaged },
{ WESTON_OPTION_STRING, "primaries", 'p', &opt_primaries },
{ WESTON_OPTION_STRING, "transfer-function", 't', &opt_transfer_function },
{ WESTON_OPTION_STRING, "min-lum", 'm', &opt_min_lum },
{ WESTON_OPTION_STRING, "max-lum", 'M', &opt_max_lum },
{ WESTON_OPTION_STRING, "ref-lum", 'r', &opt_ref_lum },
};
static const struct valid_enum valid_primaries[] = {
{ "srgb", WP_COLOR_MANAGER_V1_PRIMARIES_SRGB },
{ "bt2020", WP_COLOR_MANAGER_V1_PRIMARIES_BT2020 },
};
static const struct valid_enum valid_transfer_functions[] = {
{ "srgb", WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB },
{ "pq", WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ },
{ "linear", WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR },
};
static bool
validate_color(const char *c, uint32_t *dest, uint32_t fallback)
{
char *end;
double value;
if (!c) {
*dest = fallback;
return true;
}
value = strtod(c, &end);
if (value < 0.0 || value > 1.0 || *end != '\0') {
fprintf(stderr, "Validating color failed, it should be between 0.0 and 1.0\n");
return false;
}
*dest = value * UINT32_MAX;
return true;
}
static bool
validate_option(const struct color *color,
const char *option, uint32_t *dest,
const struct valid_enum *valid_options,
int count, uint32_t fallback)
{
int i;
if (color->unmanaged && option) {
fprintf(stderr, "Option '%s' not valid in unmanaged mode\n", option);
return false;
}
if (!option) {
*dest = fallback;
return true;
}
for (i = 0; i < count; i++) {
if (strcmp(valid_options[i].name, option) == 0) {
*dest = valid_options[i].value;
return true;
}
}
fprintf(stderr, "Validating option '%s' failed, valid options:\n", option);
for (i = 0; i < count; i++)
fprintf(stderr, "'%s' ", valid_options[i].name);
fprintf(stderr, "\n");
return false;
}
static bool
validate_luminance(const struct color *color,
const char *c, float *dest, float fallback)
{
char *end;
float value;
if (color->unmanaged && c) {
fprintf(stderr, "Luminance not valid in unmanaged mode.\n");
return false;
}
if (!c) {
*dest = fallback;
return true;
}
value = strtof(c, &end);
if (value < 0.f || value > 10000.f || *end != '\0') {
fprintf(stderr, "Validating luminance failed, it should be between 0 and 10,000\n");
return false;
}
*dest = value;
return true;
}
static bool
validate_options(struct color *color)
{
color->unmanaged = opt_unmanaged;
return validate_color(opt_r, &color->pixel_color.r, 0) &&
validate_color(opt_g, &color->pixel_color.g, 0) &&
validate_color(opt_b, &color->pixel_color.b, 0) &&
validate_color(opt_a, &color->pixel_color.a, UINT32_MAX) &&
validate_option(color, opt_primaries, &color->primaries,
valid_primaries,
ARRAY_LENGTH(valid_primaries),
WP_COLOR_MANAGER_V1_PRIMARIES_SRGB) &&
validate_option(color, opt_transfer_function, &color->transfer_function,
valid_transfer_functions,
ARRAY_LENGTH(valid_transfer_functions),
WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB) &&
validate_luminance(color, opt_min_lum, &color->min_lum, -1.f) &&
validate_luminance(color, opt_max_lum, &color->max_lum, -1.f) &&
validate_luminance(color, opt_ref_lum, &color->ref_lum, -1.f);
}
static void
usage(const char *program_name, int exit_code)
{
unsigned int i;
fprintf(stderr, "Usage: %s [OPTIONS]\n", program_name);
fprintf(stderr, " --help\n");
fprintf(stderr, " --width or -w\n");
fprintf(stderr, " --height or -h\n");
fprintf(stderr, " -R (0.0 to 1.0)\n");
fprintf(stderr, " -G (0.0 to 1.0)\n");
fprintf(stderr, " -B (0.0 to 1.0)\n");
fprintf(stderr, " -A (0.0 to 1.0)\n");
fprintf(stderr, " Mode of operation may be:\n");
fprintf(stderr, " --unmanaged or -u: do not use color-management\n");
fprintf(stderr, " Or use the following:\n");
fprintf(stderr, " --primaries or -p:");
fprintf(stderr, "\n ");
for (i = 0; i < ARRAY_LENGTH(valid_primaries); i++)
fprintf(stderr, " '%s'", valid_primaries[i].name);
fprintf(stderr, "\n");
fprintf(stderr, " --transfer-function or -t:");
fprintf(stderr, "\n ");
for (i = 0; i < ARRAY_LENGTH(valid_transfer_functions); i++)
fprintf(stderr, " '%s'", valid_transfer_functions[i].name);
fprintf(stderr, "\n");
fprintf(stderr, " --min-lum or -m (0.0 to 10000.0)\n");
fprintf(stderr, " --max-lum or -M (0.0 to 10000.0)\n");
fprintf(stderr, " --ref-lum or -r (0.0 to 10000.0)\n");
exit(exit_code);
}
static void
supported_intent(void *data, struct wp_color_manager_v1 *wp_color_manager_v1,
uint32_t render_intent)
{
struct color *color = data;
color->supported_rendering_intents |= 1 << render_intent;
}
static void
supported_feature(void *data, struct wp_color_manager_v1 *wp_color_manager_v1,
uint32_t feature)
{
struct color *color = data;
color->supported_color_features |= 1 << feature;
}
static void
supported_tf_named(void *data, struct wp_color_manager_v1 *wp_color_manager_v1,
uint32_t tf)
{
struct color *color = data;
color->supported_tf_named |= 1 << tf;
}
static void
supported_primaries_named(void *data,
struct wp_color_manager_v1 *wp_color_manager_v1,
uint32_t primaries)
{
struct color *color = data;
color->supported_primaries_named |= 1 << primaries;
}
static void
done(void *data, struct wp_color_manager_v1 *wp_color_manager_v1)
{
}
static const struct wp_color_manager_v1_listener color_manager_listener = {
supported_intent,
supported_feature,
supported_tf_named,
supported_primaries_named,
done,
};
static void
global_handler(struct display *display, uint32_t name,
const char *interface, uint32_t version, void *data)
{
struct color *color = data;
struct wl_surface *surface = widget_get_wl_surface(color->widget);
if (strcmp(interface, wp_single_pixel_buffer_manager_v1_interface.name) == 0) {
color->single_pixel_manager =
display_bind(display, name,
&wp_single_pixel_buffer_manager_v1_interface, 1);
} else if (strcmp(interface, wp_viewporter_interface.name) == 0) {
color->viewporter = display_bind(display, name,
&wp_viewporter_interface, 1);
color->viewport = wp_viewporter_get_viewport(color->viewporter, surface);
}
if (color->unmanaged)
return;
if (strcmp(interface, wp_color_manager_v1_interface.name) == 0) {
color->color_manager = display_bind(display, name,
&wp_color_manager_v1_interface, 1);
color->color_surface = wp_color_manager_v1_get_surface(color->color_manager,
surface);
wp_color_manager_v1_add_listener(color->color_manager,
&color_manager_listener, color);
}
}
static bool
check_color_requirements(struct color *color)
{
if (!color->color_manager) {
fprintf(stderr, "The compositor doesn't expose %s\n",
wp_color_manager_v1_interface.name);
return false;
}
if (!(color->supported_color_features & (1 << WP_COLOR_MANAGER_V1_FEATURE_PARAMETRIC))) {
fprintf(stderr, "The color manager doesn't support the parametric creator\n");
return false;
}
if (!(color->supported_primaries_named & (1 << color->primaries))) {
fprintf(stderr, "The color manager doesn't support the primaries name\n");
return false;
}
if (!(color->supported_tf_named & (1 << color->transfer_function))) {
fprintf(stderr, "The color manager doesn't support the transfer function\n");
return false;
}
if (!(color->supported_rendering_intents & (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL))) {
fprintf(stderr, "The color manager doesn't support perceptual render intent\n");
return false;
}
if (color->min_lum != -1.f || color->max_lum != -1.f || color->ref_lum != -1.f) {
if (!(color->supported_color_features & (1 << WP_COLOR_MANAGER_V1_FEATURE_SET_LUMINANCES))) {
fprintf(stderr, "The color manager doesn't support setting luminances\n");
return false;
}
if (color->min_lum == -1.f || color->max_lum == -1.f || color->ref_lum == -1.f) {
fprintf(stderr, "To set the luminances it is required min-lum, max-lum and ref-lum\n");
return false;
}
}
return true;
}
static void
color_destroy(struct color *color)
{
if (color->color_surface)
wp_color_management_surface_v1_destroy(color->color_surface);
if (color->color_manager)
wp_color_manager_v1_destroy(color->color_manager);
if (color->single_pixel_manager)
wp_single_pixel_buffer_manager_v1_destroy(color->single_pixel_manager);
if (color->viewport)
wp_viewport_destroy(color->viewport);
if (color->viewporter)
wp_viewporter_destroy(color->viewporter);
if (color->widget)
widget_destroy(color->widget);
if (color->parent_widget)
widget_destroy(color->parent_widget);
if (color->window)
window_destroy(color->window);
if (color->display)
display_destroy(color->display);
free(color);
}
static void
resize_handler(struct widget *parent_widget, int32_t width, int32_t height, void *data)
{
struct color *color = data;
struct rectangle allocation;
struct wl_surface *surface = widget_get_wl_surface(color->widget);
struct wl_subsurface *subsurface = widget_get_wl_subsurface(color->widget);
widget_get_allocation(parent_widget, &allocation);
wl_subsurface_set_position(subsurface, allocation.x, allocation.y);
wp_viewport_set_destination(color->viewport, width, height);
wl_surface_commit(surface);
}
static void
set_empty_input_region(struct color *color, struct widget *widget)
{
struct wl_region *region;
struct wl_compositor *compositor;
struct wl_surface *surface = widget_get_wl_surface(widget);
compositor = display_get_compositor(color->display);
region = wl_compositor_create_region(compositor);
wl_surface_set_input_region(surface, region);
wl_region_destroy(region);
}
static void
buffer_release(void *data, struct wl_buffer *buffer)
{
wl_buffer_destroy(buffer);
}
static const struct wl_buffer_listener buffer_listener = {
buffer_release
};
static void
set_single_pixel(struct color *color, struct widget *widget)
{
struct wl_surface *surface = widget_get_wl_surface(widget);
struct wl_buffer *buffer =
wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(color->single_pixel_manager,
color->pixel_color.r,
color->pixel_color.g,
color->pixel_color.b,
color->pixel_color.a);
wl_buffer_add_listener(buffer, &buffer_listener, NULL);
wl_surface_attach(surface, buffer, 0, 0);
}
static void
image_description_failed(void *data,
struct wp_image_description_v1 *wp_image_description_v1,
uint32_t cause, const char *msg)
{
enum image_description_status *image_desc_status = data;
fprintf(stderr, "Failed to create image description: %u - %s\n",
cause, msg);
*image_desc_status = IMAGE_DESCRIPTION_FAILED;
}
static void
image_description_ready(void *data, struct wp_image_description_v1 *wp_image_description_v1,
uint32_t identity)
{
enum image_description_status *image_desc_status = data;
*image_desc_status = IMAGE_DESCRIPTION_READY;
}
static const struct wp_image_description_v1_listener image_description_listener = {
image_description_failed,
image_description_ready,
};
static struct wp_image_description_v1 *
create_image_description(struct color *color, uint32_t primaries_named, uint32_t tf_named)
{
struct wp_image_description_creator_params_v1 *params_creator;
struct wp_image_description_v1 *image_description;
enum image_description_status image_desc_status = IMAGE_DESCRIPTION_NOT_CREATED;
int ret = 0;
params_creator = wp_color_manager_v1_create_parametric_creator(color->color_manager);
wp_image_description_creator_params_v1_set_primaries_named(params_creator, primaries_named);
wp_image_description_creator_params_v1_set_tf_named(params_creator, tf_named);
if (color->min_lum != -1 && color->max_lum != -1 && color->ref_lum != -1)
wp_image_description_creator_params_v1_set_luminances(params_creator,
color->min_lum * 10000,
color->max_lum,
color->ref_lum);
image_description = wp_image_description_creator_params_v1_create(params_creator);
wp_image_description_v1_add_listener(image_description,
&image_description_listener,
&image_desc_status);
while (ret != -1 && image_desc_status == IMAGE_DESCRIPTION_NOT_CREATED)
ret = wl_display_dispatch(display_get_display(color->display));
if (ret == -1) {
wp_image_description_v1_destroy(image_description);
fprintf(stderr, "Error when creating the image description: %s\n", strerror(errno));
return NULL;
}
if (image_desc_status == IMAGE_DESCRIPTION_FAILED) {
wp_image_description_v1_destroy(image_description);
return NULL;
}
assert(image_desc_status == IMAGE_DESCRIPTION_READY);
return image_description;
}
static bool
set_image_description(struct color *color, struct widget *widget)
{
struct wp_image_description_v1 *image_description;
image_description =
create_image_description(color,
color->primaries,
color->transfer_function);
if (!image_description)
return false;
wp_color_management_surface_v1_set_image_description(
color->color_surface,
image_description,
WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL);
wp_image_description_v1_destroy(image_description);
return true;
}
int
main(int argc, char *argv[])
{
struct color *color;
if (parse_options(cli_options, ARRAY_LENGTH(cli_options), &argc, argv) > 1)
usage(argv[0], EXIT_FAILURE);
if (opt_help)
usage(argv[0], EXIT_SUCCESS);
color = xzalloc(sizeof *color);
if (!validate_options(color)) {
color_destroy(color);
exit(EXIT_FAILURE);
}
color->display = display_create(&argc, argv);
if (!color->display) {
color_destroy(color);
exit(EXIT_FAILURE);
}
color->window = window_create(color->display);
color->parent_widget = window_frame_create(color->window, color);
color->widget = window_add_subsurface(color->window, color, SUBSURFACE_SYNCHRONIZED);
display_set_user_data(color->display, color);
display_set_global_handler(color->display, global_handler);
wl_display_roundtrip(display_get_display(color->display));
if (!color->unmanaged && !check_color_requirements(color)) {
color_destroy(color);
exit(EXIT_SUCCESS);
}
window_unset_shadow(color->window);
window_set_title(color->window, "Color");
window_set_appid(color->window, "org.freedesktop.weston.color");
/* The first resize call sets the min size,
* setting 0, 0 sets a default size */
window_schedule_resize(color->window, 0, 0);
window_schedule_resize(color->window, opt_width, opt_height);
widget_set_resize_handler(color->parent_widget, resize_handler);
widget_set_use_cairo(color->widget, 0);
set_empty_input_region(color, color->widget);
set_single_pixel(color, color->widget);
if (color->unmanaged || set_image_description(color, color->widget))
display_run(color->display);
color_destroy(color);
return 0;
}

510
clients/confine.c Normal file
View file

@ -0,0 +1,510 @@
/*
* Copyright © 2010 Intel Corporation
* Copyright © 2012 Collabora, Ltd.
* Copyright © 2012 Jonas Ådahl
*
* 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.
*/
#include "config.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cairo.h>
#include <math.h>
#include <assert.h>
#include <unistd.h>
#include <linux/input.h>
#include <wayland-client.h>
#include "window.h"
#include "shared/helpers.h"
#include "shared/xalloc.h"
#define NUM_COMPLEX_REGION_RECTS 9
static int32_t option_complex_confine_region;
static int32_t option_help;
struct confine {
struct display *display;
struct window *window;
struct widget *widget;
cairo_surface_t *buffer;
struct {
int32_t x, y;
int32_t old_x, old_y;
} line;
int reset;
struct input *cursor_timeout_input;
struct toytimer cursor_timeout;
bool pointer_confined;
bool complex_confine_region_enabled;
bool complex_confine_region_dirty;
struct rectangle complex_confine_region[NUM_COMPLEX_REGION_RECTS];
};
static void
draw_line(struct confine *confine, cairo_t *cr,
struct rectangle *allocation)
{
cairo_t *bcr;
cairo_surface_t *tmp_buffer = NULL;
if (confine->reset) {
tmp_buffer = confine->buffer;
confine->buffer = NULL;
confine->line.x = -1;
confine->line.y = -1;
confine->line.old_x = -1;
confine->line.old_y = -1;
confine->reset = 0;
}
if (confine->buffer == NULL) {
confine->buffer =
cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
allocation->width,
allocation->height);
bcr = cairo_create(confine->buffer);
cairo_set_source_rgba(bcr, 0, 0, 0, 0);
cairo_rectangle(bcr,
0, 0,
allocation->width, allocation->height);
cairo_fill(bcr);
}
else
bcr = cairo_create(confine->buffer);
if (tmp_buffer) {
cairo_set_source_surface(bcr, tmp_buffer, 0, 0);
cairo_rectangle(bcr, 0, 0,
allocation->width, allocation->height);
cairo_clip(bcr);
cairo_paint(bcr);
cairo_surface_destroy(tmp_buffer);
}
if (confine->line.x != -1 && confine->line.y != -1) {
if (confine->line.old_x != -1 &&
confine->line.old_y != -1) {
cairo_set_line_width(bcr, 2.0);
cairo_set_source_rgb(bcr, 1, 1, 1);
cairo_translate(bcr,
-allocation->x, -allocation->y);
cairo_move_to(bcr,
confine->line.old_x,
confine->line.old_y);
cairo_line_to(bcr,
confine->line.x,
confine->line.y);
cairo_stroke(bcr);
}
confine->line.old_x = confine->line.x;
confine->line.old_y = confine->line.y;
}
cairo_destroy(bcr);
cairo_set_source_surface(cr, confine->buffer,
allocation->x, allocation->y);
cairo_set_operator(cr, CAIRO_OPERATOR_ADD);
cairo_rectangle(cr,
allocation->x, allocation->y,
allocation->width, allocation->height);
cairo_clip(cr);
cairo_paint(cr);
}
static void
calculate_complex_confine_region(struct confine *confine)
{
struct rectangle allocation;
int32_t x, y, w, h;
struct rectangle *rs = confine->complex_confine_region;
if (!confine->complex_confine_region_dirty)
return;
widget_get_allocation(confine->widget, &allocation);
x = allocation.x;
y = allocation.y;
w = allocation.width;
h = allocation.height;
/*
* The code below constructs a region made up of rectangles that
* is then used to set up both an illustrative shaded region in the
* widget and a confine region used when confining the pointer.
*/
rs[0].x = x + (int)round(w * 0.05);
rs[0].y = y + (int)round(h * 0.15);
rs[0].width = (int)round(w * 0.35);
rs[0].height = (int)round(h * 0.7);
rs[1].x = rs[0].x + rs[0].width;
rs[1].y = y + (int)round(h * 0.45);
rs[1].width = (int)round(w * 0.09);
rs[1].height = (int)round(h * 0.1);
rs[2].x = rs[1].x + rs[1].width;
rs[2].y = y + (int)round(h * 0.48);
rs[2].width = (int)round(w * 0.02);
rs[2].height = (int)round(h * 0.04);
rs[3].x = rs[2].x + rs[2].width;
rs[3].y = y + (int)round(h * 0.45);
rs[3].width = (int)round(w * 0.09);
rs[3].height = (int)round(h * 0.1);
rs[4].x = rs[3].x + rs[3].width;
rs[4].y = y + (int)round(h * 0.15);
rs[4].width = (int)round(w * 0.35);
rs[4].height = (int)round(h * 0.7);
rs[5].x = x + (int)round(w * 0.05);
rs[5].y = y + (int)round(h * 0.05);
rs[5].width = rs[0].width + rs[1].width + rs[2].width +
rs[3].width + rs[4].width;
rs[5].height = (int)round(h * 0.10);
rs[6].x = x + (int)round(w * 0.1);
rs[6].y = rs[4].y + rs[4].height + (int)round(h * 0.02);
rs[6].width = (int)round(w * 0.8);
rs[6].height = (int)round(h * 0.03);
rs[7].x = x + (int)round(w * 0.05);
rs[7].y = rs[6].y + rs[6].height;
rs[7].width = (int)round(w * 0.9);
rs[7].height = (int)round(h * 0.03);
rs[8].x = x + (int)round(w * 0.1);
rs[8].y = rs[7].y + rs[7].height;
rs[8].width = (int)round(w * 0.8);
rs[8].height = (int)round(h * 0.03);
confine->complex_confine_region_dirty = false;
}
static void
draw_complex_confine_region_mask(struct confine *confine, cairo_t *cr)
{
int i;
calculate_complex_confine_region(confine);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
for (i = 0; i < NUM_COMPLEX_REGION_RECTS; i++) {
cairo_rectangle(cr,
confine->complex_confine_region[i].x,
confine->complex_confine_region[i].y,
confine->complex_confine_region[i].width,
confine->complex_confine_region[i].height);
cairo_set_source_rgba(cr, 0.14, 0.14, 0.14, 0.9);
cairo_fill(cr);
}
}
static void
redraw_handler(struct widget *widget, void *data)
{
struct confine *confine = data;
cairo_surface_t *surface;
cairo_t *cr;
struct rectangle allocation;
widget_get_allocation(confine->widget, &allocation);
surface = window_get_surface(confine->window);
cr = cairo_create(surface);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_rectangle(cr,
allocation.x,
allocation.y,
allocation.width,
allocation.height);
cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
cairo_fill(cr);
if (confine->complex_confine_region_enabled) {
draw_complex_confine_region_mask(confine, cr);
}
draw_line(confine, cr, &allocation);
cairo_destroy(cr);
cairo_surface_destroy(surface);
}
static void
keyboard_focus_handler(struct window *window,
struct input *device, void *data)
{
struct confine *confine = data;
window_schedule_redraw(confine->window);
}
static void
key_handler(struct window *window, struct input *input, uint32_t time,
uint32_t key, uint32_t sym,
enum wl_keyboard_key_state state, void *data)
{
struct confine *confine = data;
if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
return;
switch (sym) {
case XKB_KEY_Escape:
display_exit(confine->display);
break;
case XKB_KEY_BackSpace:
cairo_surface_destroy(confine->buffer);
confine->buffer = NULL;
window_schedule_redraw(confine->window);
break;
case XKB_KEY_m:
window_set_maximized(confine->window,
!window_is_maximized(window));
break;
}
}
static void
toggle_pointer_confine(struct confine *confine, struct input *input)
{
if (confine->pointer_confined) {
window_unconfine_pointer(confine->window);
} else if (confine->complex_confine_region_enabled) {
calculate_complex_confine_region(confine);
window_confine_pointer_to_rectangles(
confine->window,
input,
confine->complex_confine_region,
NUM_COMPLEX_REGION_RECTS);
} else {
window_confine_pointer_to_widget(confine->window,
confine->widget,
input);
}
confine->pointer_confined = !confine->pointer_confined;
}
static void
button_handler(struct widget *widget,
struct input *input, uint32_t time,
uint32_t button,
enum wl_pointer_button_state state, void *data)
{
struct confine *confine = data;
bool is_pressed = state == WL_POINTER_BUTTON_STATE_PRESSED;
if (is_pressed && button == BTN_LEFT)
toggle_pointer_confine(confine, input);
widget_schedule_redraw(widget);
}
static void
cursor_timeout_reset(struct confine *confine)
{
toytimer_arm_once_usec(&confine->cursor_timeout, 500 * 1000);
}
static int
motion_handler(struct widget *widget,
struct input *input, uint32_t time,
float x, float y, void *data)
{
struct confine *confine = data;
confine->line.x = x;
confine->line.y = y;
window_schedule_redraw(confine->window);
cursor_timeout_reset(confine);
confine->cursor_timeout_input = input;
return CURSOR_BLANK;
}
static void
resize_handler(struct widget *widget,
int32_t width, int32_t height,
void *data)
{
struct confine *confine = data;
confine->reset = 1;
if (confine->complex_confine_region_enabled) {
confine->complex_confine_region_dirty = true;
if (confine->pointer_confined) {
calculate_complex_confine_region(confine);
window_update_confine_rectangles(
confine->window,
confine->complex_confine_region,
NUM_COMPLEX_REGION_RECTS);
}
}
}
static void
leave_handler(struct widget *widget,
struct input *input, void *data)
{
struct confine *confine = data;
confine->reset = 1;
}
static void
cursor_timeout_func(struct toytimer *tt)
{
struct confine *confine =
container_of(tt, struct confine, cursor_timeout);
input_set_pointer_image(confine->cursor_timeout_input,
CURSOR_LEFT_PTR);
}
static void
pointer_unconfined(struct window *window, struct input *input, void *data)
{
struct confine *confine = data;
confine->pointer_confined = false;
}
static struct confine *
confine_create(struct display *display)
{
struct confine *confine;
confine = xzalloc(sizeof *confine);
confine->window = window_create(display);
confine->widget = window_frame_create(confine->window, confine);
window_set_title(confine->window, "Wayland Confine");
confine->display = display;
confine->buffer = NULL;
window_set_key_handler(confine->window, key_handler);
window_set_user_data(confine->window, confine);
window_set_keyboard_focus_handler(confine->window,
keyboard_focus_handler);
window_set_pointer_confined_handler(confine->window,
NULL,
pointer_unconfined);
widget_set_redraw_handler(confine->widget, redraw_handler);
widget_set_button_handler(confine->widget, button_handler);
widget_set_motion_handler(confine->widget, motion_handler);
widget_set_resize_handler(confine->widget, resize_handler);
widget_set_leave_handler(confine->widget, leave_handler);
widget_schedule_resize(confine->widget, 500, 400);
confine->line.x = -1;
confine->line.y = -1;
confine->line.old_x = -1;
confine->line.old_y = -1;
confine->reset = 0;
toytimer_init(&confine->cursor_timeout, CLOCK_MONOTONIC,
display, cursor_timeout_func);
return confine;
}
static void
confine_destroy(struct confine *confine)
{
toytimer_fini(&confine->cursor_timeout);
if (confine->buffer)
cairo_surface_destroy(confine->buffer);
widget_destroy(confine->widget);
window_destroy(confine->window);
free(confine);
}
static const struct weston_option confine_options[] = {
{ WESTON_OPTION_BOOLEAN, "complex-confine-region", 0, &option_complex_confine_region },
{ WESTON_OPTION_BOOLEAN, "help", 0, &option_help },
};
static void
print_help(const char *argv0)
{
printf("Usage: %s [--complex-confine-region]\n", argv0);
}
int
main(int argc, char *argv[])
{
struct display *display;
struct confine *confine;
if (parse_options(confine_options,
ARRAY_LENGTH(confine_options),
&argc, argv) > 1 ||
option_help) {
print_help(argv[0]);
return 0;
}
display = display_create(&argc, argv);
if (display == NULL) {
fprintf(stderr, "failed to create display: %m\n");
return -1;
}
confine = confine_create(display);
if (option_complex_confine_region) {
confine->complex_confine_region_dirty = true;
confine->complex_confine_region_enabled = true;
}
display_run(display);
confine_destroy(confine);
display_destroy(display);
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -1,386 +0,0 @@
/*
* Copyright © 2018 Intel Corporation
*
* 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.
*/
#include "config.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <cairo.h>
#include <sys/time.h>
#include <linux/input.h>
#include <wayland-client.h>
#include "weston-content-protection-client-protocol.h"
#include "window.h"
#include <wayland-client-protocol.h>
#define WIDTH 500
#define HEIGHT 400
#define FRAME_H 18
#define FRAME_W 5
#define BUTTON_WIDTH 65
#define BUTTON_HEIGHT 20
enum protection_mode {
RELAXED,
ENFORCED
};
struct protected_content_player {
struct weston_content_protection *protection;
struct weston_protected_surface *psurface;
struct display *display;
struct window *window;
struct widget *widget;
struct button_t *b0, *b1, *off, *enforced, *relaxed;
int width, height, x, y;
enum weston_protected_surface_type protection_type;
enum protection_mode mode;
};
struct button_t {
struct window *window;
struct widget *widget;
struct protected_content_player *pc_player;
const char *name;
};
/**
* An event to tell the client that there is a change in protection status
*
* This event is sent whenever there is a change in content
* protection. The content protection status can be ON or OFF. ON
* in case of the desired protection type is accepted on all
* connectors, and Off in case of any of the connector
* content-protection property is changed from "enabled"
*/
static void
handle_status_changed(void *data, struct weston_protected_surface *psurface,
uint32_t status)
{
struct protected_content_player *pc_player = data;
enum weston_protected_surface_type event_status = status;
switch (event_status) {
case WESTON_PROTECTED_SURFACE_TYPE_HDCP_0:
pc_player->protection_type = WESTON_PROTECTED_SURFACE_TYPE_HDCP_0;
break;
case WESTON_PROTECTED_SURFACE_TYPE_HDCP_1:
pc_player->protection_type = WESTON_PROTECTED_SURFACE_TYPE_HDCP_1;
break;
case WESTON_PROTECTED_SURFACE_TYPE_UNPROTECTED:
default:
pc_player->protection_type = WESTON_PROTECTED_SURFACE_TYPE_UNPROTECTED;
}
window_schedule_redraw(pc_player->window);
}
static const struct weston_protected_surface_listener pc_player_listener = {
handle_status_changed,
};
static void
draw_content(cairo_surface_t *surface, int x, int y, int width, int height,
enum weston_protected_surface_type type, enum protection_mode mode)
{
cairo_t *cr;
cairo_text_extents_t extents;
const char *content_text;
const char *mode_text;
cr = cairo_create(surface);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_rectangle(cr, x, y, width, height);
if (type == WESTON_PROTECTED_SURFACE_TYPE_HDCP_0)
cairo_set_source_rgba(cr, 0, 1.0, 0, 1.0);
else if (type == WESTON_PROTECTED_SURFACE_TYPE_HDCP_1)
cairo_set_source_rgba(cr, 0, 0, 1.0, 1.0);
else
cairo_set_source_rgba(cr, 1.0, 0, 0, 1.0);
cairo_fill(cr);
cairo_set_source_rgba(cr, 0, 0, 0, 1.0);
cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cr, 15);
if (type == WESTON_PROTECTED_SURFACE_TYPE_HDCP_0)
content_text = "Content-Type : Type-0";
else if (type == WESTON_PROTECTED_SURFACE_TYPE_HDCP_1)
content_text = "Content-Type : Type-1";
else
content_text = "Content-Type : Unprotected";
cairo_text_extents(cr, content_text, &extents);
cairo_move_to(cr, width/2 - (extents.width/2),
height/2 - (extents.height/2));
cairo_show_text(cr, content_text);
if (mode == ENFORCED)
mode_text = "Mode : Enforced";
else
mode_text = "Mode : Relaxed";
cairo_text_extents(cr, mode_text, &extents);
cairo_move_to(cr, width / 2 - (extents.width / 2),
2 * height / 3 - (2 * extents.height / 3));
cairo_show_text(cr, mode_text);
cairo_fill(cr);
cairo_destroy(cr);
}
static void
redraw_handler(struct widget *widget, void *data)
{
struct protected_content_player *pc_player = data;
cairo_surface_t *surface;
struct rectangle rect;
widget_get_allocation(pc_player->widget, &rect);
surface = window_get_surface(pc_player->window);
if (surface == NULL ||
cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
fprintf(stderr, "failed to create cairo egl surface\n");
return;
}
draw_content(surface, rect.x, rect.y, rect.width, rect.height,
pc_player->protection_type, pc_player->mode);
cairo_surface_destroy(surface);
}
static void
resize_handler(struct widget *widget, int32_t width, int32_t height, void *data)
{
struct rectangle allocation;
struct protected_content_player *pc_player = data;
widget_get_allocation(pc_player->widget, &allocation);
widget_set_allocation(pc_player->b0->widget,
allocation.x + 20, allocation.y + 30,
BUTTON_WIDTH, BUTTON_HEIGHT);
widget_set_allocation(pc_player->b1->widget,
allocation.x + 20 + BUTTON_WIDTH + 5,
allocation.y + 30,
BUTTON_WIDTH, BUTTON_HEIGHT);
widget_set_allocation(pc_player->off->widget,
allocation.x + 20 + 2 * (BUTTON_WIDTH + 5),
allocation.y + 30,
BUTTON_WIDTH, BUTTON_HEIGHT);
widget_set_allocation(pc_player->enforced->widget,
allocation.x + 20 + 3 * (BUTTON_WIDTH + 5),
allocation.y + 30,
BUTTON_WIDTH, BUTTON_HEIGHT);
widget_set_allocation(pc_player->relaxed->widget,
allocation.x + 20 + 4 * (BUTTON_WIDTH + 5),
allocation.y + 30,
BUTTON_WIDTH, BUTTON_HEIGHT);
}
static void
buttons_handler(struct widget *widget, struct input *input, uint32_t time,
uint32_t button, enum wl_pointer_button_state state, void *data)
{
struct button_t *b = data;
struct protected_content_player *pc_player = b->pc_player;
struct wl_surface *surface;
if (strcmp(b->name, "ENFORCED") == 0) {
weston_protected_surface_enforce(pc_player->psurface);
pc_player->mode = ENFORCED;
window_schedule_redraw(pc_player->window);
}
else if (strcmp(b->name, "RELAXED") == 0) {
weston_protected_surface_relax(pc_player->psurface);
pc_player->mode = RELAXED;
window_schedule_redraw(pc_player->window);
}
else if (strcmp(b->name, "TYPE-0") == 0)
weston_protected_surface_set_type(pc_player->psurface,
WESTON_PROTECTED_SURFACE_TYPE_HDCP_0);
else if (strcmp(b->name, "TYPE-1") == 0)
weston_protected_surface_set_type(pc_player->psurface,
WESTON_PROTECTED_SURFACE_TYPE_HDCP_1);
else
weston_protected_surface_set_type(pc_player->psurface,
WESTON_PROTECTED_SURFACE_TYPE_UNPROTECTED);
surface = window_get_wl_surface(pc_player->window);
wl_surface_commit(surface);
}
static void
handle_global(struct display *display, uint32_t name, const char *interface,
uint32_t version, void *data)
{
struct protected_content_player *pc_player = data;
if (strcmp(interface, "weston_content_protection") == 0) {
pc_player->protection = display_bind(display, name,
&weston_content_protection_interface,
1);
}
}
static void
buttons_redraw_handler(struct widget *widget, void *data)
{
struct button_t *b = data;
cairo_surface_t *surface;
struct rectangle allocation;
cairo_t *cr;
surface = window_get_surface(b->window);
widget_get_allocation(b->widget, &allocation);
cr = cairo_create(surface);
cairo_rectangle(cr, allocation.x, allocation.y, allocation.width,
allocation.height);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr, 1, 1, 1, 1);
cairo_fill(cr);
cairo_set_source_rgba(cr, 0, 0, 0, 1.0);
cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cr, 10);
cairo_move_to(cr, allocation.x + 5, allocation.y + 15);
cairo_show_text(cr, b->name);
cairo_fill(cr);
cairo_destroy(cr);
cairo_surface_destroy(surface);
}
static struct button_t*
create_button(struct protected_content_player *pc_player, const char *name)
{
struct button_t *b;
b = zalloc(sizeof(struct button_t));
if (b == NULL) {
fprintf(stderr, "Failed to allocate memory for button.\n");
exit(0);
}
b->widget = widget_add_widget(pc_player->widget, b);
b->window = pc_player->window;
b->pc_player = pc_player;
b->name = name;
widget_set_redraw_handler(b->widget, buttons_redraw_handler);
widget_set_button_handler(b->widget, buttons_handler);
return b;
}
static void
destroy_button(struct button_t *b)
{
if (!b)
return;
widget_destroy(b->widget);
free(b);
}
static void free_pc_player(struct protected_content_player *pc_player)
{
if (!pc_player)
return;
destroy_button(pc_player->b0);
destroy_button(pc_player->b1);
destroy_button(pc_player->off);
destroy_button(pc_player->enforced);
destroy_button(pc_player->relaxed);
widget_destroy(pc_player->widget);
window_destroy(pc_player->window);
free(pc_player);
}
int main(int argc, char *argv[])
{
struct protected_content_player *pc_player;
struct display *d;
static const char str_type_0[] = "TYPE-0";
static const char str_type_1[] = "TYPE-1";
static const char str_type_off[] = "OFF";
static const char str_type_enforced[] = "ENFORCED";
static const char str_type_relaxed[] = "RELAXED";
struct wl_surface *surface;
pc_player = zalloc(sizeof(struct protected_content_player));
if (pc_player == NULL) {
fprintf(stderr, "failed to allocate memory: %m\n");
return -1;
}
d = display_create(&argc, argv);
if (d == NULL) {
fprintf(stderr, "failed to create display: %m\n");
return -1;
}
pc_player->protection_type = WESTON_PROTECTED_SURFACE_TYPE_UNPROTECTED;
pc_player->mode = RELAXED;
pc_player->width = WIDTH * 2.0/4.0;
pc_player->height = HEIGHT * 2.0/4.0;
pc_player->x = WIDTH * 1.0/4.0;
pc_player->y = HEIGHT * 1.0/4.0;
pc_player->window = window_create(d);
pc_player->widget = window_frame_create(pc_player->window, pc_player);
pc_player->display = d;
display_set_user_data(d, pc_player);
display_set_global_handler(d, handle_global);
surface = window_get_wl_surface(pc_player->window);
if (pc_player->protection == NULL) {
printf("The content-protection object is NULL\n");
return -1;
}
pc_player->psurface = weston_content_protection_get_protection(pc_player->protection,
surface);
weston_protected_surface_add_listener(pc_player->psurface,
&pc_player_listener,
pc_player);
pc_player->b0 = create_button(pc_player, str_type_0);
pc_player->b1 = create_button(pc_player, str_type_1);
pc_player->off = create_button(pc_player, str_type_off);
pc_player->enforced = create_button(pc_player, str_type_enforced);
pc_player->relaxed = create_button(pc_player, str_type_relaxed);
window_set_title(pc_player->window, "Weston Content Protection");
window_set_appid(pc_player->window,
"org.freedesktop.weston.weston-content-protection");
widget_set_redraw_handler(pc_player->widget, redraw_handler);
widget_set_resize_handler(pc_player->widget, resize_handler);
window_schedule_resize(pc_player->window, WIDTH, HEIGHT);
widget_schedule_redraw(pc_player->b0->widget);
widget_schedule_redraw(pc_player->b1->widget);
widget_schedule_redraw(pc_player->off->widget);
display_run(d);
weston_protected_surface_destroy(pc_player->psurface);
weston_content_protection_destroy(pc_player->protection);
free_pc_player(pc_player);
display_destroy(d);
return 0;
}

View file

@ -41,30 +41,23 @@
#include <assert.h> #include <assert.h>
#include <wayland-client.h> #include <wayland-client.h>
#include "window.h"
#include <libweston/config-parser.h> #include "shared/cairo-util.h"
#include <libweston/zalloc.h> #include "shared/config-parser.h"
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/xalloc.h" #include "shared/xalloc.h"
#include "shared/cairo-util.h" #include "shared/zalloc.h"
#include "shared/file-util.h" #include "shared/file-util.h"
#include "shared/process-util.h"
#include "shared/timespec-util.h"
#include "window.h"
#include "single-pixel-buffer-v1-client-protocol.h"
#include "tablet-unstable-v2-client-protocol.h"
#include "weston-desktop-shell-client-protocol.h" #include "weston-desktop-shell-client-protocol.h"
#define DEFAULT_CLOCK_FORMAT CLOCK_FORMAT_MINUTES #define DEFAULT_CLOCK_FORMAT CLOCK_FORMAT_MINUTES
#define DEFAULT_SPACING 10
extern char **environ; /* defined by libc */
enum clock_format { enum clock_format {
CLOCK_FORMAT_MINUTES, CLOCK_FORMAT_MINUTES,
CLOCK_FORMAT_SECONDS, CLOCK_FORMAT_SECONDS,
CLOCK_FORMAT_MINUTES_24H,
CLOCK_FORMAT_SECONDS_24H,
CLOCK_FORMAT_NONE CLOCK_FORMAT_NONE
}; };
@ -83,7 +76,7 @@ struct desktop {
struct widget *grab_widget; struct widget *grab_widget;
struct weston_config *config; struct weston_config *config;
bool locking; int locking;
enum cursor_type grab_cursor; enum cursor_type grab_cursor;
@ -145,11 +138,9 @@ struct panel_launcher {
cairo_surface_t *icon; cairo_surface_t *icon;
int focused, pressed; int focused, pressed;
char *path; char *path;
char *displayname;
struct wl_list link; struct wl_list link;
struct custom_env env; struct wl_array envp;
char * const *argp; struct wl_array argv;
char * const *envp;
}; };
struct panel_clock { struct panel_clock {
@ -216,23 +207,25 @@ check_desktop_ready(struct window *window)
static void static void
panel_launcher_activate(struct panel_launcher *widget) panel_launcher_activate(struct panel_launcher *widget)
{ {
char **argv;
pid_t pid; pid_t pid;
pid = fork(); pid = fork();
if (pid < 0) { if (pid < 0) {
fprintf(stderr, "fork failed: %s\n", strerror(errno)); fprintf(stderr, "fork failed: %m\n");
return; return;
} }
if (pid) if (pid)
return; return;
argv = widget->argv.data;
if (setsid() == -1) if (setsid() == -1)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
if (execve(widget->argp[0], widget->argp, widget->envp) < 0) { if (execve(argv[0], argv, widget->envp.data) < 0) {
fprintf(stderr, "execl '%s' failed: %s\n", widget->argp[0], fprintf(stderr, "execl '%s' failed: %m\n", argv[0]);
strerror(errno));
exit(1); exit(1);
} }
} }
@ -247,14 +240,6 @@ panel_launcher_redraw_handler(struct widget *widget, void *data)
cr = widget_cairo_create(launcher->panel->widget); cr = widget_cairo_create(launcher->panel->widget);
widget_get_allocation(widget, &allocation); widget_get_allocation(widget, &allocation);
allocation.x += allocation.width / 2 -
cairo_image_surface_get_width(launcher->icon) / 2;
if (allocation.width > allocation.height)
allocation.x += allocation.width / 2 - allocation.height / 2;
allocation.y += allocation.height / 2 -
cairo_image_surface_get_height(launcher->icon) / 2;
if (allocation.height > allocation.width)
allocation.y += allocation.height / 2 - allocation.width / 2;
if (launcher->pressed) { if (launcher->pressed) {
allocation.x++; allocation.x++;
allocation.y++; allocation.y++;
@ -279,7 +264,7 @@ panel_launcher_motion_handler(struct widget *widget, struct input *input,
{ {
struct panel_launcher *launcher = data; struct panel_launcher *launcher = data;
widget_set_tooltip(widget, launcher->displayname, x, y); widget_set_tooltip(widget, basename((char *)launcher->path), x, y);
return CURSOR_LEFT_PTR; return CURSOR_LEFT_PTR;
} }
@ -376,66 +361,12 @@ panel_launcher_touch_up_handler(struct widget *widget, struct input *input,
panel_launcher_activate(launcher); panel_launcher_activate(launcher);
} }
static void
panel_launcher_tablet_tool_proximity_in_handler(struct widget *widget,
struct tablet_tool *tool,
struct tablet *tablet, void *data)
{
struct panel_launcher *launcher;
launcher = widget_get_user_data(widget);
launcher->focused = 1;
widget_schedule_redraw(widget);
}
static void
panel_launcher_tablet_tool_proximity_out_handler(struct widget *widget,
struct tablet_tool *tool, void *data)
{
struct panel_launcher *launcher;
launcher = widget_get_user_data(widget);
launcher->focused = 0;
widget_schedule_redraw(widget);
}
static void
panel_launcher_tablet_tool_up_handler(struct widget *widget,
struct tablet_tool *tool,
void *data)
{
struct panel_launcher *launcher;
launcher = widget_get_user_data(widget);
panel_launcher_activate(launcher);
}
static void
panel_launcher_tablet_tool_button_handler(struct widget *widget,
struct tablet_tool *tool,
uint32_t button,
uint32_t state_w,
void *data)
{
struct panel_launcher *launcher;
enum zwp_tablet_tool_v2_button_state state = state_w;
launcher = widget_get_user_data(widget);
if (state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED)
panel_launcher_activate(launcher);
}
static int clock_timer_reset(struct panel_clock *clock);
static void static void
clock_func(struct toytimer *tt) clock_func(struct toytimer *tt)
{ {
struct panel_clock *clock = container_of(tt, struct panel_clock, timer); struct panel_clock *clock = container_of(tt, struct panel_clock, timer);
widget_schedule_redraw(clock->widget); widget_schedule_redraw(clock->widget);
clock_timer_reset(clock);
} }
static void static void
@ -445,6 +376,7 @@ panel_clock_redraw_handler(struct widget *widget, void *data)
cairo_t *cr; cairo_t *cr;
struct rectangle allocation; struct rectangle allocation;
cairo_text_extents_t extents; cairo_text_extents_t extents;
cairo_font_extents_t font_extents;
time_t rawtime; time_t rawtime;
struct tm * timeinfo; struct tm * timeinfo;
char string[128]; char string[128];
@ -458,20 +390,19 @@ panel_clock_redraw_handler(struct widget *widget, void *data)
return; return;
cr = widget_cairo_create(clock->panel->widget); cr = widget_cairo_create(clock->panel->widget);
cairo_select_font_face(cr, "sans",
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cr, 14); cairo_set_font_size(cr, 14);
cairo_text_extents(cr, string, &extents); cairo_text_extents(cr, string, &extents);
if (allocation.x > 0) cairo_font_extents (cr, &font_extents);
allocation.x += cairo_move_to(cr, allocation.x + 5,
allocation.width - DEFAULT_SPACING * 1.5 - extents.width; allocation.y + 3 * (allocation.height >> 2) + 1);
else cairo_set_source_rgb(cr, 0, 0, 0);
allocation.x +=
allocation.width / 2 - extents.width / 2;
allocation.y += allocation.height / 2 - 1 + extents.height / 2;
cairo_move_to(cr, allocation.x + 1, allocation.y + 1);
cairo_set_source_rgba(cr, 0, 0, 0, 0.85);
cairo_show_text(cr, string); cairo_show_text(cr, string);
cairo_move_to(cr, allocation.x, allocation.y); cairo_move_to(cr, allocation.x + 4,
cairo_set_source_rgba(cr, 1, 1, 1, 0.85); allocation.y + 3 * (allocation.height >> 2));
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_show_text(cr, string); cairo_show_text(cr, string);
cairo_destroy(cr); cairo_destroy(cr);
} }
@ -480,19 +411,13 @@ static int
clock_timer_reset(struct panel_clock *clock) clock_timer_reset(struct panel_clock *clock)
{ {
struct itimerspec its; struct itimerspec its;
struct timespec ts;
struct tm *tm;
clock_gettime(CLOCK_REALTIME, &ts); its.it_interval.tv_sec = clock->refresh_timer;
tm = localtime(&ts.tv_sec);
its.it_interval.tv_sec = 0;
its.it_interval.tv_nsec = 0; its.it_interval.tv_nsec = 0;
its.it_value.tv_sec = clock->refresh_timer - tm->tm_sec % clock->refresh_timer; its.it_value.tv_sec = clock->refresh_timer;
its.it_value.tv_nsec = 10000000; /* 10 ms late to ensure the clock digit has actually changed */ its.it_value.tv_nsec = 0;
timespec_add_nsec(&its.it_value, &its.it_value, -ts.tv_nsec);
toytimer_arm(&clock->timer, &its); toytimer_arm(&clock->timer, &its);
return 0; return 0;
} }
@ -522,14 +447,6 @@ panel_add_clock(struct panel *panel)
clock->format_string = "%a %b %d, %I:%M:%S %p"; clock->format_string = "%a %b %d, %I:%M:%S %p";
clock->refresh_timer = 1; clock->refresh_timer = 1;
break; break;
case CLOCK_FORMAT_MINUTES_24H:
clock->format_string = "%a %b %d, %H:%M";
clock->refresh_timer = 60;
break;
case CLOCK_FORMAT_SECONDS_24H:
clock->format_string = "%a %b %d, %H:%M:%S";
clock->refresh_timer = 1;
break;
case CLOCK_FORMAT_NONE: case CLOCK_FORMAT_NONE:
assert(!"not reached"); assert(!"not reached");
} }
@ -548,33 +465,44 @@ panel_resize_handler(struct widget *widget,
{ {
struct panel_launcher *launcher; struct panel_launcher *launcher;
struct panel *panel = data; struct panel *panel = data;
int x = 0; int bx = width / 2;
int y = 0; int by = height / 2;
int w = height > width ? width : height; int spacing = 10;
int h = w; int x = spacing;
int y = spacing;
int w, h;
int horizontal = panel->panel_position == WESTON_DESKTOP_SHELL_PANEL_POSITION_TOP || panel->panel_position == WESTON_DESKTOP_SHELL_PANEL_POSITION_BOTTOM; int horizontal = panel->panel_position == WESTON_DESKTOP_SHELL_PANEL_POSITION_TOP || panel->panel_position == WESTON_DESKTOP_SHELL_PANEL_POSITION_BOTTOM;
int first_pad_h = horizontal ? 0 : DEFAULT_SPACING / 2;
int first_pad_w = horizontal ? DEFAULT_SPACING / 2 : 0;
wl_list_for_each(launcher, &panel->launcher_list, link) { wl_list_for_each(launcher, &panel->launcher_list, link) {
widget_set_allocation(launcher->widget, x, y, w = cairo_image_surface_get_width(launcher->icon);
w + first_pad_w + 1, h + first_pad_h + 1); h = cairo_image_surface_get_height(launcher->icon);
if (horizontal) if (horizontal)
x += w + first_pad_w; y = by - h / 2;
else else
y += h + first_pad_h; x = bx - w / 2;
first_pad_h = first_pad_w = 0; widget_set_allocation(launcher->widget,
x, y, w + 1, h + 1);
if (horizontal)
x += w + spacing;
else
y += h + spacing;
} }
if (panel->clock_format == CLOCK_FORMAT_SECONDS) h = 20;
w = 170;
else /* CLOCK_FORMAT_MINUTES and 24H versions */
w = 150;
if (horizontal) if (panel->clock_format == CLOCK_FORMAT_SECONDS)
x = width - w; w = 190;
else else /* CLOCK_FORMAT_MINUTES */
y = height - (h = DEFAULT_SPACING * 3); w = 170;
if (horizontal) {
x = width - w - spacing;
y = by - h / 2;
} else {
x = bx - w / 2;
y = height - h - spacing;
}
if (panel->clock) if (panel->clock)
widget_set_allocation(panel->clock->widget, widget_set_allocation(panel->clock->widget,
@ -615,12 +543,10 @@ panel_configure(void *data,
width = 32; width = 32;
break; break;
case CLOCK_FORMAT_MINUTES: case CLOCK_FORMAT_MINUTES:
case CLOCK_FORMAT_MINUTES_24H: width = 170;
case CLOCK_FORMAT_SECONDS_24H:
width = 150;
break; break;
case CLOCK_FORMAT_SECONDS: case CLOCK_FORMAT_SECONDS:
width = 170; width = 190;
break; break;
} }
break; break;
@ -631,10 +557,10 @@ panel_configure(void *data,
static void static void
panel_destroy_launcher(struct panel_launcher *launcher) panel_destroy_launcher(struct panel_launcher *launcher)
{ {
custom_env_fini(&launcher->env); wl_array_release(&launcher->argv);
wl_array_release(&launcher->envp);
free(launcher->path); free(launcher->path);
free(launcher->displayname);
cairo_surface_destroy(launcher->icon); cairo_surface_destroy(launcher->icon);
@ -734,19 +660,58 @@ load_icon_or_fallback(const char *icon)
} }
static void static void
panel_add_launcher(struct panel *panel, const char *icon, const char *path, const char *displayname) panel_add_launcher(struct panel *panel, const char *icon, const char *path)
{ {
struct panel_launcher *launcher; struct panel_launcher *launcher;
char *start, *p, *eq, **ps;
int i, j, k;
launcher = xzalloc(sizeof *launcher); launcher = xzalloc(sizeof *launcher);
launcher->icon = load_icon_or_fallback(icon); launcher->icon = load_icon_or_fallback(icon);
launcher->path = xstrdup(path); launcher->path = xstrdup(path);
launcher->displayname = xstrdup(displayname);
custom_env_init_from_environ(&launcher->env); wl_array_init(&launcher->envp);
custom_env_add_from_exec_string(&launcher->env, launcher->path); wl_array_init(&launcher->argv);
launcher->envp = custom_env_get_envp(&launcher->env); for (i = 0; environ[i]; i++) {
launcher->argp = custom_env_get_argp(&launcher->env); ps = wl_array_add(&launcher->envp, sizeof *ps);
*ps = environ[i];
}
j = 0;
start = launcher->path;
while (*start) {
for (p = start, eq = NULL; *p && !isspace(*p); p++)
if (*p == '=')
eq = p;
if (eq && j == 0) {
ps = launcher->envp.data;
for (k = 0; k < i; k++)
if (strncmp(ps[k], start, eq - start) == 0) {
ps[k] = start;
break;
}
if (k == i) {
ps = wl_array_add(&launcher->envp, sizeof *ps);
*ps = start;
i++;
}
} else {
ps = wl_array_add(&launcher->argv, sizeof *ps);
*ps = start;
j++;
}
while (*p && isspace(*p))
*p++ = '\0';
start = p;
}
ps = wl_array_add(&launcher->envp, sizeof *ps);
*ps = NULL;
ps = wl_array_add(&launcher->argv, sizeof *ps);
*ps = NULL;
launcher->panel = panel; launcher->panel = panel;
wl_list_insert(panel->launcher_list.prev, &launcher->link); wl_list_insert(panel->launcher_list.prev, &launcher->link);
@ -762,13 +727,6 @@ panel_add_launcher(struct panel *panel, const char *icon, const char *path, cons
panel_launcher_touch_down_handler); panel_launcher_touch_down_handler);
widget_set_touch_up_handler(launcher->widget, widget_set_touch_up_handler(launcher->widget,
panel_launcher_touch_up_handler); panel_launcher_touch_up_handler);
widget_set_tablet_tool_up_handler(launcher->widget,
panel_launcher_tablet_tool_up_handler);
widget_set_tablet_tool_proximity_handlers(launcher->widget,
panel_launcher_tablet_tool_proximity_in_handler,
panel_launcher_tablet_tool_proximity_out_handler);
widget_set_tablet_tool_button_handler(launcher->widget,
panel_launcher_tablet_tool_button_handler);
widget_set_redraw_handler(launcher->widget, widget_set_redraw_handler(launcher->widget,
panel_launcher_redraw_handler); panel_launcher_redraw_handler);
widget_set_motion_handler(launcher->widget, widget_set_motion_handler(launcher->widget,
@ -778,148 +736,95 @@ panel_add_launcher(struct panel *panel, const char *icon, const char *path, cons
enum { enum {
BACKGROUND_SCALE, BACKGROUND_SCALE,
BACKGROUND_SCALE_CROP, BACKGROUND_SCALE_CROP,
BACKGROUND_SCALE_FIT,
BACKGROUND_TILE, BACKGROUND_TILE,
BACKGROUND_CENTERED BACKGROUND_CENTERED
}; };
static void
buffer_release(void *data, struct wl_buffer *buffer)
{
wl_buffer_destroy(buffer);
}
static const struct wl_buffer_listener buffer_listener = {
buffer_release
};
static void static void
background_draw(struct widget *widget, void *data) background_draw(struct widget *widget, void *data)
{ {
struct background *background = data; struct background *background = data;
cairo_surface_t *surface, *image;
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
cairo_t *cr;
double im_w, im_h;
double sx, sy, s;
double tx, ty;
struct rectangle allocation;
if (!background->image && background->color) { surface = window_get_surface(background->window);
struct display *display = window_get_display(background->window);
struct wp_single_pixel_buffer_manager_v1 *sp_manager;
struct wl_surface *wl_surface;
struct wl_buffer *wl_buffer;
uint32_t r8, g8, b8;
uint32_t r32, g32, b32;
/* Single pixel buffer must use scale 1 */ cr = widget_cairo_create(background->widget);
window_set_buffer_scale(background->window, 1); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
if (background->color == 0)
cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
else
set_hex_color(cr, background->color);
cairo_paint(cr);
sp_manager = display_get_single_pixel_buffer_manager(display); widget_get_allocation(widget, &allocation);
assert(sp_manager); image = NULL;
wl_surface = widget_get_wl_surface(background->widget); if (background->image)
assert(wl_surface); image = load_cairo_surface(background->image);
else if (background->color == 0) {
char *name = file_name_with_datadir("pattern.png");
r8 = (background->color >> 16) & 0xff; image = load_cairo_surface(name);
g8 = (background->color >> 8) & 0xff; free(name);
b8 = (background->color >> 0) & 0xff;
r32 = r8 << 24 | r8 << 16 | r8 << 8 | r8;
g32 = g8 << 24 | g8 << 16 | g8 << 8 | g8;
b32 = b8 << 24 | b8 << 16 | b8 << 8 | b8;
wl_buffer =
wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(sp_manager,
r32,
g32,
b32,
0xffffffff);
assert(wl_buffer);
wl_surface_attach(wl_surface, wl_buffer, 0, 0);
wl_buffer_add_listener(wl_buffer, &buffer_listener, NULL);
widget_surface_flush(widget);
} else {
cairo_surface_t *surface, *image;
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
cairo_t *cr;
double im_w, im_h;
double sx, sy, s;
double tx, ty;
struct rectangle allocation;
surface = window_get_surface(background->window);
cr = widget_cairo_create(background->widget);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
if (background->color == 0)
cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
else
set_hex_color(cr, background->color);
cairo_paint(cr);
widget_get_allocation(widget, &allocation);
image = NULL;
if (background->image)
image = load_cairo_surface(background->image);
else if (background->color == 0) {
char *name = file_name_with_datadir("pattern.png");
image = load_cairo_surface(name);
free(name);
}
if (image && background->type != -1) {
im_w = cairo_image_surface_get_width(image);
im_h = cairo_image_surface_get_height(image);
sx = im_w / allocation.width;
sy = im_h / allocation.height;
pattern = cairo_pattern_create_for_surface(image);
switch (background->type) {
case BACKGROUND_SCALE:
cairo_matrix_init_scale(&matrix, sx, sy);
cairo_pattern_set_matrix(pattern, &matrix);
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
break;
case BACKGROUND_SCALE_CROP:
case BACKGROUND_SCALE_FIT:
if (background->type == BACKGROUND_SCALE_CROP)
s = (sx < sy) ? sx : sy;
else
s = (sx > sy) ? sx : sy;
/* align center */
tx = (im_w - s * allocation.width) * 0.5;
ty = (im_h - s * allocation.height) * 0.5;
cairo_matrix_init_translate(&matrix, tx, ty);
cairo_matrix_scale(&matrix, s, s);
cairo_pattern_set_matrix(pattern, &matrix);
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
break;
case BACKGROUND_TILE:
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
break;
case BACKGROUND_CENTERED:
s = (sx < sy) ? sx : sy;
if (s < 1.0)
s = 1.0;
/* align center */
tx = (im_w - s * allocation.width) * 0.5;
ty = (im_h - s * allocation.height) * 0.5;
cairo_matrix_init_translate(&matrix, tx, ty);
cairo_matrix_scale(&matrix, s, s);
cairo_pattern_set_matrix(pattern, &matrix);
break;
}
cairo_set_source(cr, pattern);
cairo_pattern_destroy (pattern);
cairo_surface_destroy(image);
cairo_mask(cr, pattern);
}
cairo_destroy(cr);
cairo_surface_destroy(surface);
} }
if (image && background->type != -1) {
im_w = cairo_image_surface_get_width(image);
im_h = cairo_image_surface_get_height(image);
sx = im_w / allocation.width;
sy = im_h / allocation.height;
pattern = cairo_pattern_create_for_surface(image);
switch (background->type) {
case BACKGROUND_SCALE:
cairo_matrix_init_scale(&matrix, sx, sy);
cairo_pattern_set_matrix(pattern, &matrix);
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
break;
case BACKGROUND_SCALE_CROP:
s = (sx < sy) ? sx : sy;
/* align center */
tx = (im_w - s * allocation.width) * 0.5;
ty = (im_h - s * allocation.height) * 0.5;
cairo_matrix_init_translate(&matrix, tx, ty);
cairo_matrix_scale(&matrix, s, s);
cairo_pattern_set_matrix(pattern, &matrix);
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
break;
case BACKGROUND_TILE:
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
break;
case BACKGROUND_CENTERED:
s = (sx < sy) ? sx : sy;
if (s < 1.0)
s = 1.0;
/* align center */
tx = (im_w - s * allocation.width) * 0.5;
ty = (im_h - s * allocation.height) * 0.5;
cairo_matrix_init_translate(&matrix, tx, ty);
cairo_matrix_scale(&matrix, s, s);
cairo_pattern_set_matrix(pattern, &matrix);
break;
}
cairo_set_source(cr, pattern);
cairo_pattern_destroy (pattern);
cairo_surface_destroy(image);
cairo_mask(cr, pattern);
}
cairo_destroy(cr);
cairo_surface_destroy(surface);
background->painted = 1; background->painted = 1;
check_desktop_ready(background->window); check_desktop_ready(background->window);
} }
@ -945,13 +850,6 @@ background_configure(void *data,
return; return;
} }
if (!background->image && background->color) {
widget_set_use_cairo(background->widget, 0);
widget_set_viewport_destination(background->widget, width, height);
width = 1;
height = 1;
}
widget_schedule_resize(background->widget, width, height); widget_schedule_resize(background->widget, width, height);
} }
@ -1246,10 +1144,6 @@ background_create(struct desktop *desktop, struct output *output)
weston_config_section_get_color(s, "background-color", weston_config_section_get_color(s, "background-color",
&background->color, 0x00000000); &background->color, 0x00000000);
/* Backgrounds must be fully opaque. */
if (background->color != 0)
background->color |= 0xFF000000;
weston_config_section_get_string(s, "background-type", weston_config_section_get_string(s, "background-type",
&type, "tile"); &type, "tile");
if (type == NULL) { if (type == NULL) {
@ -1261,8 +1155,6 @@ background_create(struct desktop *desktop, struct output *output)
background->type = BACKGROUND_SCALE; background->type = BACKGROUND_SCALE;
} else if (strcmp(type, "scale-crop") == 0) { } else if (strcmp(type, "scale-crop") == 0) {
background->type = BACKGROUND_SCALE_CROP; background->type = BACKGROUND_SCALE_CROP;
} else if (strcmp(type, "scale-fit") == 0) {
background->type = BACKGROUND_SCALE_FIT;
} else if (strcmp(type, "tile") == 0) { } else if (strcmp(type, "tile") == 0) {
background->type = BACKGROUND_TILE; background->type = BACKGROUND_TILE;
} else if (strcmp(type, "centered") == 0) { } else if (strcmp(type, "centered") == 0) {
@ -1382,11 +1274,10 @@ output_handle_scale(void *data,
int32_t scale) int32_t scale)
{ {
struct output *output = data; struct output *output = data;
struct background *background = output->background;
if (output->panel) if (output->panel)
window_set_buffer_scale(output->panel->window, scale); window_set_buffer_scale(output->panel->window, scale);
if (background && !background->color) if (output->background)
window_set_buffer_scale(output->background->window, scale); window_set_buffer_scale(output->background->window, scale);
} }
@ -1532,7 +1423,7 @@ static void
panel_add_launchers(struct panel *panel, struct desktop *desktop) panel_add_launchers(struct panel *panel, struct desktop *desktop)
{ {
struct weston_config_section *s; struct weston_config_section *s;
char *icon, *path, *displayname; char *icon, *path;
const char *name; const char *name;
int count; int count;
@ -1544,12 +1435,9 @@ panel_add_launchers(struct panel *panel, struct desktop *desktop)
weston_config_section_get_string(s, "icon", &icon, NULL); weston_config_section_get_string(s, "icon", &icon, NULL);
weston_config_section_get_string(s, "path", &path, NULL); weston_config_section_get_string(s, "path", &path, NULL);
weston_config_section_get_string(s, "displayname", &displayname, NULL);
if (displayname == NULL)
displayname = xstrdup(basename(path));
if (icon != NULL && path != NULL) { if (icon != NULL && path != NULL) {
panel_add_launcher(panel, icon, path, displayname); panel_add_launcher(panel, icon, path);
count++; count++;
} else { } else {
fprintf(stderr, "invalid launcher section\n"); fprintf(stderr, "invalid launcher section\n");
@ -1557,17 +1445,15 @@ panel_add_launchers(struct panel *panel, struct desktop *desktop)
free(icon); free(icon);
free(path); free(path);
free(displayname);
} }
if (count == 0) { if (count == 0) {
char *name = file_name_with_datadir("terminal.png"); char *name = file_name_with_datadir("terminal.png");
/* add default launcher */ /* add default launcher */
panel_add_launcher(panel, panel_add_launcher(panel,
name, name,
BINDIR "/weston-terminal", BINDIR "/weston-terminal");
"Terminal");
free(name); free(name);
} }
} }
@ -1607,10 +1493,6 @@ parse_clock_format(struct desktop *desktop, struct weston_config_section *s)
desktop->clock_format = CLOCK_FORMAT_MINUTES; desktop->clock_format = CLOCK_FORMAT_MINUTES;
else if (strcmp(clock_format, "seconds") == 0) else if (strcmp(clock_format, "seconds") == 0)
desktop->clock_format = CLOCK_FORMAT_SECONDS; desktop->clock_format = CLOCK_FORMAT_SECONDS;
else if (strcmp(clock_format, "minutes-24h") == 0)
desktop->clock_format = CLOCK_FORMAT_MINUTES_24H;
else if (strcmp(clock_format, "seconds-24h") == 0)
desktop->clock_format = CLOCK_FORMAT_SECONDS_24H;
else if (strcmp(clock_format, "none") == 0) else if (strcmp(clock_format, "none") == 0)
desktop->clock_format = CLOCK_FORMAT_NONE; desktop->clock_format = CLOCK_FORMAT_NONE;
else else
@ -1631,15 +1513,13 @@ int main(int argc, char *argv[])
config_file = weston_config_get_name_from_env(); config_file = weston_config_get_name_from_env();
desktop.config = weston_config_parse(config_file); desktop.config = weston_config_parse(config_file);
s = weston_config_get_section(desktop.config, "shell", NULL, NULL); s = weston_config_get_section(desktop.config, "shell", NULL, NULL);
weston_config_section_get_bool(s, "locking", &desktop.locking, true); weston_config_section_get_bool(s, "locking", &desktop.locking, 1);
parse_panel_position(&desktop, s); parse_panel_position(&desktop, s);
parse_clock_format(&desktop, s); parse_clock_format(&desktop, s);
desktop.display = display_create(&argc, argv); desktop.display = display_create(&argc, argv);
if (desktop.display == NULL) { if (desktop.display == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
weston_config_destroy(desktop.config);
return -1; return -1;
} }
@ -1652,7 +1532,7 @@ int main(int argc, char *argv[])
if (desktop.want_panel) if (desktop.want_panel)
weston_desktop_shell_set_panel_position(desktop.shell, desktop.panel_position); weston_desktop_shell_set_panel_position(desktop.shell, desktop.panel_position);
wl_list_for_each(output, &desktop.outputs, link) wl_list_for_each(output, &desktop.outputs, link)
if (!output->background) if (!output->panel)
output_init(output, &desktop); output_init(output, &desktop);
grab_surface_create(&desktop); grab_surface_create(&desktop);
@ -1668,7 +1548,6 @@ int main(int argc, char *argv[])
unlock_dialog_destroy(desktop.unlock_dialog); unlock_dialog_destroy(desktop.unlock_dialog);
weston_desktop_shell_destroy(desktop.shell); weston_desktop_shell_destroy(desktop.shell);
display_destroy(desktop.display); display_destroy(desktop.display);
weston_config_destroy(desktop.config);
return 0; return 0;
} }

View file

@ -35,7 +35,6 @@
#include <cairo.h> #include <cairo.h>
#include <sys/epoll.h> #include <sys/epoll.h>
#include <stdbool.h> #include <stdbool.h>
#include <errno.h>
#include <wayland-client.h> #include <wayland-client.h>
#include <wayland-cursor.h> #include <wayland-cursor.h>
@ -416,9 +415,9 @@ data_source_dnd_finished(void *data, struct wl_data_source *source)
delete_item = delete_item =
dnd_drag->dnd_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE; dnd_drag->dnd_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
/* The operation is already finished, we can destroy all /* The operation is already finished, we can destroy all
* related data. * related data.
*/ */
dnd_drag_destroy(dnd_drag, delete_item); dnd_drag_destroy(dnd_drag, delete_item);
window_schedule_redraw(dnd->window); window_schedule_redraw(dnd->window);
} }
@ -515,7 +514,7 @@ create_drag_source(struct dnd *dnd,
dnd_drag->drag_surface = dnd_drag->drag_surface =
wl_compositor_create_surface(compositor); wl_compositor_create_surface(compositor);
if (dnd->self_only || display_get_data_device_manager_version(display) < if (display_get_data_device_manager_version(display) <
WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION) { WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION) {
/* Data sources version < 3 will not get action /* Data sources version < 3 will not get action
* nor dnd_finished events, as we can't honor * nor dnd_finished events, as we can't honor
@ -546,11 +545,11 @@ create_drag_source(struct dnd *dnd,
flower_mime_type); flower_mime_type);
wl_data_source_offer(dnd_drag->data_source, wl_data_source_offer(dnd_drag->data_source,
text_mime_type); text_mime_type);
}
if (display_get_data_device_manager_version(display) >= if (display_get_data_device_manager_version(display) >=
WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION) { WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION) {
wl_data_source_set_actions(dnd_drag->data_source, actions); wl_data_source_set_actions(dnd_drag->data_source, actions);
}
} }
wl_data_device_start_drag(input_get_data_device(input), wl_data_device_start_drag(input_get_data_device(input),
@ -789,8 +788,6 @@ dnd_create(struct display *display)
dnd->window = window_create(display); dnd->window = window_create(display);
dnd->widget = window_frame_create(dnd->window, dnd); dnd->widget = window_frame_create(dnd->window, dnd);
window_set_title(dnd->window, "Wayland Drag and Drop Demo"); window_set_title(dnd->window, "Wayland Drag and Drop Demo");
window_set_appid(dnd->window,
"org.freedesktop.weston.wayland-drag-and-drop-demo");
dnd->display = display; dnd->display = display;
dnd->key = 100; dnd->key = 100;
@ -851,8 +848,7 @@ main(int argc, char *argv[])
d = display_create(&argc, argv); d = display_create(&argc, argv);
if (d == NULL) { if (d == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }

View file

@ -38,7 +38,7 @@
#include <pango/pangocairo.h> #include <pango/pangocairo.h>
#include <libweston/config-parser.h> #include "shared/config-parser.h"
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/xalloc.h" #include "shared/xalloc.h"
#include "window.h" #include "window.h"
@ -77,7 +77,7 @@ struct text_entry {
uint32_t serial; uint32_t serial;
uint32_t reset_serial; uint32_t reset_serial;
uint32_t content_purpose; uint32_t content_purpose;
bool click_to_show; uint32_t click_to_show;
char *preferred_language; char *preferred_language;
bool button_pressed; bool button_pressed;
}; };
@ -580,7 +580,7 @@ data_source_send(void *data,
struct editor *editor = data; struct editor *editor = data;
if (write(fd, editor->selected_text, strlen(editor->selected_text) + 1) < 0) if (write(fd, editor->selected_text, strlen(editor->selected_text) + 1) < 0)
fprintf(stderr, "write failed: %s\n", strerror(errno)); fprintf(stderr, "write failed: %m\n");
close(fd); close(fd);
} }
@ -1504,10 +1504,10 @@ global_handler(struct display *display, uint32_t name,
} }
/** Display help for command line options, and exit */ /** Display help for command line options, and exit */
static bool opt_help = false; static uint32_t opt_help = 0;
/** Require a distinct click to show the input panel (virtual keyboard) */ /** Require a distinct click to show the input panel (virtual keyboard) */
static bool opt_click_to_show = false; static uint32_t opt_click_to_show = 0;
/** Set a specific (RFC-3066) language. Used for the virtual keyboard, etc. */ /** Set a specific (RFC-3066) language. Used for the virtual keyboard, etc. */
static const char *opt_preferred_language = NULL; static const char *opt_preferred_language = NULL;
@ -1609,8 +1609,7 @@ main(int argc, char *argv[])
text_buffer = read_file(argv[1]); text_buffer = read_file(argv[1]);
if (text_buffer == NULL) { if (text_buffer == NULL) {
fprintf(stderr, "could not read file '%s': %s\n", fprintf(stderr, "could not read file '%s': %m\n", argv[1]);
argv[1], strerror(errno));
return -1; return -1;
} }
} }
@ -1619,8 +1618,7 @@ main(int argc, char *argv[])
editor.display = display_create(&argc, argv); editor.display = display_create(&argc, argv);
if (editor.display == NULL) { if (editor.display == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
free(text_buffer); free(text_buffer);
return -1; return -1;
} }
@ -1652,7 +1650,6 @@ main(int argc, char *argv[])
editor.selected_text = NULL; editor.selected_text = NULL;
window_set_title(editor.window, "Text Editor"); window_set_title(editor.window, "Text Editor");
window_set_appid(editor.window, "org.freedesktop.weston.text-editor");
window_set_key_handler(editor.window, key_handler); window_set_key_handler(editor.window, key_handler);
window_set_keyboard_focus_handler(editor.window, window_set_keyboard_focus_handler(editor.window,
keyboard_focus_handler); keyboard_focus_handler);

View file

@ -37,8 +37,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <cairo.h> #include <cairo.h>
@ -47,7 +45,6 @@
/** window title */ /** window title */
static char *title = "EventDemo"; static char *title = "EventDemo";
static char *appid = "org.freedesktop.weston.eventdemo";
/** window width */ /** window width */
static int width = 500; static int width = 500;
@ -56,7 +53,7 @@ static int width = 500;
static int height = 400; static int height = 400;
/** set if window has no borders */ /** set if window has no borders */
static bool noborder = false; static int noborder = 0;
/** if non-zero, maximum window width */ /** if non-zero, maximum window width */
static int width_max = 0; static int width_max = 0;
@ -65,25 +62,25 @@ static int width_max = 0;
static int height_max = 0; static int height_max = 0;
/** set to log redrawing */ /** set to log redrawing */
static bool log_redraw = false; static int log_redraw = 0;
/** set to log resizing */ /** set to log resizing */
static bool log_resize = false; static int log_resize = 0;
/** set to log keyboard focus */ /** set to log keyboard focus */
static bool log_focus = false; static int log_focus = 0;
/** set to log key events */ /** set to log key events */
static bool log_key = false; static int log_key = 0;
/** set to log button events */ /** set to log button events */
static bool log_button = false; static int log_button = 0;
/** set to log axis events */ /** set to log axis events */
static bool log_axis = false; static int log_axis = 0;
/** set to log motion events */ /** set to log motion events */
static bool log_motion = false; static int log_motion = 0;
/** /**
* \struct eventdemo * \struct eventdemo
@ -194,11 +191,10 @@ keyboard_focus_handler(struct window *window,
/** /**
* \brief CALLBACK function, Wayland informs about key event * \brief CALLBACK function, Wayland informs about key event
* \param window window * \param window window
* \param input input
* \param time time
* \param key keycode * \param key keycode
* \param unicode associated character * \param unicode associated character
* \param state pressed or released * \param state pressed or released
* \param modifiers modifiers: ctrl, alt, meta etc.
* \param data user data associated to the window * \param data user data associated to the window
*/ */
static void static void
@ -351,8 +347,10 @@ axis_discrete_handler(struct widget *widget, struct input *input,
* \param widget widget * \param widget widget
* \param input input device that caused the motion event * \param input input device that caused the motion event
* \param time time the event happened * \param time time the event happened
* \param x x position relative to the window * \param x absolute x position
* \param y y position relative to the window * \param y absolute y position
* \param sx x position relative to the window
* \param sy y position relative to the window
* \param data user data associated to the window * \param data user data associated to the window
* *
* Demonstrates the use of different cursors * Demonstrates the use of different cursors
@ -399,7 +397,6 @@ eventdemo_create(struct display *d)
} else { } else {
e->widget = window_frame_create(e->window, e); e->widget = window_frame_create(e->window, e);
window_set_title(e->window, title); window_set_title(e->window, title);
window_set_appid(e->window, appid);
} }
e->display = d; e->display = d;
@ -513,21 +510,19 @@ main(int argc, char *argv[])
if (!log_redraw && !log_resize && !log_focus && !log_key && if (!log_redraw && !log_resize && !log_focus && !log_key &&
!log_button && !log_axis && !log_motion) !log_button && !log_axis && !log_motion)
log_redraw = log_resize = log_focus = log_key = log_redraw = log_resize = log_focus = log_key =
log_button = log_axis = log_motion = true; log_button = log_axis = log_motion = 1;
/* Connect to the display and have the arguments parsed */ /* Connect to the display and have the arguments parsed */
d = display_create(&argc, argv); d = display_create(&argc, argv);
if (d == NULL) { if (d == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }
/* Create new eventdemo window */ /* Create new eventdemo window */
e = eventdemo_create(d); e = eventdemo_create(d);
if (e == NULL) { if (e == NULL) {
fprintf(stderr, "failed to create eventdemo: %s\n", fprintf(stderr, "failed to create eventdemo: %m\n");
strerror(errno));
return -1; return -1;
} }

View file

@ -30,7 +30,6 @@
#include <time.h> #include <time.h>
#include <math.h> #include <math.h>
#include <cairo.h> #include <cairo.h>
#include <errno.h>
#include <sys/time.h> #include <sys/time.h>
#include <linux/input.h> #include <linux/input.h>
@ -173,8 +172,7 @@ int main(int argc, char *argv[])
d = display_create(&argc, argv); d = display_create(&argc, argv);
if (d == NULL) { if (d == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }
@ -187,7 +185,6 @@ int main(int argc, char *argv[])
flower.window = window_create(d); flower.window = window_create(d);
flower.widget = window_add_widget(flower.window, &flower); flower.widget = window_add_widget(flower.window, &flower);
window_set_title(flower.window, "Flower"); window_set_title(flower.window, "Flower");
window_set_appid(flower.window, "org.freedesktop.weston.flower");
widget_set_resize_handler(flower.widget, resize_handler); widget_set_resize_handler(flower.widget, resize_handler);
widget_set_redraw_handler(flower.widget, redraw_handler); widget_set_redraw_handler(flower.widget, redraw_handler);

View file

@ -30,13 +30,13 @@
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include <errno.h>
#include <cairo.h> #include <cairo.h>
#include <linux/input.h> #include <linux/input.h>
#include <wayland-client.h> #include <wayland-client.h>
#include "window.h" #include "window.h"
#include <libweston/zalloc.h> #include "fullscreen-shell-unstable-v1-client-protocol.h"
#include "shared/zalloc.h"
struct fs_output { struct fs_output {
struct wl_list link; struct wl_list link;
@ -47,6 +47,8 @@ struct fullscreen {
struct display *display; struct display *display;
struct window *window; struct window *window;
struct widget *widget; struct widget *widget;
struct zwp_fullscreen_shell_v1 *fshell;
enum zwp_fullscreen_shell_v1_present_method present_method;
int width, height; int width, height;
int fullscreen; int fullscreen;
float pointer_x, pointer_y; float pointer_x, pointer_y;
@ -77,7 +79,7 @@ draw_string(cairo_t *cr,
cairo_save(cr); cairo_save(cr);
cairo_select_font_face(cr, "sans-serif", cairo_select_font_face(cr, "sans",
CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL); CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cr, 14); cairo_set_font_size(cr, 14);
@ -119,6 +121,7 @@ redraw_handler(struct widget *widget, void *data)
cairo_t *cr; cairo_t *cr;
int i; int i;
double x, y, border; double x, y, border;
const char *method_name[] = { "default", "center", "zoom", "zoom_crop", "stretch"};
surface = window_get_surface(fullscreen->window); surface = window_get_surface(fullscreen->window);
if (surface == NULL || if (surface == NULL ||
@ -144,17 +147,33 @@ redraw_handler(struct widget *widget, void *data)
allocation.y + 25); allocation.y + 25);
cairo_set_source_rgb(cr, 1, 1, 1); cairo_set_source_rgb(cr, 1, 1, 1);
draw_string(cr, if (fullscreen->fshell) {
"Surface size: %d, %d\n" draw_string(cr,
"Scale: %d, transform: %d\n" "Surface size: %d, %d\n"
"Pointer: %f,%f\n" "Scale: %d, transform: %d\n"
"Fullscreen: %d\n" "Pointer: %f,%f\n"
"Keys: (s)cale, (t)ransform, si(z)e, (f)ullscreen, (q)uit\n", "Output: %s, present method: %s\n"
fullscreen->width, fullscreen->height, "Keys: (s)cale, (t)ransform, si(z)e, (m)ethod,\n"
window_get_buffer_scale (fullscreen->window), " (o)utput, modes(w)itch, (q)uit\n",
window_get_buffer_transform (fullscreen->window), fullscreen->width, fullscreen->height,
fullscreen->pointer_x, fullscreen->pointer_y, window_get_buffer_scale (fullscreen->window),
fullscreen->fullscreen); window_get_buffer_transform (fullscreen->window),
fullscreen->pointer_x, fullscreen->pointer_y,
method_name[fullscreen->present_method],
fullscreen->current_output ? output_get_model(fullscreen->current_output->output): "null");
} else {
draw_string(cr,
"Surface size: %d, %d\n"
"Scale: %d, transform: %d\n"
"Pointer: %f,%f\n"
"Fullscreen: %d\n"
"Keys: (s)cale, (t)ransform, si(z)e, (f)ullscreen, (q)uit\n",
fullscreen->width, fullscreen->height,
window_get_buffer_scale (fullscreen->window),
window_get_buffer_transform (fullscreen->window),
fullscreen->pointer_x, fullscreen->pointer_y,
fullscreen->fullscreen);
}
y = 100; y = 100;
i = 0; i = 0;
@ -233,6 +252,8 @@ key_handler(struct window *window, struct input *input, uint32_t time,
struct fullscreen *fullscreen = data; struct fullscreen *fullscreen = data;
int transform, scale; int transform, scale;
static int current_size = 0; static int current_size = 0;
struct fs_output *fsout;
struct wl_output *wl_output;
int widths[] = { 640, 320, 800, 400 }; int widths[] = { 640, 320, 800, 400 };
int heights[] = { 480, 240, 600, 300 }; int heights[] = { 480, 240, 600, 300 };
@ -258,9 +279,6 @@ key_handler(struct window *window, struct input *input, uint32_t time,
break; break;
case XKB_KEY_z: case XKB_KEY_z:
if (fullscreen->fullscreen)
break;
current_size = (current_size + 1) % 4; current_size = (current_size + 1) % 4;
fullscreen->width = widths[current_size]; fullscreen->width = widths[current_size];
fullscreen->height = heights[current_size]; fullscreen->height = heights[current_size];
@ -268,7 +286,69 @@ key_handler(struct window *window, struct input *input, uint32_t time,
fullscreen->width, fullscreen->height); fullscreen->width, fullscreen->height);
break; break;
case XKB_KEY_m:
if (!fullscreen->fshell)
break;
wl_output = NULL;
if (fullscreen->current_output)
wl_output = output_get_wl_output(fullscreen->current_output->output);
fullscreen->present_method = (fullscreen->present_method + 1) % 5;
zwp_fullscreen_shell_v1_present_surface(fullscreen->fshell,
window_get_wl_surface(fullscreen->window),
fullscreen->present_method,
wl_output);
window_schedule_redraw(window);
break;
case XKB_KEY_o:
if (!fullscreen->fshell)
break;
fsout = fullscreen->current_output;
wl_output = fsout ? output_get_wl_output(fsout->output) : NULL;
/* Clear the current presentation */
zwp_fullscreen_shell_v1_present_surface(fullscreen->fshell, NULL,
0, wl_output);
if (fullscreen->current_output) {
if (fullscreen->current_output->link.next == &fullscreen->output_list)
fsout = NULL;
else
fsout = wl_container_of(fullscreen->current_output->link.next,
fsout, link);
} else {
fsout = wl_container_of(fullscreen->output_list.next,
fsout, link);
}
fullscreen->current_output = fsout;
wl_output = fsout ? output_get_wl_output(fsout->output) : NULL;
zwp_fullscreen_shell_v1_present_surface(fullscreen->fshell,
window_get_wl_surface(fullscreen->window),
fullscreen->present_method,
wl_output);
window_schedule_redraw(window);
break;
case XKB_KEY_w:
if (!fullscreen->fshell || !fullscreen->current_output)
break;
wl_output = NULL;
if (fullscreen->current_output)
wl_output = output_get_wl_output(fullscreen->current_output->output);
zwp_fullscreen_shell_mode_feedback_v1_destroy(
zwp_fullscreen_shell_v1_present_surface_for_mode(fullscreen->fshell,
window_get_wl_surface(fullscreen->window),
wl_output, 0));
window_schedule_redraw(window);
break;
case XKB_KEY_f: case XKB_KEY_f:
if (fullscreen->fshell)
break;
fullscreen->fullscreen ^= 1; fullscreen->fullscreen ^= 1;
window_set_fullscreen(window, fullscreen->fullscreen); window_set_fullscreen(window, fullscreen->fullscreen);
break; break;
@ -340,13 +420,31 @@ touch_handler(struct widget *widget, struct input *input,
window_move(fullscreen->window, input, display_get_serial(fullscreen->display)); window_move(fullscreen->window, input, display_get_serial(fullscreen->display));
} }
static void
fshell_capability_handler(void *data, struct zwp_fullscreen_shell_v1 *fshell,
uint32_t capability)
{
struct fullscreen *fullscreen = data;
switch (capability) {
case ZWP_FULLSCREEN_SHELL_V1_CAPABILITY_CURSOR_PLANE:
fullscreen->draw_cursor = 0;
break;
default:
break;
}
}
struct zwp_fullscreen_shell_v1_listener fullscreen_shell_listener = {
fshell_capability_handler
};
static void static void
usage(int error_code) usage(int error_code)
{ {
fprintf(stderr, "Usage: fullscreen [OPTIONS]\n\n" fprintf(stderr, "Usage: fullscreen [OPTIONS]\n\n"
" -w <width>\tSet window width to <width>\n" " -w <width>\tSet window width to <width>\n"
" -h <height>\tSet window height to <height>\n" " -h <height>\tSet window height to <height>\n"
" -f\t\tMap window as fullscreen\n"
" --help\tShow this help text\n\n"); " --help\tShow this help text\n\n");
exit(error_code); exit(error_code);
@ -372,6 +470,22 @@ output_handler(struct output *output, void *data)
wl_list_insert(&fullscreen->output_list, &fsout->link); wl_list_insert(&fullscreen->output_list, &fsout->link);
} }
static void
global_handler(struct display *display, uint32_t id, const char *interface,
uint32_t version, void *data)
{
struct fullscreen *fullscreen = data;
if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0) {
fullscreen->fshell = display_bind(display, id,
&zwp_fullscreen_shell_v1_interface,
1);
zwp_fullscreen_shell_v1_add_listener(fullscreen->fshell,
&fullscreen_shell_listener,
fullscreen);
}
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct fullscreen fullscreen; struct fullscreen fullscreen;
@ -381,6 +495,7 @@ int main(int argc, char *argv[])
fullscreen.width = 640; fullscreen.width = 640;
fullscreen.height = 480; fullscreen.height = 480;
fullscreen.fullscreen = 0; fullscreen.fullscreen = 0;
fullscreen.present_method = ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT;
wl_list_init(&fullscreen.output_list); wl_list_init(&fullscreen.output_list);
fullscreen.current_output = NULL; fullscreen.current_output = NULL;
@ -395,8 +510,6 @@ int main(int argc, char *argv[])
usage(EXIT_FAILURE); usage(EXIT_FAILURE);
fullscreen.height = atol(argv[i]); fullscreen.height = atol(argv[i]);
} else if (strcmp(argv[i], "-f") == 0) {
fullscreen.fullscreen = 1;
} else if (strcmp(argv[i], "--help") == 0) } else if (strcmp(argv[i], "--help") == 0)
usage(EXIT_SUCCESS); usage(EXIT_SUCCESS);
else else
@ -405,23 +518,33 @@ int main(int argc, char *argv[])
d = display_create(&argc, argv); d = display_create(&argc, argv);
if (d == NULL) { if (d == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }
fullscreen.display = d; fullscreen.display = d;
fullscreen.fshell = NULL;
display_set_user_data(fullscreen.display, &fullscreen); display_set_user_data(fullscreen.display, &fullscreen);
display_set_global_handler(fullscreen.display, global_handler);
display_set_output_configure_handler(fullscreen.display, output_handler); display_set_output_configure_handler(fullscreen.display, output_handler);
fullscreen.window = window_create(d); if (fullscreen.fshell) {
fullscreen.draw_cursor = 0; fullscreen.window = window_create_custom(d);
zwp_fullscreen_shell_v1_present_surface(fullscreen.fshell,
window_get_wl_surface(fullscreen.window),
fullscreen.present_method,
NULL);
/* If we get the CURSOR_PLANE capability, we'll change this */
fullscreen.draw_cursor = 1;
} else {
fullscreen.window = window_create(d);
fullscreen.draw_cursor = 0;
}
fullscreen.widget = fullscreen.widget =
window_add_widget(fullscreen.window, &fullscreen); window_add_widget(fullscreen.window, &fullscreen);
window_set_title(fullscreen.window, "Fullscreen"); window_set_title(fullscreen.window, "Fullscreen");
window_set_appid(fullscreen.window, "org.freedesktop.weston.fullscreen");
widget_set_transparent(fullscreen.widget, 0); widget_set_transparent(fullscreen.widget, 0);
@ -437,8 +560,6 @@ int main(int argc, char *argv[])
window_set_fullscreen_handler(fullscreen.window, fullscreen_handler); window_set_fullscreen_handler(fullscreen.window, fullscreen_handler);
window_set_user_data(fullscreen.window, &fullscreen); window_set_user_data(fullscreen.window, &fullscreen);
if (fullscreen.fullscreen)
window_set_fullscreen(fullscreen.window, fullscreen.fullscreen);
/* Hack to set minimum allocation so we can shrink later */ /* Hack to set minimum allocation so we can shrink later */
window_schedule_resize(fullscreen.window, window_schedule_resize(fullscreen.window,
1, 1); 1, 1);

501
clients/gears.c Normal file
View file

@ -0,0 +1,501 @@
/*
* Copyright © 2008 Kristian Høgsberg
*
* 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.
*/
#include "config.h"
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <GL/gl.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <linux/input.h>
#include <wayland-client.h>
#include "window.h"
struct gears {
struct window *window;
struct widget *widget;
struct display *d;
EGLDisplay display;
EGLDisplay config;
EGLContext context;
GLfloat angle;
struct {
GLfloat rotx;
GLfloat roty;
} view;
int button_down;
int last_x, last_y;
GLint gear_list[3];
int fullscreen;
int frames;
uint32_t last_fps;
};
struct gear_template {
GLfloat material[4];
GLfloat inner_radius;
GLfloat outer_radius;
GLfloat width;
GLint teeth;
GLfloat tooth_depth;
};
static const struct gear_template gear_templates[] = {
{ { 0.8, 0.1, 0.0, 1.0 }, 1.0, 4.0, 1.0, 20, 0.7 },
{ { 0.0, 0.8, 0.2, 1.0 }, 0.5, 2.0, 2.0, 10, 0.7 },
{ { 0.2, 0.2, 1.0, 1.0 }, 1.3, 2.0, 0.5, 10, 0.7 },
};
static GLfloat light_pos[4] = {5.0, 5.0, 10.0, 0.0};
static void die(const char *msg)
{
fprintf(stderr, "%s", msg);
exit(EXIT_FAILURE);
}
static void
make_gear(const struct gear_template *t)
{
GLint i;
GLfloat r0, r1, r2;
GLfloat angle, da;
GLfloat u, v, len;
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, t->material);
r0 = t->inner_radius;
r1 = t->outer_radius - t->tooth_depth / 2.0;
r2 = t->outer_radius + t->tooth_depth / 2.0;
da = 2.0 * M_PI / t->teeth / 4.0;
glShadeModel(GL_FLAT);
glNormal3f(0.0, 0.0, 1.0);
/* draw front face */
glBegin(GL_QUAD_STRIP);
for (i = 0; i <= t->teeth; i++) {
angle = i * 2.0 * M_PI / t->teeth;
glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
if (i < t->teeth) {
glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
}
}
glEnd();
/* draw front sides of teeth */
glBegin(GL_QUADS);
da = 2.0 * M_PI / t->teeth / 4.0;
for (i = 0; i < t->teeth; i++) {
angle = i * 2.0 * M_PI / t->teeth;
glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), t->width * 0.5);
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), t->width * 0.5);
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
}
glEnd();
glNormal3f(0.0, 0.0, -1.0);
/* draw back face */
glBegin(GL_QUAD_STRIP);
for (i = 0; i <= t->teeth; i++) {
angle = i * 2.0 * M_PI / t->teeth;
glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
if (i < t->teeth) {
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
}
}
glEnd();
/* draw back sides of teeth */
glBegin(GL_QUADS);
da = 2.0 * M_PI / t->teeth / 4.0;
for (i = 0; i < t->teeth; i++) {
angle = i * 2.0 * M_PI / t->teeth;
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -t->width * 0.5);
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -t->width * 0.5);
glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
}
glEnd();
/* draw outward faces of teeth */
glBegin(GL_QUAD_STRIP);
for (i = 0; i < t->teeth; i++) {
angle = i * 2.0 * M_PI / t->teeth;
glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
u = r2 * cos(angle + da) - r1 * cos(angle);
v = r2 * sin(angle + da) - r1 * sin(angle);
len = sqrt(u * u + v * v);
u /= len;
v /= len;
glNormal3f(v, -u, 0.0);
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), t->width * 0.5);
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -t->width * 0.5);
glNormal3f(cos(angle), sin(angle), 0.0);
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), t->width * 0.5);
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -t->width * 0.5);
u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
glNormal3f(v, -u, 0.0);
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
glNormal3f(cos(angle), sin(angle), 0.0);
}
glVertex3f(r1 * cos(0), r1 * sin(0), t->width * 0.5);
glVertex3f(r1 * cos(0), r1 * sin(0), -t->width * 0.5);
glEnd();
glShadeModel(GL_SMOOTH);
/* draw inside radius cylinder */
glBegin(GL_QUAD_STRIP);
for (i = 0; i <= t->teeth; i++) {
angle = i * 2.0 * M_PI / t->teeth;
glNormal3f(-cos(angle), -sin(angle), 0.0);
glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
}
glEnd();
}
static void
update_fps(struct gears *gears, uint32_t time)
{
long diff_ms;
static bool first_call = true;
if (first_call) {
gears->last_fps = time;
first_call = false;
} else
gears->frames++;
diff_ms = time - gears->last_fps;
if (diff_ms > 5000) {
float seconds = diff_ms / 1000.0;
float fps = gears->frames / seconds;
printf("%d frames in %6.3f seconds = %6.3f FPS\n", gears->frames, seconds, fps);
fflush(stdout);
gears->frames = 0;
gears->last_fps = time;
}
}
static void
frame_callback(void *data, struct wl_callback *callback, uint32_t time)
{
struct gears *gears = data;
update_fps(gears, time);
gears->angle = (GLfloat) (time % 8192) * 360 / 8192.0;
window_schedule_redraw(gears->window);
if (callback)
wl_callback_destroy(callback);
}
static const struct wl_callback_listener listener = {
frame_callback
};
static int
motion_handler(struct widget *widget, struct input *input,
uint32_t time, float x, float y, void *data)
{
struct gears *gears = data;
int offset_x, offset_y;
float step = 0.5;
if (gears->button_down) {
offset_x = x - gears->last_x;
offset_y = y - gears->last_y;
gears->last_x = x;
gears->last_y = y;
gears->view.roty += offset_x * step;
gears->view.rotx += offset_y * step;
if (gears->view.roty >= 360)
gears->view.roty = gears->view.roty - 360;
if (gears->view.roty <= 0)
gears->view.roty = gears->view.roty + 360;
if (gears->view.rotx >= 360)
gears->view.rotx = gears->view.rotx - 360;
if (gears->view.rotx <= 0)
gears->view.rotx = gears->view.rotx + 360;
}
return CURSOR_LEFT_PTR;
}
static void
button_handler(struct widget *widget, struct input *input,
uint32_t time, uint32_t button,
enum wl_pointer_button_state state, void *data)
{
struct gears *gears = data;
if (button == BTN_LEFT) {
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
gears->button_down = 1;
input_get_position(input,
&gears->last_x, &gears->last_y);
} else {
gears->button_down = 0;
}
}
}
static void
redraw_handler(struct widget *widget, void *data)
{
struct rectangle window_allocation;
struct rectangle allocation;
struct wl_callback *callback;
struct gears *gears = data;
widget_get_allocation(gears->widget, &allocation);
window_get_allocation(gears->window, &window_allocation);
if (display_acquire_window_surface(gears->d,
gears->window,
gears->context) < 0) {
die("Unable to acquire window surface, "
"compiled without cairo-egl?\n");
}
glViewport(allocation.x,
window_allocation.height - allocation.height - allocation.y,
allocation.width, allocation.height);
glScissor(allocation.x,
window_allocation.height - allocation.height - allocation.y,
allocation.width, allocation.height);
glEnable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(0.0, 0.0, -50);
glRotatef(gears->view.rotx, 1.0, 0.0, 0.0);
glRotatef(gears->view.roty, 0.0, 1.0, 0.0);
glPushMatrix();
glTranslatef(-3.0, -2.0, 0.0);
glRotatef(gears->angle, 0.0, 0.0, 1.0);
glCallList(gears->gear_list[0]);
glPopMatrix();
glPushMatrix();
glTranslatef(3.1, -2.0, 0.0);
glRotatef(-2.0 * gears->angle - 9.0, 0.0, 0.0, 1.0);
glCallList(gears->gear_list[1]);
glPopMatrix();
glPushMatrix();
glTranslatef(-3.1, 4.2, 0.0);
glRotatef(-2.0 * gears->angle - 25.0, 0.0, 0.0, 1.0);
glCallList(gears->gear_list[2]);
glPopMatrix();
glPopMatrix();
glFlush();
display_release_window_surface(gears->d, gears->window);
callback = wl_surface_frame(window_get_wl_surface(gears->window));
wl_callback_add_listener(callback, &listener, gears);
}
static void
resize_handler(struct widget *widget,
int32_t width, int32_t height, void *data)
{
struct gears *gears = data;
int32_t size, big, small;
/* Constrain child size to be square and at least 300x300 */
if (width < height) {
small = width;
big = height;
} else {
small = height;
big = width;
}
if (gears->fullscreen)
size = small;
else
size = big;
widget_set_size(gears->widget, size, size);
}
static void
keyboard_focus_handler(struct window *window,
struct input *device, void *data)
{
window_schedule_redraw(window);
}
static void
fullscreen_handler(struct window *window, void *data)
{
struct gears *gears = data;
gears->fullscreen ^= 1;
window_set_fullscreen(window, gears->fullscreen);
}
static struct gears *
gears_create(struct display *display)
{
const int width = 450, height = 500;
struct gears *gears;
int i;
gears = zalloc(sizeof *gears);
gears->d = display;
gears->window = window_create(display);
gears->widget = window_frame_create(gears->window, gears);
window_set_title(gears->window, "Wayland Gears");
gears->display = display_get_egl_display(gears->d);
if (gears->display == NULL)
die("failed to create egl display\n");
eglBindAPI(EGL_OPENGL_API);
gears->config = display_get_argb_egl_config(gears->d);
gears->context = eglCreateContext(gears->display, gears->config,
EGL_NO_CONTEXT, NULL);
if (gears->context == NULL)
die("failed to create context\n");
if (!eglMakeCurrent(gears->display, NULL, NULL, gears->context))
die("failed to make context current\n");
for (i = 0; i < 3; i++) {
gears->gear_list[i] = glGenLists(1);
glNewList(gears->gear_list[i], GL_COMPILE);
make_gear(&gear_templates[i]);
glEndList();
}
gears->button_down = 0;
gears->last_x = 0;
gears->last_y = 0;
gears->view.rotx = 20.0;
gears->view.roty = 30.0;
printf("Warning: FPS count is limited by the wayland compositor or monitor refresh rate\n");
glEnable(GL_NORMALIZE);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 200.0);
glMatrixMode(GL_MODELVIEW);
glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
glClearColor(0, 0, 0, 0.92);
window_set_user_data(gears->window, gears);
widget_set_resize_handler(gears->widget, resize_handler);
widget_set_redraw_handler(gears->widget, redraw_handler);
widget_set_button_handler(gears->widget, button_handler);
widget_set_motion_handler(gears->widget, motion_handler);
window_set_keyboard_focus_handler(gears->window,
keyboard_focus_handler);
window_set_fullscreen_handler(gears->window, fullscreen_handler);
window_schedule_resize(gears->window, width, height);
return gears;
}
static void
gears_destroy(struct gears *gears)
{
widget_destroy(gears->widget);
window_destroy(gears->window);
free(gears);
}
int main(int argc, char *argv[])
{
struct display *d;
struct gears *gears;
d = display_create(&argc, argv);
if (d == NULL) {
fprintf(stderr, "failed to create display: %m\n");
return -1;
}
gears = gears_create(d);
display_run(d);
gears_destroy(gears);
display_destroy(d);
return 0;
}

View file

@ -36,32 +36,16 @@
#include <time.h> #include <time.h>
#include <cairo.h> #include <cairo.h>
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <linux/input.h> #include <linux/input.h>
#include <wayland-client.h> #include <wayland-client.h>
#include "window.h" #include "window.h"
#include "shared/cairo-util.h" #include "shared/cairo-util.h"
#include "shared/helpers.h"
#include "shared/image-loader.h"
bool verbose;
#define verbose_print(...) do { \
if (verbose) \
fprintf(stderr, __VA_ARGS__); \
} while (0)
struct image { struct image {
struct window *window; struct window *window;
struct widget *widget;
/* Decorations, buttons, etc. */
struct widget *frame_widget;
/* Where we draw the image content. */
struct widget *image_widget;
struct display *display; struct display *display;
char *filename; char *filename;
cairo_surface_t *image; cairo_surface_t *image;
@ -79,39 +63,6 @@ struct image {
cairo_matrix_t matrix; cairo_matrix_t matrix;
}; };
struct cli_render_intent_option {
int render_intent;
const char *cli_option;
};
static const struct cli_render_intent_option
cli_ri_table[] = {
{
.render_intent = -1,
.cli_option = "off",
},
{
.render_intent = RENDER_INTENT_PERCEPTUAL,
.cli_option = "per",
},
{
.render_intent = RENDER_INTENT_RELATIVE,
.cli_option = "rel",
},
{
.render_intent = RENDER_INTENT_RELATIVE_BPC,
.cli_option = "rel-bpc",
},
{
.render_intent = RENDER_INTENT_SATURATION,
.cli_option = "sat",
},
{
.render_intent = RENDER_INTENT_ABSOLUTE,
.cli_option = "abs",
},
};
static double static double
get_scale(struct image *image) get_scale(struct image *image)
{ {
@ -130,7 +81,7 @@ clamp_view(struct image *image)
sw = image->width * scale; sw = image->width * scale;
sh = image->height * scale; sh = image->height * scale;
widget_get_allocation(image->frame_widget, &allocation); widget_get_allocation(image->widget, &allocation);
if (sw < allocation.width) { if (sw < allocation.width) {
image->matrix.x0 = image->matrix.x0 =
@ -154,45 +105,27 @@ clamp_view(struct image *image)
} }
static void static void
frame_redraw_handler(struct widget *widget, void *data) redraw_handler(struct widget *widget, void *data)
{
struct rectangle allocation;
cairo_t *cr;
widget_get_allocation(widget, &allocation);
cr = widget_cairo_create(widget);
cairo_rectangle(cr, allocation.x, allocation.y,
allocation.width, allocation.height);
cairo_set_source_rgba(cr, 0, 0, 0, 1);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_fill(cr);
cairo_destroy(cr);
}
static void
frame_resize_handler(struct widget *widget,
int32_t width, int32_t height, void *data)
{
struct image *image = data;
clamp_view(image);
}
static void
image_redraw_handler(struct widget *widget, void *data)
{ {
struct image *image = data; struct image *image = data;
struct rectangle allocation; struct rectangle allocation;
cairo_t *cr; cairo_t *cr;
cairo_surface_t *surface;
double width, height, doc_aspect, window_aspect, scale; double width, height, doc_aspect, window_aspect, scale;
cairo_matrix_t matrix;
cairo_matrix_t translate;
widget_get_allocation(widget, &allocation); surface = window_get_surface(image->window);
cr = cairo_create(surface);
cr = widget_cairo_create(widget); widget_get_allocation(image->widget, &allocation);
cairo_rectangle(cr, allocation.x, allocation.y, cairo_rectangle(cr, allocation.x, allocation.y,
allocation.width, allocation.height); allocation.width, allocation.height);
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); cairo_clip(cr);
cairo_push_group(cr);
cairo_translate(cr, allocation.x, allocation.y);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr, 0, 0, 0, 1);
cairo_paint(cr); cairo_paint(cr);
if (!image->initialized) { if (!image->initialized) {
@ -214,36 +147,49 @@ image_redraw_handler(struct widget *widget, void *data)
clamp_view(image); clamp_view(image);
} }
cairo_set_matrix(cr, &image->matrix); matrix = image->matrix;
cairo_matrix_init_translate(&translate, allocation.x, allocation.y);
cairo_matrix_multiply(&matrix, &matrix, &translate);
cairo_set_matrix(cr, &matrix);
cairo_set_source_surface(cr, image->image, 0, 0); cairo_set_source_surface(cr, image->image, 0, 0);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER); cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_paint(cr); cairo_paint(cr);
cairo_pop_group_to_source(cr);
cairo_paint(cr);
cairo_destroy(cr); cairo_destroy(cr);
cairo_surface_destroy(surface);
} }
static void static void
image_resize_handler(struct widget *widget, resize_handler(struct widget *widget,
int32_t width, int32_t height, void *data) int32_t width, int32_t height, void *data)
{ {
struct image *image = data; struct image *image = data;
struct rectangle allocation;
widget_get_allocation(image->frame_widget, &allocation); clamp_view(image);
}
widget_set_allocation(widget, static void
allocation.x, allocation.y, keyboard_focus_handler(struct window *window,
allocation.width, allocation.height); struct input *device, void *data)
{
struct image *image = data;
window_schedule_redraw(image->window);
} }
static int static int
image_enter_handler(struct widget *widget, enter_handler(struct widget *widget,
struct input *input, struct input *input,
float x, float y, void *data) float x, float y, void *data)
{ {
struct image *image = data; struct image *image = data;
struct rectangle allocation; struct rectangle allocation;
widget_get_allocation(widget, &allocation); widget_get_allocation(image->widget, &allocation);
x -= allocation.x; x -= allocation.x;
y -= allocation.y; y -= allocation.y;
@ -268,14 +214,14 @@ move_viewport(struct image *image, double dx, double dy)
} }
static int static int
image_motion_handler(struct widget *widget, motion_handler(struct widget *widget,
struct input *input, uint32_t time, struct input *input, uint32_t time,
float x, float y, void *data) float x, float y, void *data)
{ {
struct image *image = data; struct image *image = data;
struct rectangle allocation; struct rectangle allocation;
widget_get_allocation(widget, &allocation); widget_get_allocation(image->widget, &allocation);
x -= allocation.x; x -= allocation.x;
y -= allocation.y; y -= allocation.y;
@ -290,11 +236,11 @@ image_motion_handler(struct widget *widget,
} }
static void static void
image_button_handler(struct widget *widget, button_handler(struct widget *widget,
struct input *input, uint32_t time, struct input *input, uint32_t time,
uint32_t button, uint32_t button,
enum wl_pointer_button_state state, enum wl_pointer_button_state state,
void *data) void *data)
{ {
struct image *image = data; struct image *image = data;
@ -332,35 +278,6 @@ zoom(struct image *image, double scale)
clamp_view(image); clamp_view(image);
} }
static void
image_axis_handler(struct widget *widget, struct input *input, uint32_t time,
uint32_t axis, wl_fixed_t value, void *data)
{
struct image *image = data;
if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL &&
input_get_modifiers(input) == MOD_CONTROL_MASK) {
/* set zoom level to 2% per 10 axis units */
zoom(image, (1.0 - wl_fixed_to_double(value) / 500.0));
window_schedule_redraw(image->window);
} else if (input_get_modifiers(input) == 0) {
if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
move_viewport(image, 0, wl_fixed_to_double(value));
else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
move_viewport(image, wl_fixed_to_double(value), 0);
}
}
static void
keyboard_focus_handler(struct window *window,
struct input *device, void *data)
{
struct image *image = data;
window_schedule_redraw(image->window);
}
static void static void
key_handler(struct window *window, struct input *input, uint32_t time, key_handler(struct window *window, struct input *input, uint32_t time,
uint32_t key, uint32_t sym, enum wl_keyboard_key_state state, uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
@ -392,6 +309,26 @@ key_handler(struct window *window, struct input *input, uint32_t time,
} }
} }
static void
axis_handler(struct widget *widget, struct input *input, uint32_t time,
uint32_t axis, wl_fixed_t value, void *data)
{
struct image *image = data;
if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL &&
input_get_modifiers(input) == MOD_CONTROL_MASK) {
/* set zoom level to 2% per 10 axis units */
zoom(image, (1.0 - wl_fixed_to_double(value) / 500.0));
window_schedule_redraw(image->window);
} else if (input_get_modifiers(input) == 0) {
if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
move_viewport(image, 0, wl_fixed_to_double(value));
else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
move_viewport(image, wl_fixed_to_double(value), 0);
}
}
static void static void
fullscreen_handler(struct window *window, void *data) fullscreen_handler(struct window *window, void *data)
{ {
@ -411,40 +348,18 @@ close_handler(void *data)
if (*image->image_counter == 0) if (*image->image_counter == 0)
display_exit(image->display); display_exit(image->display);
cairo_surface_destroy(image->image); widget_destroy(image->widget);
free(image->filename);
widget_destroy(image->image_widget);
widget_destroy(image->frame_widget);
window_destroy(image->window); window_destroy(image->window);
free(image); free(image);
} }
static void
set_empty_input_region(struct widget *widget, struct display *display)
{
struct wl_compositor *compositor;
struct wl_surface *surface;
struct wl_region *region;
compositor = display_get_compositor(display);
surface = widget_get_wl_surface(widget);
region = wl_compositor_create_region(compositor);
wl_surface_set_input_region(surface, region);
wl_region_destroy(region);
}
static struct image * static struct image *
image_create(struct display *display, const char *filename, image_create(struct display *display, const char *filename,
int *image_counter, int render_intent) int *image_counter)
{ {
struct image *image; struct image *image;
struct weston_image *wimage;
char *b, *copy, title[512]; char *b, *copy, title[512];
char *err_msg;
bool ret;
image = zalloc(sizeof *image); image = zalloc(sizeof *image);
if (image == NULL) if (image == NULL)
@ -465,166 +380,51 @@ image_create(struct display *display, const char *filename,
} }
image->window = window_create(display); image->window = window_create(display);
image->widget = window_frame_create(image->window, image);
window_set_title(image->window, title); window_set_title(image->window, title);
window_set_appid(image->window, "org.freedesktop.weston.wayland-image");
image->display = display; image->display = display;
image->image_counter = image_counter; image->image_counter = image_counter;
*image_counter += 1; *image_counter += 1;
image->initialized = false; image->initialized = false;
window_set_user_data(image->window, image); window_set_user_data(image->window, image);
widget_set_redraw_handler(image->widget, redraw_handler);
widget_set_resize_handler(image->widget, resize_handler);
window_set_keyboard_focus_handler(image->window, window_set_keyboard_focus_handler(image->window,
keyboard_focus_handler); keyboard_focus_handler);
window_set_fullscreen_handler(image->window, fullscreen_handler); window_set_fullscreen_handler(image->window, fullscreen_handler);
window_set_close_handler(image->window, close_handler); window_set_close_handler(image->window, close_handler);
widget_set_enter_handler(image->widget, enter_handler);
widget_set_motion_handler(image->widget, motion_handler);
widget_set_button_handler(image->widget, button_handler);
widget_set_axis_handler(image->widget, axis_handler);
window_set_key_handler(image->window, key_handler); window_set_key_handler(image->window, key_handler);
widget_schedule_resize(image->widget, 500, 400);
image->frame_widget = window_frame_create(image->window, image);
widget_set_redraw_handler(image->frame_widget, frame_redraw_handler);
widget_set_resize_handler(image->frame_widget, frame_resize_handler);
image->image_widget = window_add_subsurface(image->window, image,
SUBSURFACE_SYNCHRONIZED);
/* We set the input region of the subsurface where the image is draw as
* NULL, as the input region of the parent surface is automatically set
* by the toytoolkit. But as the window that finds the widget in a
* certain (x, y) position looks for surfaces that are on top first, it
* will call the image_widget handlers for input related stuff. */
set_empty_input_region(image->image_widget, display);
widget_set_redraw_handler(image->image_widget, image_redraw_handler);
widget_set_resize_handler(image->image_widget, image_resize_handler);
widget_set_enter_handler(image->image_widget, image_enter_handler);
widget_set_motion_handler(image->image_widget, image_motion_handler);
widget_set_button_handler(image->image_widget, image_button_handler);
widget_set_axis_handler(image->image_widget, image_axis_handler);
wimage = load_cairo_surface_get_user_data(image->image);
assert(wimage);
if (wimage->icc_profile_data && render_intent != -1) {
verbose_print("Image contains ICC file embedded, let's try to use the Wayland\n" \
"color-management protocol to set the surface image description\n" \
"using this ICC file.\n");
ret = widget_set_image_description_icc(image->image_widget,
wimage->icc_profile_data->fd,
wimage->icc_profile_data->length,
wimage->icc_profile_data->offset,
render_intent, &err_msg);
if (ret) {
verbose_print("Successfully set surface image description " \
"using ICC file.\n");
} else {
fprintf(stderr, "Failed to set surface image description:\n%s\n",
err_msg);
free(err_msg);
}
}
/* TODO: investigate if/how to get colorimetry info from the
* PNG/JPEG/etc image. Then use that to create a parametric image
* description and set it as the widget image description. Also, if
* clients do not enforce us to avoid setting an image description (i.e.
* render_intent != -1) but no colorimetry data is present, we can
* create a sRGB image description (through parameters) and set it as
* the image description to use. For now Weston do not support creating
* image description from parameters, that's why we've added only the
* code above that depends on ICC profiles. */
widget_schedule_resize(image->frame_widget, 500, 400);
return image; return image;
} }
static void
print_usage(const char *program_name)
{
const struct render_intent_info *intent_info;
const char *desc;
unsigned int i;
fprintf(stderr, "Usage:\n %s [OPTIONS] [FILENAME0] [FILENAME1] ...\n\n" \
"Options:\n", program_name);
fprintf(stderr, "-v or --verbose to print verbose log information.\n\n");
fprintf(stderr, "-h or --help to open this HELP dialogue.\n\n");
fprintf(stderr, "-r or --rendering-intent to choose the color-management rendering intent.\n\n " \
"The rendering intent is used when an image file has colorimetry data embedded,\n " \
"and the compositor should present this image taking this into account. We use\n " \
"the Wayland color-management protocol extension to set the image description\n " \
"and a rendering intent, which is up to the client to decide. This is optional,\n " \
"and if nothing set we'll use 'perceptual'. Supported values:\n\n");
for (i = 0; i < ARRAY_LENGTH(cli_ri_table); i++) {
/* "off" option does not have a corresponding render_intent_info
* object from which we would be able to get the description. */
intent_info = render_intent_info_from(cli_ri_table[i].render_intent);
if (intent_info)
desc = intent_info->desc;
else
desc = "No render intent (do not set image description)";
fprintf(stderr, " %s: %s.\n", cli_ri_table[i].cli_option, desc);
}
}
static int
get_render_intent(int *render_intent, const char *opt_rendering_intent)
{
unsigned int i;
/* The default, if client does not set anything. */
if (!opt_rendering_intent) {
*render_intent = RENDER_INTENT_PERCEPTUAL;
return 0;
}
for (i = 0; i < ARRAY_LENGTH(cli_ri_table); i++) {
if (strcmp(opt_rendering_intent, cli_ri_table[i].cli_option) == 0) {
*render_intent = cli_ri_table[i].render_intent;
return 0;
}
}
fprintf(stderr, "Error: unknown rendering intent: %s.\n\n",
opt_rendering_intent);
return -1;
}
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
struct display *d; struct display *d;
int i; int i;
int image_counter = 0; int image_counter = 0;
int render_intent;
bool opt_help = false;
char *opt_rendering_intent = NULL;
struct weston_option cli_options[] = {
{ WESTON_OPTION_BOOLEAN, "help", 'h', &opt_help },
{ WESTON_OPTION_BOOLEAN, "verbose", 'v', &verbose },
{ WESTON_OPTION_STRING, "rendering-intent", 'r', &opt_rendering_intent },
};
parse_options(cli_options, ARRAY_LENGTH(cli_options), &argc, argv); if (argc <= 1 || argv[1][0]=='-') {
printf("Usage: %s image...\n", argv[0]);
if (argc <= 1 || opt_help ||
get_render_intent(&render_intent, opt_rendering_intent) < 0) {
free(opt_rendering_intent);
print_usage(argv[0]);
return 1; return 1;
} }
free(opt_rendering_intent);
d = display_create(&argc, argv); d = display_create(&argc, argv);
if (d == NULL) { if (d == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }
for (i = 1; i < argc; i++) for (i = 1; i < argc; i++)
image_create(d, argv[i], &image_counter, render_intent); image_create(d, argv[i], &image_counter);
if (image_counter > 0) if (image_counter > 0)
display_run(d); display_run(d);

View file

@ -35,15 +35,14 @@
#include <signal.h> #include <signal.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <getopt.h> #include <getopt.h>
#include <errno.h>
#include <wayland-cursor.h> #include <wayland-cursor.h>
#include <wayland-client-protocol.h> #include <wayland-client-protocol.h>
#include "shared/cairo-util.h" #include "shared/cairo-util.h"
#include <libweston/config-parser.h> #include "shared/config-parser.h"
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/os-compatibility.h" #include "shared/os-compatibility.h"
#include "shared/xalloc.h" #include "shared/xalloc.h"
#include <libweston/zalloc.h> #include "shared/zalloc.h"
#include "shared/file-util.h" #include "shared/file-util.h"
#include "ivi-application-client-protocol.h" #include "ivi-application-client-protocol.h"
#include "ivi-hmi-controller-client-protocol.h" #include "ivi-hmi-controller-client-protocol.h"
@ -143,8 +142,6 @@ hmi_homescreen_launcher {
uint32_t workspace_id; uint32_t workspace_id;
char *icon; char *icon;
char *path; char *path;
char **argv;
struct wl_list link; struct wl_list link;
}; };
@ -310,10 +307,12 @@ launcher_button(uint32_t surfaceId, struct wl_list *launcher_list)
struct hmi_homescreen_launcher *launcher = NULL; struct hmi_homescreen_launcher *launcher = NULL;
wl_list_for_each(launcher, launcher_list, link) { wl_list_for_each(launcher, launcher_list, link) {
char *argv[] = { NULL };
if (surfaceId != launcher->icon_surface_id) if (surfaceId != launcher->icon_surface_id)
continue; continue;
execute_process(launcher->path, launcher->argv); execute_process(launcher->path, argv);
return 1; return 1;
} }
@ -807,8 +806,8 @@ createShmBuffer(struct wlContextStruct *p_wlCtx)
fd = os_create_anonymous_file(size); fd = os_create_anonymous_file(size);
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "creating a buffer file for %d B failed: %s\n", fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
size, strerror(errno)); size);
return ; return ;
} }
@ -816,7 +815,7 @@ createShmBuffer(struct wlContextStruct *p_wlCtx)
mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (MAP_FAILED == p_wlCtx->data) { if (MAP_FAILED == p_wlCtx->data) {
fprintf(stderr, "mmap failed: %s\n", strerror(errno)); fprintf(stderr, "mmap failed: %m\n");
close(fd); close(fd);
return; return;
} }
@ -829,8 +828,7 @@ createShmBuffer(struct wlContextStruct *p_wlCtx)
WL_SHM_FORMAT_ARGB8888); WL_SHM_FORMAT_ARGB8888);
if (NULL == p_wlCtx->wlBuffer) { if (NULL == p_wlCtx->wlBuffer) {
fprintf(stderr, "wl_shm_create_buffer failed: %s\n", fprintf(stderr, "wl_shm_create_buffer failed: %m\n");
strerror(errno));
close(fd); close(fd);
return; return;
} }
@ -1065,32 +1063,6 @@ create_launchers(struct wlContextCommon *cmm, struct wl_list *launcher_list)
free(launchers); free(launchers);
} }
static char **
parse_command(char *str)
{
char **argv;
char *saveptr;
char *token;
int i;
int count = 1;
for (i = 1; str[i]; i++)
if (str[i] == ' ' && str[i-1] != ' ')
count++;
argv = xcalloc(count + 1, sizeof(char*));
i = 0;
token = strtok_r(str, " ", &saveptr);
while (token != NULL) {
argv[i++] = token;
token = strtok_r(NULL, " ", &saveptr);
}
return argv;
}
/** /**
* Internal method to read out weston.ini to get configuration * Internal method to read out weston.ini to get configuration
*/ */
@ -1203,7 +1175,6 @@ hmi_homescreen_setting_create(void)
while (weston_config_next_section(config, &section, &name)) { while (weston_config_next_section(config, &section, &name)) {
struct hmi_homescreen_launcher *launcher; struct hmi_homescreen_launcher *launcher;
char *command;
if (strcmp(name, "ivi-launcher") != 0) if (strcmp(name, "ivi-launcher") != 0)
continue; continue;
@ -1213,18 +1184,8 @@ hmi_homescreen_setting_create(void)
weston_config_section_get_string(section, "icon", weston_config_section_get_string(section, "icon",
&launcher->icon, NULL); &launcher->icon, NULL);
weston_config_section_get_string(section, "path",
weston_config_section_get_string(section, "command", &launcher->path, NULL);
&command, NULL);
if (command == NULL) {
weston_config_section_get_string(section, "path",
&launcher->path, NULL);
launcher->argv = NULL;
} else {
launcher->argv = parse_command(command);
launcher->path = launcher->argv[0];
}
weston_config_section_get_uint(section, "workspace-id", weston_config_section_get_uint(section, "workspace-id",
&launcher->workspace_id, 0); &launcher->workspace_id, 0);
weston_config_section_get_uint(section, "icon-id", weston_config_section_get_uint(section, "icon-id",
@ -1324,11 +1285,6 @@ int main(int argc, char **argv)
wlCtx_WorkSpaceBackGround.cmm = &wlCtxCommon; wlCtx_WorkSpaceBackGround.cmm = &wlCtxCommon;
/* create desktop widgets */ /* create desktop widgets */
create_launchers(&wlCtxCommon, &hmi_setting->launcher_list);
create_workspace_background(&wlCtx_WorkSpaceBackGround,
&hmi_setting->workspace_background);
for (i = 0; i < hmi_setting->screen_num; i++) { for (i = 0; i < hmi_setting->screen_num; i++) {
wlCtx_BackGround[i].cmm = &wlCtxCommon; wlCtx_BackGround[i].cmm = &wlCtxCommon;
create_background(&wlCtx_BackGround[i], create_background(&wlCtx_BackGround[i],
@ -1354,6 +1310,11 @@ int main(int argc, char **argv)
create_button(&wlCtx_Button_4, hmi_setting->random.id, create_button(&wlCtx_Button_4, hmi_setting->random.id,
hmi_setting->random.filePath, 3); hmi_setting->random.filePath, 3);
create_workspace_background(&wlCtx_WorkSpaceBackGround,
&hmi_setting->workspace_background);
create_launchers(&wlCtxCommon, &hmi_setting->launcher_list);
create_home_button(&wlCtx_HomeButton, hmi_setting->home.id, create_home_button(&wlCtx_HomeButton, hmi_setting->home.id,
hmi_setting->home.filePath); hmi_setting->home.filePath);

View file

@ -29,7 +29,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include <linux/input.h> #include <linux/input.h>
#include <cairo.h> #include <cairo.h>
@ -60,8 +59,6 @@ struct virtual_keyboard {
uint32_t surrounding_cursor; uint32_t surrounding_cursor;
struct keyboard *keyboard; struct keyboard *keyboard;
bool toplevel; bool toplevel;
bool overlay;
struct zwp_input_panel_surface_v1 *ips;
}; };
enum key_type { enum key_type {
@ -377,7 +374,7 @@ redraw_handler(struct widget *widget, void *data)
cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height); cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
cairo_clip(cr); cairo_clip(cr);
cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_select_font_face(cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 16); cairo_set_font_size(cr, 16);
cairo_translate(cr, allocation.x, allocation.y); cairo_translate(cr, allocation.x, allocation.y);
@ -506,7 +503,7 @@ delete_before_cursor(struct virtual_keyboard *keyboard)
end = keyboard->surrounding_text + keyboard->surrounding_cursor; end = keyboard->surrounding_text + keyboard->surrounding_cursor;
zwp_input_method_context_v1_delete_surrounding_text(keyboard->context, zwp_input_method_context_v1_delete_surrounding_text(keyboard->context,
start - keyboard->surrounding_text, (start - keyboard->surrounding_text) - keyboard->surrounding_cursor,
end - start); end - start);
zwp_input_method_context_v1_commit_string(keyboard->context, zwp_input_method_context_v1_commit_string(keyboard->context,
keyboard->serial, keyboard->serial,
@ -960,33 +957,25 @@ global_handler(struct display *display, uint32_t name,
static void static void
set_toplevel(struct output *output, struct virtual_keyboard *virtual_keyboard) set_toplevel(struct output *output, struct virtual_keyboard *virtual_keyboard)
{ {
zwp_input_panel_surface_v1_set_toplevel(virtual_keyboard->ips, struct zwp_input_panel_surface_v1 *ips;
struct keyboard *keyboard = virtual_keyboard->keyboard;
ips = zwp_input_panel_v1_get_input_panel_surface(virtual_keyboard->input_panel,
window_get_wl_surface(keyboard->window));
zwp_input_panel_surface_v1_set_toplevel(ips,
output_get_wl_output(output), output_get_wl_output(output),
ZWP_INPUT_PANEL_SURFACE_V1_POSITION_CENTER_BOTTOM); ZWP_INPUT_PANEL_SURFACE_V1_POSITION_CENTER_BOTTOM);
virtual_keyboard->toplevel = true;
virtual_keyboard->overlay = false;
}
static void virtual_keyboard->toplevel = true;
set_overlay(struct output *output, struct virtual_keyboard *virtual_keyboard)
{
zwp_input_panel_surface_v1_set_overlay_panel(virtual_keyboard->ips);
virtual_keyboard->toplevel = false;
virtual_keyboard->overlay = true;
} }
static void static void
display_output_handler(struct output *output, void *data) { display_output_handler(struct output *output, void *data) {
struct virtual_keyboard *keyboard = data; struct virtual_keyboard *keyboard = data;
const char *type = getenv("WESTON_KEYBOARD_SURFACE_TYPE");
if (type && strcasecmp("overlay", type) == 0) { if (!keyboard->toplevel)
if (!keyboard->overlay) set_toplevel(output, keyboard);
set_overlay(output, keyboard);
} else {
if (!keyboard->toplevel)
set_toplevel(output, keyboard);
}
} }
static void static void
@ -1002,14 +991,9 @@ keyboard_create(struct virtual_keyboard *virtual_keyboard)
keyboard->window = window_create_custom(virtual_keyboard->display); keyboard->window = window_create_custom(virtual_keyboard->display);
keyboard->widget = window_add_widget(keyboard->window, keyboard); keyboard->widget = window_add_widget(keyboard->window, keyboard);
virtual_keyboard->ips =
zwp_input_panel_v1_get_input_panel_surface(virtual_keyboard->input_panel,
window_get_wl_surface(keyboard->window));
virtual_keyboard->keyboard = keyboard; virtual_keyboard->keyboard = keyboard;
window_set_title(keyboard->window, "Virtual keyboard"); window_set_title(keyboard->window, "Virtual keyboard");
window_set_appid(keyboard->window,
"org.freedesktop.weston.virtual-keyboard");
window_set_user_data(keyboard->window, keyboard); window_set_user_data(keyboard->window, keyboard);
widget_set_redraw_handler(keyboard->widget, redraw_handler); widget_set_redraw_handler(keyboard->widget, redraw_handler);
@ -1026,23 +1010,6 @@ keyboard_create(struct virtual_keyboard *virtual_keyboard)
display_output_handler); display_output_handler);
} }
static void
keyboard_destroy(struct virtual_keyboard *virtual_keyboard)
{
if (virtual_keyboard->ips)
zwp_input_panel_surface_v1_destroy(virtual_keyboard->ips);
if (virtual_keyboard->input_panel)
zwp_input_panel_v1_destroy(virtual_keyboard->input_panel);
if (virtual_keyboard->input_method)
zwp_input_method_v1_destroy(virtual_keyboard->input_method);
widget_destroy(virtual_keyboard->keyboard->widget);
window_destroy(virtual_keyboard->keyboard->window);
free(virtual_keyboard->keyboard);
}
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
@ -1052,8 +1019,7 @@ main(int argc, char *argv[])
virtual_keyboard.display = display_create(&argc, argv); virtual_keyboard.display = display_create(&argc, argv);
if (virtual_keyboard.display == NULL) { if (virtual_keyboard.display == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }
@ -1069,8 +1035,5 @@ main(int argc, char *argv[])
display_run(virtual_keyboard.display); display_run(virtual_keyboard.display);
keyboard_destroy(&virtual_keyboard);
display_destroy(virtual_keyboard.display);
return 0; return 0;
} }

View file

@ -4,8 +4,6 @@ endif
srcs_toytoolkit = [ srcs_toytoolkit = [
'window.c', 'window.c',
color_management_v1_client_protocol_h,
color_management_v1_protocol_c,
xdg_shell_client_protocol_h, xdg_shell_client_protocol_h,
xdg_shell_protocol_c, xdg_shell_protocol_c,
text_cursor_position_client_protocol_h, text_cursor_position_client_protocol_h,
@ -14,19 +12,12 @@ srcs_toytoolkit = [
relative_pointer_unstable_v1_protocol_c, relative_pointer_unstable_v1_protocol_c,
pointer_constraints_unstable_v1_client_protocol_h, pointer_constraints_unstable_v1_client_protocol_h,
pointer_constraints_unstable_v1_protocol_c, pointer_constraints_unstable_v1_protocol_c,
single_pixel_buffer_v1_client_protocol_h,
single_pixel_buffer_v1_protocol_c,
tablet_unstable_v2_client_protocol_h,
tablet_unstable_v2_protocol_c,
ivi_application_client_protocol_h, ivi_application_client_protocol_h,
ivi_application_protocol_c, ivi_application_protocol_c,
viewporter_client_protocol_h,
viewporter_protocol_c,
] ]
deps_toytoolkit = [ deps_toytoolkit = [
dep_wayland_client, dep_wayland_client,
dep_lib_cairo_shared, dep_lib_cairo_shared,
dep_matrix_c,
dep_xkbcommon, dep_xkbcommon,
dependency('wayland-cursor'), dependency('wayland-cursor'),
cc.find_library('util'), cc.find_library('util'),
@ -34,7 +25,7 @@ deps_toytoolkit = [
lib_toytoolkit = static_library( lib_toytoolkit = static_library(
'toytoolkit', 'toytoolkit',
srcs_toytoolkit, srcs_toytoolkit,
include_directories: common_inc, include_directories: include_directories('..', '../shared'),
dependencies: deps_toytoolkit, dependencies: deps_toytoolkit,
install: false, install: false,
) )
@ -42,10 +33,6 @@ dep_toytoolkit = declare_dependency(
link_with: lib_toytoolkit, link_with: lib_toytoolkit,
dependencies: deps_toytoolkit, dependencies: deps_toytoolkit,
) )
dep_gbm = dependency('gbm', required: false, version: '>= 21.3')
simple_clients_enabled = get_option('simple-clients')
simple_build_all = simple_clients_enabled.contains('all')
simple_clients = [ simple_clients = [
{ {
@ -56,36 +43,11 @@ simple_clients = [
viewporter_protocol_c, viewporter_protocol_c,
xdg_shell_client_protocol_h, xdg_shell_client_protocol_h,
xdg_shell_protocol_c, xdg_shell_protocol_c,
fullscreen_shell_unstable_v1_client_protocol_h,
fullscreen_shell_unstable_v1_protocol_c,
], ],
'dep_objs': [ dep_wayland_client, dep_libshared ] 'dep_objs': [ dep_wayland_client, dep_libshared ]
}, },
{
'name': 'dmabuf-feedback',
'sources': [
'simple-dmabuf-feedback.c',
'../libweston/pixel-formats.c',
linux_dmabuf_unstable_v1_client_protocol_h,
linux_dmabuf_unstable_v1_protocol_c,
presentation_time_client_protocol_h,
presentation_time_protocol_c,
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
],
'dep_objs': [
dep_wayland_client,
dep_libshared,
dep_pixman,
dep_libdrm,
dependency('libudev', version: '>= 136'),
# gbm_bo_get_fd_for_plane() from 21.1.0
dependency('gbm', version: '>= 21.1.1',
required: simple_build_all or simple_clients_enabled.contains('dmabuf-feedback'),
not_found_message: 'dmabuf-feedback requires gbm which was not found. If you rather not build this, drop "dmabuf-feedback" from simple-clients option.',
disabler: true)
],
'deps': [ 'egl', 'glesv2', 'gbm' ],
'options': [ 'renderer-gl' ]
},
{ {
'name': 'dmabuf-egl', 'name': 'dmabuf-egl',
'sources': [ 'sources': [
@ -94,19 +56,17 @@ simple_clients = [
linux_dmabuf_unstable_v1_protocol_c, linux_dmabuf_unstable_v1_protocol_c,
linux_explicit_synchronization_unstable_v1_client_protocol_h, linux_explicit_synchronization_unstable_v1_client_protocol_h,
linux_explicit_synchronization_unstable_v1_protocol_c, linux_explicit_synchronization_unstable_v1_protocol_c,
xdg_shell_client_protocol_h, xdg_shell_unstable_v6_client_protocol_h,
xdg_shell_protocol_c, xdg_shell_unstable_v6_protocol_c,
weston_direct_display_client_protocol_h, fullscreen_shell_unstable_v1_client_protocol_h,
weston_direct_display_protocol_c, fullscreen_shell_unstable_v1_protocol_c,
], ],
'dep_objs': [ 'dep_objs': [
dep_wayland_client, dep_wayland_client,
dep_libdrm, dep_libdrm,
dep_libm, dep_libm
dep_matrix_c,
], ],
'deps': [ 'egl', 'glesv2', 'gbm' ], 'deps': [ 'egl', 'glesv2', 'gbm' ]
'options': [ 'renderer-gl' ]
}, },
{ {
'name': 'dmabuf-v4l', 'name': 'dmabuf-v4l',
@ -116,37 +76,22 @@ simple_clients = [
linux_dmabuf_unstable_v1_protocol_c, linux_dmabuf_unstable_v1_protocol_c,
xdg_shell_client_protocol_h, xdg_shell_client_protocol_h,
xdg_shell_protocol_c, xdg_shell_protocol_c,
weston_direct_display_client_protocol_h, fullscreen_shell_unstable_v1_client_protocol_h,
weston_direct_display_protocol_c, fullscreen_shell_unstable_v1_protocol_c,
viewporter_client_protocol_h,
viewporter_protocol_c,
], ],
'dep_objs': [ dep_wayland_client, dep_libdrm_headers ], 'dep_objs': [ dep_wayland_client, dep_libdrm_headers ]
'deps': [ 'wayland-cursor' ]
}, },
{ {
'name': 'egl', 'name': 'egl',
'sources': [ 'sources': [
'simple-egl.c', 'simple-egl.c',
fractional_scale_v1_client_protocol_h,
fractional_scale_v1_protocol_c,
tearing_control_v1_client_protocol_h,
tearing_control_v1_protocol_c,
viewporter_client_protocol_h,
viewporter_protocol_c,
xdg_shell_client_protocol_h, xdg_shell_client_protocol_h,
xdg_shell_protocol_c, xdg_shell_protocol_c,
ivi_application_client_protocol_h, ivi_application_client_protocol_h,
ivi_application_protocol_c, ivi_application_protocol_c,
], ],
'dep_objs': [ 'dep_objs': [ dep_wayland_client, dep_libshared, dep_libm ],
dep_libm, 'deps': [ 'egl', 'wayland-egl', 'glesv2', 'wayland-cursor' ]
dep_libshared,
dep_matrix_c,
dep_wayland_client,
],
'deps': [ 'egl', 'wayland-egl', 'glesv2', 'wayland-cursor' ],
'options': [ 'renderer-gl' ]
}, },
# weston-simple-im is handled specially separately due to install_dir and odd window.h usage # weston-simple-im is handled specially separately due to install_dir and odd window.h usage
{ {
@ -155,120 +100,24 @@ simple_clients = [
'simple-shm.c', 'simple-shm.c',
xdg_shell_client_protocol_h, xdg_shell_client_protocol_h,
xdg_shell_protocol_c, xdg_shell_protocol_c,
fullscreen_shell_unstable_v1_client_protocol_h,
fullscreen_shell_unstable_v1_protocol_c,
ivi_application_client_protocol_h, ivi_application_client_protocol_h,
ivi_application_protocol_c, ivi_application_protocol_c,
], ],
'dep_objs': [ dep_wayland_client, dep_libshared ] 'dep_objs': [ dep_wayland_client, dep_libshared ]
}, },
{
'name': 'timing',
'sources': [
'simple-timing.c',
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
commit_timing_v1_client_protocol_h,
commit_timing_v1_protocol_c,
fifo_v1_client_protocol_h,
fifo_v1_protocol_c,
presentation_time_client_protocol_h,
presentation_time_protocol_c,
],
'dep_objs': [ dep_wayland_client, dep_libshared ]
},
{ {
'name': 'touch', 'name': 'touch',
'sources': [ 'sources': [
'simple-touch.c', 'simple-touch.c',
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
], ],
'dep_objs': [ dep_wayland_client, dep_libshared ] 'dep_objs': [ dep_wayland_client, dep_libshared ]
}, },
] ]
if dep_vulkan.found() and prog_glslang.found() simple_clients_enabled = get_option('simple-clients')
srcs_simple_vulkan_shaders = [ simple_build_all = simple_clients_enabled.contains('all')
'simple_vulkan_vertex_shader.vert',
'simple_vulkan_fragment_shader.frag',
]
simple_vulkan_shaders = []
foreach s : srcs_simple_vulkan_shaders
simple_vulkan_shaders += custom_target(s + '.spv.h',
command: [ prog_glslang, '@INPUT@', '--quiet', '--variable-name', '@BASENAME@', '-V', '-x', '-o', '@OUTPUT@' ],
input: s,
output: '@BASENAME@.spv.h',
)
endforeach
simple_clients += {
'name': 'vulkan',
'sources': [
'simple-vulkan.c',
simple_vulkan_shaders,
fractional_scale_v1_client_protocol_h,
fractional_scale_v1_protocol_c,
tearing_control_v1_client_protocol_h,
tearing_control_v1_protocol_c,
viewporter_client_protocol_h,
viewporter_protocol_c,
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
],
'dep_objs': [
dep_vulkan,
dep_libm,
dep_libshared,
dep_matrix_c,
dep_wayland_client,
],
'deps': [ 'vulkan', 'wayland-cursor' ],
'options': [ 'renderer-gl' ]
}
srcs_simple_dmabuf_vulkan_shaders = [
'simple_dmabuf_vulkan_vertex_shader.vert',
'simple_dmabuf_vulkan_fragment_shader.frag',
]
simple_dmabuf_vulkan_shaders = []
foreach s : srcs_simple_dmabuf_vulkan_shaders
simple_dmabuf_vulkan_shaders += custom_target(s + '.spv.h',
command: [ prog_glslang, '@INPUT@', '--quiet', '--variable-name', '@BASENAME@', '-V', '-x', '-o', '@OUTPUT@' ],
input: s,
output: '@BASENAME@.spv.h',
)
endforeach
simple_clients += {
'name': 'dmabuf-vulkan',
'sources': [
'simple-dmabuf-vulkan.c',
simple_dmabuf_vulkan_shaders,
linux_dmabuf_unstable_v1_client_protocol_h,
linux_dmabuf_unstable_v1_protocol_c,
linux_explicit_synchronization_unstable_v1_client_protocol_h,
linux_explicit_synchronization_unstable_v1_protocol_c,
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
weston_direct_display_client_protocol_h,
weston_direct_display_protocol_c,
],
'dep_objs': [
dep_vulkan,
dep_libdrm_headers,
dep_libm,
dep_libdrm,
dep_libshared,
dep_matrix_c,
dep_wayland_client,
dep_libweston_private, # for pixel-formats.h
],
'deps': [ 'vulkan', 'wayland-cursor', 'gbm' ],
'options': [ 'renderer-gl' ]
}
endif
foreach t : simple_clients foreach t : simple_clients
if simple_build_all or simple_clients_enabled.contains(t.get('name')) if simple_build_all or simple_clients_enabled.contains(t.get('name'))
t_name = 'weston-simple-' + t.get('name') t_name = 'weston-simple-' + t.get('name')
@ -281,15 +130,9 @@ foreach t : simple_clients
t_deps += dep t_deps += dep
endforeach endforeach
foreach optname : t.get('options', [])
if not get_option(optname)
error('@0@ requires option @1@ which is not enabled. If you rather not build this, drop "@2@" from simple-clients option.'.format(t_name, optname, t.get('name')))
endif
endforeach
executable( executable(
t_name, t.get('sources'), t_name, t.get('sources'),
include_directories: common_inc, include_directories: include_directories('..'),
dependencies: t_deps, dependencies: t_deps,
install: true install: true
) )
@ -303,7 +146,7 @@ if simple_build_all or simple_clients_enabled.contains('im')
input_method_unstable_v1_client_protocol_h, input_method_unstable_v1_client_protocol_h,
input_method_unstable_v1_protocol_c, input_method_unstable_v1_protocol_c,
], ],
include_directories: common_inc, include_directories: include_directories('..'),
dependencies: [ dependencies: [
dep_libshared, dep_libshared,
dep_wayland_client, dep_wayland_client,
@ -320,8 +163,11 @@ tools_enabled = get_option('tools')
tools_list = [ tools_list = [
{ {
'name': 'calibrator', 'name': 'calibrator',
'sources': [ 'calibrator.c' ], 'sources': [
'deps': [ dep_toytoolkit, dep_matrix_c ], 'calibrator.c',
'../shared/matrix.c',
],
'deps': [ dep_toytoolkit ],
}, },
{ {
'name': 'debug', 'name': 'debug',
@ -332,6 +178,21 @@ tools_list = [
], ],
'deps': [ dep_wayland_client ] 'deps': [ dep_wayland_client ]
}, },
{
'name': 'info',
'sources': [
'weston-info.c',
presentation_time_client_protocol_h,
presentation_time_protocol_c,
linux_dmabuf_unstable_v1_client_protocol_h,
linux_dmabuf_unstable_v1_protocol_c,
tablet_unstable_v2_client_protocol_h,
tablet_unstable_v2_protocol_c,
xdg_output_unstable_v1_client_protocol_h,
xdg_output_unstable_v1_protocol_c,
],
'deps': [ dep_wayland_client, dep_libshared ]
},
{ {
'name': 'terminal', 'name': 'terminal',
'sources': [ 'terminal.c' ], 'sources': [ 'terminal.c' ],
@ -341,10 +202,11 @@ tools_list = [
'name': 'touch-calibrator', 'name': 'touch-calibrator',
'sources': [ 'sources': [
'touch-calibrator.c', 'touch-calibrator.c',
'../shared/matrix.c',
weston_touch_calibration_client_protocol_h, weston_touch_calibration_client_protocol_h,
weston_touch_calibration_protocol_c, weston_touch_calibration_protocol_c,
], ],
'deps': [ dep_toytoolkit, dep_matrix_c ], 'deps': [ dep_toytoolkit ],
}, },
] ]
@ -353,7 +215,7 @@ foreach t : tools_list
executable( executable(
'weston-@0@'.format(t.get('name')), 'weston-@0@'.format(t.get('name')),
t.get('sources'), t.get('sources'),
include_directories: common_inc, include_directories: include_directories('..', '../shared'),
dependencies: t.get('deps', []), dependencies: t.get('deps', []),
install: true install: true
) )
@ -364,32 +226,9 @@ demo_clients = [
{ 'basename': 'clickdot' }, { 'basename': 'clickdot' },
{ {
'basename': 'cliptest', 'basename': 'cliptest',
'dep_objs': [ dep_vertex_clipping, dep_matrix_c ] 'add_sources': [ '../libweston/vertex-clipping.c' ]
}, },
{ { 'basename': 'confine' },
'basename': 'color',
'add_sources': [
color_management_v1_client_protocol_h,
color_management_v1_protocol_c,
single_pixel_buffer_v1_client_protocol_h,
single_pixel_buffer_v1_protocol_c,
],
},
{
'basename': 'constraints',
'add_sources': [
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
],
},
{
'basename': 'content_protection',
'add_sources': [
weston_content_protection_client_protocol_h,
weston_content_protection_protocol_c,
]
},
{ 'basename': 'dnd' }, { 'basename': 'dnd' },
{ {
'basename': 'editor', 'basename': 'editor',
@ -397,28 +236,24 @@ demo_clients = [
text_input_unstable_v1_client_protocol_h, text_input_unstable_v1_client_protocol_h,
text_input_unstable_v1_protocol_c, text_input_unstable_v1_protocol_c,
], ],
'deps': [ 'pangocairo', 'gobject-2.0' ] 'deps': [ 'pangocairo' ]
}, },
{ 'basename': 'eventdemo' }, { 'basename': 'eventdemo' },
{ 'basename': 'flower' }, { 'basename': 'flower' },
{ {
'basename': 'fullscreen', 'basename': 'fullscreen',
},
{ 'basename': 'image' },
{
'basename': 'multi-resource',
'add_sources': [ 'add_sources': [
xdg_shell_client_protocol_h, fullscreen_shell_unstable_v1_client_protocol_h,
xdg_shell_protocol_c, fullscreen_shell_unstable_v1_protocol_c,
] ]
}, },
{ 'basename': 'image' },
{ 'basename': 'multi-resource' },
{ {
'basename': 'presentation-shm', 'basename': 'presentation-shm',
'add_sources': [ 'add_sources': [
presentation_time_client_protocol_h, presentation_time_client_protocol_h,
presentation_time_protocol_c, presentation_time_protocol_c,
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
] ]
}, },
{ 'basename': 'resizor' }, { 'basename': 'resizor' },
@ -435,13 +270,6 @@ demo_clients = [
'basename': 'subsurfaces', 'basename': 'subsurfaces',
'deps': [ 'egl', 'glesv2', 'wayland-egl' ] 'deps': [ 'egl', 'glesv2', 'wayland-egl' ]
}, },
{
'basename': 'tablet',
'add_sources': [
tablet_unstable_v2_client_protocol_h,
tablet_unstable_v2_protocol_c,
],
},
{ 'basename': 'transformed' }, { 'basename': 'transformed' },
] ]
@ -449,7 +277,7 @@ if get_option('demo-clients')
foreach t : demo_clients foreach t : demo_clients
t_name = 'weston-' + t.get('basename') t_name = 'weston-' + t.get('basename')
t_srcs = [ t.get('basename') + '.c' ] + t.get('add_sources', []) t_srcs = [ t.get('basename') + '.c' ] + t.get('add_sources', [])
t_deps = [ dep_toytoolkit, t.get('dep_objs', []) ] t_deps = [ dep_toytoolkit ]
foreach depname : t.get('deps', []) foreach depname : t.get('deps', [])
dep = dependency(depname, required: false) dep = dependency(depname, required: false)
if not dep.found() if not dep.found()
@ -460,13 +288,56 @@ if get_option('demo-clients')
executable( executable(
t_name, t_srcs, t_name, t_srcs,
include_directories: common_inc, include_directories: include_directories('..', '../shared'),
dependencies: t_deps, dependencies: t_deps,
install: true install: true
) )
endforeach endforeach
endif endif
simple_dmabuf_drm_opts = get_option('simple-dmabuf-drm')
simple_dmabuf_drm_deps = []
foreach driver : [ 'etnaviv', 'intel', 'freedreno' ]
if simple_dmabuf_drm_opts.contains(driver)
required = true
enabled = true
elif simple_dmabuf_drm_opts.contains('auto')
required = get_option('auto_features').enabled()
enabled = not get_option('auto_features').disabled()
else
enabled = false
endif
if enabled
dep = dependency('libdrm_' + driver, required: false)
if dep.found()
simple_dmabuf_drm_deps += dep
config_h.set('HAVE_LIBDRM_' + driver.to_upper(), 1)
elif required
error('simple-dmabuf-drm is configured to use @0@ but it was not found. Or, you can remove @1@ from \'-Dsimple-dmabuf-drm\' list.'.format('libdrm_' + driver, driver))
endif
endif
endforeach
if simple_dmabuf_drm_deps.length() > 0
executable(
'weston-simple-dmabuf-drm',
'simple-dmabuf-drm.c',
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
fullscreen_shell_unstable_v1_client_protocol_h,
fullscreen_shell_unstable_v1_protocol_c,
linux_dmabuf_unstable_v1_client_protocol_h,
linux_dmabuf_unstable_v1_protocol_c,
include_directories: include_directories('..'),
dependencies: [
dep_wayland_client,
dep_libdrm,
simple_dmabuf_drm_deps
],
install: true
)
endif
if get_option('shell-desktop') if get_option('shell-desktop')
exe_keyboard = executable( exe_keyboard = executable(
'weston-keyboard', 'weston-keyboard',
@ -475,21 +346,31 @@ if get_option('shell-desktop')
text_input_unstable_v1_protocol_c, text_input_unstable_v1_protocol_c,
input_method_unstable_v1_client_protocol_h, input_method_unstable_v1_client_protocol_h,
input_method_unstable_v1_protocol_c, input_method_unstable_v1_protocol_c,
include_directories: common_inc, include_directories: include_directories('..'),
dependencies: dep_toytoolkit, dependencies: dep_toytoolkit,
install_dir: get_option('libexecdir'), install_dir: get_option('libexecdir'),
install: true install: true
) )
env_modmap += 'weston-keyboard=@0@;'.format(exe_keyboard.full_path()) env_modmap += 'weston-keyboard=@0@;'.format(exe_keyboard.full_path())
exe_shooter = executable(
'weston-screenshooter',
'screenshot.c',
weston_screenshooter_client_protocol_h,
weston_screenshooter_protocol_c,
include_directories: include_directories('..'),
dependencies: dep_toytoolkit,
install_dir: get_option('bindir'),
install: true
)
env_modmap += 'weston-screenshooter=@0@;'.format(exe_shooter.full_path())
exe_shell_desktop = executable( exe_shell_desktop = executable(
'weston-desktop-shell', 'weston-desktop-shell',
'desktop-shell.c', 'desktop-shell.c',
weston_desktop_shell_client_protocol_h, weston_desktop_shell_client_protocol_h,
weston_desktop_shell_protocol_c, weston_desktop_shell_protocol_c,
tablet_unstable_v2_client_protocol_h, include_directories: include_directories('..'),
tablet_unstable_v2_protocol_c,
include_directories: common_inc,
dependencies: dep_toytoolkit, dependencies: dep_toytoolkit,
install_dir: get_option('libexecdir'), install_dir: get_option('libexecdir'),
install: true install: true
@ -497,24 +378,6 @@ if get_option('shell-desktop')
env_modmap += 'weston-desktop-shell=@0@;'.format(exe_shell_desktop.full_path()) env_modmap += 'weston-desktop-shell=@0@;'.format(exe_shell_desktop.full_path())
endif endif
if get_option('shell-desktop') or get_option('shell-kiosk') or get_option('shell-ivi')
exe_shooter = executable(
'weston-screenshooter',
'screenshot.c',
weston_output_capture_client_protocol_h,
weston_output_capture_protocol_c,
include_directories: common_inc,
dependencies: [
dep_client_buffer,
dep_toytoolkit,
dep_libweston_private, # for pixel-formats.h
dep_pixman,
],
install_dir: get_option('bindir'),
install: true
)
env_modmap += 'weston-screenshooter=@0@;'.format(exe_shooter.full_path())
endif
if get_option('shell-ivi') if get_option('shell-ivi')
exe_shell_ivi_ui = executable( exe_shell_ivi_ui = executable(
@ -524,7 +387,7 @@ if get_option('shell-ivi')
ivi_hmi_controller_protocol_c, ivi_hmi_controller_protocol_c,
ivi_application_client_protocol_h, ivi_application_client_protocol_h,
ivi_application_protocol_c, ivi_application_protocol_c,
include_directories: common_inc, include_directories: include_directories('..'),
dependencies: dep_toytoolkit, dependencies: dep_toytoolkit,
install: true, install: true,
install_dir: get_option('libexecdir') install_dir: get_option('libexecdir')

View file

@ -1,7 +1,6 @@
/* /*
* Copyright © 2011 Benjamin Franzke * Copyright © 2011 Benjamin Franzke
* Copyright © 2010, 2013 Intel Corporation * Copyright © 2010, 2013 Intel Corporation
* Copyright © 2021 Collabora, Ltd.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
@ -36,18 +35,14 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <signal.h> #include <signal.h>
#include <time.h> #include <time.h>
#include <poll.h> #include <sys/poll.h>
#include <float.h> #include <float.h>
#include <math.h> #include <math.h>
#include <wayland-client.h> #include <wayland-client.h>
#include "shared/os-compatibility.h" #include "shared/os-compatibility.h"
#include "shared/xalloc.h" #include "shared/xalloc.h"
#include <libweston/zalloc.h> #include "shared/zalloc.h"
#include "xdg-shell-client-protocol.h"
static int running = 1;
struct device { struct device {
enum { KEYBOARD, POINTER } type; enum { KEYBOARD, POINTER } type;
@ -66,9 +61,9 @@ struct display {
struct wl_display *display; struct wl_display *display;
struct wl_registry *registry; struct wl_registry *registry;
struct wl_compositor *compositor; struct wl_compositor *compositor;
struct wl_shell *shell;
struct wl_seat *seat; struct wl_seat *seat;
struct wl_shm *shm; struct wl_shm *shm;
struct xdg_wm_base *wm_base;
uint32_t formats; uint32_t formats;
struct wl_list devices; struct wl_list devices;
}; };
@ -77,9 +72,7 @@ struct window {
struct display *display; struct display *display;
int width, height; int width, height;
struct wl_surface *surface; struct wl_surface *surface;
struct xdg_toplevel *xdg_toplevel; struct wl_shell_surface *shell_surface;
struct xdg_surface *xdg_surface;
bool wait_for_configure;
}; };
static void static void
@ -104,8 +97,8 @@ attach_buffer(struct window *window, int width, int height)
fd = os_create_anonymous_file(size); fd = os_create_anonymous_file(size);
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "creating a buffer file for %d B failed: %s\n", fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
size, strerror(errno)); size);
return -1; return -1;
} }
@ -123,54 +116,27 @@ attach_buffer(struct window *window, int width, int height)
} }
static void static void
handle_xdg_surface_configure(void *data, struct xdg_surface *surface, handle_ping(void *data, struct wl_shell_surface *shell_surface,
uint32_t serial) uint32_t serial)
{ {
struct window *window = data; wl_shell_surface_pong(shell_surface, serial);
xdg_surface_ack_configure(surface, serial);
if (window->wait_for_configure) {
attach_buffer(window, window->width, window->height);
wl_surface_damage(window->surface, 0, 0, window->width, window->height);
wl_surface_commit(window->surface);
window->wait_for_configure = false;
}
} }
static const struct xdg_surface_listener xdg_surface_listener = {
handle_xdg_surface_configure,
};
static void static void
xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial) handle_configure(void *data, struct wl_shell_surface *shell_surface,
{ uint32_t edges, int32_t width, int32_t height)
xdg_wm_base_pong(shell, serial);
}
static const struct xdg_wm_base_listener wm_base_listener = {
xdg_wm_base_ping,
};
static void
handle_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
int32_t width, int32_t height,
struct wl_array *state)
{ {
} }
static void static void
handle_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel) handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
{ {
running = 0;
} }
static const struct xdg_toplevel_listener xdg_toplevel_listener = { static const struct wl_shell_surface_listener shell_surface_listener = {
handle_toplevel_configure, handle_ping,
handle_toplevel_close, handle_configure,
handle_popup_done
}; };
static struct window * static struct window *
@ -183,19 +149,19 @@ create_window(struct display *display, int width, int height)
window->width = width; window->width = width;
window->height = height; window->height = height;
window->surface = wl_compositor_create_surface(display->compositor); window->surface = wl_compositor_create_surface(display->compositor);
window->shell_surface = wl_shell_get_shell_surface(display->shell,
window->surface);
window->xdg_surface = if (window->shell_surface)
xdg_wm_base_get_xdg_surface(display->wm_base, window->surface); wl_shell_surface_add_listener(window->shell_surface,
assert(window->xdg_surface); &shell_surface_listener, window);
xdg_surface_add_listener(window->xdg_surface, &xdg_surface_listener, window); wl_shell_surface_set_title(window->shell_surface, "simple-shm");
window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface); wl_shell_surface_set_toplevel(window->shell_surface);
assert(window->xdg_toplevel);
xdg_toplevel_add_listener(window->xdg_toplevel, wl_surface_damage(window->surface, 0, 0, width, height);
&xdg_toplevel_listener, window); attach_buffer(window, width, height);
xdg_toplevel_set_title(window->xdg_toplevel, "multi-resource");
window->wait_for_configure = true;
wl_surface_commit(window->surface); wl_surface_commit(window->surface);
return window; return window;
@ -204,11 +170,7 @@ create_window(struct display *display, int width, int height)
static void static void
destroy_window(struct window *window) destroy_window(struct window *window)
{ {
if (window->xdg_surface) wl_shell_surface_destroy(window->shell_surface);
xdg_surface_destroy(window->xdg_surface);
if (window->xdg_toplevel)
xdg_toplevel_destroy(window->xdg_toplevel);
wl_surface_destroy(window->surface); wl_surface_destroy(window->surface);
free(window); free(window);
} }
@ -235,10 +197,9 @@ registry_handle_global(void *data, struct wl_registry *registry,
d->compositor = d->compositor =
wl_registry_bind(registry, wl_registry_bind(registry,
id, &wl_compositor_interface, 1); id, &wl_compositor_interface, 1);
} else if (strcmp(interface, "xdg_wm_base") == 0) { } else if (strcmp(interface, "wl_shell") == 0) {
d->wm_base = wl_registry_bind(registry, d->shell = wl_registry_bind(registry,
id, &xdg_wm_base_interface, 1); id, &wl_shell_interface, 1);
xdg_wm_base_add_listener(d->wm_base, &wm_base_listener, d);
} else if (strcmp(interface, "wl_shm") == 0) { } else if (strcmp(interface, "wl_shm") == 0) {
d->shm = wl_registry_bind(registry, d->shm = wl_registry_bind(registry,
id, &wl_shm_interface, 1); id, &wl_shm_interface, 1);
@ -287,11 +248,6 @@ create_display(void)
exit(1); exit(1);
} }
if (!display->wm_base) {
fprintf(stderr, "xdg-shell required!\n");
exit(1);
}
wl_list_init(&display->devices); wl_list_init(&display->devices);
return display; return display;
@ -340,8 +296,6 @@ static void
keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
uint32_t format, int fd, uint32_t size) uint32_t format, int fd, uint32_t size)
{ {
/* Just so we dont leak the keymap fd */
close(fd);
} }
static void static void
@ -443,8 +397,8 @@ destroy_display(struct display *display)
if (display->shm) if (display->shm)
wl_shm_destroy(display->shm); wl_shm_destroy(display->shm);
if (display->wm_base) if (display->shell)
xdg_wm_base_destroy(display->wm_base); wl_shell_destroy(display->shell);
if (display->seat) if (display->seat)
wl_seat_destroy(display->seat); wl_seat_destroy(display->seat);
@ -458,6 +412,7 @@ destroy_display(struct display *display)
free(display); free(display);
} }
static int running = 1;
static void static void
signal_int(int signum) signal_int(int signum)

374
clients/nested-client.c Normal file
View file

@ -0,0 +1,374 @@
/*
* Copyright © 2013 Intel Corporation
*
* 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.
*/
#include "config.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wayland-egl.h>
#include <wayland-cursor.h>
#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include "../shared/platform.h"
struct window;
struct seat;
struct nested_client {
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
EGLDisplay egl_display;
EGLContext egl_context;
EGLConfig egl_config;
EGLSurface egl_surface;
struct program *color_program;
GLuint vert, frag, program;
GLuint rotation;
GLuint pos;
GLuint col;
struct wl_surface *surface;
struct wl_egl_window *native;
int width, height;
};
#define POS 0
#define COL 1
static GLuint
create_shader(const char *source, GLenum shader_type)
{
GLuint shader;
GLint status;
shader = glCreateShader(shader_type);
if (shader == 0)
return 0;
glShaderSource(shader, 1, (const char **) &source, NULL);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (!status) {
char log[1000];
GLsizei len;
glGetShaderInfoLog(shader, 1000, &len, log);
fprintf(stderr, "Error: compiling %s: %*s\n",
shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
len, log);
return 0;
}
return shader;
}
static void
create_program(struct nested_client *client,
const char *vert, const char *frag)
{
GLint status;
client->vert = create_shader(vert, GL_VERTEX_SHADER);
client->frag = create_shader(frag, GL_FRAGMENT_SHADER);
client->program = glCreateProgram();
glAttachShader(client->program, client->frag);
glAttachShader(client->program, client->vert);
glBindAttribLocation(client->program, POS, "pos");
glBindAttribLocation(client->program, COL, "color");
glLinkProgram(client->program);
glGetProgramiv(client->program, GL_LINK_STATUS, &status);
if (!status) {
char log[1000];
GLsizei len;
glGetProgramInfoLog(client->program, 1000, &len, log);
fprintf(stderr, "Error: linking:\n%*s\n", len, log);
exit(1);
}
client->rotation =
glGetUniformLocation(client->program, "rotation");
}
static const char vertex_shader_text[] =
"uniform mat4 rotation;\n"
"attribute vec4 pos;\n"
"attribute vec4 color;\n"
"varying vec4 v_color;\n"
"void main() {\n"
" gl_Position = rotation * pos;\n"
" v_color = color;\n"
"}\n";
static const char color_fragment_shader_text[] =
"precision mediump float;\n"
"varying vec4 v_color;\n"
"void main() {\n"
" gl_FragColor = v_color;\n"
"}\n";
static void
render_triangle(struct nested_client *client, uint32_t time)
{
static const GLfloat verts[3][2] = {
{ -0.5, -0.5 },
{ 0.5, -0.5 },
{ 0, 0.5 }
};
static const GLfloat colors[3][3] = {
{ 1, 0, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 }
};
GLfloat angle;
GLfloat rotation[4][4] = {
{ 1, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 1, 0 },
{ 0, 0, 0, 1 }
};
static const int32_t speed_div = 5;
static uint32_t start_time = 0;
if (client->program == 0)
create_program(client, vertex_shader_text,
color_fragment_shader_text);
if (start_time == 0)
start_time = time;
angle = ((time - start_time) / speed_div) % 360 * M_PI / 180.0;
rotation[0][0] = cos(angle);
rotation[0][2] = sin(angle);
rotation[2][0] = -sin(angle);
rotation[2][2] = cos(angle);
glClearColor(0.4, 0.4, 0.4, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(client->program);
glViewport(0, 0, client->width, client->height);
glUniformMatrix4fv(client->rotation, 1, GL_FALSE,
(GLfloat *) rotation);
glVertexAttribPointer(POS, 2, GL_FLOAT, GL_FALSE, 0, verts);
glVertexAttribPointer(COL, 3, GL_FLOAT, GL_FALSE, 0, colors);
glEnableVertexAttribArray(POS);
glEnableVertexAttribArray(COL);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(POS);
glDisableVertexAttribArray(COL);
glFlush();
}
static void
frame_callback(void *data, struct wl_callback *callback, uint32_t time);
static const struct wl_callback_listener frame_listener = {
frame_callback
};
static void
frame_callback(void *data, struct wl_callback *callback, uint32_t time)
{
struct nested_client *client = data;
if (callback)
wl_callback_destroy(callback);
callback = wl_surface_frame(client->surface);
wl_callback_add_listener(callback, &frame_listener, client);
render_triangle(client, time);
eglSwapBuffers(client->egl_display, client->egl_surface);
}
static void
registry_handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
{
struct nested_client *client = data;
if (strcmp(interface, "wl_compositor") == 0) {
client->compositor =
wl_registry_bind(registry, name,
&wl_compositor_interface, 1);
}
}
static void
registry_handle_global_remove(void *data, struct wl_registry *registry,
uint32_t name)
{
}
static const struct wl_registry_listener registry_listener = {
registry_handle_global,
registry_handle_global_remove
};
static struct nested_client *
nested_client_create(void)
{
static const EGLint context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
static const EGLint config_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_ALPHA_SIZE, 1,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
EGLint major, minor, n;
EGLBoolean ret;
struct nested_client *client;
client = malloc(sizeof *client);
if (client == NULL)
return NULL;
client->width = 250;
client->height = 250;
client->display = wl_display_connect(NULL);
client->registry = wl_display_get_registry(client->display);
wl_registry_add_listener(client->registry,
&registry_listener, client);
/* get globals */
wl_display_roundtrip(client->display);
client->egl_display =
weston_platform_get_egl_display(EGL_PLATFORM_WAYLAND_KHR,
client->display, NULL);
if (client->egl_display == NULL)
return NULL;
ret = eglInitialize(client->egl_display, &major, &minor);
if (!ret)
return NULL;
ret = eglBindAPI(EGL_OPENGL_ES_API);
if (!ret)
return NULL;
ret = eglChooseConfig(client->egl_display, config_attribs,
&client->egl_config, 1, &n);
if (!ret || n != 1)
return NULL;
client->egl_context = eglCreateContext(client->egl_display,
client->egl_config,
EGL_NO_CONTEXT,
context_attribs);
if (!client->egl_context)
return NULL;
client->surface = wl_compositor_create_surface(client->compositor);
client->native = wl_egl_window_create(client->surface,
client->width, client->height);
client->egl_surface = weston_platform_create_egl_surface(client->egl_display,
client->egl_config,
client->native, NULL);
eglMakeCurrent(client->egl_display, client->egl_surface,
client->egl_surface, client->egl_context);
wl_egl_window_resize(client->native,
client->width, client->height, 0, 0);
frame_callback(client, NULL, 0);
return client;
}
static void
nested_client_destroy(struct nested_client *client)
{
eglMakeCurrent(client->egl_display,
EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT);
weston_platform_destroy_egl_surface(client->egl_display,
client->egl_surface);
wl_egl_window_destroy(client->native);
wl_surface_destroy(client->surface);
if (client->compositor)
wl_compositor_destroy(client->compositor);
wl_registry_destroy(client->registry);
eglTerminate(client->egl_display);
eglReleaseThread();
wl_display_flush(client->display);
wl_display_disconnect(client->display);
}
int
main(int argc, char **argv)
{
struct nested_client *client;
int ret = 0;
if (getenv("WAYLAND_SOCKET") == NULL) {
fprintf(stderr,
"must be run by nested, don't run standalone\n");
return EXIT_FAILURE;
}
client = nested_client_create();
if (client == NULL)
return EXIT_FAILURE;
while (ret != -1)
ret = wl_display_dispatch(client->display);
nested_client_destroy(client);
return 0;
}

1133
clients/nested.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -35,15 +35,13 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <signal.h> #include <signal.h>
#include <time.h> #include <time.h>
#include <errno.h>
#include <wayland-client.h> #include <wayland-client.h>
#include "shared/helpers.h" #include "shared/helpers.h"
#include <libweston/zalloc.h> #include "shared/zalloc.h"
#include "shared/timespec-util.h" #include "shared/timespec-util.h"
#include "shared/os-compatibility.h" #include "shared/os-compatibility.h"
#include "presentation-time-client-protocol.h" #include "presentation-time-client-protocol.h"
#include "xdg-shell-client-protocol.h"
enum run_mode { enum run_mode {
RUN_MODE_FEEDBACK, RUN_MODE_FEEDBACK,
@ -67,7 +65,7 @@ struct display {
struct wl_display *display; struct wl_display *display;
struct wl_registry *registry; struct wl_registry *registry;
struct wl_compositor *compositor; struct wl_compositor *compositor;
struct xdg_wm_base *wm_base; struct wl_shell *shell;
struct wl_shm *shm; struct wl_shm *shm;
uint32_t formats; uint32_t formats;
@ -100,9 +98,7 @@ struct window {
int width, height; int width, height;
enum run_mode mode; enum run_mode mode;
struct wl_surface *surface; struct wl_surface *surface;
struct xdg_surface *xdg_surface; struct wl_shell_surface *shell_surface;
struct xdg_toplevel *xdg_toplevel;
uint32_t configure_serial;
struct buffer *buffers; struct buffer *buffers;
int num_buffers; int num_buffers;
@ -145,14 +141,14 @@ create_shm_buffers(struct display *display, struct buffer **buffers,
fd = os_create_anonymous_file(size); fd = os_create_anonymous_file(size);
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "creating a buffer file for %d B failed: %s\n", fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
size, strerror(errno)); size);
return -1; return -1;
} }
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) { if (data == MAP_FAILED) {
fprintf(stderr, "mmap failed: %s\n", strerror(errno)); fprintf(stderr, "mmap failed: %m\n");
close(fd); close(fd);
return -1; return -1;
} }
@ -184,48 +180,27 @@ create_shm_buffers(struct display *display, struct buffer **buffers,
} }
static void static void
xdg_wm_base_handle_ping(void *data, struct xdg_wm_base *xdg_wm_base, handle_ping(void *data, struct wl_shell_surface *shell_surface,
uint32_t serial) uint32_t serial)
{ {
xdg_wm_base_pong(xdg_wm_base, serial); wl_shell_surface_pong(shell_surface, serial);
}
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
.ping = xdg_wm_base_handle_ping,
};
static void
xdg_surface_handle_configure(void *data, struct xdg_surface *xdg_surface,
uint32_t serial)
{
struct window *window = data;
window->configure_serial = serial;
}
static const struct xdg_surface_listener xdg_surface_listener = {
.configure = xdg_surface_handle_configure,
};
static void
xdg_toplevel_handle_configure(void *data, struct xdg_toplevel *xdg_toplevel,
int32_t width, int32_t height,
struct wl_array *states)
{
/* noop */
} }
static void static void
xdg_toplevel_handle_close(void *data, struct xdg_toplevel *xdg_toplevel) handle_configure(void *data, struct wl_shell_surface *shell_surface,
uint32_t edges, int32_t width, int32_t height)
{ {
fprintf(stderr, "presentation-shm exiting\n");
exit(0);
} }
static const struct xdg_toplevel_listener xdg_toplevel_listener = { static void
.configure = xdg_toplevel_handle_configure, handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
.close = xdg_toplevel_handle_close, {
}
static const struct wl_shell_surface_listener shell_surface_listener = {
handle_ping,
handle_configure,
handle_popup_done
}; };
static struct window * static struct window *
@ -252,30 +227,16 @@ create_window(struct display *display, int width, int height,
window->width = width; window->width = width;
window->height = height; window->height = height;
window->surface = wl_compositor_create_surface(display->compositor); window->surface = wl_compositor_create_surface(display->compositor);
window->xdg_surface = xdg_wm_base_get_xdg_surface(display->wm_base, window->shell_surface = wl_shell_get_shell_surface(display->shell,
window->surface); window->surface);
if (!window->xdg_surface) if (window->shell_surface)
return NULL; wl_shell_surface_add_listener(window->shell_surface,
&shell_surface_listener, window);
window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface); wl_shell_surface_set_title(window->shell_surface, title);
if (!window->xdg_toplevel) wl_shell_surface_set_toplevel(window->shell_surface);
return NULL;
xdg_wm_base_add_listener(display->wm_base, &xdg_wm_base_listener,
NULL);
xdg_surface_add_listener(window->xdg_surface, &xdg_surface_listener,
window);
xdg_toplevel_add_listener(window->xdg_toplevel, &xdg_toplevel_listener,
window);
xdg_toplevel_set_title(window->xdg_toplevel, title);
xdg_toplevel_set_min_size(window->xdg_toplevel, width, height);
xdg_toplevel_set_max_size(window->xdg_toplevel, width, height);
wl_surface_commit(window->surface);
wl_display_roundtrip(window->display->display);
window->num_buffers = 60; window->num_buffers = 60;
window->refresh_nsec = NSEC_PER_SEC / 60; /* 60 Hz guess */ window->refresh_nsec = NSEC_PER_SEC / 60; /* 60 Hz guess */
@ -315,7 +276,7 @@ destroy_window(struct window *window)
if (window->callback) if (window->callback)
wl_callback_destroy(window->callback); wl_callback_destroy(window->callback);
xdg_surface_destroy(window->xdg_surface); wl_shell_surface_destroy(window->shell_surface);
wl_surface_destroy(window->surface); wl_surface_destroy(window->surface);
for (i = 0; i < window->num_buffers; i++) for (i = 0; i < window->num_buffers; i++)
@ -446,7 +407,7 @@ feedback_presented(void *data,
struct feedback *feedback = data; struct feedback *feedback = data;
struct window *window = feedback->window; struct window *window = feedback->window;
struct feedback *prev_feedback = window->received_feedback; struct feedback *prev_feedback = window->received_feedback;
uint64_t seq = u64_from_u32s(seq_hi, seq_lo); uint64_t seq = ((uint64_t)seq_hi << 32) + seq_lo;
const struct timespec *prevpresent; const struct timespec *prevpresent;
uint32_t commit, present; uint32_t commit, present;
uint32_t f2c, c2p, f2p; uint32_t f2c, c2p, f2p;
@ -519,7 +480,7 @@ window_emulate_rendering(struct window *window)
ret = nanosleep(&delay, NULL); ret = nanosleep(&delay, NULL);
if (ret) if (ret)
printf("nanosleep failed: %s\n", strerror(errno)); printf("nanosleep failed: %m\n");
} }
static void static void
@ -560,12 +521,6 @@ window_commit_next(struct window *window)
buffer = window_next_buffer(window); buffer = window_next_buffer(window);
assert(buffer); assert(buffer);
if (window->configure_serial) {
xdg_surface_ack_configure(window->xdg_surface,
window->configure_serial);
window->configure_serial = 0;
}
wl_surface_attach(window->surface, buffer->buffer, 0, 0); wl_surface_attach(window->surface, buffer->buffer, 0, 0);
wl_surface_damage(window->surface, 0, 0, window->width, window->height); wl_surface_damage(window->surface, 0, 0, window->width, window->height);
wl_surface_commit(window->surface); wl_surface_commit(window->surface);
@ -762,10 +717,9 @@ registry_handle_global(void *data, struct wl_registry *registry,
d->compositor = d->compositor =
wl_registry_bind(registry, wl_registry_bind(registry,
name, &wl_compositor_interface, 1); name, &wl_compositor_interface, 1);
} else if (strcmp(interface, "xdg_wm_base") == 0) { } else if (strcmp(interface, "wl_shell") == 0) {
d->wm_base = d->shell = wl_registry_bind(registry,
wl_registry_bind(registry, name, name, &wl_shell_interface, 1);
&xdg_wm_base_interface, 1);
} else if (strcmp(interface, "wl_shm") == 0) { } else if (strcmp(interface, "wl_shm") == 0) {
d->shm = wl_registry_bind(registry, d->shm = wl_registry_bind(registry,
name, &wl_shm_interface, 1); name, &wl_shm_interface, 1);
@ -775,7 +729,7 @@ registry_handle_global(void *data, struct wl_registry *registry,
} else if (strcmp(interface, wp_presentation_interface.name) == 0) { } else if (strcmp(interface, wp_presentation_interface.name) == 0) {
d->presentation = d->presentation =
wl_registry_bind(registry, wl_registry_bind(registry,
name, &wp_presentation_interface, 2); name, &wp_presentation_interface, 1);
wp_presentation_add_listener(d->presentation, wp_presentation_add_listener(d->presentation,
&presentation_listener, d); &presentation_listener, d);
} }
@ -851,8 +805,8 @@ destroy_display(struct display *display)
if (display->shm) if (display->shm)
wl_shm_destroy(display->shm); wl_shm_destroy(display->shm);
if (display->wm_base) if (display->shell)
xdg_wm_base_destroy(display->wm_base); wl_shell_destroy(display->shell);
if (display->compositor) if (display->compositor)
wl_compositor_destroy(display->compositor); wl_compositor_destroy(display->compositor);

View file

@ -31,7 +31,6 @@
#include <cairo.h> #include <cairo.h>
#include <math.h> #include <math.h>
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <linux/input.h> #include <linux/input.h>
#include <wayland-client.h> #include <wayland-client.h>
@ -392,8 +391,6 @@ resizor_create(struct display *display)
resizor->window = window_create(display); resizor->window = window_create(display);
resizor->widget = window_frame_create(resizor->window, resizor); resizor->widget = window_frame_create(resizor->window, resizor);
window_set_title(resizor->window, "Wayland Resizor"); window_set_title(resizor->window, "Wayland Resizor");
window_set_appid(resizor->window,
"org.freedesktop.weston.wayland-resizor");
resizor->display = display; resizor->display = display;
window_set_key_handler(resizor->window, key_handler); window_set_key_handler(resizor->window, key_handler);
@ -442,8 +439,7 @@ main(int argc, char *argv[])
display = display_create(&argc, argv); display = display_create(&argc, argv);
if (display == NULL) { if (display == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }

View file

@ -28,7 +28,6 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <cairo.h> #include <cairo.h>
#include <linux/input.h> #include <linux/input.h>
@ -289,8 +288,7 @@ main(int argc, char *argv[])
d = display_create(&argc, argv); d = display_create(&argc, argv);
if (d == NULL) { if (d == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }
@ -303,7 +301,6 @@ main(int argc, char *argv[])
box.window = window_create(d); box.window = window_create(d);
box.widget = window_add_widget(box.window, &box); box.widget = window_add_widget(box.window, &box);
window_set_title(box.window, "Scaler Test Box"); window_set_title(box.window, "Scaler Test Box");
window_set_appid(box.window, "org.freedesktop.weston.scaler-test-box");
window_set_buffer_scale(box.window, BUFFER_SCALE); window_set_buffer_scale(box.window, BUFFER_SCALE);
widget_set_resize_handler(box.widget, resize_handler); widget_set_resize_handler(box.widget, resize_handler);
@ -317,11 +314,6 @@ main(int argc, char *argv[])
display_set_user_data(box.display, &box); display_set_user_data(box.display, &box);
display_set_global_handler(box.display, global_handler); display_set_global_handler(box.display, global_handler);
if (box.mode != MODE_NO_VIEWPORT && !box.viewport) {
fprintf(stderr, "compositor doesn't support viewporter\n");
return -1;
}
display_run(d); display_run(d);
widget_destroy(box.widget); widget_destroy(box.widget);

View file

@ -1,6 +1,5 @@
/* /*
* Copyright © 2008 Kristian Høgsberg * Copyright © 2008 Kristian Høgsberg
* Copyright 2022 Collabora, Ltd.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
@ -24,72 +23,35 @@
#include "config.h" #include "config.h"
#include <assert.h>
#include <cairo.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <pixman.h>
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/mman.h> #include <fcntl.h>
#include <sys/param.h>
#include <unistd.h> #include <unistd.h>
#include <limits.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <cairo.h>
#include <wayland-client.h> #include <wayland-client.h>
#include "weston-screenshooter-client-protocol.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "pixel-formats.h"
#include "shared/client-buffer-util.h"
#include "shared/file-util.h"
#include "shared/os-compatibility.h" #include "shared/os-compatibility.h"
#include "shared/string-helpers.h"
#include "shared/xalloc.h" #include "shared/xalloc.h"
#include "weston-output-capture-client-protocol.h" #include "shared/file-util.h"
struct screenshooter_app { /* The screenshooter is a good example of a custom object exposed by
struct wl_display *display; * the compositor and serves as a test bed for implementing client
struct wl_registry *registry; * side marshalling outside libwayland.so */
struct wl_shm *shm;
struct zwp_linux_dmabuf_v1 *dmabuf;
struct weston_capture_v1 *capture_factory;
bool verbose;
const struct pixel_format_info *requested_format;
enum weston_capture_v1_source src_type;
enum client_buffer_type buffer_type;
struct wl_list output_list; /* struct screenshooter_output::link */
bool retry;
bool failed;
int waitcount;
};
struct screenshooter_buffer {
struct client_buffer *buf;
pixman_image_t *image;
enum weston_capture_v1_source src_type;
};
struct screenshooter_output { struct screenshooter_output {
struct screenshooter_app *app; struct wl_output *output;
uint32_t name; struct wl_buffer *buffer;
struct wl_list link; /* struct screenshooter_app::output_list */ int width, height, offset_x, offset_y;
void *data;
struct wl_output *wl_output; struct wl_list link;
int offset_x, offset_y;
struct weston_capture_source_v1 *source;
int buffer_width;
int buffer_height;
struct wl_array formats;
bool formats_done;
struct screenshooter_buffer *buffer;
}; };
struct buffer_size { struct buffer_size {
@ -99,250 +61,97 @@ struct buffer_size {
int max_x, max_y; int max_x, max_y;
}; };
static struct screenshooter_buffer * struct screenshooter_data {
screenshot_create_shm_buffer(struct screenshooter_app *app, struct wl_shm *shm;
size_t width, size_t height, struct wl_list output_list;
const struct pixel_format_info *fmt)
{
struct screenshooter_buffer *buffer;
assert(width > 0); struct weston_screenshooter *screenshooter;
assert(height > 0); int buffer_copy_done;
assert(fmt && fmt->bpp > 0);
assert(fmt->pixman_format);
buffer = xzalloc(sizeof *buffer);
buffer->buf = client_buffer_util_create_shm_buffer(app->shm,
fmt,
width,
height);
buffer->image = pixman_image_create_bits(fmt->pixman_format,
width, height,
buffer->buf->data,
buffer->buf->strides[0]);
abort_oom_if_null(buffer->image);
return buffer;
}
static struct screenshooter_buffer *
screenshot_create_udmabuf(struct screenshooter_app *app,
int width, int height,
const struct pixel_format_info *fmt)
{
struct screenshooter_buffer* buffer = NULL;
assert(width > 0);
assert(height > 0);
assert(fmt);
buffer = xzalloc(sizeof *buffer);
buffer->buf = client_buffer_util_create_dmabuf_buffer(app->display,
app->dmabuf,
fmt,
width,
height);
if (fmt->pixman_format) {
buffer->image = pixman_image_create_bits(fmt->pixman_format,
width, height,
buffer->buf->data,
buffer->buf->strides[0]);
abort_oom_if_null(buffer->image);
}
return buffer;
}
static void
screenshooter_buffer_destroy(struct screenshooter_buffer *buffer)
{
if (!buffer)
return;
if (buffer->image)
pixman_image_unref(buffer->image);
client_buffer_util_destroy_buffer(buffer->buf);
free(buffer);
}
static void
capture_source_handle_format(void *data,
struct weston_capture_source_v1 *proxy,
uint32_t drm_format)
{
struct screenshooter_output *output = data;
uint32_t *fmt;
assert(output->source == proxy);
if (output->formats_done) {
wl_array_release(&output->formats);
wl_array_init(&output->formats);
output->formats_done = false;
}
fmt = wl_array_add(&output->formats, sizeof(uint32_t));
assert(fmt);
*fmt = drm_format;
if (output->app->verbose) {
const struct pixel_format_info *fmt_info;
fmt_info = pixel_format_get_info(drm_format);
assert(fmt_info);
printf("Got format %s / 0x%x\n", fmt_info->drm_format_name,
drm_format);
}
}
static void
capture_source_handle_formats_done(void *data,
struct weston_capture_source_v1 *proxy)
{
struct screenshooter_output *output = data;
output->formats_done = true;
}
static void
capture_source_handle_size(void *data,
struct weston_capture_source_v1 *proxy,
int32_t width, int32_t height)
{
struct screenshooter_output *output = data;
assert(width > 0);
assert(height > 0);
output->buffer_width = width;
output->buffer_height = height;
if (output->app->verbose)
printf("Got size %dx%d\n", width, height);
}
static void
capture_source_handle_complete(void *data,
struct weston_capture_source_v1 *proxy)
{
struct screenshooter_output *output = data;
output->app->waitcount--;
}
static void
capture_source_handle_retry(void *data,
struct weston_capture_source_v1 *proxy)
{
struct screenshooter_output *output = data;
output->app->waitcount--;
output->app->retry = true;
}
static void
capture_source_handle_failed(void *data,
struct weston_capture_source_v1 *proxy,
const char *msg)
{
struct screenshooter_output *output = data;
output->app->waitcount--;
/* We don't set app.failed here because there could be other
* outputs we still want to capture!
*/
if (msg)
fprintf(stderr, "Output capture error: %s\n", msg);
}
static const struct weston_capture_source_v1_listener capture_source_handlers = {
.format = capture_source_handle_format,
.formats_done = capture_source_handle_formats_done,
.size = capture_source_handle_size,
.complete = capture_source_handle_complete,
.retry = capture_source_handle_retry,
.failed = capture_source_handle_failed,
}; };
static void static void
create_output(struct screenshooter_app *app, uint32_t output_name, uint32_t version) display_handle_geometry(void *data,
struct wl_output *wl_output,
int x,
int y,
int physical_width,
int physical_height,
int subpixel,
const char *make,
const char *model,
int transform)
{ {
struct screenshooter_output *output; struct screenshooter_output *output;
version = MIN(version, 4); output = wl_output_get_user_data(wl_output);
output = xzalloc(sizeof *output);
output->app = app;
output->name = output_name;
output->wl_output = wl_registry_bind(app->registry, output_name,
&wl_output_interface, version);
abort_oom_if_null(output->wl_output);
output->source = weston_capture_v1_create(app->capture_factory, if (wl_output == output->output) {
output->wl_output, output->offset_x = x;
app->src_type); output->offset_y = y;
abort_oom_if_null(output->source); }
weston_capture_source_v1_add_listener(output->source,
&capture_source_handlers, output);
wl_array_init(&output->formats);
wl_list_insert(&app->output_list, &output->link);
} }
static void static void
destroy_output(struct screenshooter_output *output) display_handle_mode(void *data,
struct wl_output *wl_output,
uint32_t flags,
int width,
int height,
int refresh)
{ {
weston_capture_source_v1_destroy(output->source); struct screenshooter_output *output;
wl_array_release(&output->formats); output = wl_output_get_user_data(wl_output);
if (wl_output_get_version(output->wl_output) >= WL_OUTPUT_RELEASE_SINCE_VERSION) if (wl_output == output->output && (flags & WL_OUTPUT_MODE_CURRENT)) {
wl_output_release(output->wl_output); output->width = width;
else output->height = height;
wl_output_destroy(output->wl_output); }
screenshooter_buffer_destroy(output->buffer);
wl_list_remove(&output->link);
free(output);
} }
static const struct wl_output_listener output_listener = {
display_handle_geometry,
display_handle_mode
};
static void
screenshot_done(void *data, struct weston_screenshooter *screenshooter)
{
struct screenshooter_data *sh_data = data;
sh_data->buffer_copy_done = 1;
}
static const struct weston_screenshooter_listener screenshooter_listener = {
screenshot_done
};
static void static void
handle_global(void *data, struct wl_registry *registry, handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version) uint32_t name, const char *interface, uint32_t version)
{ {
struct screenshooter_app *app = data; static struct screenshooter_output *output;
struct screenshooter_data *sh_data = data;
if (strcmp(interface, wl_output_interface.name) == 0) { if (strcmp(interface, "wl_output") == 0) {
create_output(app, name, version); output = xmalloc(sizeof *output);
} else if (strcmp(interface, wl_shm_interface.name) == 0) { output->output = wl_registry_bind(registry, name,
app->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); &wl_output_interface, 1);
/* wl_list_insert(&sh_data->output_list, &output->link);
* Not listening for format advertisements, wl_output_add_listener(output->output, &output_listener, output);
* weston_capture_source_v1.format event tells us what to use. } else if (strcmp(interface, "wl_shm") == 0) {
*/ sh_data->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
} else if (strcmp(interface, weston_capture_v1_interface.name) == 0) { } else if (strcmp(interface, "weston_screenshooter") == 0) {
app->capture_factory = wl_registry_bind(registry, name, sh_data->screenshooter = wl_registry_bind(registry, name,
&weston_capture_v1_interface, &weston_screenshooter_interface,
2); 1);
} else if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0) {
if (version < 3)
return;
app->dmabuf = wl_registry_bind(registry, name,
&zwp_linux_dmabuf_v1_interface,
3);
} }
} }
static void static void
handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
{ {
/* Dynamic output removals will just fail the respective shot. */ /* XXX: unimplemented */
} }
static const struct wl_registry_listener registry_listener = { static const struct wl_registry_listener registry_listener = {
@ -350,87 +159,80 @@ static const struct wl_registry_listener registry_listener = {
handle_global_remove handle_global_remove
}; };
static void static struct wl_buffer *
screenshooter_output_capture(struct screenshooter_output *output) screenshot_create_shm_buffer(int width, int height, void **data_out,
struct wl_shm *shm)
{ {
const struct pixel_format_info *fmt_info = NULL; struct wl_shm_pool *pool;
uint32_t *fmt; struct wl_buffer *buffer;
int fd, size, stride;
void *data;
screenshooter_buffer_destroy(output->buffer); stride = width * 4;
size = stride * height;
wl_array_for_each(fmt, &output->formats) { fd = os_create_anonymous_file(size);
fmt_info = pixel_format_get_info(*fmt); if (fd < 0) {
assert(fmt_info); fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
size);
if (fmt_info == output->app->requested_format || return NULL;
output->app->requested_format == NULL)
break;
fmt_info = NULL;
}
if (!fmt_info) {
fprintf(stderr, "No supported format found\n");
exit(1);
} }
if (output->app->verbose) data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
printf("Creating buffer with format %s / 0x%x and size %ux%u\n", if (data == MAP_FAILED) {
fmt_info->drm_format_name, fmt_info->format, fprintf(stderr, "mmap failed: %m\n");
output->buffer_width, output->buffer_height); close(fd);
return NULL;
if (output->app->buffer_type == CLIENT_BUFFER_TYPE_SHM) {
output->buffer = screenshot_create_shm_buffer(output->app,
output->buffer_width,
output->buffer_height,
fmt_info);
} else if (output->app->buffer_type == CLIENT_BUFFER_TYPE_DMABUF) {
output->buffer = screenshot_create_udmabuf(output->app,
output->buffer_width,
output->buffer_height,
fmt_info);
} }
abort_oom_if_null(output->buffer);
weston_capture_source_v1_capture(output->source, pool = wl_shm_create_pool(shm, fd, size);
output->buffer->buf->wl_buffer); close(fd);
output->app->waitcount++; buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride,
WL_SHM_FORMAT_XRGB8888);
wl_shm_pool_destroy(pool);
*data_out = data;
return buffer;
} }
static void static void
screenshot_write_png(const struct buffer_size *buff_size, screenshot_write_png(const struct buffer_size *buff_size,
struct wl_list *output_list) struct wl_list *output_list)
{ {
pixman_image_t *shot; int output_stride, buffer_stride, i;
cairo_surface_t *surface; cairo_surface_t *surface;
struct screenshooter_output *output; void *data, *d, *s;
struct screenshooter_output *output, *next;
FILE *fp; FILE *fp;
char filepath[PATH_MAX]; char filepath[PATH_MAX];
shot = pixman_image_create_bits(PIXMAN_a8r8g8b8, buffer_stride = buff_size->width * 4;
buff_size->width, buff_size->height,
NULL, 0);
abort_oom_if_null(shot);
wl_list_for_each(output, output_list, link) { data = xmalloc(buffer_stride * buff_size->height);
client_buffer_util_maybe_sync_dmabuf_start(output->buffer->buf); if (!data)
return;
pixman_image_composite32(PIXMAN_OP_SRC, wl_list_for_each_safe(output, next, output_list, link) {
output->buffer->image, /* src */ output_stride = output->width * 4;
NULL, /* mask */ s = output->data;
shot, /* dest */ d = data + (output->offset_y - buff_size->min_y) * buffer_stride +
0, 0, /* src x,y */ (output->offset_x - buff_size->min_x) * 4;
0, 0, /* mask x,y */
output->offset_x, output->offset_y, /* dst x,y */
output->buffer_width, output->buffer_height);
client_buffer_util_maybe_sync_dmabuf_end(output->buffer->buf); for (i = 0; i < output->height; i++) {
memcpy(d, s, output_stride);
d += buffer_stride;
s += output_stride;
}
free(output);
} }
surface = cairo_image_surface_create_for_data((void *)pixman_image_get_data(shot), surface = cairo_image_surface_create_for_data(data,
CAIRO_FORMAT_ARGB32, CAIRO_FORMAT_ARGB32,
pixman_image_get_width(shot), buff_size->width,
pixman_image_get_height(shot), buff_size->height,
pixman_image_get_stride(shot)); buffer_stride);
fp = file_create_dated(getenv("XDG_PICTURES_DIR"), "wayland-screenshot-", fp = file_create_dated(getenv("XDG_PICTURES_DIR"), "wayland-screenshot-",
".png", filepath, sizeof(filepath)); ".png", filepath, sizeof(filepath));
@ -439,65 +241,11 @@ screenshot_write_png(const struct buffer_size *buff_size,
cairo_surface_write_to_png(surface, filepath); cairo_surface_write_to_png(surface, filepath);
} }
cairo_surface_destroy(surface); cairo_surface_destroy(surface);
pixman_image_unref(shot); free(data);
}
static void
screenshot_write_yuv(const struct buffer_size *buff_size,
struct wl_list *output_list)
{
struct screenshooter_output *output;
int i = 0;
wl_list_for_each(output, output_list, link) {
struct screenshooter_buffer *buffer = output->buffer;
char filepath[PATH_MAX];
char filepath_prefix[100];
int write_offset = 0;
FILE *fp;
sprintf(filepath_prefix, "wayland-screenshot-output-%d-", i++);
fp = file_create_dated(getenv("XDG_PICTURES_DIR"),
filepath_prefix, ".yuv", filepath,
sizeof(filepath));
if (!fp) {
fprintf(stderr, "Writing yuv file for output %d failed\n", i);
return;
}
client_buffer_util_maybe_sync_dmabuf_start(buffer->buf);
for (unsigned int j = 0; j < pixel_format_get_plane_count(buffer->buf->fmt); j++) {
int plane_height =
buffer->buf->height / pixel_format_hsub(buffer->buf->fmt, j);
for (int k = 0; k < plane_height; k++) {
size_t lines_written;
lines_written = fwrite(buffer->buf->data + write_offset,
buffer->buf->bytes_per_line[j],
1, fp);
if (lines_written != 1) {
fprintf(stderr,
"Writing yuv file for output %d " \
"failed during write(): %s\n",
i, strerror(errno));
return;
}
write_offset += buffer->buf->strides[j];
}
}
fclose (fp);
client_buffer_util_maybe_sync_dmabuf_end(buffer->buf);
}
} }
static int static int
screenshot_set_buffer_size(struct buffer_size *buff_size, screenshot_set_buffer_size(struct buffer_size *buff_size, struct wl_list *output_list)
struct wl_list *output_list)
{ {
struct screenshooter_output *output; struct screenshooter_output *output;
buff_size->min_x = buff_size->min_y = INT_MAX; buff_size->min_x = buff_size->min_y = INT_MAX;
@ -506,16 +254,16 @@ screenshot_set_buffer_size(struct buffer_size *buff_size,
wl_list_for_each_reverse(output, output_list, link) { wl_list_for_each_reverse(output, output_list, link) {
output->offset_x = position; output->offset_x = position;
position += output->buffer_width; position += output->width;
} }
wl_list_for_each(output, output_list, link) { wl_list_for_each(output, output_list, link) {
buff_size->min_x = MIN(buff_size->min_x, output->offset_x); buff_size->min_x = MIN(buff_size->min_x, output->offset_x);
buff_size->min_y = MIN(buff_size->min_y, output->offset_y); buff_size->min_y = MIN(buff_size->min_y, output->offset_y);
buff_size->max_x = buff_size->max_x =
MAX(buff_size->max_x, output->offset_x + output->buffer_width); MAX(buff_size->max_x, output->offset_x + output->width);
buff_size->max_y = buff_size->max_y =
MAX(buff_size->max_y, output->offset_y + output->buffer_height); MAX(buff_size->max_y, output->offset_y + output->height);
} }
if (buff_size->max_x <= buff_size->min_x || if (buff_size->max_x <= buff_size->min_x ||
@ -528,212 +276,53 @@ screenshot_set_buffer_size(struct buffer_size *buff_size,
return 0; return 0;
} }
static bool int main(int argc, char *argv[])
received_formats_for_all_outputs(struct screenshooter_app *app)
{ {
struct wl_display *display;
struct wl_registry *registry;
struct screenshooter_output *output; struct screenshooter_output *output;
wl_list_for_each(output, &app->output_list, link) {
if (!output->formats_done)
return false;
}
return true;
}
static bool
all_output_formats_are_yuv(struct wl_list *output_list)
{
struct screenshooter_output *output;
int color_model = -1;
wl_list_for_each(output, output_list, link) {
if (color_model == -1) {
color_model = output->buffer->buf->fmt->color_model;
continue;
}
if ((int)output->buffer->buf->fmt->color_model != color_model) {
fprintf(stderr, "Mixing of RGB and YUV output formats not supported\n");
exit(1);
}
}
assert(color_model == (int)COLOR_MODEL_RGB ||
color_model == (int)COLOR_MODEL_YUV);
return color_model == COLOR_MODEL_YUV;
}
static void
print_usage_and_exit(void)
{
printf("usage flags:\n"
"\t'-h,--help'"
"\n\t\tprint this help output\n"
"\t'-v,--verbose'"
"\n\t\tprint additional output\n"
"\t'-f,--format=<>'"
"\n\t\tthe DRM format name to use without the DRM_FORMAT_ prefix, e.g. RGBA8888 or NV12\n"
"\n\t\tIn case of YCbCr formats like NV12, instead of a single .png, the output will consist of raw .yuv files for each output."
"\n\t\tThese files do not contain any metadata, however that can be added by converting to .y4m with a command like:"
"\n\t\tffmpeg -s 1024x768 -r 1 -pix_fmt yuv420p -i ~/wayland-screenshot-output-0-2025-08-01_15-58-24.yuv -c:v copy screenshot.y4m\n"
"\n\t\tNote that this may not work for all YCbCr pixel formats.\n"
"\t'-s,--source-type=<>'"
"\n\t\tframebuffer to use framebuffer source (default), "
"\n\t\twriteback to use writeback source\n"
"\t'-b,--buffer-type=<>'"
"\n\t\tshm to use a SHM buffer (default), "
"\n\t\tdmabuf to use a DMA buffer\n");
exit(0);
}
static const struct weston_enum_map source_types [] = {
{ "framebuffer", WESTON_CAPTURE_V1_SOURCE_FRAMEBUFFER },
{ "writeback", WESTON_CAPTURE_V1_SOURCE_WRITEBACK },
};
static const struct weston_enum_map buffer_types [] = {
{ "shm", CLIENT_BUFFER_TYPE_SHM },
{ "dmabuf", CLIENT_BUFFER_TYPE_DMABUF },
};
int
main(int argc, char *argv[])
{
struct screenshooter_output *output;
struct screenshooter_output *tmp_output;
struct buffer_size buff_size = {}; struct buffer_size buff_size = {};
struct screenshooter_app app = {}; struct screenshooter_data sh_data = {};
int c, option_index;
app.src_type = WESTON_CAPTURE_V1_SOURCE_FRAMEBUFFER; display = wl_display_connect(NULL);
app.buffer_type = CLIENT_BUFFER_TYPE_SHM; if (display == NULL) {
fprintf(stderr, "failed to create display: %m\n");
static struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
{"verbose", no_argument, NULL, 'v'},
{"format", required_argument, NULL, 'f'},
{"source-type", required_argument, NULL, 's'},
{"buffer-type", required_argument, NULL, 'b'},
{0, 0, 0, 0}
};
while ((c = getopt_long(argc, argv, "hvf:s:b:",
long_options, &option_index)) != -1) {
const struct weston_enum_map *entry;
switch(c) {
case 'v':
app.verbose = true;
break;
case 'f':
app.requested_format = pixel_format_get_info_by_drm_name(optarg);
if (!app.requested_format) {
fprintf(stderr, "Unknown format %s\n", optarg);
return -1;
}
break;
case 's':
entry = weston_enum_map_find_name(source_types,
optarg);
if (!entry)
print_usage_and_exit();
app.src_type = entry->value;
break;
case 'b':
entry = weston_enum_map_find_name(buffer_types,
optarg);
if (!entry)
print_usage_and_exit();
app.buffer_type = entry->value;
break;
default:
print_usage_and_exit();
}
}
wl_list_init(&app.output_list);
app.display = wl_display_connect(NULL);
if (app.display == NULL) {
fprintf(stderr, "failed to create display: %s\n",
strerror(errno));
return -1; return -1;
} }
app.registry = wl_display_get_registry(app.display); wl_list_init(&sh_data.output_list);
wl_registry_add_listener(app.registry, &registry_listener, &app); registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, &sh_data);
/* Process wl_registry advertisements */ wl_display_dispatch(display);
wl_display_roundtrip(app.display); wl_display_roundtrip(display);
if (sh_data.screenshooter == NULL) {
if (!app.capture_factory) { fprintf(stderr, "display doesn't support screenshooter\n");
fprintf(stderr, "Error: display does not support weston_capture_v1\n");
return -1; return -1;
} }
if(app.buffer_type == CLIENT_BUFFER_TYPE_SHM && !app.shm) { weston_screenshooter_add_listener(sh_data.screenshooter,
fprintf(stderr, "Error: display does not support wl_shm\n"); &screenshooter_listener,
return -1; &sh_data);
}
if (app.buffer_type == CLIENT_BUFFER_TYPE_DMABUF && !app.dmabuf) { if (screenshot_set_buffer_size(&buff_size, &sh_data.output_list))
fprintf(stderr, "Error: Compositor does not support zwp_linux_dmabuf_v1\n");
return -1; return -1;
wl_list_for_each(output, &sh_data.output_list, link) {
output->buffer =
screenshot_create_shm_buffer(output->width,
output->height,
&output->data,
sh_data.shm);
weston_screenshooter_shoot(sh_data.screenshooter,
output->output,
output->buffer);
sh_data.buffer_copy_done = 0;
while (!sh_data.buffer_copy_done)
wl_display_roundtrip(display);
} }
if (app.verbose) { screenshot_write_png(&buff_size, &sh_data.output_list);
printf("Taking screenshot with %s source %s buffer\n",
(app.src_type == WESTON_CAPTURE_V1_SOURCE_FRAMEBUFFER) ? "framebuffer" : "writeback",
(app.buffer_type == CLIENT_BUFFER_TYPE_SHM) ? "shm" : "dma");
}
/* Process initial events for wl_output and weston_capture_source_v1 */
wl_display_roundtrip(app.display);
while (!received_formats_for_all_outputs(&app)) {
if (app.verbose)
printf("Waiting for compositor to send capture source data\n");
if (wl_display_dispatch(app.display) < 0) {
fprintf(stderr, "Error: connection terminated\n");
return -1;
}
}
do {
app.retry = false;
wl_list_for_each(output, &app.output_list, link)
screenshooter_output_capture(output);
while (app.waitcount > 0 && !app.failed) {
if (wl_display_dispatch(app.display) < 0)
app.failed = true;
assert(app.waitcount >= 0);
}
} while (app.retry && !app.failed);
if (!app.failed) {
if (screenshot_set_buffer_size(&buff_size, &app.output_list) < 0)
return -1;
if (all_output_formats_are_yuv(&app.output_list))
screenshot_write_yuv(&buff_size, &app.output_list);
else
screenshot_write_png(&buff_size, &app.output_list);
} else {
fprintf(stderr, "Error: screenshot or protocol failure\n");
}
wl_list_for_each_safe(output, tmp_output, &app.output_list, link)
destroy_output(output);
weston_capture_v1_destroy(app.capture_factory);
wl_shm_destroy(app.shm);
if (app.dmabuf)
zwp_linux_dmabuf_v1_destroy(app.dmabuf);
wl_registry_destroy(app.registry);
wl_display_disconnect(app.display);
return 0; return 0;
} }

View file

@ -35,12 +35,12 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/time.h> #include <sys/time.h>
#include <signal.h> #include <signal.h>
#include <errno.h>
#include <wayland-client.h> #include <wayland-client.h>
#include "shared/os-compatibility.h" #include "shared/os-compatibility.h"
#include <libweston/zalloc.h> #include "shared/zalloc.h"
#include "xdg-shell-client-protocol.h" #include "xdg-shell-client-protocol.h"
#include "fullscreen-shell-unstable-v1-client-protocol.h"
#include "viewporter-client-protocol.h" #include "viewporter-client-protocol.h"
int print_debug = 0; int print_debug = 0;
@ -52,6 +52,7 @@ struct display {
struct wl_compositor *compositor; struct wl_compositor *compositor;
struct wp_viewporter *viewporter; struct wp_viewporter *viewporter;
struct xdg_wm_base *wm_base; struct xdg_wm_base *wm_base;
struct zwp_fullscreen_shell_v1 *fshell;
struct wl_shm *shm; struct wl_shm *shm;
uint32_t formats; uint32_t formats;
}; };
@ -122,14 +123,14 @@ create_shm_buffer(struct display *display, struct buffer *buffer,
fd = os_create_anonymous_file(size); fd = os_create_anonymous_file(size);
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "creating a buffer file for %d B failed: %s\n", fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
size, strerror(errno)); size);
return -1; return -1;
} }
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) { if (data == MAP_FAILED) {
fprintf(stderr, "mmap failed: %s\n", strerror(errno)); fprintf(stderr, "mmap failed: %m\n");
close(fd); close(fd);
return -1; return -1;
} }
@ -335,11 +336,14 @@ create_window(struct display *display, int width, int height,
&xdg_toplevel_listener, window); &xdg_toplevel_listener, window);
xdg_toplevel_set_title(window->xdg_toplevel, "simple-damage"); xdg_toplevel_set_title(window->xdg_toplevel, "simple-damage");
xdg_toplevel_set_app_id(window->xdg_toplevel,
"org.freedesktop.weston.simple-damage");
window->wait_for_configure = true; window->wait_for_configure = true;
wl_surface_commit(window->surface); wl_surface_commit(window->surface);
} else if (display->fshell) {
zwp_fullscreen_shell_v1_present_surface(display->fshell,
window->surface,
ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT,
NULL);
} else { } else {
assert(0); assert(0);
} }
@ -456,32 +460,32 @@ window_get_transformed_ball(struct window *window, float *bx, float *by)
*by = wy; *by = wy;
break; break;
case WL_OUTPUT_TRANSFORM_90: case WL_OUTPUT_TRANSFORM_90:
*bx = wy; *bx = window->height - wy;
*by = window->width - wx; *by = wx;
break; break;
case WL_OUTPUT_TRANSFORM_180: case WL_OUTPUT_TRANSFORM_180:
*bx = window->width - wx; *bx = window->width - wx;
*by = window->height - wy; *by = window->height - wy;
break; break;
case WL_OUTPUT_TRANSFORM_270: case WL_OUTPUT_TRANSFORM_270:
*bx = window->height - wy; *bx = wy;
*by = wx; *by = window->width - wx;
break; break;
case WL_OUTPUT_TRANSFORM_FLIPPED: case WL_OUTPUT_TRANSFORM_FLIPPED:
*bx = window->width - wx; *bx = window->width - wx;
*by = wy; *by = wy;
break; break;
case WL_OUTPUT_TRANSFORM_FLIPPED_90: case WL_OUTPUT_TRANSFORM_FLIPPED_90:
*bx = wy; *bx = window->height - wy;
*by = wx; *by = window->width - wx;
break; break;
case WL_OUTPUT_TRANSFORM_FLIPPED_180: case WL_OUTPUT_TRANSFORM_FLIPPED_180:
*bx = wx; *bx = wx;
*by = window->height - wy; *by = window->height - wy;
break; break;
case WL_OUTPUT_TRANSFORM_FLIPPED_270: case WL_OUTPUT_TRANSFORM_FLIPPED_270:
*bx = window->height - wy; *bx = wy;
*by = window->width - wx; *by = wx;
break; break;
} }
@ -497,20 +501,6 @@ window_get_transformed_ball(struct window *window, float *bx, float *by)
static const struct wl_callback_listener frame_listener; static const struct wl_callback_listener frame_listener;
static void
set_opaque_region(struct window *window)
{
struct wl_region *region;
region = wl_compositor_create_region(window->display->compositor);
wl_region_add(region, 0, 0, window->width, window->height);
wl_region_subtract(region, window->border, window->border,
window->width - 2 * window->border,
window->height - 2 * window->border);
wl_surface_set_opaque_region(window->surface, region);
wl_region_destroy(region);
}
static void static void
redraw(void *data, struct wl_callback *callback, uint32_t time) redraw(void *data, struct wl_callback *callback, uint32_t time)
{ {
@ -579,32 +569,32 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
off_x = tx; off_x = tx;
break; break;
case WL_OUTPUT_TRANSFORM_90: case WL_OUTPUT_TRANSFORM_90:
off_y = bheight - tx; off_y = tx;
off_x = ty; off_x = bwidth - ty;
break; break;
case WL_OUTPUT_TRANSFORM_180: case WL_OUTPUT_TRANSFORM_180:
off_y = bheight - ty; off_y = bheight - ty;
off_x = bwidth - tx; off_x = bwidth - tx;
break; break;
case WL_OUTPUT_TRANSFORM_270: case WL_OUTPUT_TRANSFORM_270:
off_y = tx; off_y = bheight - tx;
off_x = bwidth - ty; off_x = ty;
break; break;
case WL_OUTPUT_TRANSFORM_FLIPPED: case WL_OUTPUT_TRANSFORM_FLIPPED:
off_y = ty; off_y = ty;
off_x = bwidth - tx; off_x = bwidth - tx;
break; break;
case WL_OUTPUT_TRANSFORM_FLIPPED_90: case WL_OUTPUT_TRANSFORM_FLIPPED_90:
off_y = tx; off_y = bheight - tx;
off_x = ty; off_x = bwidth - ty;
break; break;
case WL_OUTPUT_TRANSFORM_FLIPPED_180: case WL_OUTPUT_TRANSFORM_FLIPPED_180:
off_y = bheight - ty; off_y = bheight - ty;
off_x = tx; off_x = tx;
break; break;
case WL_OUTPUT_TRANSFORM_FLIPPED_270: case WL_OUTPUT_TRANSFORM_FLIPPED_270:
off_y = bheight - tx; off_y = tx;
off_x = bwidth - ty; off_x = ty;
break; break;
} }
wp_viewport_set_source(window->viewport, wp_viewport_set_source(window->viewport,
@ -698,8 +688,6 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
if (callback) if (callback)
wl_callback_destroy(callback); wl_callback_destroy(callback);
set_opaque_region(window);
window->callback = wl_surface_frame(window->surface); window->callback = wl_surface_frame(window->surface);
wl_callback_add_listener(window->callback, &frame_listener, window); wl_callback_add_listener(window->callback, &frame_listener, window);
wl_surface_commit(window->surface); wl_surface_commit(window->surface);
@ -759,6 +747,9 @@ registry_handle_global(void *data, struct wl_registry *registry,
d->wm_base = wl_registry_bind(registry, d->wm_base = wl_registry_bind(registry,
id, &xdg_wm_base_interface, 1); id, &xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(d->wm_base, &wm_base_listener, d); xdg_wm_base_add_listener(d->wm_base, &wm_base_listener, d);
} else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0) {
d->fshell = wl_registry_bind(registry,
id, &zwp_fullscreen_shell_v1_interface, 1);
} else if (strcmp(interface, "wl_shm") == 0) { } else if (strcmp(interface, "wl_shm") == 0) {
d->shm = wl_registry_bind(registry, d->shm = wl_registry_bind(registry,
id, &wl_shm_interface, 1); id, &wl_shm_interface, 1);
@ -782,7 +773,7 @@ create_display(int version)
{ {
struct display *display; struct display *display;
display = zalloc(sizeof *display); display = malloc(sizeof *display);
if (display == NULL) { if (display == NULL) {
fprintf(stderr, "out of memory\n"); fprintf(stderr, "out of memory\n");
exit(1); exit(1);
@ -820,6 +811,9 @@ destroy_display(struct display *display)
if (display->wm_base) if (display->wm_base)
xdg_wm_base_destroy(display->wm_base); xdg_wm_base_destroy(display->wm_base);
if (display->fshell)
zwp_fullscreen_shell_v1_release(display->fshell);
if (display->viewporter) if (display->viewporter)
wp_viewporter_destroy(display->viewporter); wp_viewporter_destroy(display->viewporter);
@ -954,7 +948,7 @@ main(int argc, char **argv)
while (running && ret != -1) while (running && ret != -1)
ret = wl_display_dispatch(display->display); ret = wl_display_dispatch(display->display);
fprintf(stderr, "simple-damage exiting\n"); fprintf(stderr, "simple-shm exiting\n");
destroy_window(window); destroy_window(window);
destroy_display(display); destroy_display(display);

File diff suppressed because it is too large Load diff

1014
clients/simple-dmabuf-drm.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -39,17 +39,17 @@
#include <unistd.h> #include <unistd.h>
#include <sys/time.h> #include <sys/time.h>
#include <drm_fourcc.h>
#include <xf86drm.h> #include <xf86drm.h>
#include <gbm.h> #include <gbm.h>
#include <wayland-client.h> #include <wayland-client.h>
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/platform.h" #include "shared/platform.h"
#include "shared/weston-drm-fourcc.h" #include "shared/zalloc.h"
#include <libweston/zalloc.h> #include "xdg-shell-unstable-v6-client-protocol.h"
#include "xdg-shell-client-protocol.h" #include "fullscreen-shell-unstable-v1-client-protocol.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h" #include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "weston-direct-display-client-protocol.h"
#include "linux-explicit-synchronization-unstable-v1-client-protocol.h" #include "linux-explicit-synchronization-unstable-v1-client-protocol.h"
#include <EGL/egl.h> #include <EGL/egl.h>
@ -57,27 +57,28 @@
#include <GLES2/gl2.h> #include <GLES2/gl2.h>
#include <GLES2/gl2ext.h> #include <GLES2/gl2ext.h>
#include <libweston/matrix.h>
#include "shared/weston-egl-ext.h" #include "shared/weston-egl-ext.h"
#ifndef DRM_FORMAT_MOD_INVALID
#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
#endif
/* Possible options that affect the displayed image */ /* Possible options that affect the displayed image */
#define OPT_IMMEDIATE (1 << 0) /* create wl_buffer immediately */ #define OPT_IMMEDIATE (1 << 0) /* create wl_buffer immediately */
#define OPT_IMPLICIT_SYNC (1 << 1) /* force implicit sync */ #define OPT_IMPLICIT_SYNC (1 << 1) /* force implicit sync */
#define OPT_MANDELBROT (1 << 2) /* render mandelbrot */ #define OPT_MANDELBROT (1 << 2) /* render mandelbrot */
#define OPT_DIRECT_DISPLAY (1 << 3) /* direct-display */
#define BUFFER_FORMAT DRM_FORMAT_XRGB8888
#define MAX_BUFFER_PLANES 4 #define MAX_BUFFER_PLANES 4
struct display { struct display {
struct wl_display *display; struct wl_display *display;
struct wl_registry *registry; struct wl_registry *registry;
struct wl_compositor *compositor; struct wl_compositor *compositor;
struct xdg_wm_base *wm_base; struct zxdg_shell_v6 *shell;
struct zwp_fullscreen_shell_v1 *fshell;
struct zwp_linux_dmabuf_v1 *dmabuf; struct zwp_linux_dmabuf_v1 *dmabuf;
struct weston_direct_display_v1 *direct_display;
struct zwp_linux_explicit_synchronization_v1 *explicit_sync; struct zwp_linux_explicit_synchronization_v1 *explicit_sync;
uint32_t format;
bool format_supported;
uint64_t *modifiers; uint64_t *modifiers;
int modifiers_count; int modifiers_count;
int req_dmabuf_immediate; int req_dmabuf_immediate;
@ -85,9 +86,7 @@ struct display {
struct { struct {
EGLDisplay display; EGLDisplay display;
EGLContext context; EGLContext context;
EGLConfig conf;
bool has_dma_buf_import_modifiers; bool has_dma_buf_import_modifiers;
bool has_no_config_context;
PFNEGLQUERYDMABUFMODIFIERSEXTPROC query_dma_buf_modifiers; PFNEGLQUERYDMABUFMODIFIERSEXTPROC query_dma_buf_modifiers;
PFNEGLCREATEIMAGEKHRPROC create_image; PFNEGLCREATEIMAGEKHRPROC create_image;
PFNEGLDESTROYIMAGEKHRPROC destroy_image; PFNEGLDESTROYIMAGEKHRPROC destroy_image;
@ -130,14 +129,14 @@ struct buffer {
int release_fence_fd; int release_fence_fd;
}; };
#define NUM_BUFFERS 4 #define NUM_BUFFERS 3
struct window { struct window {
struct display *display; struct display *display;
int width, height; int width, height;
struct wl_surface *surface; struct wl_surface *surface;
struct xdg_surface *xdg_surface; struct zxdg_surface_v6 *xdg_surface;
struct xdg_toplevel *xdg_toplevel; struct zxdg_toplevel_v6 *xdg_toplevel;
struct zwp_linux_surface_synchronization_v1 *surface_sync; struct zwp_linux_surface_synchronization_v1 *surface_sync;
struct buffer buffers[NUM_BUFFERS]; struct buffer buffers[NUM_BUFFERS];
struct wl_callback *callback; struct wl_callback *callback;
@ -148,7 +147,6 @@ struct window {
GLuint pos; GLuint pos;
GLuint color; GLuint color;
GLuint offset_uniform; GLuint offset_uniform;
GLuint reflection_uniform;
} gl; } gl;
bool render_mandelbrot; bool render_mandelbrot;
}; };
@ -295,7 +293,7 @@ create_fbo_for_buffer(struct display *display, struct buffer *buffer)
EGL_NO_CONTEXT, EGL_NO_CONTEXT,
EGL_LINUX_DMA_BUF_EXT, EGL_LINUX_DMA_BUF_EXT,
NULL, attribs); NULL, attribs);
if (buffer->egl_image == EGL_NO_IMAGE_KHR) { if (buffer->egl_image == EGL_NO_IMAGE) {
fprintf(stderr, "EGLImageKHR creation failed\n"); fprintf(stderr, "EGLImageKHR creation failed\n");
return false; return false;
} }
@ -327,29 +325,32 @@ create_fbo_for_buffer(struct display *display, struct buffer *buffer)
static int static int
create_dmabuf_buffer(struct display *display, struct buffer *buffer, create_dmabuf_buffer(struct display *display, struct buffer *buffer,
int width, int height, uint32_t opts) int width, int height)
{ {
static uint32_t flags = 0; /* Y-Invert the buffer image, since we are going to renderer to the
* buffer through a FBO. */
static const uint32_t flags = ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT;
struct zwp_linux_buffer_params_v1 *params; struct zwp_linux_buffer_params_v1 *params;
int i; int i;
buffer->display = display; buffer->display = display;
buffer->width = width; buffer->width = width;
buffer->height = height; buffer->height = height;
buffer->format = display->format; buffer->format = BUFFER_FORMAT;
buffer->release_fence_fd = -1; buffer->release_fence_fd = -1;
#ifdef HAVE_GBM_MODIFIERS
if (display->modifiers_count > 0) { if (display->modifiers_count > 0) {
buffer->bo = gbm_bo_create_with_modifiers2(display->gbm.device, buffer->bo = gbm_bo_create_with_modifiers(display->gbm.device,
buffer->width, buffer->width,
buffer->height, buffer->height,
buffer->format, buffer->format,
display->modifiers, display->modifiers,
display->modifiers_count, display->modifiers_count);
GBM_BO_USE_RENDERING);
if (buffer->bo) if (buffer->bo)
buffer->modifier = gbm_bo_get_modifier(buffer->bo); buffer->modifier = gbm_bo_get_modifier(buffer->bo);
} }
#endif
if (!buffer->bo) { if (!buffer->bo) {
buffer->bo = gbm_bo_create(display->gbm.device, buffer->bo = gbm_bo_create(display->gbm.device,
@ -365,19 +366,12 @@ create_dmabuf_buffer(struct display *display, struct buffer *buffer,
goto error; goto error;
} }
#ifdef HAVE_GBM_MODIFIERS
buffer->plane_count = gbm_bo_get_plane_count(buffer->bo); buffer->plane_count = gbm_bo_get_plane_count(buffer->bo);
for (i = 0; i < buffer->plane_count; ++i) { for (i = 0; i < buffer->plane_count; ++i) {
int ret; uint32_t handle = gbm_bo_get_handle_for_plane(buffer->bo, i).u32;
union gbm_bo_handle handle; int ret = drmPrimeHandleToFD(display->gbm.drm_fd, handle, 0,
&buffer->dmabuf_fds[i]);
handle = gbm_bo_get_handle_for_plane(buffer->bo, i);
if (handle.s32 == -1) {
fprintf(stderr, "error: failed to get gbm_bo_handle\n");
goto error;
}
ret = drmPrimeHandleToFD(display->gbm.drm_fd, handle.u32, 0,
&buffer->dmabuf_fds[i]);
if (ret < 0 || buffer->dmabuf_fds[i] < 0) { if (ret < 0 || buffer->dmabuf_fds[i] < 0) {
fprintf(stderr, "error: failed to get dmabuf_fd\n"); fprintf(stderr, "error: failed to get dmabuf_fd\n");
goto error; goto error;
@ -385,12 +379,17 @@ create_dmabuf_buffer(struct display *display, struct buffer *buffer,
buffer->strides[i] = gbm_bo_get_stride_for_plane(buffer->bo, i); buffer->strides[i] = gbm_bo_get_stride_for_plane(buffer->bo, i);
buffer->offsets[i] = gbm_bo_get_offset(buffer->bo, i); buffer->offsets[i] = gbm_bo_get_offset(buffer->bo, i);
} }
#else
buffer->plane_count = 1;
buffer->strides[0] = gbm_bo_get_stride(buffer->bo);
buffer->dmabuf_fds[0] = gbm_bo_get_fd(buffer->bo);
if (buffer->dmabuf_fds[0] < 0) {
fprintf(stderr, "error: failed to get dmabuf_fd\n");
goto error;
}
#endif
params = zwp_linux_dmabuf_v1_create_params(display->dmabuf); params = zwp_linux_dmabuf_v1_create_params(display->dmabuf);
if ((opts & OPT_DIRECT_DISPLAY) && display->direct_display)
weston_direct_display_v1_enable(display->direct_display, params);
for (i = 0; i < buffer->plane_count; ++i) { for (i = 0; i < buffer->plane_count; ++i) {
zwp_linux_buffer_params_v1_add(params, zwp_linux_buffer_params_v1_add(params,
buffer->dmabuf_fds[i], buffer->dmabuf_fds[i],
@ -437,48 +436,47 @@ error:
} }
static void static void
xdg_surface_handle_configure(void *data, struct xdg_surface *surface, xdg_surface_handle_configure(void *data, struct zxdg_surface_v6 *surface,
uint32_t serial) uint32_t serial)
{ {
struct window *window = data; struct window *window = data;
xdg_surface_ack_configure(surface, serial); zxdg_surface_v6_ack_configure(surface, serial);
if (window->initialized && window->wait_for_configure) if (window->initialized && window->wait_for_configure)
redraw(window, NULL, 0); redraw(window, NULL, 0);
window->wait_for_configure = false; window->wait_for_configure = false;
} }
static const struct xdg_surface_listener xdg_surface_listener = { static const struct zxdg_surface_v6_listener xdg_surface_listener = {
xdg_surface_handle_configure, xdg_surface_handle_configure,
}; };
static void static void
xdg_toplevel_handle_configure(void *data, struct xdg_toplevel *toplevel, xdg_toplevel_handle_configure(void *data, struct zxdg_toplevel_v6 *toplevel,
int32_t width, int32_t height, int32_t width, int32_t height,
struct wl_array *states) struct wl_array *states)
{ {
} }
static void static void
xdg_toplevel_handle_close(void *data, struct xdg_toplevel *xdg_toplevel) xdg_toplevel_handle_close(void *data, struct zxdg_toplevel_v6 *xdg_toplevel)
{ {
running = 0; running = 0;
} }
static const struct xdg_toplevel_listener xdg_toplevel_listener = { static const struct zxdg_toplevel_v6_listener xdg_toplevel_listener = {
xdg_toplevel_handle_configure, xdg_toplevel_handle_configure,
xdg_toplevel_handle_close, xdg_toplevel_handle_close,
}; };
static const char *vert_shader_text = static const char *vert_shader_text =
"uniform float offset;\n" "uniform float offset;\n"
"uniform mat4 reflection;\n"
"attribute vec4 pos;\n" "attribute vec4 pos;\n"
"attribute vec4 color;\n" "attribute vec4 color;\n"
"varying vec4 v_color;\n" "varying vec4 v_color;\n"
"void main() {\n" "void main() {\n"
" gl_Position = reflection * (pos + vec4(offset, offset, 0.0, 0.0));\n" " gl_Position = pos + vec4(offset, offset, 0.0, 0.0);\n"
" v_color = color;\n" " v_color = color;\n"
"}\n"; "}\n";
@ -491,12 +489,11 @@ static const char *frag_shader_text =
static const char *vert_shader_mandelbrot_text = static const char *vert_shader_mandelbrot_text =
"uniform float offset;\n" "uniform float offset;\n"
"uniform mat4 reflection;\n"
"attribute vec4 pos;\n" "attribute vec4 pos;\n"
"varying vec2 v_pos;\n" "varying vec2 v_pos;\n"
"void main() {\n" "void main() {\n"
" v_pos = pos.xy;\n" " v_pos = pos.xy;\n"
" gl_Position = reflection * (pos + vec4(offset, offset, 0.0, 0.0));\n" " gl_Position = pos + vec4(offset, offset, 0.0, 0.0);\n"
"}\n"; "}\n";
@ -541,7 +538,7 @@ create_shader(const char *source, GLenum shader_type)
char log[1000]; char log[1000];
GLsizei len; GLsizei len;
glGetShaderInfoLog(shader, 1000, &len, log); glGetShaderInfoLog(shader, 1000, &len, log);
fprintf(stderr, "Error: compiling %s: %.*s\n", fprintf(stderr, "Error: compiling %s: %*s\n",
shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment", shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
len, log); len, log);
return 0; return 0;
@ -565,7 +562,7 @@ create_and_link_program(GLuint vert, GLuint frag)
char log[1000]; char log[1000];
GLsizei len; GLsizei len;
glGetProgramInfoLog(program, 1000, &len, log); glGetProgramInfoLog(program, 1000, &len, log);
fprintf(stderr, "Error: linking:\n%.*s\n", len, log); fprintf(stderr, "Error: linking:\n%*s\n", len, log);
return 0; return 0;
} }
@ -596,8 +593,6 @@ window_set_up_gl(struct window *window)
window->gl.offset_uniform = window->gl.offset_uniform =
glGetUniformLocation(window->gl.program, "offset"); glGetUniformLocation(window->gl.program, "offset");
window->gl.reflection_uniform =
glGetUniformLocation(window->gl.program, "reflection");
return window->gl.program != 0; return window->gl.program != 0;
} }
@ -619,9 +614,9 @@ destroy_window(struct window *window)
} }
if (window->xdg_toplevel) if (window->xdg_toplevel)
xdg_toplevel_destroy(window->xdg_toplevel); zxdg_toplevel_v6_destroy(window->xdg_toplevel);
if (window->xdg_surface) if (window->xdg_surface)
xdg_surface_destroy(window->xdg_surface); zxdg_surface_v6_destroy(window->xdg_surface);
if (window->surface_sync) if (window->surface_sync)
zwp_linux_surface_synchronization_v1_destroy(window->surface_sync); zwp_linux_surface_synchronization_v1_destroy(window->surface_sync);
wl_surface_destroy(window->surface); wl_surface_destroy(window->surface);
@ -645,30 +640,33 @@ create_window(struct display *display, int width, int height, int opts)
window->height = height; window->height = height;
window->surface = wl_compositor_create_surface(display->compositor); window->surface = wl_compositor_create_surface(display->compositor);
if (display->wm_base) { if (display->shell) {
window->xdg_surface = window->xdg_surface =
xdg_wm_base_get_xdg_surface(display->wm_base, zxdg_shell_v6_get_xdg_surface(display->shell,
window->surface); window->surface);
assert(window->xdg_surface); assert(window->xdg_surface);
xdg_surface_add_listener(window->xdg_surface, zxdg_surface_v6_add_listener(window->xdg_surface,
&xdg_surface_listener, window); &xdg_surface_listener, window);
window->xdg_toplevel = window->xdg_toplevel =
xdg_surface_get_toplevel(window->xdg_surface); zxdg_surface_v6_get_toplevel(window->xdg_surface);
assert(window->xdg_toplevel); assert(window->xdg_toplevel);
xdg_toplevel_add_listener(window->xdg_toplevel, zxdg_toplevel_v6_add_listener(window->xdg_toplevel,
&xdg_toplevel_listener, window); &xdg_toplevel_listener, window);
xdg_toplevel_set_title(window->xdg_toplevel, "simple-dmabuf-egl"); zxdg_toplevel_v6_set_title(window->xdg_toplevel, "simple-dmabuf-egl");
xdg_toplevel_set_app_id(window->xdg_toplevel,
"org.freedesktop.weston.simple-dmabuf-egl");
window->wait_for_configure = true; window->wait_for_configure = true;
wl_surface_commit(window->surface); wl_surface_commit(window->surface);
} else if (display->fshell) {
zwp_fullscreen_shell_v1_present_surface(display->fshell,
window->surface,
ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT,
NULL);
} else { } else {
assert(0); assert(0);
} }
@ -689,7 +687,7 @@ create_window(struct display *display, int width, int height, int opts)
for (i = 0; i < NUM_BUFFERS; ++i) { for (i = 0; i < NUM_BUFFERS; ++i) {
ret = create_dmabuf_buffer(display, &window->buffers[i], ret = create_dmabuf_buffer(display, &window->buffers[i],
width, height, opts); width, height);
if (ret < 0) if (ret < 0)
goto error; goto error;
@ -772,7 +770,6 @@ render(struct window *window, struct buffer *buffer)
GLfloat offset; GLfloat offset;
struct timeval tv; struct timeval tv;
uint64_t time_ms; uint64_t time_ms;
struct weston_matrix reflection;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
time_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000; time_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
@ -781,32 +778,12 @@ render(struct window *window, struct buffer *buffer)
* to offsets in the [-0.5, 0.5) range. */ * to offsets in the [-0.5, 0.5) range. */
offset = (time_ms % iteration_ms) / (float) iteration_ms - 0.5; offset = (time_ms % iteration_ms) / (float) iteration_ms - 0.5;
weston_matrix_init(&reflection);
/* perform a reflection about x-axis to keep the same orientation of
* the vertices colors, as outlined in the comment at the beginning
* of this function.
*
* We need to render upside-down, because rendering through an FBO
* causes the bottom of the image to be written to the top pixel row of
* the buffer, y-flipping the image.
*
* Reflection is a specialized version of scaling with the
* following matrix:
*
* [1, 0, 0]
* [0, -1, 0]
* [0, 0, 1]
*/
weston_matrix_scale(&reflection, 1, -1, 1);
/* Direct all GL draws to the buffer through the FBO */ /* Direct all GL draws to the buffer through the FBO */
glBindFramebuffer(GL_FRAMEBUFFER, buffer->gl_fbo); glBindFramebuffer(GL_FRAMEBUFFER, buffer->gl_fbo);
glViewport(0, 0, window->width, window->height); glViewport(0, 0, window->width, window->height);
glUniform1f(window->gl.offset_uniform, offset); glUniform1f(window->gl.offset_uniform, offset);
glUniformMatrix4fv(window->gl.reflection_uniform, 1, GL_FALSE,
(GLfloat *) reflection.M.colmaj);
glClearColor(0.0,0.0, 0.0, 1.0); glClearColor(0.0,0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
@ -836,7 +813,6 @@ render_mandelbrot(struct window *window, struct buffer *buffer)
struct timeval tv; struct timeval tv;
uint64_t time_ms; uint64_t time_ms;
int i; int i;
struct weston_matrix reflection;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
time_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000; time_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
@ -845,17 +821,12 @@ render_mandelbrot(struct window *window, struct buffer *buffer)
* to offsets in the [-0.5, 0.5) range. */ * to offsets in the [-0.5, 0.5) range. */
offset = (time_ms % iteration_ms) / (float) iteration_ms - 0.5; offset = (time_ms % iteration_ms) / (float) iteration_ms - 0.5;
weston_matrix_init(&reflection);
weston_matrix_scale(&reflection, 1, -1, 1);
/* Direct all GL draws to the buffer through the FBO */ /* Direct all GL draws to the buffer through the FBO */
glBindFramebuffer(GL_FRAMEBUFFER, buffer->gl_fbo); glBindFramebuffer(GL_FRAMEBUFFER, buffer->gl_fbo);
glViewport(0, 0, window->width, window->height); glViewport(0, 0, window->width, window->height);
glUniform1f(window->gl.offset_uniform, offset); glUniform1f(window->gl.offset_uniform, offset);
glUniformMatrix4fv(window->gl.reflection_uniform, 1, GL_FALSE,
(GLfloat *) reflection.M.colmaj);
glClearColor(0.6, 0.6, 0.6, 1.0); glClearColor(0.6, 0.6, 0.6, 1.0);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
@ -982,7 +953,7 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
zwp_linux_buffer_release_v1_add_listener( zwp_linux_buffer_release_v1_add_listener(
buffer->buffer_release, &buffer_release_listener, buffer); buffer->buffer_release, &buffer_release_listener, buffer);
} else { } else {
glFlush(); glFinish();
} }
wl_surface_attach(window->surface, buffer->buffer, 0, 0); wl_surface_attach(window->surface, buffer->buffer, 0, 0);
@ -1006,19 +977,17 @@ dmabuf_modifiers(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo) uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo)
{ {
struct display *d = data; struct display *d = data;
uint64_t modifier = u64_from_u32s(modifier_hi, modifier_lo);
if (format != d->format) { switch (format) {
return; case BUFFER_FORMAT:
}
d->format_supported = true;
if (modifier != DRM_FORMAT_MOD_INVALID) {
++d->modifiers_count; ++d->modifiers_count;
d->modifiers = realloc(d->modifiers, d->modifiers = realloc(d->modifiers,
d->modifiers_count * sizeof(*d->modifiers)); d->modifiers_count * sizeof(*d->modifiers));
d->modifiers[d->modifiers_count - 1] = modifier; d->modifiers[d->modifiers_count - 1] =
((uint64_t)modifier_hi << 32) | modifier_lo;
break;
default:
break;
} }
} }
@ -1034,13 +1003,13 @@ static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
}; };
static void static void
xdg_wm_base_ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial) xdg_shell_ping(void *data, struct zxdg_shell_v6 *shell, uint32_t serial)
{ {
xdg_wm_base_pong(wm_base, serial); zxdg_shell_v6_pong(shell, serial);
} }
static const struct xdg_wm_base_listener xdg_wm_base_listener = { static const struct zxdg_shell_v6_listener xdg_shell_listener = {
xdg_wm_base_ping, xdg_shell_ping,
}; };
static void static void
@ -1053,10 +1022,13 @@ registry_handle_global(void *data, struct wl_registry *registry,
d->compositor = d->compositor =
wl_registry_bind(registry, wl_registry_bind(registry,
id, &wl_compositor_interface, 1); id, &wl_compositor_interface, 1);
} else if (strcmp(interface, "xdg_wm_base") == 0) { } else if (strcmp(interface, "zxdg_shell_v6") == 0) {
d->wm_base = wl_registry_bind(registry, d->shell = wl_registry_bind(registry,
id, &xdg_wm_base_interface, 1); id, &zxdg_shell_v6_interface, 1);
xdg_wm_base_add_listener(d->wm_base, &xdg_wm_base_listener, d); zxdg_shell_v6_add_listener(d->shell, &xdg_shell_listener, d);
} else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0) {
d->fshell = wl_registry_bind(registry,
id, &zwp_fullscreen_shell_v1_interface, 1);
} else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) { } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) {
if (version < 3) if (version < 3)
return; return;
@ -1067,9 +1039,6 @@ registry_handle_global(void *data, struct wl_registry *registry,
d->explicit_sync = wl_registry_bind( d->explicit_sync = wl_registry_bind(
registry, id, registry, id,
&zwp_linux_explicit_synchronization_v1_interface, 1); &zwp_linux_explicit_synchronization_v1_interface, 1);
} else if (strcmp(interface, "weston_direct_display_v1") == 0) {
d->direct_display = wl_registry_bind(registry,
id, &weston_direct_display_v1_interface, 1);
} }
} }
@ -1101,17 +1070,14 @@ destroy_display(struct display *display)
free(display->modifiers); free(display->modifiers);
if (display->direct_display)
weston_direct_display_v1_destroy(display->direct_display);
if (display->explicit_sync)
zwp_linux_explicit_synchronization_v1_destroy(display->explicit_sync);
if (display->dmabuf) if (display->dmabuf)
zwp_linux_dmabuf_v1_destroy(display->dmabuf); zwp_linux_dmabuf_v1_destroy(display->dmabuf);
if (display->wm_base) if (display->shell)
xdg_wm_base_destroy(display->wm_base); zxdg_shell_v6_destroy(display->shell);
if (display->fshell)
zwp_fullscreen_shell_v1_release(display->fshell);
if (display->compositor) if (display->compositor)
wl_compositor_destroy(display->compositor); wl_compositor_destroy(display->compositor);
@ -1134,20 +1100,10 @@ display_set_up_egl(struct display *display)
EGL_CONTEXT_CLIENT_VERSION, 2, EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE EGL_NONE
}; };
EGLint major, minor, ret, count; EGLint major, minor;
const char *egl_extensions = NULL; const char *egl_extensions = NULL;
const char *gl_extensions = NULL; const char *gl_extensions = NULL;
EGLint config_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_ALPHA_SIZE, 1,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
display->egl.display = display->egl.display =
weston_platform_get_egl_display(EGL_PLATFORM_GBM_KHR, weston_platform_get_egl_display(EGL_PLATFORM_GBM_KHR,
display->gbm.device, NULL); display->gbm.device, NULL);
@ -1181,23 +1137,14 @@ display_set_up_egl(struct display *display)
goto error; goto error;
} }
if (weston_check_egl_extension(egl_extensions, if (!weston_check_egl_extension(egl_extensions,
"EGL_KHR_no_config_context")) { "EGL_KHR_no_config_context")) {
display->egl.has_no_config_context = true; fprintf(stderr, "EGL_KHR_no_config_context not supported\n");
} goto error;
if (display->egl.has_no_config_context) {
display->egl.conf = EGL_NO_CONFIG_KHR;
} else {
fprintf(stderr,
"Warning: EGL_KHR_no_config_context not supported\n");
ret = eglChooseConfig(display->egl.display, config_attribs,
&display->egl.conf, 1, &count);
assert(ret && count >= 1);
} }
display->egl.context = eglCreateContext(display->egl.display, display->egl.context = eglCreateContext(display->egl.display,
display->egl.conf, EGL_NO_CONFIG_KHR,
EGL_NO_CONTEXT, EGL_NO_CONTEXT,
context_attribs); context_attribs);
if (display->egl.context == EGL_NO_CONTEXT) { if (display->egl.context == EGL_NO_CONTEXT) {
@ -1277,36 +1224,30 @@ display_update_supported_modifiers_for_egl(struct display *d)
int num_egl_modifiers = 0; int num_egl_modifiers = 0;
EGLBoolean ret; EGLBoolean ret;
int i; int i;
bool try_modifiers = d->egl.has_dma_buf_import_modifiers;
if (try_modifiers) {
ret = d->egl.query_dma_buf_modifiers(d->egl.display,
d->format,
0, /* max_modifiers */
NULL, /* modifiers */
NULL, /* external_only */
&num_egl_modifiers);
if (ret == EGL_FALSE) {
fprintf(stderr, "Failed to query num EGL modifiers for format\n");
goto error;
}
}
if (!num_egl_modifiers)
try_modifiers = false;
/* If EGL doesn't support modifiers, don't use them at all. */ /* If EGL doesn't support modifiers, don't use them at all. */
if (!try_modifiers) { if (!d->egl.has_dma_buf_import_modifiers) {
d->modifiers_count = 0; d->modifiers_count = 0;
free(d->modifiers); free(d->modifiers);
d->modifiers = NULL; d->modifiers = NULL;
return true; return true;
} }
ret = d->egl.query_dma_buf_modifiers(d->egl.display,
BUFFER_FORMAT,
0, /* max_modifiers */
NULL, /* modifiers */
NULL, /* external_only */
&num_egl_modifiers);
if (ret == EGL_FALSE || num_egl_modifiers == 0) {
fprintf(stderr, "Failed to query num EGL modifiers for format\n");
goto error;
}
egl_modifiers = zalloc(num_egl_modifiers * sizeof(*egl_modifiers)); egl_modifiers = zalloc(num_egl_modifiers * sizeof(*egl_modifiers));
ret = d->egl.query_dma_buf_modifiers(d->egl.display, ret = d->egl.query_dma_buf_modifiers(d->egl.display,
d->format, BUFFER_FORMAT,
num_egl_modifiers, num_egl_modifiers,
egl_modifiers, egl_modifiers,
NULL, /* external_only */ NULL, /* external_only */
@ -1366,7 +1307,7 @@ display_set_up_gbm(struct display *display, char const* drm_render_node)
} }
static struct display * static struct display *
create_display(char const *drm_render_node, uint32_t format, int opts) create_display(char const *drm_render_node, int opts)
{ {
struct display *display = NULL; struct display *display = NULL;
@ -1381,7 +1322,6 @@ create_display(char const *drm_render_node, uint32_t format, int opts)
display->display = wl_display_connect(NULL); display->display = wl_display_connect(NULL);
assert(display->display); assert(display->display);
display->format = format;
display->req_dmabuf_immediate = opts & OPT_IMMEDIATE; display->req_dmabuf_immediate = opts & OPT_IMMEDIATE;
display->registry = wl_display_get_registry(display->display); display->registry = wl_display_get_registry(display->display);
@ -1395,9 +1335,8 @@ create_display(char const *drm_render_node, uint32_t format, int opts)
wl_display_roundtrip(display->display); wl_display_roundtrip(display->display);
if (!display->format_supported) { if (!display->modifiers_count) {
fprintf(stderr, "format 0x%"PRIX32" is not available\n", fprintf(stderr, "format XRGB8888 is not available\n");
display->format);
goto error; goto error;
} }
@ -1463,15 +1402,8 @@ print_usage_and_exit(void)
"\t'-e,--explicit-sync=<>'" "\t'-e,--explicit-sync=<>'"
"\n\t\t0 to disable explicit sync, " "\n\t\t0 to disable explicit sync, "
"\n\t\t1 to enable explicit sync (default: 1)\n" "\n\t\t1 to enable explicit sync (default: 1)\n"
"\t'-f,--format=0x<>'"
"\n\t\tthe DRM format code to use\n"
"\t'-m,--mandelbrot'" "\t'-m,--mandelbrot'"
"\n\t\trender a mandelbrot set with multiple draw calls\n" "\n\t\trender a mandelbrot set with multiple draw calls\n");
"\t'-g,--direct-display'"
"\n\t\tenables weston-direct-display extension to attempt "
"direct scan-out;\n\t\tnote this will cause the image to be "
"displayed inverted as GL uses a\n\t\tdifferent texture "
"coordinate system\n");
exit(0); exit(0);
} }
@ -1494,7 +1426,6 @@ main(int argc, char **argv)
struct sigaction sigint; struct sigaction sigint;
struct display *display; struct display *display;
struct window *window; struct window *window;
uint32_t format = DRM_FORMAT_XRGB8888;
int opts = 0; int opts = 0;
char const *drm_render_node = "/dev/dri/renderD128"; char const *drm_render_node = "/dev/dri/renderD128";
int c, option_index, ret = 0; int c, option_index, ret = 0;
@ -1505,14 +1436,12 @@ main(int argc, char **argv)
{"drm-render-node", required_argument, 0, 'd' }, {"drm-render-node", required_argument, 0, 'd' },
{"size", required_argument, 0, 's' }, {"size", required_argument, 0, 's' },
{"explicit-sync", required_argument, 0, 'e' }, {"explicit-sync", required_argument, 0, 'e' },
{"format", required_argument, 0, 'f' },
{"mandelbrot", no_argument, 0, 'm' }, {"mandelbrot", no_argument, 0, 'm' },
{"direct-display", no_argument, 0, 'g' },
{"help", no_argument , 0, 'h' }, {"help", no_argument , 0, 'h' },
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
while ((c = getopt_long(argc, argv, "hi:d:s:e:f:mg", while ((c = getopt_long(argc, argv, "hi:d:s:e:m",
long_options, &option_index)) != -1) { long_options, &option_index)) != -1) {
switch (c) { switch (c) {
case 'i': case 'i':
@ -1532,18 +1461,12 @@ main(int argc, char **argv)
case 'm': case 'm':
opts |= OPT_MANDELBROT; opts |= OPT_MANDELBROT;
break; break;
case 'g':
opts |= OPT_DIRECT_DISPLAY;
break;
case 'f':
format = strtoul(optarg, NULL, 0);
break;
default: default:
print_usage_and_exit(); print_usage_and_exit();
} }
} }
display = create_display(drm_render_node, format, opts); display = create_display(drm_render_node, opts);
if (!display) if (!display)
return 1; return 1;
window = create_window(display, window_size, window_size, opts); window = create_window(display, window_size, window_size, opts);

File diff suppressed because it is too large Load diff

View file

@ -30,13 +30,14 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
#include <getopt.h>
#include <assert.h> #include <assert.h>
#include <unistd.h> #include <unistd.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <signal.h> #include <signal.h>
#include <fcntl.h> #include <fcntl.h>
#include <drm_fourcc.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
@ -45,23 +46,12 @@
#include <linux/input.h> #include <linux/input.h>
#include <wayland-client.h> #include <wayland-client.h>
#include <wayland-cursor.h> #include "shared/zalloc.h"
#include <libweston/zalloc.h>
#include "xdg-shell-client-protocol.h" #include "xdg-shell-client-protocol.h"
#include "fullscreen-shell-unstable-v1-client-protocol.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h" #include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "weston-direct-display-client-protocol.h"
#include "viewporter-client-protocol.h"
#include "shared/helpers.h"
#include "shared/weston-drm-fourcc.h"
#define CLEAR(x) memset(&(x), 0, sizeof(x)) #define CLEAR(x) memset(&(x), 0, sizeof(x))
#define OPT_FLAG_INVERT (1 << 0)
#define OPT_FLAG_DIRECT_DISPLAY (1 << 1)
#define WIN_FLAG_FULLSCREEN (1 << 0)
#define WIN_FLAG_FULLSCREEN_CURSOR (1 << 1)
struct window;
static void static void
redraw(void *data, struct wl_callback *callback, uint32_t time); redraw(void *data, struct wl_callback *callback, uint32_t time);
@ -88,7 +78,7 @@ static inline const char *
dump_format(uint32_t format, char out[4]) dump_format(uint32_t format, char out[4])
{ {
#if BYTE_ORDER == BIG_ENDIAN #if BYTE_ORDER == BIG_ENDIAN
format = bswap32(format); format = __builtin_bswap32(format);
#endif #endif
memcpy(out, &format, 4); memcpy(out, &format, 4);
return out; return out;
@ -109,23 +99,15 @@ struct display {
struct wl_registry *registry; struct wl_registry *registry;
struct wl_compositor *compositor; struct wl_compositor *compositor;
struct wl_seat *seat; struct wl_seat *seat;
struct wl_pointer *pointer;
struct wl_keyboard *keyboard; struct wl_keyboard *keyboard;
struct wl_shm *shm;
struct wl_cursor_theme *cursor_theme;
struct wl_cursor *default_cursor;
struct wl_surface *cursor_surface;
struct xdg_wm_base *wm_base; struct xdg_wm_base *wm_base;
struct zwp_fullscreen_shell_v1 *fshell;
struct zwp_linux_dmabuf_v1 *dmabuf; struct zwp_linux_dmabuf_v1 *dmabuf;
struct weston_direct_display_v1 *direct_display;
struct wp_viewporter *viewporter;
bool requested_format_found; bool requested_format_found;
uint32_t opts;
int v4l_fd; int v4l_fd;
struct buffer_format format; struct buffer_format format;
uint32_t drm_format; uint32_t drm_format;
struct window *window;
}; };
struct buffer { struct buffer {
@ -138,7 +120,7 @@ struct buffer {
int data_offsets[VIDEO_MAX_PLANES]; int data_offsets[VIDEO_MAX_PLANES];
}; };
#define NUM_BUFFERS 4 #define NUM_BUFFERS 3
struct window { struct window {
struct display *display; struct display *display;
@ -147,11 +129,8 @@ struct window {
struct xdg_toplevel *xdg_toplevel; struct xdg_toplevel *xdg_toplevel;
struct buffer buffers[NUM_BUFFERS]; struct buffer buffers[NUM_BUFFERS];
struct wl_callback *callback; struct wl_callback *callback;
struct wp_viewport *viewport;
bool wait_for_configure; bool wait_for_configure;
bool initialized; bool initialized;
bool fullscreen;
bool fullscreen_cursor;
}; };
static bool running = true; static bool running = true;
@ -217,6 +196,7 @@ static unsigned int
set_format(struct display *display, uint32_t format) set_format(struct display *display, uint32_t format)
{ {
struct v4l2_format fmt; struct v4l2_format fmt;
char buf[4];
CLEAR(fmt); CLEAR(fmt);
@ -227,33 +207,30 @@ set_format(struct display *display, uint32_t format)
return 0; return 0;
} }
/* NOTE: pix and pix_mp are in a union, pixelformat member maps between them. */
const int format_matches = fmt.fmt.pix.pixelformat == format;
/* No need to set the format if it already is the one we want */ /* No need to set the format if it already is the one we want */
if (display->format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE && if (display->format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
format_matches) fmt.fmt.pix.pixelformat == format)
return 1; return 1;
if (display->format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && if (display->format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
format_matches) fmt.fmt.pix_mp.pixelformat == format)
return fmt.fmt.pix_mp.num_planes; return fmt.fmt.pix_mp.num_planes;
fmt.fmt.pix.pixelformat = format; if (display->format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
fmt.fmt.pix.pixelformat = format;
else
fmt.fmt.pix_mp.pixelformat = format;
if (xioctl(display->v4l_fd, VIDIOC_S_FMT, &fmt) == -1) { if (xioctl(display->v4l_fd, VIDIOC_S_FMT, &fmt) == -1) {
perror("VIDIOC_S_FMT"); perror("VIDIOC_S_FMT");
return 0; return 0;
} }
const int format_was_set = fmt.fmt.pix.pixelformat == format; if ((display->format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
if (!format_was_set) { fmt.fmt.pix.pixelformat != format) ||
char want_name[4]; (display->format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
char have_name[4]; fmt.fmt.pix_mp.pixelformat != format)) {
fprintf(stderr, "Failed to set format to %.4s\n",
dump_format(format, want_name); dump_format(format, buf));
dump_format(fmt.fmt.pix.pixelformat, have_name);
fprintf(stderr, "Tried to set format: %.4s but have: %.4s\n",
want_name, have_name);
return 0; return 0;
} }
@ -268,8 +245,6 @@ v4l_connect(struct display *display, const char *dev_name)
{ {
struct v4l2_capability cap; struct v4l2_capability cap;
struct v4l2_requestbuffers req; struct v4l2_requestbuffers req;
struct v4l2_input input;
int index_input = -1;
unsigned int num_planes; unsigned int num_planes;
display->v4l_fd = open(dev_name, O_RDWR); display->v4l_fd = open(dev_name, O_RDWR);
@ -287,16 +262,6 @@ v4l_connect(struct display *display, const char *dev_name)
return 0; return 0;
} }
if (xioctl(display->v4l_fd, VIDIOC_G_INPUT, &index_input) == 0) {
input.index = index_input;
if (xioctl(display->v4l_fd, VIDIOC_ENUMINPUT, &input) == 0) {
if (input.status & V4L2_IN_ST_VFLIP) {
fprintf(stdout, "Found camera sensor y-flipped\n");
display->opts |= OPT_FLAG_INVERT;
}
}
}
if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
display->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; display->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
else if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) else if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
@ -395,33 +360,18 @@ create_dmabuf_buffer(struct display *display, struct buffer *buffer)
struct zwp_linux_buffer_params_v1 *params; struct zwp_linux_buffer_params_v1 *params;
uint64_t modifier; uint64_t modifier;
uint32_t flags; uint32_t flags;
int i; unsigned i;
modifier = 0; modifier = 0;
flags = 0; flags = 0;
if (display->opts & OPT_FLAG_INVERT) /* XXX: apparently some webcams may actually provide y-inverted images,
flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT; * in which case we should set
* flags = ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT
*/
params = zwp_linux_dmabuf_v1_create_params(display->dmabuf); params = zwp_linux_dmabuf_v1_create_params(display->dmabuf);
for (i = 0; i < display->format.num_planes; ++i)
if ((display->opts & OPT_FLAG_DIRECT_DISPLAY) && display->direct_display) {
weston_direct_display_v1_enable(display->direct_display, params);
if (display->opts & OPT_FLAG_INVERT) {
flags &= ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT;
fprintf(stdout, "dmabuf y-inverted attribute flag was removed"
", as display-direct flag was set\n");
}
}
const int num_planes = (int) display->format.num_planes;
for (i = 0; i < num_planes; ++i) {
fprintf(stderr, "buffer %d, plane %d has dma fd %d and stride "
"%d and modifier %" PRIu64 "\n",
buffer->index, i, buffer->dmabuf_fds[i],
display->format.strides[i], modifier);
zwp_linux_buffer_params_v1_add(params, zwp_linux_buffer_params_v1_add(params,
buffer->dmabuf_fds[i], buffer->dmabuf_fds[i],
i, /* plane_idx */ i, /* plane_idx */
@ -429,124 +379,8 @@ create_dmabuf_buffer(struct display *display, struct buffer *buffer)
display->format.strides[i], display->format.strides[i],
modifier >> 32, modifier >> 32,
modifier & 0xffffffff); modifier & 0xffffffff);
} zwp_linux_buffer_params_v1_add_listener(params, &params_listener,
buffer);
/* Some v4l2 devices can output NV12, but will do so without the MPLANE
* api. Instead, it outputs both the luminance and chrominance planes
* in the same dma buffer. Here we account for that, and add an extra
* plane from the same buffer if necessary. If it needs an extra plane,
* set the stride of the chrominance plane. NOTE: Also handles cases
* where 3 planes are expected in 1 dma buffer (untested)
*/
enum plane_layout_t {
DISJOINT = 0,
CONTIGUOUS,
};
enum chrom_packing_t {
CHROM_SEPARATE = 0, /* Cr/Cb are in their own planes. */
CHROM_COMBINED, /* Cr/Cb are interleaved. */
};
/* This table contains some planar formats we could fix-up and support. */
const struct planar_layout_t {
/* Format identification. */
uint32_t v4l_fourcc;
/* Disjoint or contigious planes? */
enum plane_layout_t plane_layout;
/* Zero if Cb/Cr in separate planes. */
enum chrom_packing_t chrom_packing;
/* Expected plane count. */
int num_planes;
/* Horizontal sub-sampling for chroma. */
int chroma_subsample_hori;
/* Vertical sub-sampling for chroma. */
int chroma_subsample_vert;
} planar_layouts[] = {
{ V4L2_PIX_FMT_NV12M, DISJOINT, CHROM_COMBINED, 2, 2,2 },
{ V4L2_PIX_FMT_NV21M, DISJOINT, CHROM_COMBINED, 2, 2,2 },
{ V4L2_PIX_FMT_NV16M, DISJOINT, CHROM_COMBINED, 2, 2,1 },
{ V4L2_PIX_FMT_NV61M, DISJOINT, CHROM_COMBINED, 2, 2,1 },
{ V4L2_PIX_FMT_NV12, CONTIGUOUS, CHROM_COMBINED, 2, 2,2 },
{ V4L2_PIX_FMT_NV21, CONTIGUOUS, CHROM_COMBINED, 2, 2,2 },
{ V4L2_PIX_FMT_NV16, CONTIGUOUS, CHROM_COMBINED, 2, 2,1 },
{ V4L2_PIX_FMT_NV61, CONTIGUOUS, CHROM_COMBINED, 2, 2,1 },
{ V4L2_PIX_FMT_NV24, CONTIGUOUS, CHROM_COMBINED, 2, 1,1 },
{ V4L2_PIX_FMT_NV42, CONTIGUOUS, CHROM_COMBINED, 2, 1,1 },
{ V4L2_PIX_FMT_YUV420, CONTIGUOUS, CHROM_SEPARATE, 3, 2,2 },
{ V4L2_PIX_FMT_YVU420, CONTIGUOUS, CHROM_SEPARATE, 3, 2,2 },
{ V4L2_PIX_FMT_YUV420M, DISJOINT, CHROM_SEPARATE, 3, 2,2 },
{ V4L2_PIX_FMT_YVU420M, DISJOINT, CHROM_SEPARATE, 3, 2,2 },
{ 0, 0, 0, 0, 0 },
};
int layoutnr = 0;
int num_missing_planes = 0; /* Non-zero if format needs more planes in dma buf. */
int stride_extra_plane = 0;
int vrtres_extra_plane = 0;
const uint32_t stride0 = display->format.strides[0];
/* Search the table. */
while (planar_layouts[layoutnr].v4l_fourcc) {
const struct planar_layout_t *layout =
planar_layouts + layoutnr;
if (layout->v4l_fourcc == display->format.format) {
/* If disjoint planes are missing, there is nothing to
* salvage. */
if (layout->plane_layout == DISJOINT)
assert(num_planes == layout->num_planes);
/* Is this a case where we need to add 1 or 2 missing
* planes? */
num_missing_planes = layout->num_planes - num_planes;
if (num_missing_planes > 0) {
/* With this knowledge:
* - Stride for Y
* - Packing of chrominance
* - Horizontal subsampling ...we can compute
* the stride for Cr and Cb.
*/
const uint32_t num_chrom_parts =
layout->chrom_packing == CHROM_COMBINED ? 2 : 1;
stride_extra_plane =
stride0 * num_chrom_parts /
layout->chroma_subsample_hori;
vrtres_extra_plane =
display->format.height /
layout->chroma_subsample_vert;
break;
}
}
layoutnr += 1;
}
/* If we determined we need additional planes, add them. */
int offset_in_buffer = buffer->data_offsets[0] +
display->format.height * stride0;
for (i = 0; i < num_missing_planes; ++i) {
/* Add same dma buffer, but with offset for chromimance plane. */
fprintf(stderr,"Adding additional chrominance plane.\n");
zwp_linux_buffer_params_v1_add(params,
buffer->dmabuf_fds[0],
1 + i, /* plane_idx */
offset_in_buffer,
stride_extra_plane,
modifier >> 32,
modifier & 0xffffffff);
offset_in_buffer += vrtres_extra_plane * stride_extra_plane;
}
zwp_linux_buffer_params_v1_add_listener(params, &params_listener, buffer);
fprintf(stderr,"creating buffer of size %dx%d format %c%c%c%c flags %d\n",
display->format.width,
display->format.height,
(display->drm_format >> 0) & 0xff,
(display->drm_format >> 8) & 0xff,
(display->drm_format >> 16) & 0xff,
(display->drm_format >> 24) & 0xff,
flags
);
zwp_linux_buffer_params_v1_create(params, zwp_linux_buffer_params_v1_create(params,
display->format.width, display->format.width,
display->format.height, display->format.height,
@ -723,41 +557,6 @@ xdg_toplevel_handle_configure(void *data, struct xdg_toplevel *toplevel,
int32_t width, int32_t height, int32_t width, int32_t height,
struct wl_array *states) struct wl_array *states)
{ {
struct window *window = data;
uint32_t *p;
window->fullscreen = 0;
wl_array_for_each(p, states) {
uint32_t state = *p;
switch (state) {
case XDG_TOPLEVEL_STATE_FULLSCREEN:
window->fullscreen = 1;
break;
}
}
if (!window->viewport)
return;
if (window->fullscreen) {
float ratio_w = (float)width / window->display->format.width;
float ratio_h = (float)height / window->display->format.height;
int32_t viewport_w;
int32_t viewport_h;
if (ratio_w > ratio_h) {
viewport_w = width / ratio_w * ratio_h;
viewport_h = height;
} else {
viewport_w = width;
viewport_h = height / ratio_h * ratio_w;
}
wp_viewport_set_destination(window->viewport, viewport_w,
viewport_h);
} else {
wp_viewport_set_destination(window->viewport, -1, -1);
}
} }
static void static void
@ -772,7 +571,7 @@ static const struct xdg_toplevel_listener xdg_toplevel_listener = {
}; };
static struct window * static struct window *
create_window(struct display *display, uint32_t win_flags) create_window(struct display *display)
{ {
struct window *window; struct window *window;
@ -785,12 +584,6 @@ create_window(struct display *display, uint32_t win_flags)
window->surface = wl_compositor_create_surface(display->compositor); window->surface = wl_compositor_create_surface(display->compositor);
if (display->wm_base) { if (display->wm_base) {
if (display->viewporter) {
window->viewport =
wp_viewporter_get_viewport(display->viewporter,
window->surface);
}
window->xdg_surface = window->xdg_surface =
xdg_wm_base_get_xdg_surface(display->wm_base, xdg_wm_base_get_xdg_surface(display->wm_base,
window->surface); window->surface);
@ -809,16 +602,14 @@ create_window(struct display *display, uint32_t win_flags)
&xdg_toplevel_listener, window); &xdg_toplevel_listener, window);
xdg_toplevel_set_title(window->xdg_toplevel, "simple-dmabuf-v4l"); xdg_toplevel_set_title(window->xdg_toplevel, "simple-dmabuf-v4l");
xdg_toplevel_set_app_id(window->xdg_toplevel,
"org.freedesktop.weston.simple-dmabuf-v4l");
if (win_flags & WIN_FLAG_FULLSCREEN)
xdg_toplevel_set_fullscreen(window->xdg_toplevel, NULL);
if (win_flags & WIN_FLAG_FULLSCREEN_CURSOR)
window->fullscreen_cursor = true;
window->wait_for_configure = true; window->wait_for_configure = true;
wl_surface_commit(window->surface); wl_surface_commit(window->surface);
} else if (display->fshell) {
zwp_fullscreen_shell_v1_present_surface(display->fshell,
window->surface,
ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT,
NULL);
} else { } else {
assert(0); assert(0);
} }
@ -835,9 +626,6 @@ destroy_window(struct window *window)
if (window->callback) if (window->callback)
wl_callback_destroy(window->callback); wl_callback_destroy(window->callback);
if (window->viewport)
wp_viewport_destroy(window->viewport);
if (window->xdg_toplevel) if (window->xdg_toplevel)
xdg_toplevel_destroy(window->xdg_toplevel); xdg_toplevel_destroy(window->xdg_toplevel);
if (window->xdg_surface) if (window->xdg_surface)
@ -890,7 +678,9 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
assert(!buffer->busy); assert(!buffer->busy);
wl_surface_attach(window->surface, buffer->buffer, 0, 0); wl_surface_attach(window->surface, buffer->buffer, 0, 0);
wl_surface_damage(window->surface, 0, 0, INT32_MAX, INT32_MAX); wl_surface_damage(window->surface, 0, 0,
window->display->format.width,
window->display->format.height);
if (callback) if (callback)
wl_callback_destroy(callback); wl_callback_destroy(callback);
@ -905,97 +695,18 @@ static const struct wl_callback_listener frame_listener = {
redraw redraw
}; };
static void
dmabuf_modifier(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo)
{
struct display *d = data;
uint64_t modifier = u64_from_u32s(modifier_hi, modifier_lo);
if (format == d->drm_format && modifier == DRM_FORMAT_MOD_LINEAR)
d->requested_format_found = true;
}
static void static void
dmabuf_format(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, dmabuf_format(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
uint32_t format) uint32_t format)
{ {
/* deprecated */ struct display *d = data;
if (format == d->drm_format)
d->requested_format_found = true;
} }
static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = { static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
dmabuf_format, dmabuf_format
dmabuf_modifier
};
static void
pointer_handle_enter(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface,
wl_fixed_t sx, wl_fixed_t sy)
{
struct display *display = data;
struct wl_buffer *buffer;
struct wl_cursor *cursor = display->default_cursor;
struct wl_cursor_image *image;
if (display->window->fullscreen && !display->window->fullscreen_cursor)
wl_pointer_set_cursor(pointer, serial, NULL, 0, 0);
else if (cursor) {
image = cursor->images[0];
buffer = wl_cursor_image_get_buffer(image);
if (!buffer)
return;
wl_pointer_set_cursor(pointer, serial,
display->cursor_surface,
image->hotspot_x,
image->hotspot_y);
wl_surface_attach(display->cursor_surface, buffer, 0, 0);
wl_surface_damage(display->cursor_surface, 0, 0,
image->width, image->height);
wl_surface_commit(display->cursor_surface);
}
}
static void
pointer_handle_leave(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface)
{
}
static void
pointer_handle_motion(void *data, struct wl_pointer *pointer,
uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
{
}
static void
pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, uint32_t time, uint32_t button,
uint32_t state)
{
struct display *display = data;
if (!display->window->xdg_toplevel)
return;
if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED)
xdg_toplevel_move(display->window->xdg_toplevel,
display->seat, serial);
}
static void
pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
uint32_t time, uint32_t axis, wl_fixed_t value)
{
}
static const struct wl_pointer_listener pointer_listener = {
pointer_handle_enter,
pointer_handle_leave,
pointer_handle_motion,
pointer_handle_button,
pointer_handle_axis,
}; };
static void static void
@ -1029,12 +740,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
if (!d->wm_base) if (!d->wm_base)
return; return;
if (key == KEY_F11 && state) { if (key == KEY_ESC && state)
if (d->window->fullscreen)
xdg_toplevel_unset_fullscreen(d->window->xdg_toplevel);
else
xdg_toplevel_set_fullscreen(d->window->xdg_toplevel, NULL);
} else if (key == KEY_ESC && state)
running = false; running = false;
} }
@ -1060,14 +766,6 @@ seat_handle_capabilities(void *data, struct wl_seat *seat,
{ {
struct display *d = data; struct display *d = data;
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !d->pointer) {
d->pointer = wl_seat_get_pointer(seat);
wl_pointer_add_listener(d->pointer, &pointer_listener, d);
} else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && d->pointer) {
wl_pointer_destroy(d->pointer);
d->pointer = NULL;
}
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !d->keyboard) { if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !d->keyboard) {
d->keyboard = wl_seat_get_keyboard(seat); d->keyboard = wl_seat_get_keyboard(seat);
wl_keyboard_add_listener(d->keyboard, &keyboard_listener, d); wl_keyboard_add_listener(d->keyboard, &keyboard_listener, d);
@ -1097,44 +795,28 @@ registry_handle_global(void *data, struct wl_registry *registry,
{ {
struct display *d = data; struct display *d = data;
if (strcmp(interface, wl_compositor_interface.name) == 0) { if (strcmp(interface, "wl_compositor") == 0) {
d->compositor = d->compositor =
wl_registry_bind(registry, wl_registry_bind(registry,
id, &wl_compositor_interface, 1); id, &wl_compositor_interface, 1);
} else if (strcmp(interface, wl_seat_interface.name) == 0) { } else if (strcmp(interface, "wl_seat") == 0) {
d->seat = wl_registry_bind(registry, d->seat = wl_registry_bind(registry,
id, &wl_seat_interface, 1); id, &wl_seat_interface, 1);
wl_seat_add_listener(d->seat, &seat_listener, d); wl_seat_add_listener(d->seat, &seat_listener, d);
} else if (strcmp(interface, wl_shm_interface.name) == 0) { } else if (strcmp(interface, "xdg_wm_base") == 0) {
d->shm = wl_registry_bind(registry, id,
&wl_shm_interface, 1);
d->cursor_theme = wl_cursor_theme_load(NULL, 32, d->shm);
if (!d->cursor_theme) {
fprintf(stderr, "unable to load default theme\n");
return;
}
d->default_cursor =
wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
if (!d->default_cursor) {
fprintf(stderr, "unable to load default left pointer\n");
// TODO: abort ?
}
} else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
d->wm_base = wl_registry_bind(registry, d->wm_base = wl_registry_bind(registry,
id, &xdg_wm_base_interface, 1); id, &xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(d->wm_base, &wm_base_listener, d); xdg_wm_base_add_listener(d->wm_base, &wm_base_listener, d);
} else if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0) { } else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0) {
d->fshell = wl_registry_bind(registry,
id, &zwp_fullscreen_shell_v1_interface,
1);
} else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) {
d->dmabuf = wl_registry_bind(registry, d->dmabuf = wl_registry_bind(registry,
id, &zwp_linux_dmabuf_v1_interface, 3); id, &zwp_linux_dmabuf_v1_interface,
1);
zwp_linux_dmabuf_v1_add_listener(d->dmabuf, &dmabuf_listener, zwp_linux_dmabuf_v1_add_listener(d->dmabuf, &dmabuf_listener,
d); d);
} else if (strcmp(interface, weston_direct_display_v1_interface.name) == 0) {
d->direct_display = wl_registry_bind(registry,
id, &weston_direct_display_v1_interface, 1);
} else if (strcmp(interface, wp_viewporter_interface.name) == 0) {
d->viewporter = wl_registry_bind(registry, id,
&wp_viewporter_interface,
1);
} }
} }
@ -1150,11 +832,11 @@ static const struct wl_registry_listener registry_listener = {
}; };
static struct display * static struct display *
create_display(uint32_t requested_format, uint32_t opt_flags) create_display(uint32_t requested_format)
{ {
struct display *display; struct display *display;
display = zalloc(sizeof *display); display = malloc(sizeof *display);
if (display == NULL) { if (display == NULL) {
fprintf(stderr, "out of memory\n"); fprintf(stderr, "out of memory\n");
exit(1); exit(1);
@ -1175,37 +857,29 @@ create_display(uint32_t requested_format, uint32_t opt_flags)
wl_display_roundtrip(display->display); wl_display_roundtrip(display->display);
if (!display->requested_format_found) { /* XXX: fake, because the compositor does not yet advertise anything */
char want_name[4]; display->requested_format_found = true;
dump_format(requested_format, want_name); if (!display->requested_format_found) {
fprintf(stderr, "Requested DRM format %4s not available\n", want_name); fprintf(stderr, "DRM_FORMAT_YUYV not available\n");
exit(1); exit(1);
} }
if (opt_flags)
display->opts = opt_flags;
display->cursor_surface =
wl_compositor_create_surface(display->compositor);
return display; return display;
} }
static void static void
destroy_display(struct display *display) destroy_display(struct display *display)
{ {
wl_surface_destroy(display->cursor_surface);
if (display->dmabuf) if (display->dmabuf)
zwp_linux_dmabuf_v1_destroy(display->dmabuf); zwp_linux_dmabuf_v1_destroy(display->dmabuf);
if (display->viewporter)
wp_viewporter_destroy(display->viewporter);
if (display->wm_base) if (display->wm_base)
xdg_wm_base_destroy(display->wm_base); xdg_wm_base_destroy(display->wm_base);
if (display->fshell)
zwp_fullscreen_shell_v1_release(display->fshell);
if (display->compositor) if (display->compositor)
wl_compositor_destroy(display->compositor); wl_compositor_destroy(display->compositor);
@ -1218,7 +892,7 @@ destroy_display(struct display *display)
static void static void
usage(const char *argv0) usage(const char *argv0)
{ {
printf("Usage: %s [-v v4l2_device] [-f v4l2_format] [-d drm_format] [-i|--y-invert] [-g|--d-display] [-s|--fullscreen]\n" printf("Usage: %s [V4L2 device] [V4L2 format] [DRM format]\n"
"\n" "\n"
"The default V4L2 device is /dev/video0\n" "The default V4L2 device is /dev/video0\n"
"\n" "\n"
@ -1227,16 +901,7 @@ usage(const char *argv0)
"DRM formats are defined in <libdrm/drm_fourcc.h>\n" "DRM formats are defined in <libdrm/drm_fourcc.h>\n"
"The default for both formats is YUYV.\n" "The default for both formats is YUYV.\n"
"If the V4L2 and DRM formats differ, the data is simply " "If the V4L2 and DRM formats differ, the data is simply "
"reinterpreted rather than converted.\n\n" "reinterpreted rather than converted.\n", argv0);
"Flags:\n"
"- y-invert force the image to be y-flipped;\n note will be "
"automatically added if we detect if the camera sensor is "
"y-flipped\n"
"- d-display skip importing dmabuf-based buffer into the GPU\n "
"and attempt pass the buffer straight to the display controller\n"
"- fullscreen make the window fullscreen and scale up the image\n"
"- fs-cursor show the cursor in fullscreen mode\n",
argv0);
printf("\n" printf("\n"
"How to set up Vivid the virtual video driver for testing:\n" "How to set up Vivid the virtual video driver for testing:\n"
@ -1247,11 +912,8 @@ usage(const char *argv0)
" here we assume /dev/video0\n" " here we assume /dev/video0\n"
"- set the pixel format:\n" "- set the pixel format:\n"
" $ v4l2-ctl -d /dev/video0 --set-fmt-video=width=640,pixelformat=XR24\n" " $ v4l2-ctl -d /dev/video0 --set-fmt-video=width=640,pixelformat=XR24\n"
"- optionally could add 'allocators=0x1' to options as to create"
" the buffer in a dmabuf-contiguous way\n"
" (as some display-controllers require it)\n"
"- launch the demo:\n" "- launch the demo:\n"
" $ %s -v /dev/video0 -f XR24 -d XR24\n" " $ %s /dev/video0 XR24 XR24\n"
"You should see a test pattern with color bars, and some text.\n" "You should see a test pattern with color bars, and some text.\n"
"\n" "\n"
"More about vivid: https://www.kernel.org/doc/Documentation/video4linux/vivid.txt\n" "More about vivid: https://www.kernel.org/doc/Documentation/video4linux/vivid.txt\n"
@ -1272,69 +934,32 @@ main(int argc, char **argv)
struct sigaction sigint; struct sigaction sigint;
struct display *display; struct display *display;
struct window *window; struct window *window;
const char *v4l_device = NULL; const char *v4l_device;
uint32_t v4l_format = 0x0; uint32_t v4l_format, drm_format;
uint32_t drm_format = 0x0; int ret = 0;
uint32_t opts_flags = 0x0;
uint32_t win_flags = 0x0;
int c, opt_index, ret = 0;
static struct option long_options[] = { if (argc < 2) {
{ "v4l2-device", required_argument, NULL, 'v' }, v4l_device = "/dev/video0";
{ "v4l2-format", required_argument, NULL, 'f' }, } else if (!strcmp(argv[1], "--help")) {
{ "drm-format", required_argument, NULL, 'd' }, usage(argv[0]);
{ "y-invert", no_argument, NULL, 'i' }, } else {
{ "d-display", no_argument, NULL, 'g' }, v4l_device = argv[1];
{ "fullscreen", no_argument, NULL, 's' },
{ "fs-cursor", no_argument, NULL, 'c' },
{ "help", no_argument, NULL, 'h' },
{ 0, 0, NULL, 0 }
};
while ((c = getopt_long(argc, argv, "hiv:d:f:gsc", long_options,
&opt_index)) != -1) {
switch (c) {
case 'v':
v4l_device = optarg;
break;
case 'f':
v4l_format = parse_format(optarg);
break;
case 'd':
drm_format = parse_format(optarg);
break;
case 'i':
opts_flags |= OPT_FLAG_INVERT;
break;
case 'g':
opts_flags |= OPT_FLAG_DIRECT_DISPLAY;
break;
case 's':
win_flags |= WIN_FLAG_FULLSCREEN;
break;
case 'c':
win_flags |= WIN_FLAG_FULLSCREEN_CURSOR;
break;
default:
case 'h':
usage(argv[0]);
break;
}
} }
if (!v4l_device) if (argc < 3)
v4l_device = "/dev/video0";
if (v4l_format == 0x0)
v4l_format = parse_format("YUYV"); v4l_format = parse_format("YUYV");
else
v4l_format = parse_format(argv[2]);
if (drm_format == 0x0) if (argc < 4)
drm_format = v4l_format; drm_format = v4l_format;
else
drm_format = parse_format(argv[3]);
display = create_display(drm_format, opts_flags); display = create_display(drm_format);
display->format.format = v4l_format; display->format.format = v4l_format;
display->window = window = create_window(display, win_flags); window = create_window(display);
if (!window) if (!window)
return 1; return 1;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -28,9 +28,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <signal.h>
#include <linux/input.h> #include <linux/input.h>
@ -106,8 +104,6 @@ static const uint32_t ignore_keys_on_compose[] = {
XKB_KEY_Shift_R XKB_KEY_Shift_R
}; };
static int running = 1;
static void static void
handle_surrounding_text(void *data, handle_surrounding_text(void *data,
struct zwp_input_method_context_v1 *context, struct zwp_input_method_context_v1 *context,
@ -279,8 +275,8 @@ input_method_keyboard_modifiers(void *data,
keyboard->modifiers |= MOD_SHIFT_MASK; keyboard->modifiers |= MOD_SHIFT_MASK;
zwp_input_method_context_v1_modifiers(context, serial, zwp_input_method_context_v1_modifiers(context, serial,
mods_depressed, mods_latched, mods_depressed, mods_depressed,
mods_locked, group); mods_latched, group);
} }
static const struct wl_keyboard_listener input_method_keyboard_listener = { static const struct wl_keyboard_listener input_method_keyboard_listener = {
@ -397,7 +393,7 @@ simple_im_key_handler(struct simple_im *keyboard,
if (keyboard->compose_state == state_compose) { if (keyboard->compose_state == state_compose) {
uint32_t i = 0; uint32_t i = 0;
const struct compose_seq *cs; struct compose_seq *cs;
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
return; return;
@ -484,25 +480,17 @@ simple_im_key_handler(struct simple_im *keyboard,
text); text);
} }
static void
signal_int(int signum)
{
running = 0;
}
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
struct simple_im simple_im; struct simple_im simple_im;
struct sigaction sigint;
int ret = 0; int ret = 0;
memset(&simple_im, 0, sizeof(simple_im)); memset(&simple_im, 0, sizeof(simple_im));
simple_im.display = wl_display_connect(NULL); simple_im.display = wl_display_connect(NULL);
if (simple_im.display == NULL) { if (simple_im.display == NULL) {
fprintf(stderr, "Failed to connect to server: %s\n", fprintf(stderr, "Failed to connect to server: %m\n");
strerror(errno));
return -1; return -1;
} }
@ -524,33 +512,11 @@ main(int argc, char *argv[])
simple_im.context = NULL; simple_im.context = NULL;
simple_im.key_handler = simple_im_key_handler; simple_im.key_handler = simple_im_key_handler;
sigint.sa_handler = signal_int; while (ret != -1)
sigemptyset(&sigint.sa_mask);
sigint.sa_flags = SA_RESETHAND;
sigaction(SIGINT, &sigint, NULL);
while (running && ret != -1)
ret = wl_display_dispatch(simple_im.display); ret = wl_display_dispatch(simple_im.display);
if (simple_im.input_method)
zwp_input_method_v1_destroy(simple_im.input_method);
if (simple_im.context)
zwp_input_method_context_v1_destroy(simple_im.context);
if (simple_im.keyboard)
wl_keyboard_destroy(simple_im.keyboard);
xkb_context_unref(simple_im.xkb_context);
xkb_state_unref(simple_im.state);
xkb_keymap_unref(simple_im.keymap);
wl_registry_destroy(simple_im.registry);
wl_display_flush(simple_im.display);
wl_display_disconnect(simple_im.display);
if (ret == -1) { if (ret == -1) {
fprintf(stderr, "Dispatch error: %s\n", strerror(errno)); fprintf(stderr, "Dispatch error: %m\n");
return -1; return -1;
} }

View file

@ -33,130 +33,39 @@
#include <unistd.h> #include <unistd.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <signal.h> #include <signal.h>
#include <errno.h>
#include <assert.h>
#include <linux/input.h>
#include <wayland-client.h> #include <wayland-client.h>
#include "shared/os-compatibility.h" #include "shared/os-compatibility.h"
#include <libweston/zalloc.h> #include "shared/zalloc.h"
#include "xdg-shell-client-protocol.h" #include "xdg-shell-client-protocol.h"
#include "fullscreen-shell-unstable-v1-client-protocol.h"
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
#define FMT(fmt, bpp, r, g, b, a) { WL_SHM_FORMAT_ ## fmt, #fmt, bpp, { r, g, b, a } }
#define MAX_BUFFER_ALLOC 2
struct window;
struct format {
uint32_t code;
const char *string;
int bpp;
uint64_t color[4];
};
struct display { struct display {
struct wl_display *display; struct wl_display *display;
struct wl_registry *registry; struct wl_registry *registry;
struct wl_compositor *compositor; struct wl_compositor *compositor;
struct xdg_wm_base *wm_base; struct xdg_wm_base *wm_base;
struct wl_seat *seat; struct zwp_fullscreen_shell_v1 *fshell;
struct wl_keyboard *keyboard;
struct wl_shm *shm; struct wl_shm *shm;
const struct format *format; bool has_xrgb;
bool paint_format;
bool has_format;
struct window *window;
}; };
struct buffer { struct buffer {
struct window *window;
struct wl_buffer *buffer; struct wl_buffer *buffer;
void *shm_data; void *shm_data;
int busy; int busy;
int width, height;
size_t size; /* width * 4 * height */
struct wl_list buffer_link; /** window::buffer_list */
}; };
struct window { struct window {
struct display *display; struct display *display;
int width, height; int width, height;
int init_width, init_height;
struct wl_surface *surface; struct wl_surface *surface;
struct xdg_surface *xdg_surface; struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel; struct xdg_toplevel *xdg_toplevel;
struct wl_list buffer_list; struct buffer buffers[2];
struct buffer *prev_buffer; struct buffer *prev_buffer;
struct wl_callback *callback; struct wl_callback *callback;
bool wait_for_configure; bool wait_for_configure;
bool maximized;
bool fullscreen;
bool needs_update_buffer;
};
static const struct format shm_formats[] = {
/* 8 bpp formats */
FMT(R8, 8, 0x00, 0x55, 0xaa, 0xff ),
/* 16 bpp formats */
FMT(R16, 16, 0x0000, 0x5555, 0xaaaa, 0xffff ),
FMT(GR88, 16, 0x00ff, 0xff00, 0x0000, 0xffff ),
FMT(RG88, 16, 0xff00, 0x00ff, 0x0000, 0xffff ),
FMT(RGB565, 16, 0xf800, 0x07e0, 0x001f, 0xffff ),
FMT(BGR565, 16, 0x001f, 0x07e0, 0xf800, 0xffff ),
FMT(XRGB4444, 16, 0xff00, 0xf0f0, 0xf00f, 0x7777 ),
FMT(ARGB4444, 16, 0xff00, 0xf0f0, 0xf00f, 0x7777 ),
FMT(XBGR4444, 16, 0xf00f, 0xf0f0, 0xff00, 0x7777 ),
FMT(ABGR4444, 16, 0xf00f, 0xf0f0, 0xff00, 0x7777 ),
FMT(RGBX4444, 16, 0xf00f, 0x0f0f, 0x00ff, 0x7777 ),
FMT(RGBA4444, 16, 0xf00f, 0x0f0f, 0x00ff, 0x7777 ),
FMT(BGRX4444, 16, 0x00ff, 0x0f0f, 0xf00f, 0x7777 ),
FMT(BGRA4444, 16, 0x00ff, 0x0f0f, 0xf00f, 0x7777 ),
FMT(XRGB1555, 16, 0xfc00, 0x83e1, 0x801f, 0x0000 ),
FMT(ARGB1555, 16, 0xfc00, 0x83e1, 0x801f, 0x0000 ),
FMT(XBGR1555, 16, 0x801f, 0x83e1, 0xfc00, 0x0000 ),
FMT(ABGR1555, 16, 0x801f, 0x83e1, 0xfc00, 0x0000 ),
FMT(RGBX5551, 16, 0xf801, 0x07c1, 0x003f, 0x0000 ),
FMT(RGBA5551, 16, 0xf801, 0x07c1, 0x003f, 0x0000 ),
FMT(BGRX5551, 16, 0x003f, 0x07c1, 0xf801, 0x0000 ),
FMT(BGRA5551, 16, 0x003f, 0x07c1, 0xf801, 0x0000 ),
/* 24 bpp formats */
FMT(RGB888, 24, 0xff0000, 0x00ff00, 0x0000ff, 0xffffff ),
FMT(BGR888, 24, 0x0000ff, 0x00ff00, 0xff0000, 0xffffff ),
/* 32 bpp formats */
FMT(GR1616, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0xffffffff ),
FMT(RG1616, 32, 0xffff0000, 0x0000ffff, 0x00000000, 0xffffffff ),
FMT(XRGB8888, 32, 0xffff0000, 0xff00ff00, 0xff0000ff, 0x7f7f7f7f ),
FMT(ARGB8888, 32, 0xffff0000, 0xff00ff00, 0xff0000ff, 0x7f7f7f7f ),
FMT(XBGR8888, 32, 0xff0000ff, 0xff00ff00, 0xffff0000, 0x7f7f7f7f ),
FMT(ABGR8888, 32, 0xff0000ff, 0xff00ff00, 0xffff0000, 0x7f7f7f7f ),
FMT(RGBX8888, 32, 0xff0000ff, 0x00ff00ff, 0x0000ffff, 0x7f7f7f7f ),
FMT(RGBA8888, 32, 0xff0000ff, 0x00ff00ff, 0x0000ffff, 0x7f7f7f7f ),
FMT(BGRX8888, 32, 0x0000ffff, 0x00ff00ff, 0xff0000ff, 0x7f7f7f7f ),
FMT(BGRA8888, 32, 0x0000ffff, 0x00ff00ff, 0xff0000ff, 0x7f7f7f7f ),
FMT(XRGB2101010, 32, 0xfff00000, 0xc00ffc00, 0xc00003ff, 0x5ff7fdff ),
FMT(ARGB2101010, 32, 0xfff00000, 0xc00ffc00, 0xc00003ff, 0x5ff7fdff ),
FMT(XBGR2101010, 32, 0xc00003ff, 0xc00ffc00, 0xfff00000, 0x5ff7fdff ),
FMT(ABGR2101010, 32, 0xc00003ff, 0xc00ffc00, 0xfff00000, 0x5ff7fdff ),
FMT(RGBX1010102, 32, 0xffc00003, 0x003ff003, 0x00000fff, 0x7fdff7fd ),
FMT(RGBA1010102, 32, 0xffc00003, 0x003ff003, 0x00000fff, 0x7fdff7fd ),
FMT(BGRX1010102, 32, 0x00000fff, 0x003ff003, 0xffc00003, 0x7fdff7fd ),
FMT(BGRA1010102, 32, 0x00000fff, 0x003ff003, 0xffc00003, 0x7fdff7fd ),
/* 64 bpp formats */
FMT(XRGB16161616, 64, 0xffffffff00000000, 0xffff0000ffff0000, 0xffff00000000ffff, 0x7fff7fff7fff7fff ),
FMT(ARGB16161616, 64, 0xffffffff00000000, 0xffff0000ffff0000, 0xffff00000000ffff, 0x7fff7fff7fff7fff ),
FMT(XBGR16161616, 64, 0xffff00000000ffff, 0xffff0000ffff0000, 0xffffffff00000000, 0x7fff7fff7fff7fff ),
FMT(ABGR16161616, 64, 0xffff00000000ffff, 0xffff0000ffff0000, 0xffffffff00000000, 0x7fff7fff7fff7fff ),
FMT(XRGB16161616F, 64, 0x3c003c0000000000, 0x3c0000003c000000, 0x3c00000000003c00, 0x3800380038003800 ),
FMT(ARGB16161616F, 64, 0x3c003c0000000000, 0x3c0000003c000000, 0x3c00000000003c00, 0x3800380038003800 ),
FMT(XBGR16161616F, 64, 0x3c00000000003c00, 0x3c0000003c000000, 0x3c003c0000000000, 0x3800380038003800 ),
FMT(ABGR16161616F, 64, 0x3c00000000003c00, 0x3c0000003c000000, 0x3c003c0000000000, 0x3800380038003800 ),
}; };
static int running = 1; static int running = 1;
@ -164,58 +73,6 @@ static int running = 1;
static void static void
redraw(void *data, struct wl_callback *callback, uint32_t time); redraw(void *data, struct wl_callback *callback, uint32_t time);
static struct buffer *
alloc_buffer(struct window *window, int width, int height)
{
struct buffer *buffer = calloc(1, sizeof(*buffer));
buffer->width = width;
buffer->height = height;
wl_list_insert(&window->buffer_list, &buffer->buffer_link);
return buffer;
}
static void
destroy_buffer(struct buffer *buffer)
{
if (buffer->buffer)
wl_buffer_destroy(buffer->buffer);
munmap(buffer->shm_data, buffer->size);
wl_list_remove(&buffer->buffer_link);
free(buffer);
}
static struct buffer *
pick_free_buffer(struct window *window)
{
struct buffer *b;
struct buffer *buffer = NULL;
wl_list_for_each(b, &window->buffer_list, buffer_link) {
if (!b->busy) {
buffer = b;
break;
}
}
return buffer;
}
static void
prune_old_released_buffers(struct window *window)
{
struct buffer *b, *b_next;
wl_list_for_each_safe(b, b_next,
&window->buffer_list, buffer_link) {
if (!b->busy && (b->width != window->width ||
b->height != window->height))
destroy_buffer(b);
}
}
static void static void
buffer_release(void *data, struct wl_buffer *buffer) buffer_release(void *data, struct wl_buffer *buffer)
{ {
@ -229,31 +86,26 @@ static const struct wl_buffer_listener buffer_listener = {
}; };
static int static int
create_shm_buffer(struct window *window, struct buffer *buffer, create_shm_buffer(struct display *display, struct buffer *buffer,
const struct format *format) int width, int height, uint32_t format)
{ {
struct wl_shm_pool *pool; struct wl_shm_pool *pool;
int fd, size, stride; int fd, size, stride;
void *data; void *data;
int width, height;
struct display *display;
width = window->width; stride = width * 4;
height = window->height;
stride = width * (format->bpp / 8);
size = stride * height; size = stride * height;
display = window->display;
fd = os_create_anonymous_file(size); fd = os_create_anonymous_file(size);
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "creating a buffer file for %d B failed: %s\n", fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
size, strerror(errno)); size);
return -1; return -1;
} }
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) { if (data == MAP_FAILED) {
fprintf(stderr, "mmap failed: %s\n", strerror(errno)); fprintf(stderr, "mmap failed: %m\n");
close(fd); close(fd);
return -1; return -1;
} }
@ -261,90 +113,16 @@ create_shm_buffer(struct window *window, struct buffer *buffer,
pool = wl_shm_create_pool(display->shm, fd, size); pool = wl_shm_create_pool(display->shm, fd, size);
buffer->buffer = wl_shm_pool_create_buffer(pool, 0, buffer->buffer = wl_shm_pool_create_buffer(pool, 0,
width, height, width, height,
stride, format->code); stride, format);
wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer); wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
wl_shm_pool_destroy(pool); wl_shm_pool_destroy(pool);
close(fd); close(fd);
buffer->size = size;
buffer->shm_data = data; buffer->shm_data = data;
return 0; return 0;
} }
static void
keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
uint32_t format, int fd, uint32_t size)
{
/* Just so we dont leak the keymap fd */
close(fd);
}
static void
keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface,
struct wl_array *keys)
{
}
static void
keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface)
{
}
static void
keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t time, uint32_t key,
uint32_t state)
{
struct display *d = data;
if (key == KEY_F11 && state) {
if (d->window->fullscreen)
xdg_toplevel_unset_fullscreen(d->window->xdg_toplevel);
else
xdg_toplevel_set_fullscreen(d->window->xdg_toplevel, NULL);
} else if (key == KEY_ESC && state) {
running = 0;
}
}
static void
keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t mods_depressed,
uint32_t mods_latched, uint32_t mods_locked,
uint32_t group)
{
}
static const struct wl_keyboard_listener keyboard_listener = {
keyboard_handle_keymap,
keyboard_handle_enter,
keyboard_handle_leave,
keyboard_handle_key,
keyboard_handle_modifiers,
};
static void
seat_handle_capabilities(void *data, struct wl_seat *seat,
enum wl_seat_capability caps)
{
struct display *d = data;
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !d->keyboard) {
d->keyboard = wl_seat_get_keyboard(seat);
wl_keyboard_add_listener(d->keyboard, &keyboard_listener, d);
} else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && d->keyboard) {
wl_keyboard_destroy(d->keyboard);
d->keyboard = NULL;
}
}
static const struct wl_seat_listener seat_listener = {
seat_handle_capabilities,
};
static void static void
handle_xdg_surface_configure(void *data, struct xdg_surface *surface, handle_xdg_surface_configure(void *data, struct xdg_surface *surface,
uint32_t serial) uint32_t serial)
@ -366,39 +144,8 @@ static const struct xdg_surface_listener xdg_surface_listener = {
static void static void
handle_xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, handle_xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
int32_t width, int32_t height, int32_t width, int32_t height,
struct wl_array *states) struct wl_array *state)
{ {
struct window *window = data;
uint32_t *p;
window->fullscreen = false;
window->maximized = false;
wl_array_for_each(p, states) {
uint32_t state = *p;
switch (state) {
case XDG_TOPLEVEL_STATE_FULLSCREEN:
window->fullscreen = true;
break;
case XDG_TOPLEVEL_STATE_MAXIMIZED:
window->maximized = true;
break;
}
}
if (width > 0 && height > 0) {
if (!window->fullscreen && !window->maximized) {
window->init_width = width;
window->init_height = height;
}
window->width = width;
window->height = height;
} else if (!window->fullscreen && !window->maximized) {
window->width = window->init_width;
window->height = window->init_height;
}
window->needs_update_buffer = true;
} }
static void static void
@ -416,7 +163,6 @@ static struct window *
create_window(struct display *display, int width, int height) create_window(struct display *display, int width, int height)
{ {
struct window *window; struct window *window;
int i;
window = zalloc(sizeof *window); window = zalloc(sizeof *window);
if (!window) if (!window)
@ -426,11 +172,7 @@ create_window(struct display *display, int width, int height)
window->display = display; window->display = display;
window->width = width; window->width = width;
window->height = height; window->height = height;
window->init_width = width;
window->init_height = height;
window->surface = wl_compositor_create_surface(display->compositor); window->surface = wl_compositor_create_surface(display->compositor);
window->needs_update_buffer = false;
wl_list_init(&window->buffer_list);
if (display->wm_base) { if (display->wm_base) {
window->xdg_surface = window->xdg_surface =
@ -447,32 +189,30 @@ create_window(struct display *display, int width, int height)
&xdg_toplevel_listener, window); &xdg_toplevel_listener, window);
xdg_toplevel_set_title(window->xdg_toplevel, "simple-shm"); xdg_toplevel_set_title(window->xdg_toplevel, "simple-shm");
xdg_toplevel_set_app_id(window->xdg_toplevel,
"org.freedesktop.weston.simple-shm");
wl_surface_commit(window->surface); wl_surface_commit(window->surface);
window->wait_for_configure = true; window->wait_for_configure = true;
} else if (display->fshell) {
zwp_fullscreen_shell_v1_present_surface(display->fshell,
window->surface,
ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT,
NULL);
} else { } else {
assert(0); assert(0);
} }
for (i = 0; i < MAX_BUFFER_ALLOC; i++)
alloc_buffer(window, window->width, window->height);
return window; return window;
} }
static void static void
destroy_window(struct window *window) destroy_window(struct window *window)
{ {
struct buffer *buffer, *buffer_next;
if (window->callback) if (window->callback)
wl_callback_destroy(window->callback); wl_callback_destroy(window->callback);
wl_list_for_each_safe(buffer, buffer_next, if (window->buffers[0].buffer)
&window->buffer_list, buffer_link) wl_buffer_destroy(window->buffers[0].buffer);
destroy_buffer(buffer); if (window->buffers[1].buffer)
wl_buffer_destroy(window->buffers[1].buffer);
if (window->xdg_toplevel) if (window->xdg_toplevel)
xdg_toplevel_destroy(window->xdg_toplevel); xdg_toplevel_destroy(window->xdg_toplevel);
@ -485,34 +225,27 @@ destroy_window(struct window *window)
static struct buffer * static struct buffer *
window_next_buffer(struct window *window) window_next_buffer(struct window *window)
{ {
struct buffer *buffer = NULL; struct buffer *buffer;
int ret = 0; int ret = 0;
if (window->needs_update_buffer) { if (!window->buffers[0].busy)
int i; buffer = &window->buffers[0];
else if (!window->buffers[1].busy)
for (i = 0; i < MAX_BUFFER_ALLOC; i++) buffer = &window->buffers[1];
alloc_buffer(window, window->width, window->height); else
window->needs_update_buffer = false;
}
buffer = pick_free_buffer(window);
if (!buffer)
return NULL; return NULL;
if (!buffer->buffer) { if (!buffer->buffer) {
ret = create_shm_buffer(window, buffer, ret = create_shm_buffer(window->display, buffer,
window->display->format); window->width, window->height,
WL_SHM_FORMAT_XRGB8888);
if (ret < 0) if (ret < 0)
return NULL; return NULL;
/* paint the padding */ /* paint the padding */
memset(buffer->shm_data, 0xff, memset(buffer->shm_data, 0xff,
window->width * window->height * window->width * window->height * 4);
(window->display->format->bpp / 8));
} }
return buffer; return buffer;
@ -564,122 +297,6 @@ paint_pixels(void *image, int padding, int width, int height, uint32_t time)
} }
} }
static void
paint_format(void *image, const struct format *format, int width, int height)
{
uint64_t *img64 = (uint64_t*) image;
uint32_t *img32 = (uint32_t*) image;
uint16_t *img16 = (uint16_t*) image;
uint8_t *img8 = (uint8_t*) image;
uint64_t color;
int i, j;
#define GET_COLOR(y) \
(y < (1 * (height / 4))) ? format->color[0] : \
(y < (2 * (height / 4))) ? format->color[1] : \
(y < (3 * (height / 4))) ? format->color[2] : \
format->color[3]
switch (format->code) {
case WL_SHM_FORMAT_R8:
for (i = 0; i < height; i++) {
color = GET_COLOR(i);
for (j = 0; j < width; j++)
img8[i * width + j] = color;
}
break;
case WL_SHM_FORMAT_R16:
case WL_SHM_FORMAT_GR88:
case WL_SHM_FORMAT_RG88:
case WL_SHM_FORMAT_RGB565:
case WL_SHM_FORMAT_BGR565:
case WL_SHM_FORMAT_XRGB4444:
case WL_SHM_FORMAT_ARGB4444:
case WL_SHM_FORMAT_XBGR4444:
case WL_SHM_FORMAT_ABGR4444:
case WL_SHM_FORMAT_RGBX4444:
case WL_SHM_FORMAT_RGBA4444:
case WL_SHM_FORMAT_BGRX4444:
case WL_SHM_FORMAT_BGRA4444:
case WL_SHM_FORMAT_XRGB1555:
case WL_SHM_FORMAT_ARGB1555:
case WL_SHM_FORMAT_XBGR1555:
case WL_SHM_FORMAT_ABGR1555:
case WL_SHM_FORMAT_RGBX5551:
case WL_SHM_FORMAT_RGBA5551:
case WL_SHM_FORMAT_BGRX5551:
case WL_SHM_FORMAT_BGRA5551:
for (i = 0; i < height; i++) {
color = GET_COLOR(i);
for (j = 0; j < width; j++)
img16[i * width + j] = color;
}
break;
case WL_SHM_FORMAT_RGB888:
case WL_SHM_FORMAT_BGR888:
for (i = 0; i < height; i++) {
color = GET_COLOR(i);
for (j = 0; j < width; j++) {
img8[(i * width + j) * 3 + 0] =
(color >> 0) & 0xff;
img8[(i * width + j) * 3 + 1] =
(color >> 8) & 0xff;
img8[(i * width + j) * 3 + 2] =
(color >> 16) & 0xff;
}
}
break;
case WL_SHM_FORMAT_GR1616:
case WL_SHM_FORMAT_RG1616:
case WL_SHM_FORMAT_XRGB8888:
case WL_SHM_FORMAT_ARGB8888:
case WL_SHM_FORMAT_XBGR8888:
case WL_SHM_FORMAT_ABGR8888:
case WL_SHM_FORMAT_RGBX8888:
case WL_SHM_FORMAT_RGBA8888:
case WL_SHM_FORMAT_BGRX8888:
case WL_SHM_FORMAT_BGRA8888:
case WL_SHM_FORMAT_XRGB2101010:
case WL_SHM_FORMAT_ARGB2101010:
case WL_SHM_FORMAT_XBGR2101010:
case WL_SHM_FORMAT_ABGR2101010:
case WL_SHM_FORMAT_RGBX1010102:
case WL_SHM_FORMAT_RGBA1010102:
case WL_SHM_FORMAT_BGRX1010102:
case WL_SHM_FORMAT_BGRA1010102:
for (i = 0; i < height; i++) {
color = GET_COLOR(i);
for (j = 0; j < width; j++)
img32[i * width + j] = color;
}
break;
case WL_SHM_FORMAT_XRGB16161616:
case WL_SHM_FORMAT_ARGB16161616:
case WL_SHM_FORMAT_XBGR16161616:
case WL_SHM_FORMAT_ABGR16161616:
case WL_SHM_FORMAT_XRGB16161616F:
case WL_SHM_FORMAT_ARGB16161616F:
case WL_SHM_FORMAT_XBGR16161616F:
case WL_SHM_FORMAT_ABGR16161616F:
for (i = 0; i < height; i++) {
color = GET_COLOR(i);
for (j = 0; j < width; j++)
img64[i * width + j] = color;
}
break;
default:
assert(0);
break;
};
#undef GET_COLOR
}
static const struct wl_callback_listener frame_listener; static const struct wl_callback_listener frame_listener;
static void static void
@ -688,8 +305,6 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
struct window *window = data; struct window *window = data;
struct buffer *buffer; struct buffer *buffer;
prune_old_released_buffers(window);
buffer = window_next_buffer(window); buffer = window_next_buffer(window);
if (!buffer) { if (!buffer) {
fprintf(stderr, fprintf(stderr,
@ -698,12 +313,7 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
abort(); abort();
} }
if (window->display->paint_format) paint_pixels(buffer->shm_data, 20, window->width, window->height, time);
paint_format(buffer->shm_data, window->display->format,
window->width, window->height);
else
paint_pixels(buffer->shm_data, 20, window->width,
window->height, time);
wl_surface_attach(window->surface, buffer->buffer, 0, 0); wl_surface_attach(window->surface, buffer->buffer, 0, 0);
wl_surface_damage(window->surface, wl_surface_damage(window->surface,
@ -727,8 +337,8 @@ shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
{ {
struct display *d = data; struct display *d = data;
if (format == d->format->code) if (format == WL_SHM_FORMAT_XRGB8888)
d->has_format = true; d->has_xrgb = true;
} }
struct wl_shm_listener shm_listener = { struct wl_shm_listener shm_listener = {
@ -759,10 +369,9 @@ registry_handle_global(void *data, struct wl_registry *registry,
d->wm_base = wl_registry_bind(registry, d->wm_base = wl_registry_bind(registry,
id, &xdg_wm_base_interface, 1); id, &xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(d->wm_base, &xdg_wm_base_listener, d); xdg_wm_base_add_listener(d->wm_base, &xdg_wm_base_listener, d);
} else if (strcmp(interface, "wl_seat") == 0) { } else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0) {
d->seat = wl_registry_bind(registry, id, d->fshell = wl_registry_bind(registry,
&wl_seat_interface, 1); id, &zwp_fullscreen_shell_v1_interface, 1);
wl_seat_add_listener(d->seat, &seat_listener, d);
} else if (strcmp(interface, "wl_shm") == 0) { } else if (strcmp(interface, "wl_shm") == 0) {
d->shm = wl_registry_bind(registry, d->shm = wl_registry_bind(registry,
id, &wl_shm_interface, 1); id, &wl_shm_interface, 1);
@ -782,11 +391,11 @@ static const struct wl_registry_listener registry_listener = {
}; };
static struct display * static struct display *
create_display(const struct format *format, bool paint_format) create_display(void)
{ {
struct display *display; struct display *display;
display = zalloc(sizeof *display); display = malloc(sizeof *display);
if (display == NULL) { if (display == NULL) {
fprintf(stderr, "out of memory\n"); fprintf(stderr, "out of memory\n");
exit(1); exit(1);
@ -794,9 +403,7 @@ create_display(const struct format *format, bool paint_format)
display->display = wl_display_connect(NULL); display->display = wl_display_connect(NULL);
assert(display->display); assert(display->display);
display->format = format; display->has_xrgb = false;
display->paint_format = paint_format;
display->has_format= false;
display->registry = wl_display_get_registry(display->display); display->registry = wl_display_get_registry(display->display);
wl_registry_add_listener(display->registry, wl_registry_add_listener(display->registry,
&registry_listener, display); &registry_listener, display);
@ -848,9 +455,8 @@ create_display(const struct format *format, bool paint_format)
* technique. * technique.
*/ */
if (!display->has_format) { if (!display->has_xrgb) {
fprintf(stderr, "Format '%s' not supported by compositor.\n", fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n");
format->string);
exit(1); exit(1);
} }
@ -866,6 +472,9 @@ destroy_display(struct display *display)
if (display->wm_base) if (display->wm_base)
xdg_wm_base_destroy(display->wm_base); xdg_wm_base_destroy(display->wm_base);
if (display->fshell)
zwp_fullscreen_shell_v1_release(display->fshell);
if (display->compositor) if (display->compositor)
wl_compositor_destroy(display->compositor); wl_compositor_destroy(display->compositor);
@ -881,86 +490,19 @@ signal_int(int signum)
running = 0; running = 0;
} }
static void
usage(const char *program)
{
fprintf(stdout,
"Usage: %s [OPTIONS]\n"
"\n"
"Draw pixels into shared memory buffers using wl_shm\n"
"\n"
"Options:\n"
" -h, --help Show this help\n"
" -F, --format <format> Test format (see list below)\n"
"\n"
"RGB formats:\n"
" - 8 bpp: r8.\n"
"\n"
" - 16 bpp: r16, gr88, rg88, rgb565, bgr565, xrgb4444, argb4444, xbgr4444,\n"
" abgr4444, rgbx4444, rgba4444, bgrx4444, bgra4444, xrgb1555,\n"
" argb1555, xbgr1555, abgr1555, rgbx5551, rgba5551, bgrx5551,\n"
" bgra5551.\n"
"\n"
" - 24 bpp: rgb888, bgr888.\n"
"\n"
" - 32 bpp: gr1616, rg1616, xrgb8888, argb8888, xbgr8888, abgr8888, rgbx8888,\n"
" rgba8888, bgrx8888, bgra8888, xrgb2101010, argb2101010, xbgr2101010,\n"
" abgr2101010, rgbx1010102, rgba1010102, bgrx1010102, bgra1010102.\n"
"\n"
" - 64 bpp: xrgb16161616, argb16161616, xbgr16161616, abgr16161616,\n"
" xrgb16161616f, argb16161616f, xbgr16161616f, abgr16161616f.\n",
program);
}
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
struct sigaction sigint; struct sigaction sigint;
struct display *display; struct display *display;
struct window *window; struct window *window;
const struct format *format = NULL; int ret = 0;
bool paint_format = false;
const char *value;
int ret = 0, i, j;
for (i = 1; i < argc; i++) { display = create_display();
if (!strcmp(argv[i], "-h") || window = create_window(display, 250, 250);
!strcmp(argv[i], "--help")) {
usage(argv[0]);
return 0;
} else if (!strcmp(argv[i], "-F") ||
!strcmp(argv[i], "--format")) {
value = ++i == argc ? "" : argv[i];
for (j = 0; j < (int) ARRAY_SIZE(shm_formats); j++) {
if (!strcasecmp(shm_formats[j].string, value)) {
format = &shm_formats[j];
paint_format = true;
break;
}
}
if (!format) {
fprintf(stderr, "Format '%s' not supported by "
"client.\n", value);
return 1;
}
} else {
fprintf(stderr, "Invalid argument: '%s'\n", argv[i - 1]);
return 1;
}
}
if (!format)
for (i = 0; i < (int) ARRAY_SIZE(shm_formats); i++)
if (shm_formats[i].code == WL_SHM_FORMAT_XRGB8888)
format = &shm_formats[i];
assert(format);
display = create_display(format, paint_format);
window = create_window(display, 256, 256);
if (!window) if (!window)
return 1; return 1;
display->window = window;
sigint.sa_handler = signal_int; sigint.sa_handler = signal_int;
sigemptyset(&sigint.sa_mask); sigemptyset(&sigint.sa_mask);
sigint.sa_flags = SA_RESETHAND; sigint.sa_flags = SA_RESETHAND;

View file

@ -1,880 +0,0 @@
/*
* Copyright © 2011 Benjamin Franzke
* Copyright © 2010 Intel Corporation
* Copyright © 2025 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.
*/
#include "config.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include <unistd.h>
#include <sys/mman.h>
#include <signal.h>
#include <errno.h>
#include <assert.h>
#include <linux/input.h>
#include <wayland-client.h>
#include "shared/os-compatibility.h"
#include "shared/timespec-util.h"
#include "shared/xalloc.h"
#include <libweston/zalloc.h>
#include "xdg-shell-client-protocol.h"
#include "commit-timing-v1-client-protocol.h"
#include "fifo-v1-client-protocol.h"
#include "presentation-time-client-protocol.h"
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
#define MAX_BUFFER_ALLOC 1000
struct display {
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct xdg_wm_base *wm_base;
struct wl_seat *seat;
struct wl_keyboard *keyboard;
struct wl_shm *shm;
struct wp_commit_timing_manager_v1 *commit_timing_manager;
struct wp_fifo_manager_v1 *fifo_manager;
struct wp_presentation *presentation;
bool have_clock_id;
clockid_t presentation_clock_id;
int64_t first_frame_time;
int64_t refresh_nsec;
};
struct buffer {
struct window *window;
struct wl_buffer *buffer;
void *shm_data;
int busy;
int width, height;
size_t size; /* width * 4 * height */
struct wl_list buffer_link; /** window::buffer_list */
};
struct window {
struct display *display;
int width, height;
int init_width, init_height;
struct wl_surface *surface;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
struct wl_list buffer_list;
struct wp_fifo_v1 *fifo;
struct wp_commit_timer_v1 *commit_timer;
bool wait_for_configure;
bool maximized;
bool fullscreen;
bool needs_update_buffer;
};
struct feedback {
struct wp_presentation_feedback *fb;
struct window *window;
int64_t target_time;
bool final;
};
static int running = 1;
static void
draw_for_time(void *data, int64_t time, bool wait_fifo);
static void
finish_run(struct window *window);
static struct buffer *
alloc_buffer(struct window *window, int width, int height)
{
struct buffer *buffer = calloc(1, sizeof(*buffer));
buffer->width = width;
buffer->height = height;
wl_list_insert(&window->buffer_list, &buffer->buffer_link);
return buffer;
}
static void
destroy_buffer(struct buffer *buffer)
{
if (buffer->buffer)
wl_buffer_destroy(buffer->buffer);
munmap(buffer->shm_data, buffer->size);
wl_list_remove(&buffer->buffer_link);
free(buffer);
}
static struct buffer *
pick_free_buffer(struct window *window)
{
struct buffer *b;
struct buffer *buffer = NULL;
wl_list_for_each(b, &window->buffer_list, buffer_link) {
if (!b->busy) {
buffer = b;
break;
}
}
return buffer;
}
static void
prune_old_released_buffers(struct window *window)
{
struct buffer *b, *b_next;
wl_list_for_each_safe(b, b_next,
&window->buffer_list, buffer_link) {
if (!b->busy && (b->width != window->width ||
b->height != window->height))
destroy_buffer(b);
}
}
static void
buffer_release(void *data, struct wl_buffer *buffer)
{
struct buffer *mybuf = data;
mybuf->busy = 0;
}
static const struct wl_buffer_listener buffer_listener = {
buffer_release
};
static int
create_shm_buffer(struct window *window, struct buffer *buffer)
{
struct wl_shm_pool *pool;
int fd, size, stride;
void *data;
int width, height;
struct display *display;
width = window->width;
height = window->height;
stride = width * 4;
size = stride * height;
display = window->display;
fd = os_create_anonymous_file(size);
if (fd < 0) {
fprintf(stderr, "creating a buffer file for %d B failed: %s\n",
size, strerror(errno));
return -1;
}
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
fprintf(stderr, "mmap failed: %s\n", strerror(errno));
close(fd);
return -1;
}
pool = wl_shm_create_pool(display->shm, fd, size);
buffer->buffer = wl_shm_pool_create_buffer(pool, 0,
width, height,
stride,
WL_SHM_FORMAT_XRGB8888);
wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
wl_shm_pool_destroy(pool);
close(fd);
buffer->size = size;
buffer->shm_data = data;
return 0;
}
static void
keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
uint32_t format, int fd, uint32_t size)
{
/* Just so we dont leak the keymap fd */
close(fd);
}
static void
keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface,
struct wl_array *keys)
{
}
static void
keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface)
{
}
static void
keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t time, uint32_t key,
uint32_t state)
{
if (key == KEY_ESC && state)
running = 0;
}
static void
keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t mods_depressed,
uint32_t mods_latched, uint32_t mods_locked,
uint32_t group)
{
}
static const struct wl_keyboard_listener keyboard_listener = {
keyboard_handle_keymap,
keyboard_handle_enter,
keyboard_handle_leave,
keyboard_handle_key,
keyboard_handle_modifiers,
};
static void
seat_handle_capabilities(void *data, struct wl_seat *seat,
enum wl_seat_capability caps)
{
struct display *d = data;
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !d->keyboard) {
d->keyboard = wl_seat_get_keyboard(seat);
wl_keyboard_add_listener(d->keyboard, &keyboard_listener, d);
} else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && d->keyboard) {
wl_keyboard_destroy(d->keyboard);
d->keyboard = NULL;
}
}
static const struct wl_seat_listener seat_listener = {
seat_handle_capabilities,
};
static void
handle_xdg_surface_configure(void *data, struct xdg_surface *surface,
uint32_t serial)
{
struct window *window = data;
xdg_surface_ack_configure(surface, serial);
if (window->wait_for_configure) {
draw_for_time(window, 0, false);
window->wait_for_configure = false;
}
}
static const struct xdg_surface_listener xdg_surface_listener = {
handle_xdg_surface_configure,
};
static void
handle_xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
int32_t width, int32_t height,
struct wl_array *states)
{
struct window *window = data;
uint32_t *p;
window->fullscreen = false;
window->maximized = false;
wl_array_for_each(p, states) {
uint32_t state = *p;
switch (state) {
case XDG_TOPLEVEL_STATE_FULLSCREEN:
window->fullscreen = true;
break;
case XDG_TOPLEVEL_STATE_MAXIMIZED:
window->maximized = true;
break;
}
}
if (width > 0 && height > 0) {
if (!window->fullscreen && !window->maximized) {
window->init_width = width;
window->init_height = height;
}
window->width = width;
window->height = height;
} else if (!window->fullscreen && !window->maximized) {
window->width = window->init_width;
window->height = window->init_height;
}
window->needs_update_buffer = true;
}
static void
handle_xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
{
running = 0;
}
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
handle_xdg_toplevel_configure,
handle_xdg_toplevel_close,
};
static struct window *
create_window(struct display *display, int width, int height)
{
struct window *window;
int i;
window = zalloc(sizeof *window);
if (!window)
return NULL;
window->display = display;
window->width = width;
window->height = height;
window->init_width = width;
window->init_height = height;
window->surface = wl_compositor_create_surface(display->compositor);
window->fifo = wp_fifo_manager_v1_get_fifo(display->fifo_manager,
window->surface);
window->commit_timer = wp_commit_timing_manager_v1_get_timer(display->commit_timing_manager,
window->surface);
window->needs_update_buffer = false;
wl_list_init(&window->buffer_list);
assert(display->wm_base);
window->xdg_surface =
xdg_wm_base_get_xdg_surface(display->wm_base,
window->surface);
assert(window->xdg_surface);
xdg_surface_add_listener(window->xdg_surface,
&xdg_surface_listener, window);
window->xdg_toplevel =
xdg_surface_get_toplevel(window->xdg_surface);
assert(window->xdg_toplevel);
xdg_toplevel_add_listener(window->xdg_toplevel,
&xdg_toplevel_listener, window);
xdg_toplevel_set_title(window->xdg_toplevel, "simple-timing");
xdg_toplevel_set_app_id(window->xdg_toplevel,
"org.freedesktop.weston.simple-timing");
wl_surface_commit(window->surface);
window->wait_for_configure = true;
for (i = 0; i < MAX_BUFFER_ALLOC; i++)
alloc_buffer(window, window->width, window->height);
return window;
}
static void
destroy_window(struct window *window)
{
struct buffer *buffer, *buffer_next;
wl_list_for_each_safe(buffer, buffer_next,
&window->buffer_list, buffer_link)
destroy_buffer(buffer);
if (window->xdg_toplevel)
xdg_toplevel_destroy(window->xdg_toplevel);
if (window->xdg_surface)
xdg_surface_destroy(window->xdg_surface);
wl_surface_destroy(window->surface);
if (window->fifo)
wp_fifo_v1_destroy(window->fifo);
if (window->commit_timer)
wp_commit_timer_v1_destroy(window->commit_timer);
free(window);
}
static struct buffer *
window_next_buffer(struct window *window)
{
struct buffer *buffer = NULL;
int ret = 0;
if (window->needs_update_buffer) {
int i;
for (i = 0; i < MAX_BUFFER_ALLOC; i++)
alloc_buffer(window, window->width, window->height);
window->needs_update_buffer = false;
}
buffer = pick_free_buffer(window);
if (!buffer)
return NULL;
if (!buffer->buffer) {
ret = create_shm_buffer(window, buffer);
if (ret < 0)
return NULL;
/* paint the padding */
memset(buffer->shm_data, 0xff,
window->width * window->height * 4);
}
return buffer;
}
static void
paint_pixels(void *image, int width, int height, uint32_t time)
{
const int halfh = height / 2;
const int halfw = width / 2;
int ir, or;
uint32_t *pixel = image;
int y;
/* squared radii thresholds */
or = (halfw < halfh ? halfw : halfh) - 8;
ir = or - 32;
or *= or;
ir *= ir;
for (y = 0; y < height; y++) {
int x;
int y2 = (y - halfh) * (y - halfh);
for (x = 0; x < width; x++) {
uint32_t v;
/* squared distance from center */
int r2 = (x - halfw) * (x - halfw) + y2;
if (r2 < ir)
v = (r2 / 32 + time / 64) * 0x0080401;
else if (r2 < or)
v = (y + time / 32) * 0x0080401;
else
v = (x + time / 16) * 0x0080401;
v &= 0x00ffffff;
/* cross if compositor uses X from XRGB as alpha */
if (abs(x - y) > 6 && abs(x + y - height) > 6)
v |= 0xff000000;
*pixel++ = v;
}
}
}
static void
queue_some_frames(struct window *window)
{
struct display *display = window->display;
int64_t target_nsec;
int i;
assert(display->first_frame_time);
/* Round off error will cause us problems if we don't
* reduce this a bit, because we could end up rounding
* to either side of a refresh.
*/
target_nsec = display->first_frame_time - 100000;
for (i = 0; i < 60; i++) {
target_nsec += display->refresh_nsec * 2;
draw_for_time(window, target_nsec, false);
}
for (i = 0; i < 30; i++) {
target_nsec += display->refresh_nsec * 4;
draw_for_time(window, target_nsec, false);
}
for (i = 0; i < 10; i++) {
target_nsec += display->refresh_nsec * 10;
draw_for_time(window, target_nsec, false);
}
for (i = 0; i < 10; i++) {
target_nsec += display->refresh_nsec * 100;
draw_for_time(window, target_nsec, false);
}
finish_run(window);
}
static void
feedback_sync_output(void *data,
struct wp_presentation_feedback *presentation_feedback,
struct wl_output *output)
{
/* Just don't care */
}
static void
feedback_presented(void *data,
struct wp_presentation_feedback *presentation_feedback,
uint32_t tv_sec_hi,
uint32_t tv_sec_lo,
uint32_t tv_nsec,
uint32_t refresh_nsec,
uint32_t seq_hi,
uint32_t seq_lo,
uint32_t flags)
{
struct feedback *feedback = data;
struct window *window = feedback->window;
struct display *display = window->display;
struct timespec pres_ts = {
.tv_sec = ((int64_t)tv_sec_hi << 32) + tv_sec_lo,
.tv_nsec = tv_nsec,
};
int64_t ntime = timespec_to_nsec(&pres_ts);
double delay;
if (feedback->final) {
running = 0;
goto out;
}
if (!feedback->target_time) {
display->first_frame_time = ntime;
display->refresh_nsec = refresh_nsec;
queue_some_frames(window);
goto out;
}
delay = (ntime - feedback->target_time) / 1000000.0;
printf("%fms away from intended time\n", delay);
if (fabs(delay) > display->refresh_nsec / 1000000)
printf("Warning: we missed the intended target display cycle.\n");
out:
wp_presentation_feedback_destroy(feedback->fb);
free(feedback);
}
static void
feedback_discarded(void *data,
struct wp_presentation_feedback *presentation_feedback)
{
struct feedback *feedback = data;
printf("Warning: a frame was discarded\n");
if (feedback->final)
running = 0;
wp_presentation_feedback_destroy(feedback->fb);
free(feedback);
}
static const struct wp_presentation_feedback_listener feedback_listener = {
feedback_sync_output,
feedback_presented,
feedback_discarded,
};
static void
finish_run(struct window *window)
{
struct display *display = window->display;
struct feedback *feedback;
struct buffer *buffer;
feedback = xzalloc(sizeof *feedback);
feedback->window = window;
feedback->final = true;
feedback->target_time = 0;
buffer = window_next_buffer(window);
assert(buffer);
paint_pixels(buffer->shm_data, window->width,
window->height, 1);
wl_surface_attach(window->surface, buffer->buffer, 0, 0);
wl_surface_damage(window->surface, 0, 0, window->width, window->height);
feedback->fb = wp_presentation_feedback(display->presentation,
window->surface);
wp_presentation_feedback_add_listener(feedback->fb,
&feedback_listener, feedback);
wp_fifo_v1_wait_barrier(window->fifo);
wl_surface_commit(window->surface);
}
static void
draw_for_time(void *data, int64_t time, bool wait_fifo)
{
struct window *window = data;
struct display *display = window->display;
struct buffer *buffer;
struct feedback *feedback;
assert(display->have_clock_id);
prune_old_released_buffers(window);
buffer = window_next_buffer(window);
assert(buffer);
paint_pixels(buffer->shm_data, window->width,
window->height, time / 1000000);
wl_surface_attach(window->surface, buffer->buffer, 0, 0);
wl_surface_damage(window->surface, 0, 0, window->width, window->height);
feedback = xzalloc(sizeof *feedback);
feedback->window = window;
feedback->fb = wp_presentation_feedback(display->presentation,
window->surface);
wp_presentation_feedback_add_listener(feedback->fb,
&feedback_listener, feedback);
feedback->target_time = time;
if (time) {
struct timespec target;
timespec_from_nsec(&target, time);
wp_commit_timer_v1_set_timestamp(window->commit_timer,
(int64_t)target.tv_sec >> 32,
target.tv_sec,
target.tv_nsec);
}
wp_fifo_v1_set_barrier(window->fifo);
wl_surface_commit(window->surface);
buffer->busy = 1;
}
static void
xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial)
{
xdg_wm_base_pong(shell, serial);
}
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
xdg_wm_base_ping,
};
static void
presentation_handle_clock_id(void *data,
struct wp_presentation *wp_presentation,
uint32_t clock_id)
{
struct display *display = data;
display->presentation_clock_id = clock_id;
display->have_clock_id = true;
}
static const struct wp_presentation_listener presentation_listener = {
presentation_handle_clock_id,
};
static void
registry_handle_global(void *data, struct wl_registry *registry,
uint32_t id, const char *interface, uint32_t version)
{
struct display *d = data;
if (strcmp(interface, "wl_compositor") == 0) {
d->compositor =
wl_registry_bind(registry,
id, &wl_compositor_interface, 1);
} else if (strcmp(interface, "xdg_wm_base") == 0) {
d->wm_base = wl_registry_bind(registry,
id, &xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(d->wm_base, &xdg_wm_base_listener, d);
} else if (strcmp(interface, "wl_seat") == 0) {
d->seat = wl_registry_bind(registry, id,
&wl_seat_interface, 1);
wl_seat_add_listener(d->seat, &seat_listener, d);
} else if (strcmp(interface, "wl_shm") == 0) {
d->shm = wl_registry_bind(registry,
id, &wl_shm_interface, 1);
} else if (strcmp(interface, wp_commit_timing_manager_v1_interface.name) == 0) {
d->commit_timing_manager = wl_registry_bind(registry, id,
&wp_commit_timing_manager_v1_interface,
1);
} else if (strcmp(interface, wp_fifo_manager_v1_interface.name) == 0) {
d->fifo_manager = wl_registry_bind(registry, id,
&wp_fifo_manager_v1_interface,
1);
} else if (strcmp(interface, wp_presentation_interface.name) == 0) {
d->presentation = wl_registry_bind(registry, id,
&wp_presentation_interface,
2);
wp_presentation_add_listener(d->presentation,
&presentation_listener, d);
}
}
static void
registry_handle_global_remove(void *data, struct wl_registry *registry,
uint32_t name)
{
}
static const struct wl_registry_listener registry_listener = {
registry_handle_global,
registry_handle_global_remove
};
static struct display *
create_display(void)
{
struct display *display;
display = xzalloc(sizeof *display);
display->display = wl_display_connect(NULL);
assert(display->display);
display->registry = wl_display_get_registry(display->display);
wl_registry_add_listener(display->registry,
&registry_listener, display);
wl_display_roundtrip(display->display);
if (display->shm == NULL) {
fprintf(stderr, "No wl_shm global\n");
exit(1);
}
wl_display_roundtrip(display->display);
return display;
}
static void
destroy_display(struct display *display)
{
if (display->shm)
wl_shm_destroy(display->shm);
if (display->wm_base)
xdg_wm_base_destroy(display->wm_base);
if (display->compositor)
wl_compositor_destroy(display->compositor);
if (display->presentation)
wp_presentation_destroy(display->presentation);
if (display->fifo_manager)
wp_fifo_manager_v1_destroy(display->fifo_manager);
if (display->commit_timing_manager)
wp_commit_timing_manager_v1_destroy(display->commit_timing_manager);
if (display->keyboard)
wl_keyboard_destroy(display->keyboard);
if (display->seat)
wl_seat_destroy(display->seat);
wl_registry_destroy(display->registry);
wl_display_flush(display->display);
wl_display_disconnect(display->display);
free(display);
}
static void
signal_int(int signum)
{
running = 0;
}
static void
usage(const char *program)
{
fprintf(stdout,
"Usage: %s [OPTIONS]\n"
"\n"
"Schedule frames in the future with commit-timing\n"
"\n"
"Options:\n"
" -h, --help Show this help\n"
"\n",
program);
}
int
main(int argc, char **argv)
{
struct sigaction sigint;
struct display *display;
struct window *window;
int ret = 0, i;
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-h") ||
!strcmp(argv[i], "--help")) {
usage(argv[0]);
return 0;
} else {
fprintf(stderr, "Invalid argument: '%s'\n", argv[i - 1]);
return 1;
}
}
display = create_display();
window = create_window(display, 256, 256);
if (!window)
return 1;
sigint.sa_handler = signal_int;
sigemptyset(&sigint.sa_mask);
sigint.sa_flags = SA_RESETHAND;
sigaction(SIGINT, &sigint, NULL);
while (running && ret != -1)
ret = wl_display_dispatch(display->display);
fprintf(stderr, "simple-timing exiting\n");
destroy_window(window);
destroy_display(display);
return 0;
}

View file

@ -1,7 +1,6 @@
/* /*
* Copyright © 2011 Benjamin Franzke * Copyright © 2011 Benjamin Franzke
* Copyright © 2011 Intel Corporation * Copyright © 2011 Intel Corporation
* Copyright © 2021 Collabora, Ltd.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
@ -32,108 +31,66 @@
#include <stdbool.h> #include <stdbool.h>
#include <assert.h> #include <assert.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <wayland-client.h> #include <wayland-client.h>
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/xalloc.h"
#include "shared/os-compatibility.h" #include "shared/os-compatibility.h"
#include "xdg-shell-client-protocol.h"
struct seat { struct seat {
struct touch *touch; struct touch *touch;
struct wl_seat *seat; struct wl_seat *seat;
struct wl_touch *wl_touch; struct wl_touch *wl_touch;
}; };
struct buffer {
struct wl_buffer *buffer;
void *data;
};
struct touch { struct touch {
struct wl_display *display; struct wl_display *display;
struct wl_registry *registry; struct wl_registry *registry;
struct wl_compositor *compositor; struct wl_compositor *compositor;
struct xdg_wm_base *wm_base; struct wl_shell *shell;
struct wl_shm *shm; struct wl_shm *shm;
struct wl_pointer *pointer;
struct wl_keyboard *keyboard;
struct wl_surface *surface; struct wl_surface *surface;
struct xdg_surface *xdg_surface; struct wl_shell_surface *shell_surface;
struct xdg_toplevel *xdg_toplevel; struct wl_buffer *buffer;
struct buffer *buffer; int has_argb;
int width, height; int width, height;
int init_width, init_height; void *data;
bool running;
bool wait_for_configure;
bool needs_buffer_update;
bool has_argb;
bool maximized;
bool fullscreen;
}; };
static struct buffer * static void
create_shm_buffer(struct touch *touch) create_shm_buffer(struct touch *touch)
{ {
struct wl_shm_pool *pool; struct wl_shm_pool *pool;
int fd, size, stride; int fd, size, stride;
void *data;
struct buffer *buffer;
buffer = xzalloc(sizeof(*buffer));
stride = touch->width * 4; stride = touch->width * 4;
size = stride * touch->height; size = stride * touch->height;
fd = os_create_anonymous_file(size); fd = os_create_anonymous_file(size);
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "creating a buffer file for %d B failed: %s\n", fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
size, strerror(errno)); size);
exit(1); exit(1);
} }
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); touch->data =
if (data == MAP_FAILED) { mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
fprintf(stderr, "mmap failed: %s\n", strerror(errno)); if (touch->data == MAP_FAILED) {
fprintf(stderr, "mmap failed: %m\n");
close(fd); close(fd);
return NULL; exit(1);
} }
pool = wl_shm_create_pool(touch->shm, fd, size); pool = wl_shm_create_pool(touch->shm, fd, size);
buffer->buffer = touch->buffer =
wl_shm_pool_create_buffer(pool, 0, wl_shm_pool_create_buffer(pool, 0,
touch->width, touch->height, stride, touch->width, touch->height, stride,
WL_SHM_FORMAT_ARGB8888); WL_SHM_FORMAT_ARGB8888);
wl_shm_pool_destroy(pool); wl_shm_pool_destroy(pool);
buffer->data = data;
close(fd); close(fd);
return buffer;
}
static void
redraw(void *data)
{
struct touch *touch = data;
struct buffer *buffer = NULL;
buffer = create_shm_buffer(touch);
assert(buffer);
if (touch->buffer)
free(touch->buffer);
touch->buffer = buffer;
/* paint the "work-area" */
memset(buffer->data, 64, touch->width * touch->height * 4);
wl_surface_attach(touch->surface, buffer->buffer, 0, 0);
wl_surface_damage(touch->surface, 0, 0, touch->width, touch->height);
wl_surface_commit(touch->surface);
} }
static void static void
@ -142,7 +99,7 @@ shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
struct touch *touch = data; struct touch *touch = data;
if (format == WL_SHM_FORMAT_ARGB8888) if (format == WL_SHM_FORMAT_ARGB8888)
touch->has_argb = true; touch->has_argb = 1;
} }
struct wl_shm_listener shm_listener = { struct wl_shm_listener shm_listener = {
@ -172,7 +129,7 @@ touch_paint(struct touch *touch, int32_t x, int32_t y, int32_t id)
y < 2 || y >= touch->height - 2) y < 2 || y >= touch->height - 2)
return; return;
p = ((uint32_t *) touch->buffer->data) + (x - 2) + (y - 2) * touch->width; p = (uint32_t *) touch->data + (x - 2) + (y - 2) * touch->width;
p[2] = c; p[2] = c;
p += touch->width; p += touch->width;
p[1] = c; p[1] = c;
@ -191,7 +148,7 @@ touch_paint(struct touch *touch, int32_t x, int32_t y, int32_t id)
p += touch->width; p += touch->width;
p[2] = c; p[2] = c;
wl_surface_attach(touch->surface, touch->buffer->buffer, 0, 0); wl_surface_attach(touch->surface, touch->buffer, 0, 0);
wl_surface_damage(touch->surface, x - 2, y - 2, 5, 5); wl_surface_damage(touch->surface, x - 2, y - 2, 5, 5);
/* todo: We could queue up more damage before committing, if there /* todo: We could queue up more damage before committing, if there
* are more input events to handle. * are more input events to handle.
@ -283,32 +240,27 @@ add_seat(struct touch *touch, uint32_t name, uint32_t version)
} }
static void static void
handle_xdg_surface_configure(void *data, struct xdg_surface *surface, handle_ping(void *data, struct wl_shell_surface *shell_surface,
uint32_t serial) uint32_t serial)
{ {
struct touch *touch = data; wl_shell_surface_pong(shell_surface, serial);
xdg_surface_ack_configure(surface, serial);
if (touch->wait_for_configure || touch->needs_buffer_update) {
redraw(touch);
touch->wait_for_configure = false;
touch->needs_buffer_update = false;
}
} }
static const struct xdg_surface_listener xdg_surface_listener = {
handle_xdg_surface_configure,
};
static void static void
xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial) handle_configure(void *data, struct wl_shell_surface *shell_surface,
uint32_t edges, int32_t width, int32_t height)
{ {
xdg_wm_base_pong(shell, serial);
} }
static const struct xdg_wm_base_listener wm_base_listener = { static void
xdg_wm_base_ping, handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
{
}
static const struct wl_shell_surface_listener shell_surface_listener = {
handle_ping,
handle_configure,
handle_popup_done
}; };
static void static void
@ -321,12 +273,10 @@ handle_global(void *data, struct wl_registry *registry,
touch->compositor = touch->compositor =
wl_registry_bind(registry, name, wl_registry_bind(registry, name,
&wl_compositor_interface, 1); &wl_compositor_interface, 1);
} else if (strcmp(interface, "xdg_wm_base") == 0) { } else if (strcmp(interface, "wl_shell") == 0) {
touch->wm_base = touch->shell =
wl_registry_bind(registry, name, wl_registry_bind(registry, name,
&xdg_wm_base_interface, 1); &wl_shell_interface, 1);
xdg_wm_base_add_listener(touch->wm_base,
&wm_base_listener, touch);
} else if (strcmp(interface, "wl_shm") == 0) { } else if (strcmp(interface, "wl_shm") == 0) {
touch->shm = wl_registry_bind(registry, name, touch->shm = wl_registry_bind(registry, name,
&wl_shm_interface, 1); &wl_shm_interface, 1);
@ -346,56 +296,6 @@ static const struct wl_registry_listener registry_listener = {
handle_global_remove handle_global_remove
}; };
static void
handle_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
int32_t width, int32_t height, struct wl_array *states)
{
struct touch *touch = data;
uint32_t *p;
touch->fullscreen = false;
touch->maximized = false;
wl_array_for_each(p, states) {
uint32_t state = *p;
switch (state) {
case XDG_TOPLEVEL_STATE_FULLSCREEN:
touch->fullscreen = true;
break;
case XDG_TOPLEVEL_STATE_MAXIMIZED:
touch->maximized = true;
break;
}
}
if (width > 0 && height > 0) {
if (!touch->fullscreen && !touch->maximized) {
touch->init_width = width;
touch->init_width = height;
}
touch->width = width;
touch->height = height;
} else if (!touch->fullscreen && !touch->maximized) {
touch->width = touch->init_width;
touch->height = touch->init_height;
}
touch->needs_buffer_update = true;
}
static void
handle_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
{
struct touch *touch = data;
touch->running = false;
}
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
handle_toplevel_configure,
handle_toplevel_close,
};
static struct touch * static struct touch *
touch_create(int width, int height) touch_create(int width, int height)
{ {
@ -409,8 +309,7 @@ touch_create(int width, int height)
touch->display = wl_display_connect(NULL); touch->display = wl_display_connect(NULL);
assert(touch->display); assert(touch->display);
touch->has_argb = false; touch->has_argb = 0;
touch->buffer = NULL;
touch->registry = wl_display_get_registry(touch->display); touch->registry = wl_display_get_registry(touch->display);
wl_registry_add_listener(touch->registry, &registry_listener, touch); wl_registry_add_listener(touch->registry, &registry_listener, touch);
wl_display_dispatch(touch->display); wl_display_dispatch(touch->display);
@ -421,59 +320,30 @@ touch_create(int width, int height)
exit(1); exit(1);
} }
if (!touch->wm_base) { touch->width = width;
fprintf(stderr, "xdg-shell required!\n"); touch->height = height;
exit(1); touch->surface = wl_compositor_create_surface(touch->compositor);
touch->shell_surface = wl_shell_get_shell_surface(touch->shell,
touch->surface);
create_shm_buffer(touch);
if (touch->shell_surface) {
wl_shell_surface_add_listener(touch->shell_surface,
&shell_surface_listener, touch);
wl_shell_surface_set_toplevel(touch->shell_surface);
} }
touch->init_width = width; wl_surface_set_user_data(touch->surface, touch);
touch->init_height = height; wl_shell_surface_set_title(touch->shell_surface, "simple-touch");
touch->surface = wl_compositor_create_surface(touch->compositor);
touch->xdg_surface = memset(touch->data, 64, width * height * 4);
xdg_wm_base_get_xdg_surface(touch->wm_base, touch->surface); wl_surface_attach(touch->surface, touch->buffer, 0, 0);
assert(touch->xdg_surface); wl_surface_damage(touch->surface, 0, 0, width, height);
xdg_surface_add_listener(touch->xdg_surface, &xdg_surface_listener, touch);
touch->xdg_toplevel = xdg_surface_get_toplevel(touch->xdg_surface);
assert(touch->xdg_toplevel);
xdg_toplevel_add_listener(touch->xdg_toplevel,
&xdg_toplevel_listener, touch);
xdg_toplevel_set_title(touch->xdg_toplevel, "simple-touch");
xdg_toplevel_set_app_id(touch->xdg_toplevel, "simple-touch");
touch->wait_for_configure = true;
touch->needs_buffer_update = false;
wl_surface_commit(touch->surface); wl_surface_commit(touch->surface);
touch->running = true;
return touch; return touch;
} }
static void
destroy_touch(struct touch *touch)
{
if (touch->buffer->buffer)
wl_buffer_destroy(touch->buffer->buffer);
if (touch->xdg_toplevel)
xdg_toplevel_destroy(touch->xdg_toplevel);
if (touch->xdg_surface)
xdg_surface_destroy(touch->xdg_surface);
if (touch->wm_base)
xdg_wm_base_destroy(touch->wm_base);
if (touch->shm)
wl_shm_destroy(touch->shm);
if (touch->compositor)
wl_compositor_destroy(touch->compositor);
wl_surface_destroy(touch->surface);
free(touch->buffer);
free(touch);
}
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
@ -482,9 +352,8 @@ main(int argc, char **argv)
touch = touch_create(600, 500); touch = touch_create(600, 500);
while (ret != -1 && touch->running) while (ret != -1)
ret = wl_display_dispatch(touch->display); ret = wl_display_dispatch(touch->display);
destroy_touch(touch);
return 0; return 0;
} }

File diff suppressed because it is too large Load diff

View file

@ -1,9 +0,0 @@
#version 450 core
layout(location = 0) in vec4 v_color;
layout(location = 0) out vec4 f_color;
void main() {
f_color = v_color;
}

View file

@ -1,17 +0,0 @@
#version 450 core
layout(std140, set = 0, binding = 0) uniform block {
uniform mat4 reflection;
uniform float offset;
};
layout(location = 0) in vec4 pos;
layout(location = 1) in vec4 color;
layout(location = 0) out vec4 v_color;
void main()
{
gl_Position = reflection * (pos + vec4(offset, offset, 0.0, 0.0));
v_color = color;
}

View file

@ -1,9 +0,0 @@
#version 450 core
layout(location = 0) in vec4 vVaryingColor;
layout(location = 0) out vec4 f_color;
void main()
{
f_color = vVaryingColor;
}

View file

@ -1,16 +0,0 @@
#version 450 core
layout(std140, set = 0, binding = 0) uniform block {
uniform mat4 rotation;
};
layout(location = 0) in vec4 in_position;
layout(location = 1) in vec4 in_color;
layout(location = 0) out vec4 vVaryingColor;
void main()
{
gl_Position = rotation * in_position;
vVaryingColor = vec4(in_color.rgba);
}

View file

@ -29,7 +29,6 @@
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <math.h> #include <math.h>
#include <errno.h>
#include <cairo.h> #include <cairo.h>
#include <wayland-client.h> #include <wayland-client.h>
@ -274,8 +273,7 @@ int main(int argc, char *argv[])
d = display_create(&argc, argv); d = display_create(&argc, argv);
if (d == NULL) { if (d == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }
@ -285,7 +283,6 @@ int main(int argc, char *argv[])
smoke.window = window_create(d); smoke.window = window_create(d);
smoke.widget = window_add_widget(smoke.window, &smoke); smoke.widget = window_add_widget(smoke.window, &smoke);
window_set_title(smoke.window, "smoke"); window_set_title(smoke.window, "smoke");
window_set_appid(smoke.window, "org.freedesktop.weston.smoke");
window_set_buffer_type(smoke.window, WINDOW_BUFFER_TYPE_SHM); window_set_buffer_type(smoke.window, WINDOW_BUFFER_TYPE_SHM);
clock_gettime(CLOCK_MONOTONIC, &ts); clock_gettime(CLOCK_MONOTONIC, &ts);

View file

@ -29,30 +29,19 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
#include <errno.h>
#include <linux/input.h> #include <linux/input.h>
#include <cairo.h> #include <cairo.h>
#include <wayland-util.h> #include <wayland-util.h>
#include "shared/xalloc.h"
#include "shared/helpers.h" #include "shared/helpers.h"
#include "window.h" #include "window.h"
struct stacking_window {
struct stacking *stacking;
struct window *window;
struct widget *widget;
struct wl_list link;
};
struct stacking { struct stacking {
struct display *display; struct display *display;
struct wl_list windows; struct window *root_window;
}; };
static void
close_handler(void *data);
static void static void
button_handler(struct widget *widget, button_handler(struct widget *widget,
struct input *input, uint32_t time, struct input *input, uint32_t time,
@ -73,54 +62,29 @@ redraw_handler(struct widget *widget, void *data);
/* Iff parent_window is set, the new window will be transient. */ /* Iff parent_window is set, the new window will be transient. */
static struct window * static struct window *
create_window(struct stacking *stacking, struct window *parent_window) new_window(struct stacking *stacking, struct window *parent_window)
{ {
struct stacking_window *new_stacking_window;
struct window *new_window; struct window *new_window;
struct widget *new_widget; struct widget *new_widget;
new_stacking_window = xzalloc(sizeof *new_stacking_window);
new_stacking_window->stacking = stacking;
new_window = window_create(stacking->display); new_window = window_create(stacking->display);
new_stacking_window->window = new_window;
window_set_parent(new_window, parent_window); window_set_parent(new_window, parent_window);
new_widget = window_frame_create(new_window, new_window); new_widget = window_frame_create(new_window, new_window);
new_stacking_window->widget = new_widget;
wl_list_insert(stacking->windows.prev, &new_stacking_window->link);
window_set_title(new_window, "Stacking Test"); window_set_title(new_window, "Stacking Test");
window_set_appid(new_window, "org.freedesktop.weston.stacking-test");
window_set_key_handler(new_window, key_handler); window_set_key_handler(new_window, key_handler);
window_set_keyboard_focus_handler(new_window, keyboard_focus_handler); window_set_keyboard_focus_handler(new_window, keyboard_focus_handler);
window_set_fullscreen_handler(new_window, fullscreen_handler); window_set_fullscreen_handler(new_window, fullscreen_handler);
window_set_close_handler(new_window, close_handler);
widget_set_button_handler(new_widget, button_handler); widget_set_button_handler(new_widget, button_handler);
widget_set_redraw_handler(new_widget, redraw_handler); widget_set_redraw_handler(new_widget, redraw_handler);
window_set_user_data(new_window, new_stacking_window); window_set_user_data(new_window, stacking);
window_schedule_resize(new_window, 300, 300); window_schedule_resize(new_window, 300, 300);
return new_window; return new_window;
} }
static void
destroy_window(struct stacking_window *stacking_window)
{
struct stacking *stacking = stacking_window->stacking;
widget_destroy(stacking_window->widget);
window_destroy(stacking_window->window);
wl_list_remove(&stacking_window->link);
free(stacking_window);
if (wl_list_empty(&stacking->windows))
display_exit(stacking->display);
}
static void static void
show_popup_cb(void *data, struct input *input, int index) show_popup_cb(void *data, struct input *input, int index)
{ {
@ -142,27 +106,18 @@ show_popup(struct stacking *stacking, struct input *input, uint32_t time,
show_popup_cb, entries, ARRAY_LENGTH(entries)); show_popup_cb, entries, ARRAY_LENGTH(entries));
} }
static void
close_handler(void *data)
{
struct stacking_window *stacking_window = data;
destroy_window(stacking_window);
}
static void static void
button_handler(struct widget *widget, button_handler(struct widget *widget,
struct input *input, uint32_t time, struct input *input, uint32_t time,
uint32_t button, uint32_t button,
enum wl_pointer_button_state state, void *data) enum wl_pointer_button_state state, void *data)
{ {
struct window *window = data; struct stacking *stacking = data;
struct stacking_window *stacking_window = window_get_user_data(window);
switch (button) { switch (button) {
case BTN_RIGHT: case BTN_RIGHT:
if (state == WL_POINTER_BUTTON_STATE_PRESSED) if (state == WL_POINTER_BUTTON_STATE_PRESSED)
show_popup(stacking_window->stacking, input, time, show_popup(stacking, input, time,
widget_get_user_data(widget)); widget_get_user_data(widget));
break; break;
@ -178,8 +133,7 @@ key_handler(struct window *window,
uint32_t key, uint32_t sym, enum wl_keyboard_key_state state, uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
void *data) void *data)
{ {
struct stacking_window *stacking_window = data; struct stacking *stacking = data;
struct stacking *stacking = stacking_window->stacking;
if (state != WL_KEYBOARD_KEY_STATE_PRESSED) if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
return; return;
@ -195,24 +149,20 @@ key_handler(struct window *window,
case XKB_KEY_n: case XKB_KEY_n:
/* New top-level window. */ /* New top-level window. */
create_window(stacking, NULL); new_window(stacking, NULL);
break; break;
case XKB_KEY_p: case XKB_KEY_p:
show_popup(stacking, input, time, window); show_popup(stacking, input, time, window);
break; break;
case XKB_KEY_c:
destroy_window(stacking_window);
break;
case XKB_KEY_q: case XKB_KEY_q:
display_exit(stacking->display); exit (0);
break; break;
case XKB_KEY_t: case XKB_KEY_t:
/* New transient window. */ /* New transient window. */
create_window(stacking, window); new_window(stacking, window);
break; break;
default: default:
@ -249,7 +199,7 @@ draw_string(cairo_t *cr,
cairo_save(cr); cairo_save(cr);
cairo_select_font_face(cr, "sans-serif", cairo_select_font_face(cr, "sans",
CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL); CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cr, 14); cairo_set_font_size(cr, 14);
@ -297,11 +247,12 @@ set_window_background_colour(cairo_t *cr, struct window *window)
static void static void
redraw_handler(struct widget *widget, void *data) redraw_handler(struct widget *widget, void *data)
{ {
struct window *window = data; struct window *window;
struct rectangle allocation; struct rectangle allocation;
cairo_t *cr; cairo_t *cr;
widget_get_allocation(widget, &allocation); widget_get_allocation(widget, &allocation);
window = widget_get_user_data(widget);
cr = widget_cairo_create(widget); cr = widget_cairo_create(widget);
cairo_translate(cr, allocation.x, allocation.y); cairo_translate(cr, allocation.x, allocation.y);
@ -323,8 +274,7 @@ redraw_handler(struct widget *widget, void *data)
"Transient? %u\n" "Transient? %u\n"
"Keys: (f)ullscreen, (m)aximize,\n" "Keys: (f)ullscreen, (m)aximize,\n"
" (n)ew window, (p)opup,\n" " (n)ew window, (p)opup,\n"
" (c)lose, (q)uit,\n" " (q)uit, (t)ransient window\n",
" (t)ransient window\n",
window, window_is_fullscreen(window), window, window_is_fullscreen(window),
window_is_maximized(window), window_get_parent(window) ? 1 : 0); window_is_maximized(window), window_get_parent(window) ? 1 : 0);
@ -335,27 +285,22 @@ int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
struct stacking stacking; struct stacking stacking;
struct stacking_window *stacking_window, *tmp;
memset(&stacking, 0, sizeof stacking); memset(&stacking, 0, sizeof stacking);
wl_list_init(&stacking.windows);
stacking.display = display_create(&argc, argv); stacking.display = display_create(&argc, argv);
if (stacking.display == NULL) { if (stacking.display == NULL) {
fprintf(stderr, "Failed to create display: %s\n", fprintf(stderr, "Failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }
display_set_user_data(stacking.display, &stacking); display_set_user_data(stacking.display, &stacking);
create_window(&stacking, NULL); stacking.root_window = new_window(&stacking, NULL);
display_run(stacking.display); display_run(stacking.display);
wl_list_for_each_safe(stacking_window, tmp, &stacking.windows, link) window_destroy(stacking.root_window);
destroy_window(stacking_window);
display_destroy(stacking.display); display_destroy(stacking.display);
return 0; return 0;

View file

@ -32,7 +32,6 @@
#include <cairo.h> #include <cairo.h>
#include <math.h> #include <math.h>
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <linux/input.h> #include <linux/input.h>
#include <wayland-client.h> #include <wayland-client.h>
@ -44,7 +43,7 @@
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/xalloc.h" #include "shared/xalloc.h"
#include <libweston/zalloc.h> #include "shared/zalloc.h"
#include "window.h" #include "window.h"
#if 0 #if 0
@ -56,8 +55,8 @@
static int32_t option_red_mode; static int32_t option_red_mode;
static int32_t option_triangle_mode; static int32_t option_triangle_mode;
static bool option_no_triangle; static int32_t option_no_triangle;
static bool option_help; static int32_t option_help;
static const struct weston_option options[] = { static const struct weston_option options[] = {
{ WESTON_OPTION_INTEGER, "red-mode", 'r', &option_red_mode }, { WESTON_OPTION_INTEGER, "red-mode", 'r', &option_red_mode },
@ -296,7 +295,7 @@ create_shader(const char *source, GLenum shader_type)
char log[1000]; char log[1000];
GLsizei len; GLsizei len;
glGetShaderInfoLog(shader, 1000, &len, log); glGetShaderInfoLog(shader, 1000, &len, log);
fprintf(stderr, "Error: compiling %s: %.*s\n", fprintf(stderr, "Error: compiling %s: %*s\n",
shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment", shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
len, log); len, log);
exit(1); exit(1);
@ -325,7 +324,7 @@ triangle_init_gl(struct triangle_gl_state *trigl)
char log[1000]; char log[1000];
GLsizei len; GLsizei len;
glGetProgramInfoLog(program, 1000, &len, log); glGetProgramInfoLog(program, 1000, &len, log);
fprintf(stderr, "Error: linking:\n%.*s\n", len, log); fprintf(stderr, "Error: linking:\n%*s\n", len, log);
exit(1); exit(1);
} }
@ -733,8 +732,6 @@ demoapp_create(struct display *display)
app->window = window_create(app->display); app->window = window_create(app->display);
app->widget = window_frame_create(app->window, app); app->widget = window_frame_create(app->window, app);
window_set_title(app->window, "Wayland Sub-surface Demo"); window_set_title(app->window, "Wayland Sub-surface Demo");
window_set_appid(app->window,
"org.freedesktop.weston.wayland-sub-surface-demo");
window_set_key_handler(app->window, key_handler); window_set_key_handler(app->window, key_handler);
window_set_user_data(app->window, app); window_set_user_data(app->window, app);
@ -791,8 +788,7 @@ main(int argc, char *argv[])
display = display_create(&argc, argv); display = display_create(&argc, argv);
if (display == NULL) { if (display == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }

View file

@ -1,254 +0,0 @@
/*
* Copyright © 2014 Lyude
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of the copyright holders not be used in
* advertising or publicity pertaining to distribution of the software
* without specific, written prior permission. The copyright holders make
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE
*/
#include "config.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cairo.h>
#include <math.h>
#include <assert.h>
#include <stdbool.h>
#include <linux/input.h>
#include <wayland-client.h>
#include "window.h"
#include "tablet-unstable-v2-client-protocol.h"
struct display *display;
struct window *window;
struct widget *widget;
cairo_surface_t *draw_buffer;
int old_x, old_y;
int current_x, current_y;
enum zwp_tablet_tool_v2_type tool_type;
bool tablet_is_down;
double current_pressure;
#define WL_TABLET_AXIS_MAX 65535
static void
redraw_handler(struct widget *widget, void *data)
{
cairo_surface_t *surface;
cairo_t *window_cr, *drawing_cr;
struct rectangle allocation;
widget_get_allocation(widget, &allocation);
surface = window_get_surface(window);
/* Setup the background */
window_cr = cairo_create(surface);
cairo_set_operator(window_cr, CAIRO_OPERATOR_SOURCE);
cairo_rectangle(window_cr,
allocation.x,
allocation.y,
allocation.width,
allocation.height);
cairo_set_source_rgba(window_cr, 0, 0, 0, 0.8);
cairo_fill(window_cr);
/* Update the drawing buffer */
if (tablet_is_down) {
if (old_x != -1 && old_y != -1) {
drawing_cr = cairo_create(draw_buffer);
if (tool_type == ZWP_TABLET_TOOL_V2_TYPE_PEN) {
cairo_set_source_rgb(drawing_cr, 1, 1, 1);
cairo_set_line_width(drawing_cr,
current_pressure /
WL_TABLET_AXIS_MAX * 7 + 1);
} else if (tool_type == ZWP_TABLET_TOOL_V2_TYPE_ERASER) {
cairo_set_operator(drawing_cr, CAIRO_OPERATOR_CLEAR);
cairo_set_source_rgb(drawing_cr, 0, 0, 0);
cairo_set_line_width(drawing_cr,
current_pressure /
WL_TABLET_AXIS_MAX * 30 + 10);
}
cairo_set_line_cap(drawing_cr, CAIRO_LINE_CAP_ROUND);
cairo_translate(drawing_cr,
-allocation.x,
-allocation.y);
cairo_move_to(drawing_cr, old_x, old_y);
cairo_line_to(drawing_cr, current_x, current_y);
cairo_stroke(drawing_cr);
cairo_destroy(drawing_cr);
}
old_x = current_x;
old_y = current_y;
}
/* Squash the drawing buffer onto the window's buffer */
cairo_set_source_surface(window_cr,
draw_buffer,
allocation.x,
allocation.y);
cairo_set_operator(window_cr, CAIRO_OPERATOR_ADD);
cairo_rectangle(window_cr,
allocation.x,
allocation.y,
allocation.width,
allocation.height);
cairo_clip(window_cr);
cairo_paint(window_cr);
cairo_destroy(window_cr);
cairo_surface_destroy(surface);
}
static void
resize_handler(struct widget *widget,
int32_t width, int32_t height,
void *data)
{
cairo_surface_t *tmp_buffer;
cairo_t *cr;
tmp_buffer = draw_buffer;
draw_buffer = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
width, height);
cr = cairo_create(draw_buffer);
cairo_set_source_rgba(cr, 0, 0, 0, 0);
cairo_rectangle(cr, 0, 0, width, height);
cairo_fill(cr);
if (tmp_buffer) {
cairo_set_source_surface(cr, tmp_buffer, 0, 0);
cairo_rectangle(cr, 0, 0, width, height);
cairo_clip(cr);
cairo_paint(cr);
}
cairo_destroy(cr);
cairo_surface_destroy(tmp_buffer);
}
static void
proximity_in_handler(struct widget *widget, struct tablet_tool *tool,
struct tablet *tablet, void *data)
{
tool_type = tablet_tool_get_type(tool);
}
static void
pressure_handler(struct widget *widget, struct tablet_tool *tool,
uint32_t pressure, void *data)
{
current_pressure = pressure;
}
static int
tablet_motion_handler(struct widget *widget, struct tablet_tool *tool,
float x, float y, void *data)
{
int cursor;
current_x = x;
current_y = y;
if (tablet_is_down) {
widget_schedule_redraw(widget);
cursor = CURSOR_HAND1;
} else {
cursor = CURSOR_LEFT_PTR;
}
return cursor;
}
static void
tablet_down_handler(struct widget *widget, struct tablet_tool *tool, void *data)
{
tablet_is_down = true;
}
static void
tablet_up_handler(struct widget *widget, struct tablet_tool *tool, void *data)
{
tablet_is_down = false;
old_x = -1;
old_y = -1;
}
static void
init_globals(void)
{
window = window_create(display);
widget = window_frame_create(window, NULL);
window_set_title(window, "Wayland Tablet Demo");
old_x = -1;
old_y = -1;
widget_set_tablet_tool_axis_handlers(widget,
tablet_motion_handler,
pressure_handler,
NULL, NULL,
NULL, NULL, NULL);
widget_set_tablet_tool_down_handler(widget, tablet_down_handler);
widget_set_tablet_tool_up_handler(widget, tablet_up_handler);
widget_set_tablet_tool_proximity_handlers(widget,
proximity_in_handler,
NULL);
widget_set_redraw_handler(widget, redraw_handler);
widget_set_resize_handler(widget, resize_handler);
widget_schedule_resize(widget, 1000, 800);
}
static void
cleanup(void)
{
widget_destroy(widget);
window_destroy(window);
}
int
main(int argc, char *argv[])
{
display = display_create(&argc, argv);
if (display == NULL) {
fprintf(stderr, "failed to create display: %m\n");
return -1;
}
init_globals();
display_run(display);
cleanup();
display_destroy(display);
return 0;
}

View file

@ -23,7 +23,6 @@
#include "config.h" #include "config.h"
#include <signal.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -45,20 +44,19 @@
#include <wayland-client.h> #include <wayland-client.h>
#include <libweston/config-parser.h> #include "shared/config-parser.h"
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/xalloc.h" #include "shared/xalloc.h"
#include "window.h" #include "window.h"
static bool option_fullscreen; static int option_fullscreen;
static bool option_maximize; static int option_maximize;
static char *option_font; static char *option_font;
static int option_font_size; static int option_font_size;
static char *option_term; static char *option_term;
static char *option_shell; static char *option_shell;
static struct wl_list terminal_list; static struct wl_list terminal_list;
struct sigaction oldact;
static struct terminal * static struct terminal *
terminal_create(struct display *display); terminal_create(struct display *display);
@ -869,8 +867,8 @@ resize_handler(struct widget *widget,
terminal->pace_pipe = -1; terminal->pace_pipe = -1;
} }
m = 2 * terminal->margin; m = 2 * terminal->margin;
columns = (int32_t) round((width - m) / terminal->average_width); columns = (width - m) / (int32_t) terminal->average_width;
rows = (int32_t) round((height - m) / terminal->extents.height); rows = (height - m) / (int32_t) terminal->extents.height;
if (!window_is_fullscreen(terminal->window) && if (!window_is_fullscreen(terminal->window) &&
!window_is_maximized(terminal->window)) { !window_is_maximized(terminal->window)) {
@ -1125,9 +1123,9 @@ redraw_handler(struct widget *widget, void *data)
cairo_stroke(cr); cairo_stroke(cr);
} }
/* skip space glyph (RLE) we use as a placeholder of /* skip space glyph (RLE) we use as a placeholder of
the right half of a double-width character, the right half of a double-width character,
because RLE is not available in every font. */ because RLE is not available in every font. */
if (p_row[col].ch == 0x200B) if (p_row[col].ch == 0x200B)
continue; continue;
@ -1712,7 +1710,7 @@ handle_non_csi_escape(struct terminal *terminal, char code)
break; break;
case 'E': /* NEL - Newline */ case 'E': /* NEL - Newline */
terminal->column = 0; terminal->column = 0;
FALLTHROUGH; // fallthrough
case 'D': /* IND - Linefeed */ case 'D': /* IND - Linefeed */
terminal->row += 1; terminal->row += 1;
if (terminal->row > terminal->margin_bottom) { if (terminal->row > terminal->margin_bottom) {
@ -1894,7 +1892,7 @@ handle_special_char(struct terminal *terminal, char c)
if (terminal->mode & MODE_LF_NEWLINE) { if (terminal->mode & MODE_LF_NEWLINE) {
terminal->column = 0; terminal->column = 0;
} }
FALLTHROUGH; /* fallthrough */
case '\v': case '\v':
case '\f': case '\f':
terminal->row++; terminal->row++;
@ -2209,29 +2207,10 @@ data_source_cancelled(void *data, struct wl_data_source *source)
wl_data_source_destroy(source); wl_data_source_destroy(source);
} }
static void
data_source_dnd_drop_performed(void *data, struct wl_data_source *source)
{
}
static void
data_source_dnd_finished(void *data, struct wl_data_source *source)
{
}
static void
data_source_action(void *data,
struct wl_data_source *source, uint32_t dnd_action)
{
}
static const struct wl_data_source_listener data_source_listener = { static const struct wl_data_source_listener data_source_listener = {
data_source_target, data_source_target,
data_source_send, data_source_send,
data_source_cancelled, data_source_cancelled
data_source_dnd_drop_performed,
data_source_dnd_finished,
data_source_action
}; };
static const char text_mime_type[] = "text/plain;charset=utf-8"; static const char text_mime_type[] = "text/plain;charset=utf-8";
@ -2950,8 +2929,6 @@ terminal_create(struct display *display)
terminal->widget = window_frame_create(terminal->window, terminal); terminal->widget = window_frame_create(terminal->window, terminal);
terminal->title = xstrdup("Wayland Terminal"); terminal->title = xstrdup("Wayland Terminal");
window_set_title(terminal->window, terminal->title); window_set_title(terminal->window, terminal->title);
window_set_appid(terminal->window,
"org.freedesktop.weston.wayland-terminal");
widget_set_transparent(terminal->widget, 0); widget_set_transparent(terminal->widget, 0);
init_state_machine(&terminal->state_machine); init_state_machine(&terminal->state_machine);
@ -3024,22 +3001,13 @@ static void
terminal_destroy(struct terminal *terminal) terminal_destroy(struct terminal *terminal)
{ {
display_unwatch_fd(terminal->display, terminal->master); display_unwatch_fd(terminal->display, terminal->master);
close(terminal->master);
cairo_scaled_font_destroy(terminal->font_bold);
cairo_scaled_font_destroy(terminal->font_normal);
widget_destroy(terminal->widget);
window_destroy(terminal->window); window_destroy(terminal->window);
close(terminal->master);
wl_list_remove(&terminal->link); wl_list_remove(&terminal->link);
if (wl_list_empty(&terminal_list)) if (wl_list_empty(&terminal_list))
display_exit(terminal->display); display_exit(terminal->display);
free(terminal->data);
free(terminal->data_attr);
free(terminal->tab_ruler);
free(terminal->title); free(terminal->title);
free(terminal); free(terminal);
} }
@ -3058,12 +3026,10 @@ io_handler(struct task *task, uint32_t events)
} }
len = read(terminal->master, buffer, sizeof buffer); len = read(terminal->master, buffer, sizeof buffer);
if (len < 0) { if (len < 0)
terminal_destroy(terminal); terminal_destroy(terminal);
return; else
} terminal_data(terminal, buffer, len);
terminal_data(terminal, buffer, len);
} }
static int static int
@ -3101,16 +3067,12 @@ terminal_run(struct terminal *terminal, const char *path)
close(pipes[0]); close(pipes[0]);
setenv("TERM", option_term, 1); setenv("TERM", option_term, 1);
setenv("COLORTERM", option_term, 1); setenv("COLORTERM", option_term, 1);
sigaction(SIGPIPE, &oldact, NULL);
if (execl(path, path, NULL)) { if (execl(path, path, NULL)) {
printf("exec failed: %s\n", strerror(errno)); printf("exec failed: %m\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} else if (pid < 0) { } else if (pid < 0) {
fprintf(stderr, "failed to fork and create pty (%s).\n", fprintf(stderr, "failed to fork and create pty (%m).\n");
strerror(errno));
return -1; return -1;
} }
@ -3143,9 +3105,8 @@ static const struct weston_option terminal_options[] = {
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct display *d; struct display *d;
struct terminal *terminal, *tmp; struct terminal *terminal;
const char *config_file; const char *config_file;
struct sigaction sigpipe;
struct weston_config *config; struct weston_config *config;
struct weston_config_section *s; struct weston_config_section *s;
@ -3155,12 +3116,12 @@ int main(int argc, char *argv[])
option_shell = getenv("SHELL"); option_shell = getenv("SHELL");
if (!option_shell) if (!option_shell)
option_shell = "/bin/sh"; option_shell = "/bin/bash";
config_file = weston_config_get_name_from_env(); config_file = weston_config_get_name_from_env();
config = weston_config_parse(config_file); config = weston_config_parse(config_file);
s = weston_config_get_section(config, "terminal", NULL, NULL); s = weston_config_get_section(config, "terminal", NULL, NULL);
weston_config_section_get_string(s, "font", &option_font, "monospace"); weston_config_section_get_string(s, "font", &option_font, "mono");
weston_config_section_get_int(s, "font-size", &option_font_size, 14); weston_config_section_get_int(s, "font-size", &option_font_size, 14);
weston_config_section_get_string(s, "term", &option_term, "xterm"); weston_config_section_get_string(s, "term", &option_term, "xterm");
weston_config_destroy(config); weston_config_destroy(config);
@ -3176,20 +3137,9 @@ int main(int argc, char *argv[])
return 1; return 1;
} }
/* Disable SIGPIPE so that paste operations do not crash the program
* when the file descriptor provided to receive data is a pipe or
* socket whose reading end has been closed */
sigpipe.sa_handler = SIG_IGN;
sigemptyset(&sigpipe.sa_mask);
sigemptyset(&oldact.sa_mask);
sigpipe.sa_flags = 0;
sigaction(SIGPIPE, &sigpipe, &oldact);
d = display_create(&argc, argv); d = display_create(&argc, argv);
if (d == NULL) { if (d == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }
@ -3200,9 +3150,5 @@ int main(int argc, char *argv[])
display_run(d); display_run(d);
wl_list_for_each_safe(terminal, tmp, &terminal_list, link)
terminal_destroy(terminal);
display_destroy(d);
return 0; return 0;
} }

View file

@ -40,7 +40,7 @@
#include "clients/window.h" #include "clients/window.h"
#include "shared/helpers.h" #include "shared/helpers.h"
#include <libweston/matrix.h> #include "shared/matrix.h"
#include "weston-touch-calibration-client-protocol.h" #include "weston-touch-calibration-client-protocol.h"
@ -108,8 +108,8 @@ struct poly {
* cancel, multiple touch-downs) needs to undo the current sample and * cancel, multiple touch-downs) needs to undo the current sample and
* possibly show user feedback "wrong". * possibly show user feedback "wrong".
* *
* \<STATE\> * <STATE>
* - \<triggers\>: \<actions\> * - <triggers>: <actions>
* *
* IDLE * IDLE
* - touch down: sample, -> DOWN * - touch down: sample, -> DOWN
@ -330,9 +330,9 @@ compute_calibration(struct calibrator *cal, float *result)
*/ */
weston_matrix_init(&m); weston_matrix_init(&m);
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
m.M.col[0].el[i] = cal->samples[i].touched.x; m.d[i + 0] = cal->samples[i].touched.x;
m.M.col[1].el[i] = cal->samples[i].touched.y; m.d[i + 4] = cal->samples[i].touched.y;
m.M.col[2].el[i] = 1.0f; m.d[i + 8] = 1.0f;
} }
m.type = WESTON_MATRIX_TRANSFORM_OTHER; m.type = WESTON_MATRIX_TRANSFORM_OTHER;
@ -342,20 +342,20 @@ compute_calibration(struct calibrator *cal, float *result)
} }
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
x_calib.v.el[i] = cal->samples[i].drawn_cal.x; x_calib.f[i] = cal->samples[i].drawn_cal.x;
y_calib.v.el[i] = cal->samples[i].drawn_cal.y; y_calib.f[i] = cal->samples[i].drawn_cal.y;
} }
x_calib.v.el[3] = 0.0f; x_calib.f[3] = 0.0f;
y_calib.v.el[3] = 0.0f; y_calib.f[3] = 0.0f;
/* Multiples into the vector */ /* Multiples into the vector */
weston_matrix_transform(&inverse, &x_calib); weston_matrix_transform(&inverse, &x_calib);
weston_matrix_transform(&inverse, &y_calib); weston_matrix_transform(&inverse, &y_calib);
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
result[i] = x_calib.v.el[i]; result[i] = x_calib.f[i];
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
result[i + 3] = y_calib.v.el[i]; result[i + 3] = y_calib.f[i];
return 0; return 0;
} }
@ -557,8 +557,6 @@ calibrator_create(struct display *display, const char *match_name)
cal->widget = window_add_widget(cal->window, cal); cal->widget = window_add_widget(cal->window, cal);
window_inhibit_redraw(cal->window); window_inhibit_redraw(cal->window);
window_set_title(cal->window, "Touchscreen calibrator"); window_set_title(cal->window, "Touchscreen calibrator");
window_set_appid(cal->window,
"org.freedesktop.weston.touchscreen-calibrator");
cal->display = display; cal->display = display;
widget_set_redraw_handler(cal->widget, redraw_handler); widget_set_redraw_handler(cal->widget, redraw_handler);

View file

@ -29,7 +29,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include <errno.h>
#include <cairo.h> #include <cairo.h>
#include <linux/input.h> #include <linux/input.h>
@ -227,13 +226,11 @@ static void
usage(int error_code) usage(int error_code)
{ {
fprintf(stderr, "Usage: transformed [OPTIONS]\n\n" fprintf(stderr, "Usage: transformed [OPTIONS]\n\n"
" -d\t\tUse \"driver\" fullscreen method\n"
" -w <width>\tSet window width to <width>\n" " -w <width>\tSet window width to <width>\n"
" -h <height>\tSet window height to <height>\n" " -h <height>\tSet window height to <height>\n"
" --help\tShow this help text\n\n"); " --help\tShow this help text\n\n");
fprintf(stderr, "This version has been fixed for "
"https://gitlab.freedesktop.org/wayland/weston/issues/99 .\n");
exit(error_code); exit(error_code);
} }
@ -266,8 +263,7 @@ int main(int argc, char *argv[])
d = display_create(&argc, argv); d = display_create(&argc, argv);
if (d == NULL) { if (d == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }
@ -277,8 +273,6 @@ int main(int argc, char *argv[])
window_add_widget(transformed.window, &transformed); window_add_widget(transformed.window, &transformed);
window_set_title(transformed.window, "Transformed"); window_set_title(transformed.window, "Transformed");
window_set_appid(transformed.window,
"org.freedesktop.weston.transformed");
widget_set_transparent(transformed.widget, 0); widget_set_transparent(transformed.widget, 0);
widget_set_default_cursor(transformed.widget, CURSOR_BLANK); widget_set_default_cursor(transformed.widget, CURSOR_BLANK);

View file

@ -42,7 +42,7 @@
#include <wayland-client.h> #include <wayland-client.h>
#include "shared/helpers.h" #include "shared/helpers.h"
#include <libweston/zalloc.h> #include "shared/zalloc.h"
#include "weston-debug-client-protocol.h" #include "weston-debug-client-protocol.h"
struct debug_app { struct debug_app {
@ -135,7 +135,6 @@ stream_destroy(struct debug_stream *stream)
weston_debug_stream_v1_destroy(stream->obj); weston_debug_stream_v1_destroy(stream->obj);
wl_list_remove(&stream->link); wl_list_remove(&stream->link);
free(stream->desc);
free(stream->name); free(stream->name);
free(stream); free(stream);
} }
@ -277,8 +276,8 @@ setup_out_fd(const char *output, const char *outfd)
O_WRONLY | O_APPEND | O_CREAT, 0644); O_WRONLY | O_APPEND | O_CREAT, 0644);
if (fd < 0) { if (fd < 0) {
fprintf(stderr, fprintf(stderr,
"Error: opening file '%s' failed: %s\n", "Error: opening file '%s' failed: %m\n",
output, strerror(errno)); output);
} }
return fd; return fd;
} }
@ -291,8 +290,7 @@ setup_out_fd(const char *output, const char *outfd)
flags = fcntl(fd, F_GETFL); flags = fcntl(fd, F_GETFL);
if (flags == -1) { if (flags == -1) {
fprintf(stderr, fprintf(stderr,
"Error: cannot use file descriptor %d: %s\n", fd, "Error: cannot use file descriptor %d: %m\n", fd);
strerror(errno));
return -1; return -1;
} }
@ -434,8 +432,7 @@ main(int argc, char **argv)
app.dpy = wl_display_connect(NULL); app.dpy = wl_display_connect(NULL);
if (!app.dpy) { if (!app.dpy) {
fprintf(stderr, "Error: Could not connect to Wayland display: %s\n", fprintf(stderr, "Error: Could not connect to Wayland display: %m\n");
strerror(errno));
ret = 1; ret = 1;
goto out_parse; goto out_parse;
} }

1881
clients/weston-info.c Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -31,8 +31,8 @@
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include <wayland-client.h> #include <wayland-client.h>
#include <cairo.h> #include <cairo.h>
#include <libweston/config-parser.h> #include "shared/config-parser.h"
#include <libweston/zalloc.h> #include "shared/zalloc.h"
#include "shared/platform.h" #include "shared/platform.h"
struct window; struct window;
@ -40,8 +40,6 @@ struct widget;
struct display; struct display;
struct input; struct input;
struct output; struct output;
struct tablet;
struct tablet_tool;
struct task { struct task {
void (*run)(struct task *task, uint32_t events); void (*run)(struct task *task, uint32_t events);
@ -73,12 +71,12 @@ display_get_display(struct display *display);
int int
display_has_subcompositor(struct display *display); display_has_subcompositor(struct display *display);
cairo_device_t *
display_get_cairo_device(struct display *display);
struct wl_compositor * struct wl_compositor *
display_get_compositor(struct display *display); display_get_compositor(struct display *display);
struct wp_single_pixel_buffer_manager_v1 *
display_get_single_pixel_buffer_manager(struct display *display);
struct output * struct output *
display_get_output(struct display *display); display_get_output(struct display *display);
@ -116,11 +114,29 @@ display_set_output_configure_handler(struct display *display,
struct wl_data_source * struct wl_data_source *
display_create_data_source(struct display *display); display_create_data_source(struct display *display);
#ifdef EGL_NO_DISPLAY
EGLDisplay
display_get_egl_display(struct display *d);
EGLConfig
display_get_argb_egl_config(struct display *d);
int
display_acquire_window_surface(struct display *display,
struct window *window,
EGLContext ctx);
void
display_release_window_surface(struct display *display,
struct window *window);
#endif
#define SURFACE_OPAQUE 0x01 #define SURFACE_OPAQUE 0x01
#define SURFACE_SHM 0x02 #define SURFACE_SHM 0x02
#define SURFACE_HINT_RESIZE 0x10 #define SURFACE_HINT_RESIZE 0x10
#define SURFACE_HINT_RGB565 0x100
cairo_surface_t * cairo_surface_t *
display_create_surface(struct display *display, display_create_surface(struct display *display,
struct wl_surface *surface, struct wl_surface *surface,
@ -270,57 +286,6 @@ typedef void (*widget_axis_handler_t)(struct widget *widget,
uint32_t axis, uint32_t axis,
wl_fixed_t value, wl_fixed_t value,
void *data); void *data);
typedef int (*widget_tablet_tool_motion_handler_t)(struct widget *widget,
struct tablet_tool *tool,
float x, float y,
void *data);
typedef void (*widget_tablet_tool_down_handler_t)(struct widget *widget,
struct tablet_tool *tool,
void *data);
typedef void (*widget_tablet_tool_up_handler_t)(struct widget *widget,
struct tablet_tool *tool,
void *data);
typedef void (*widget_tablet_tool_pressure_handler_t)(struct widget *widget,
struct tablet_tool *tool,
uint32_t pressure,
void *data);
typedef void (*widget_tablet_tool_distance_handler_t)(struct widget *widget,
struct tablet_tool *tool,
uint32_t distance,
void *data);
typedef void (*widget_tablet_tool_tilt_handler_t)(struct widget *widget,
struct tablet_tool *tool,
int32_t tilt_x, int32_t tilt_y,
void *data);
typedef void (*widget_tablet_tool_rotation_handler_t)(struct widget *widget,
struct tablet_tool *tool,
int32_t rotation,
void *data);
typedef void (*widget_tablet_tool_slider_handler_t)(struct widget *widget,
struct tablet_tool *tool,
int32_t slider,
void *data);
typedef void (*widget_tablet_tool_wheel_handler_t)(struct widget *widget,
struct tablet_tool *tool,
wl_fixed_t degrees,
int32_t clicks,
void *data);
typedef void (*widget_tablet_tool_proximity_in_handler_t)(struct widget *widget,
struct tablet_tool *tool,
struct tablet *tablet,
void *data);
typedef void (*widget_tablet_tool_proximity_out_handler_t)(struct widget *widget,
struct tablet_tool *tool,
void *data);
typedef void (*widget_tablet_tool_button_handler_t)(struct widget *widget,
struct tablet_tool *tool,
uint32_t button,
uint32_t state,
void *data);
typedef void (*widget_tablet_tool_frame_handler_t)(struct widget *widget,
struct tablet_tool *tool,
uint32_t time,
void *data);
typedef void (*widget_pointer_frame_handler_t)(struct widget *widget, typedef void (*widget_pointer_frame_handler_t)(struct widget *widget,
struct input *input, struct input *input,
@ -453,6 +418,7 @@ struct wl_subsurface *
widget_get_wl_subsurface(struct widget *widget); widget_get_wl_subsurface(struct widget *widget);
enum window_buffer_type { enum window_buffer_type {
WINDOW_BUFFER_TYPE_EGL_WINDOW,
WINDOW_BUFFER_TYPE_SHM, WINDOW_BUFFER_TYPE_SHM,
}; };
@ -533,48 +499,23 @@ void
window_set_locked_pointer_motion_handler( window_set_locked_pointer_motion_handler(
struct window *window, window_locked_pointer_motion_handler_t handler); struct window *window, window_locked_pointer_motion_handler_t handler);
void
window_set_shadow(struct window *window);
void
window_unset_shadow(struct window *window);
void void
window_set_title(struct window *window, const char *title); window_set_title(struct window *window, const char *title);
void
window_set_appid(struct window *window, const char *appid);
const char * const char *
window_get_title(struct window *window); window_get_title(struct window *window);
const char *
window_get_appid(struct window *window);
void void
window_set_text_cursor_position(struct window *window, int32_t x, int32_t y); window_set_text_cursor_position(struct window *window, int32_t x, int32_t y);
enum render_intent { enum preferred_format {
RENDER_INTENT_PERCEPTUAL, WINDOW_PREFERRED_FORMAT_NONE,
RENDER_INTENT_RELATIVE, WINDOW_PREFERRED_FORMAT_RGB565
RENDER_INTENT_RELATIVE_BPC,
RENDER_INTENT_SATURATION,
RENDER_INTENT_ABSOLUTE,
}; };
struct render_intent_info { void
enum render_intent intent; window_set_preferred_format(struct window *window,
uint32_t protocol_intent; enum preferred_format format);
const char *desc;
};
const struct render_intent_info *
render_intent_info_from(enum render_intent intent);
bool
widget_set_image_description_icc(struct widget *widget, int icc_fd,
uint32_t length, uint32_t offset,
enum render_intent intent, char **err_msg);
int int
widget_set_tooltip(struct widget *parent, char *entry, float x, float y); widget_set_tooltip(struct widget *parent, char *entry, float x, float y);
@ -590,8 +531,6 @@ widget_destroy(struct widget *widget);
void void
widget_set_default_cursor(struct widget *widget, int cursor); widget_set_default_cursor(struct widget *widget, int cursor);
void void
widget_set_default_tablet_cursor(struct widget *widget, int cursor);
void
widget_get_allocation(struct widget *widget, struct rectangle *allocation); widget_get_allocation(struct widget *widget, struct rectangle *allocation);
void void
@ -613,9 +552,6 @@ widget_cairo_create(struct widget *widget);
struct wl_surface * struct wl_surface *
widget_get_wl_surface(struct widget *widget); widget_get_wl_surface(struct widget *widget);
void
widget_surface_flush(struct widget *widget);
uint32_t uint32_t
widget_get_last_time(struct widget *widget); widget_get_last_time(struct widget *widget);
@ -667,31 +603,6 @@ widget_set_axis_handlers(struct widget *widget,
widget_axis_source_handler_t axis_source_handler, widget_axis_source_handler_t axis_source_handler,
widget_axis_stop_handler_t axis_stop_handler, widget_axis_stop_handler_t axis_stop_handler,
widget_axis_discrete_handler_t axis_discrete_handler); widget_axis_discrete_handler_t axis_discrete_handler);
void
widget_set_tablet_tool_axis_handlers(struct widget *widget,
widget_tablet_tool_motion_handler_t motion,
widget_tablet_tool_pressure_handler_t pressure,
widget_tablet_tool_distance_handler_t distance,
widget_tablet_tool_tilt_handler_t tilt,
widget_tablet_tool_rotation_handler_t rotation,
widget_tablet_tool_slider_handler_t slider,
widget_tablet_tool_wheel_handler_t wheel);
void
widget_set_tablet_tool_up_handler(struct widget *widget,
widget_tablet_tool_up_handler_t handler);
void
widget_set_tablet_tool_down_handler(struct widget *widget,
widget_tablet_tool_down_handler_t handler);
void
widget_set_tablet_tool_proximity_handlers(struct widget *widget,
widget_tablet_tool_proximity_in_handler_t in_handler,
widget_tablet_tool_proximity_out_handler_t out_handler);
void
widget_set_tablet_tool_button_handler(struct widget *widget,
widget_tablet_tool_button_handler_t handler);
void
widget_set_tablet_tool_frame_handler(struct widget *widget,
widget_tablet_tool_frame_handler_t handler);
void void
window_inhibit_redraw(struct window *window); window_inhibit_redraw(struct window *window);
@ -702,14 +613,6 @@ widget_schedule_redraw(struct widget *widget);
void void
widget_set_use_cairo(struct widget *widget, int use_cairo); widget_set_use_cairo(struct widget *widget, int use_cairo);
/*
* Sets the viewport destination for the widget's surface
* return 0 on success and -1 on failure. Set width and height to
* -1 to reset the viewport.
*/
int
widget_set_viewport_destination(struct widget *widget, int width, int height);
struct widget * struct widget *
window_frame_create(struct window *window, void *data); window_frame_create(struct window *window, void *data);
@ -815,18 +718,6 @@ xkb_mod_mask_t
keysym_modifiers_get_mask(struct wl_array *modifiers_map, keysym_modifiers_get_mask(struct wl_array *modifiers_map,
const char *name); const char *name);
uint32_t
tablet_tool_get_type(struct tablet_tool *tool);
uint64_t
tablet_tool_get_serial(struct tablet_tool *tool);
uint64_t
tablet_tool_get_hwid(struct tablet_tool *tool);
void
tablet_tool_set_cursor_image(struct tablet_tool *tool, int cursor);
struct toytimer; struct toytimer;
typedef void (*toytimer_cb)(struct toytimer *); typedef void (*toytimer_cb)(struct toytimer *);

583
compositor/cms-colord.c Normal file
View file

@ -0,0 +1,583 @@
/*
* Copyright © 2013 Richard Hughes
*
* 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.
*/
#include "config.h"
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <colord.h>
#include "compositor.h"
#include "weston.h"
#include "cms-helper.h"
#include "shared/helpers.h"
struct cms_colord {
struct weston_compositor *ec;
CdClient *client;
GHashTable *devices; /* key = device-id, value = cms_output */
GHashTable *pnp_ids; /* key = pnp-id, value = vendor */
gchar *pnp_ids_data;
GMainLoop *loop;
GThread *thread;
GList *pending;
GMutex pending_mutex;
struct wl_event_source *source;
int readfd;
int writefd;
struct wl_listener destroy_listener;
struct wl_listener output_created_listener;
};
struct cms_output {
CdDevice *device;
guint32 backlight_value;
struct cms_colord *cms;
struct weston_color_profile *p;
struct weston_output *o;
struct wl_listener destroy_listener;
};
static gint
colord_idle_find_output_cb(gconstpointer a, gconstpointer b)
{
struct cms_output *ocms = (struct cms_output *) a;
struct weston_output *o = (struct weston_output *) b;
return ocms->o == o ? 0 : -1;
}
static void
colord_idle_cancel_for_output(struct cms_colord *cms, struct weston_output *o)
{
GList *l;
/* cancel and remove any helpers that match the output */
g_mutex_lock(&cms->pending_mutex);
l = g_list_find_custom (cms->pending, o, colord_idle_find_output_cb);
if (l) {
struct cms_output *ocms = l->data;
cms->pending = g_list_remove (cms->pending, ocms);
}
g_mutex_unlock(&cms->pending_mutex);
}
static bool
edid_value_valid(const char *str)
{
if (str == NULL)
return false;
if (str[0] == '\0')
return false;
if (strcmp(str, "unknown") == 0)
return false;
return true;
}
static gchar *
get_output_id(struct cms_colord *cms, struct weston_output *o)
{
struct weston_head *head;
const gchar *tmp;
GString *device_id;
/* XXX: What to do with multiple heads?
* This is potentially unstable, if head configuration is changed
* while the output is enabled. */
head = weston_output_get_first_head(o);
if (wl_list_length(&o->head_list) > 1) {
weston_log("colord: WARNING: multiple heads are not supported (output %s).\n",
o->name);
}
/* see https://github.com/hughsie/colord/blob/master/doc/device-and-profile-naming-spec.txt
* for format and allowed values */
device_id = g_string_new("xrandr");
if (edid_value_valid(head->make)) {
tmp = g_hash_table_lookup(cms->pnp_ids, head->make);
if (tmp == NULL)
tmp = head->make;
g_string_append_printf(device_id, "-%s", tmp);
}
if (edid_value_valid(head->model))
g_string_append_printf(device_id, "-%s", head->model);
if (edid_value_valid(head->serial_number))
g_string_append_printf(device_id, "-%s", head->serial_number);
/* no EDID data, so use fallback */
if (strcmp(device_id->str, "xrandr") == 0)
g_string_append_printf(device_id, "-drm-%i", o->id);
return g_string_free(device_id, FALSE);
}
static void
update_device_with_profile_in_idle(struct cms_output *ocms)
{
gboolean signal_write = FALSE;
ssize_t rc;
struct cms_colord *cms = ocms->cms;
colord_idle_cancel_for_output(cms, ocms->o);
g_mutex_lock(&cms->pending_mutex);
if (cms->pending == NULL)
signal_write = TRUE;
cms->pending = g_list_prepend(cms->pending, ocms);
g_mutex_unlock(&cms->pending_mutex);
/* signal we've got updates to do */
if (signal_write) {
gchar tmp = '\0';
rc = write(cms->writefd, &tmp, 1);
if (rc == 0)
weston_log("colord: failed to write to pending fd\n");
}
}
static void
colord_update_output_from_device (struct cms_output *ocms)
{
CdProfile *profile;
const gchar *tmp;
gboolean ret;
GError *error = NULL;
gint percentage;
/* old profile is no longer valid */
weston_cms_destroy_profile(ocms->p);
ocms->p = NULL;
ret = cd_device_connect_sync(ocms->device, NULL, &error);
if (!ret) {
weston_log("colord: failed to connect to device %s: %s\n",
cd_device_get_object_path (ocms->device),
error->message);
g_error_free(error);
goto out;
}
profile = cd_device_get_default_profile(ocms->device);
if (!profile) {
weston_log("colord: no assigned color profile for %s\n",
cd_device_get_id (ocms->device));
goto out;
}
ret = cd_profile_connect_sync(profile, NULL, &error);
if (!ret) {
weston_log("colord: failed to connect to profile %s: %s\n",
cd_profile_get_object_path (profile),
error->message);
g_error_free(error);
goto out;
}
/* get the calibration brightness level (only set for some profiles) */
tmp = cd_profile_get_metadata_item(profile, CD_PROFILE_METADATA_SCREEN_BRIGHTNESS);
if (tmp != NULL) {
percentage = atoi(tmp);
if (percentage > 0 && percentage <= 100)
ocms->backlight_value = percentage * 255 / 100;
}
ocms->p = weston_cms_load_profile(cd_profile_get_filename(profile));
if (ocms->p == NULL) {
weston_log("colord: warning failed to load profile %s: %s\n",
cd_profile_get_object_path (profile),
error->message);
g_error_free(error);
goto out;
}
out:
update_device_with_profile_in_idle(ocms);
}
static void
colord_device_changed_cb(CdDevice *device, struct cms_output *ocms)
{
weston_log("colord: device %s changed, update output\n",
cd_device_get_object_path (ocms->device));
colord_update_output_from_device(ocms);
}
static void
colord_notifier_output_destroy(struct wl_listener *listener, void *data)
{
struct cms_output *ocms =
container_of(listener, struct cms_output, destroy_listener);
struct weston_output *o = (struct weston_output *) data;
struct cms_colord *cms = ocms->cms;
gchar *device_id;
device_id = get_output_id(cms, o);
g_hash_table_remove (cms->devices, device_id);
g_free (device_id);
}
static void
colord_output_created(struct cms_colord *cms, struct weston_output *o)
{
struct weston_head *head;
CdDevice *device;
const gchar *tmp;
gchar *device_id;
GError *error = NULL;
GHashTable *device_props;
struct cms_output *ocms;
/* XXX: What to do with multiple heads? */
head = weston_output_get_first_head(o);
/* create device */
device_id = get_output_id(cms, o);
weston_log("colord: output added %s\n", device_id);
device_props = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, g_free);
g_hash_table_insert (device_props,
g_strdup(CD_DEVICE_PROPERTY_KIND),
g_strdup(cd_device_kind_to_string (CD_DEVICE_KIND_DISPLAY)));
g_hash_table_insert (device_props,
g_strdup(CD_DEVICE_PROPERTY_FORMAT),
g_strdup("ColorModel.OutputMode.OutputResolution"));
g_hash_table_insert (device_props,
g_strdup(CD_DEVICE_PROPERTY_COLORSPACE),
g_strdup(cd_colorspace_to_string(CD_COLORSPACE_RGB)));
if (edid_value_valid(head->make)) {
tmp = g_hash_table_lookup(cms->pnp_ids, head->make);
if (tmp == NULL)
tmp = head->make;
g_hash_table_insert (device_props,
g_strdup(CD_DEVICE_PROPERTY_VENDOR),
g_strdup(tmp));
}
if (edid_value_valid(head->model)) {
g_hash_table_insert (device_props,
g_strdup(CD_DEVICE_PROPERTY_MODEL),
g_strdup(head->model));
}
if (edid_value_valid(head->serial_number)) {
g_hash_table_insert (device_props,
g_strdup(CD_DEVICE_PROPERTY_SERIAL),
g_strdup(head->serial_number));
}
if (head->connection_internal) {
g_hash_table_insert (device_props,
g_strdup (CD_DEVICE_PROPERTY_EMBEDDED),
NULL);
}
device = cd_client_create_device_sync(cms->client,
device_id,
CD_OBJECT_SCOPE_TEMP,
device_props,
NULL,
&error);
if (g_error_matches (error,
CD_CLIENT_ERROR,
CD_CLIENT_ERROR_ALREADY_EXISTS)) {
g_clear_error(&error);
device = cd_client_find_device_sync (cms->client,
device_id,
NULL,
&error);
}
if (!device) {
weston_log("colord: failed to create new or "
"find existing device: %s\n",
error->message);
g_error_free(error);
goto out;
}
/* create object and watch for the output to be destroyed */
ocms = g_slice_new0(struct cms_output);
ocms->cms = cms;
ocms->o = o;
ocms->device = g_object_ref(device);
ocms->destroy_listener.notify = colord_notifier_output_destroy;
wl_signal_add(&o->destroy_signal, &ocms->destroy_listener);
/* add to local cache */
g_hash_table_insert (cms->devices, g_strdup(device_id), ocms);
g_signal_connect (ocms->device, "changed",
G_CALLBACK (colord_device_changed_cb), ocms);
/* get profiles */
colord_update_output_from_device (ocms);
out:
g_hash_table_unref (device_props);
if (device)
g_object_unref (device);
g_free (device_id);
}
static void
colord_notifier_output_created(struct wl_listener *listener, void *data)
{
struct weston_output *o = (struct weston_output *) data;
struct cms_colord *cms =
container_of(listener, struct cms_colord, destroy_listener);
weston_log("colord: output %s created\n", o->name);
colord_output_created(cms, o);
}
static gpointer
colord_run_loop_thread(gpointer data)
{
struct cms_colord *cms = (struct cms_colord *) data;
struct weston_output *o;
/* coldplug outputs */
wl_list_for_each(o, &cms->ec->output_list, link) {
weston_log("colord: output %s coldplugged\n", o->name);
colord_output_created(cms, o);
}
g_main_loop_run(cms->loop);
return NULL;
}
static int
colord_dispatch_all_pending(int fd, uint32_t mask, void *data)
{
gchar tmp;
GList *l;
ssize_t rc;
struct cms_colord *cms = data;
struct cms_output *ocms;
weston_log("colord: dispatching events\n");
g_mutex_lock(&cms->pending_mutex);
for (l = cms->pending; l != NULL; l = l->next) {
ocms = l->data;
/* optionally set backlight to calibration value */
if (ocms->o->set_backlight && ocms->backlight_value != 0) {
weston_log("colord: profile calibration backlight to %i/255\n",
ocms->backlight_value);
ocms->o->set_backlight(ocms->o, ocms->backlight_value);
}
weston_cms_set_color_profile(ocms->o, ocms->p);
}
g_list_free (cms->pending);
cms->pending = NULL;
g_mutex_unlock(&cms->pending_mutex);
/* done */
rc = read(cms->readfd, &tmp, 1);
if (rc == 0)
weston_log("colord: failed to read from pending fd\n");
return 1;
}
static void
colord_load_pnp_ids(struct cms_colord *cms)
{
gboolean ret = FALSE;
gchar *tmp;
GError *error = NULL;
guint i;
const gchar *pnp_ids_fn[] = { "/usr/share/hwdata/pnp.ids",
"/usr/share/misc/pnp.ids",
NULL };
/* find and load file */
for (i = 0; pnp_ids_fn[i] != NULL; i++) {
if (!g_file_test(pnp_ids_fn[i], G_FILE_TEST_EXISTS))
continue;
ret = g_file_get_contents(pnp_ids_fn[i],
&cms->pnp_ids_data,
NULL,
&error);
if (!ret) {
weston_log("colord: failed to load %s: %s\n",
pnp_ids_fn[i], error->message);
g_error_free(error);
return;
}
break;
}
if (!ret) {
weston_log("colord: no pnp.ids found\n");
return;
}
/* parse fixed offsets into lines */
tmp = cms->pnp_ids_data;
for (i = 0; cms->pnp_ids_data[i] != '\0'; i++) {
if (cms->pnp_ids_data[i] != '\n')
continue;
cms->pnp_ids_data[i] = '\0';
if (tmp[0] && tmp[1] && tmp[2] && tmp[3] == '\t' && tmp[4]) {
tmp[3] = '\0';
g_hash_table_insert(cms->pnp_ids, tmp, tmp+4);
tmp = &cms->pnp_ids_data[i+1];
}
}
}
static void
colord_module_destroy(struct cms_colord *cms)
{
if (cms->loop) {
g_main_loop_quit(cms->loop);
g_main_loop_unref(cms->loop);
}
if (cms->thread)
g_thread_join(cms->thread);
/* cms->devices must be destroyed before other resources, as
* the other resources are needed during output cleanup in
* cms->devices unref.
*/
if (cms->devices)
g_hash_table_unref(cms->devices);
if (cms->client)
g_object_unref(cms->client);
if (cms->readfd)
close(cms->readfd);
if (cms->writefd)
close(cms->writefd);
g_free(cms->pnp_ids_data);
g_hash_table_unref(cms->pnp_ids);
free(cms);
}
static void
colord_notifier_destroy(struct wl_listener *listener, void *data)
{
struct cms_colord *cms =
container_of(listener, struct cms_colord, destroy_listener);
colord_module_destroy(cms);
}
static void
colord_cms_output_destroy(gpointer data)
{
struct cms_output *ocms = (struct cms_output *) data;
struct cms_colord *cms = ocms->cms;
struct weston_output *o = ocms->o;
gboolean ret;
gchar *device_id;
GError *error = NULL;
colord_idle_cancel_for_output(cms, o);
device_id = get_output_id(cms, o);
weston_log("colord: output unplugged %s\n", device_id);
wl_list_remove(&ocms->destroy_listener.link);
g_signal_handlers_disconnect_by_data(ocms->device, ocms);
ret = cd_client_delete_device_sync (cms->client,
ocms->device,
NULL,
&error);
if (!ret) {
weston_log("colord: failed to delete device: %s\n",
error->message);
g_error_free(error);
}
g_object_unref(ocms->device);
g_slice_free(struct cms_output, ocms);
g_free (device_id);
}
WL_EXPORT int
wet_module_init(struct weston_compositor *ec,
int *argc, char *argv[])
{
gboolean ret;
GError *error = NULL;
int fd[2];
struct cms_colord *cms;
struct wl_event_loop *loop;
weston_log("colord: initialized\n");
/* create local state object */
cms = zalloc(sizeof *cms);
if (cms == NULL)
return -1;
cms->ec = ec;
#if !GLIB_CHECK_VERSION(2,36,0)
g_type_init();
#endif
cms->client = cd_client_new();
ret = cd_client_connect_sync(cms->client, NULL, &error);
if (!ret) {
weston_log("colord: failed to contact daemon: %s\n", error->message);
g_error_free(error);
colord_module_destroy(cms);
return -1;
}
g_mutex_init(&cms->pending_mutex);
cms->devices = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, colord_cms_output_destroy);
/* destroy */
cms->destroy_listener.notify = colord_notifier_destroy;
wl_signal_add(&ec->destroy_signal, &cms->destroy_listener);
/* devices added */
cms->output_created_listener.notify = colord_notifier_output_created;
wl_signal_add(&ec->output_created_signal, &cms->output_created_listener);
/* add all the PNP IDs */
cms->pnp_ids = g_hash_table_new_full(g_str_hash,
g_str_equal,
NULL,
NULL);
colord_load_pnp_ids(cms);
/* setup a thread for the GLib callbacks */
cms->loop = g_main_loop_new(NULL, FALSE);
cms->thread = g_thread_new("colord CMS main loop",
colord_run_loop_thread, cms);
/* batch device<->profile updates */
if (pipe2(fd, O_CLOEXEC) == -1) {
colord_module_destroy(cms);
return -1;
}
cms->readfd = fd[0];
cms->writefd = fd[1];
loop = wl_display_get_event_loop(ec->wl_display);
cms->source = wl_event_loop_add_fd (loop,
cms->readfd,
WL_EVENT_READABLE,
colord_dispatch_all_pending,
cms);
if (!cms->source) {
colord_module_destroy(cms);
return -1;
}
return 0;
}

136
compositor/cms-helper.c Normal file
View file

@ -0,0 +1,136 @@
/*
* Copyright © 2013 Richard Hughes
*
* 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.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#ifdef HAVE_LCMS
#include <lcms2.h>
#endif
#include "compositor.h"
#include "cms-helper.h"
#ifdef HAVE_LCMS
static void
weston_cms_gamma_clear(struct weston_output *o)
{
int i;
uint16_t *red;
if (!o->set_gamma)
return;
red = calloc(o->gamma_size, sizeof(uint16_t));
for (i = 0; i < o->gamma_size; i++)
red[i] = (uint32_t) 0xffff * (uint32_t) i / (uint32_t) (o->gamma_size - 1);
o->set_gamma(o, o->gamma_size, red, red, red);
free(red);
}
#endif
void
weston_cms_set_color_profile(struct weston_output *o,
struct weston_color_profile *p)
{
#ifdef HAVE_LCMS
cmsFloat32Number in;
const cmsToneCurve **vcgt;
int i;
int size;
uint16_t *red = NULL;
uint16_t *green = NULL;
uint16_t *blue = NULL;
if (!o->set_gamma)
return;
if (!p) {
weston_cms_gamma_clear(o);
return;
}
weston_log("Using ICC profile %s\n", p->filename);
vcgt = cmsReadTag (p->lcms_handle, cmsSigVcgtTag);
if (vcgt == NULL || vcgt[0] == NULL) {
weston_cms_gamma_clear(o);
return;
}
size = o->gamma_size;
red = calloc(size, sizeof(uint16_t));
green = calloc(size, sizeof(uint16_t));
blue = calloc(size, sizeof(uint16_t));
for (i = 0; i < size; i++) {
in = (cmsFloat32Number) i / (cmsFloat32Number) (size - 1);
red[i] = cmsEvalToneCurveFloat(vcgt[0], in) * (double) 0xffff;
green[i] = cmsEvalToneCurveFloat(vcgt[1], in) * (double) 0xffff;
blue[i] = cmsEvalToneCurveFloat(vcgt[2], in) * (double) 0xffff;
}
o->set_gamma(o, size, red, green, blue);
free(red);
free(green);
free(blue);
#endif
}
void
weston_cms_destroy_profile(struct weston_color_profile *p)
{
if (!p)
return;
#ifdef HAVE_LCMS
cmsCloseProfile(p->lcms_handle);
#endif
free(p->filename);
free(p);
}
struct weston_color_profile *
weston_cms_create_profile(const char *filename,
void *lcms_profile)
{
struct weston_color_profile *p;
p = zalloc(sizeof(struct weston_color_profile));
p->filename = strdup(filename);
p->lcms_handle = lcms_profile;
return p;
}
struct weston_color_profile *
weston_cms_load_profile(const char *filename)
{
struct weston_color_profile *p = NULL;
#ifdef HAVE_LCMS
cmsHPROFILE lcms_profile;
lcms_profile = cmsOpenProfileFromFile(filename, "r");
if (lcms_profile)
p = weston_cms_create_profile(filename, lcms_profile);
#endif
return p;
}

75
compositor/cms-helper.h Normal file
View file

@ -0,0 +1,75 @@
/*
* Copyright © 2013 Richard Hughes
*
* 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.
*/
#ifndef _WESTON_CMS_H_
#define _WESTON_CMS_H_
#include "config.h"
#include "compositor.h"
/* General overview on how to be a CMS plugin:
*
* First, some nomenclature:
*
* CMF: Color management framework, i.e. "Use foo.icc for device $bar"
* CMM: Color management module that converts pixel colors, which is
* usually lcms2 on any modern OS.
* CMS: Color management system that encompasses both a CMF and CMM.
* ICC: International Color Consortium, the people that define the
* binary encoding of a .icc file.
* VCGT: Video Card Gamma Tag. An Apple extension to the ICC specification
* that allows the calibration state to be stored in the ICC profile
* Output: Physical port with a display attached, e.g. LVDS1
*
* As a CMF is probably something you don't want or need on an embedded install
* these functions will not be called if the icc_profile key is set for a
* specific [output] section in weston.ini
*
* Most desktop environments want the CMF to decide what profile to use in
* different situations, so that displays can be profiled and also so that
* the ICC profiles can be changed at runtime depending on the task or ambient
* environment.
*
* The CMF can be selected using the 'modules' key in the [core] section.
*/
struct weston_color_profile {
char *filename;
void *lcms_handle;
};
void
weston_cms_set_color_profile(struct weston_output *o,
struct weston_color_profile *p);
struct weston_color_profile *
weston_cms_create_profile(const char *filename,
void *lcms_profile);
struct weston_color_profile *
weston_cms_load_profile(const char *filename);
void
weston_cms_destroy_profile(struct weston_color_profile *p);
#endif

119
compositor/cms-static.c Normal file
View file

@ -0,0 +1,119 @@
/*
* Copyright © 2013 Richard Hughes
*
* 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.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include "compositor.h"
#include "cms-helper.h"
#include "shared/helpers.h"
#include "weston.h"
struct cms_static {
struct weston_compositor *ec;
struct wl_listener destroy_listener;
struct wl_listener output_created_listener;
};
static void
cms_output_created(struct cms_static *cms, struct weston_output *o)
{
struct weston_color_profile *p;
struct weston_config_section *s;
char *profile;
weston_log("cms-static: output %i [%s] created\n", o->id, o->name);
if (o->name == NULL)
return;
s = weston_config_get_section(wet_get_config(cms->ec),
"output", "name", o->name);
if (s == NULL)
return;
if (weston_config_section_get_string(s, "icc_profile", &profile, NULL) < 0)
return;
p = weston_cms_load_profile(profile);
if (p == NULL && strlen(profile) > 0) {
weston_log("cms-static: failed to load %s\n", profile);
} else {
weston_log("cms-static: loading %s for %s\n",
(p != NULL) ? profile : "identity LUT",
o->name);
weston_cms_set_color_profile(o, p);
}
}
static void
cms_notifier_output_created(struct wl_listener *listener, void *data)
{
struct weston_output *o = (struct weston_output *) data;
struct cms_static *cms =
container_of(listener, struct cms_static, output_created_listener);
cms_output_created(cms, o);
}
static void
cms_module_destroy(struct cms_static *cms)
{
free(cms);
}
static void
cms_notifier_destroy(struct wl_listener *listener, void *data)
{
struct cms_static *cms = container_of(listener, struct cms_static, destroy_listener);
cms_module_destroy(cms);
}
WL_EXPORT int
wet_module_init(struct weston_compositor *ec,
int *argc, char *argv[])
{
struct cms_static *cms;
struct weston_output *output;
weston_log("cms-static: initialized\n");
/* create local state object */
cms = zalloc(sizeof *cms);
if (cms == NULL)
return -1;
cms->ec = ec;
cms->destroy_listener.notify = cms_notifier_destroy;
wl_signal_add(&ec->destroy_signal, &cms->destroy_listener);
cms->output_created_listener.notify = cms_notifier_output_created;
wl_signal_add(&ec->output_created_signal, &cms->output_created_listener);
/* discover outputs */
wl_list_for_each(output, &ec->output_list, link)
cms_output_created(cms, output);
return 0;
}

3185
compositor/main.c Normal file

File diff suppressed because it is too large Load diff

158
compositor/meson.build Normal file
View file

@ -0,0 +1,158 @@
srcs_weston = [
git_version_h,
'main.c',
'text-backend.c',
'weston-screenshooter.c',
text_input_unstable_v1_server_protocol_h,
text_input_unstable_v1_protocol_c,
input_method_unstable_v1_server_protocol_h,
input_method_unstable_v1_protocol_c,
weston_screenshooter_server_protocol_h,
weston_screenshooter_protocol_c,
]
deps_weston = [
dep_libshared,
dep_libweston,
dep_libinput,
dep_libevdev,
dep_libdl,
dep_threads,
]
if get_option('xwayland')
config_h.set('BUILD_XWAYLAND', '1')
srcs_weston += 'xwayland.c'
config_h.set_quoted('XSERVER_PATH', get_option('xwayland-path'))
endif
exe_weston = executable(
'weston',
srcs_weston,
include_directories: include_directories('..', '../shared'),
link_args: [ '-Wl,-export-dynamic' ],
dependencies: deps_weston,
install: true
)
install_headers('weston.h', subdir: 'weston')
pkgconfig.generate(
filebase: 'weston',
name: 'Weston Plugin API',
version: version_weston,
description: 'Header files for Weston plugin development',
requires_private: [ lib_weston ],
variables: [
'libexecdir=' + join_paths('${prefix}', get_option('libexecdir')),
'pkglibexecdir=${libexecdir}/weston'
],
subdirs: 'weston'
)
install_data(
'weston.desktop',
install_dir: join_paths(dir_data, 'wayland-sessions')
)
if get_option('screenshare')
srcs_screenshare = [
'screen-share.c',
fullscreen_shell_unstable_v1_client_protocol_h,
fullscreen_shell_unstable_v1_protocol_c,
]
deps_screenshare = [
dep_libweston,
dep_wayland_client,
]
plugin_screenshare = shared_library(
'screen-share',
srcs_screenshare,
include_directories: include_directories('..', '../shared'),
dependencies: deps_screenshare,
name_prefix: '',
install: true,
install_dir: dir_module_weston
)
env_modmap += 'screen-share.so=@0@;'.format(plugin_screenshare.full_path())
endif
if get_option('color-management-lcms')
config_h.set('HAVE_LCMS', '1')
srcs_lcms = [
'cms-static.c',
'cms-helper.c',
]
dep_lcms2 = dependency('lcms2', required: false)
if not dep_lcms2.found()
error('cms-static requires lcms2 which was not found. Or, you can use \'-Dcolor-management-lcms=false\'.')
endif
plugin_lcms = shared_library(
'cms-static',
srcs_lcms,
include_directories: include_directories('..', '../shared'),
dependencies: [ dep_libweston, dep_lcms2 ],
name_prefix: '',
install: true,
install_dir: dir_module_weston
)
env_modmap += 'cms-static.so=@0@;'.format(plugin_lcms.full_path())
endif
if get_option('color-management-colord')
if not get_option('color-management-lcms')
error('LCMS must be enabled to support colord')
endif
srcs_colord = [
'cms-colord.c',
'cms-helper.c',
]
dep_colord = dependency('colord', version: '>= 0.1.27', required: false)
if not dep_colord.found()
error('cms-colord requires colord >= 0.1.27 which was not found. Or, you can use \'-Dcolor-management-colord=false\'.')
endif
plugin_colord = shared_library(
'cms-colord',
srcs_colord,
include_directories: include_directories('..', '../shared'),
dependencies: [ dep_libweston, dep_colord ],
name_prefix: '',
install: true,
install_dir: dir_module_weston
)
env_modmap += 'cms-colord.so=@0@;'.format(plugin_colord.full_path())
endif
if get_option('systemd')
dep_libsystemd = dependency('libsystemd', required: false)
if not dep_libsystemd.found()
error('systemd-notify requires libsystemd which was not found. Or, you can use \'-Dsystemd=false\'.')
endif
plugin_systemd_notify = shared_library(
'systemd-notify',
'systemd-notify.c',
include_directories: include_directories('..', '../shared'),
dependencies: [ dep_libweston, dep_libsystemd ],
name_prefix: '',
install: true,
install_dir: dir_module_weston
)
env_modmap += 'systemd-notify.so=@0@;'.format(plugin_systemd_notify.full_path())
endif
weston_ini_config = configuration_data()
weston_ini_config.set('bindir', dir_bin)
weston_ini_config.set('libexecdir', dir_libexec)
weston_ini_config.set('abs_top_srcdir', meson.source_root())
weston_ini_config.set('abs_top_builddir', meson.build_root())
configure_file(
input: '../weston.ini.in',
output: 'weston.ini',
configuration: weston_ini_config
)

1142
compositor/screen-share.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -32,8 +32,8 @@
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/string-helpers.h" #include "shared/string-helpers.h"
#include <libweston/zalloc.h> #include "shared/zalloc.h"
#include <libweston/libweston.h> #include "compositor.h"
#include "weston.h" #include "weston.h"
struct systemd_notifier { struct systemd_notifier {
@ -127,12 +127,10 @@ wet_module_init(struct weston_compositor *compositor,
if (notifier == NULL) if (notifier == NULL)
return -1; return -1;
if (!weston_compositor_add_destroy_listener_once(compositor, notifier->compositor_destroy_listener.notify =
&notifier->compositor_destroy_listener, weston_compositor_destroy_listener;
weston_compositor_destroy_listener)) { wl_signal_add(&compositor->destroy_signal,
free(notifier); &notifier->compositor_destroy_listener);
return 0;
}
if (add_systemd_sockets(compositor) < 0) if (add_systemd_sockets(compositor) < 0)
return -1; return -1;

View file

@ -33,13 +33,12 @@
#include <unistd.h> #include <unistd.h>
#include <time.h> #include <time.h>
#include <libweston/libweston.h> #include "compositor.h"
#include "weston.h" #include "weston.h"
#include "text-input-unstable-v1-server-protocol.h" #include "text-input-unstable-v1-server-protocol.h"
#include "input-method-unstable-v1-server-protocol.h" #include "input-method-unstable-v1-server-protocol.h"
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/timespec-util.h" #include "shared/timespec-util.h"
#include "shared/xalloc.h"
struct text_input_manager; struct text_input_manager;
struct input_method; struct input_method;
@ -104,7 +103,6 @@ struct text_backend {
struct { struct {
char *path; char *path;
bool overlay_keyboard;
struct wl_client *client; struct wl_client *client;
unsigned deathcount; unsigned deathcount;
@ -142,12 +140,6 @@ deactivate_input_method(struct input_method *input_method)
input_method->input = NULL; input_method->input = NULL;
input_method->context = NULL; input_method->context = NULL;
/* text_input_manager::destroy_listener by compositor shutdown */
if (!text_input->manager) {
zwp_text_input_v1_send_leave(text_input->resource);
return;
}
if (wl_list_empty(&text_input->input_methods) && if (wl_list_empty(&text_input->input_methods) &&
text_input->input_panel_visible && text_input->input_panel_visible &&
text_input->manager->current_text_input == text_input) { text_input->manager->current_text_input == text_input) {
@ -413,7 +405,9 @@ static void text_input_manager_create_text_input(struct wl_client *client,
wl_resource_get_user_data(resource); wl_resource_get_user_data(resource);
struct text_input *text_input; struct text_input *text_input;
text_input = xzalloc(sizeof *text_input); text_input = zalloc(sizeof *text_input);
if (text_input == NULL)
return;
text_input->resource = text_input->resource =
wl_resource_create(client, &zwp_text_input_v1_interface, 1, id); wl_resource_create(client, &zwp_text_input_v1_interface, 1, id);
@ -461,8 +455,6 @@ text_input_manager_notifier_destroy(struct wl_listener *listener, void *data)
wl_list_remove(&text_input_manager->destroy_listener.link); wl_list_remove(&text_input_manager->destroy_listener.link);
wl_global_destroy(text_input_manager->text_input_manager_global); wl_global_destroy(text_input_manager->text_input_manager_global);
if (text_input_manager->current_text_input)
text_input_manager->current_text_input->manager = NULL;
free(text_input_manager); free(text_input_manager);
} }
@ -471,7 +463,9 @@ text_input_manager_create(struct weston_compositor *ec)
{ {
struct text_input_manager *text_input_manager; struct text_input_manager *text_input_manager;
text_input_manager = xzalloc(sizeof *text_input_manager); text_input_manager = zalloc(sizeof *text_input_manager);
if (text_input_manager == NULL)
return;
text_input_manager->ec = ec; text_input_manager->ec = ec;
@ -681,9 +675,6 @@ input_method_context_grab_keyboard(struct wl_client *client,
struct weston_seat *seat = context->input_method->seat; struct weston_seat *seat = context->input_method->seat;
struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat); struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
if (!keyboard)
return;
cr = wl_resource_create(client, &wl_keyboard_interface, 1, id); cr = wl_resource_create(client, &wl_keyboard_interface, 1, id);
wl_resource_set_implementation(cr, NULL, context, unbind_keyboard); wl_resource_set_implementation(cr, NULL, context, unbind_keyboard);
@ -811,7 +802,9 @@ input_method_context_create(struct text_input *input,
if (!input_method->input_method_binding) if (!input_method->input_method_binding)
return; return;
context = xzalloc(sizeof *context); context = zalloc(sizeof *context);
if (context == NULL)
return;
binding = input_method->input_method_binding; binding = input_method->input_method_binding;
context->resource = context->resource =
@ -856,9 +849,6 @@ unbind_input_method(struct wl_resource *resource)
{ {
struct input_method *input_method = wl_resource_get_user_data(resource); struct input_method *input_method = wl_resource_get_user_data(resource);
if (!input_method)
return;
input_method->input_method_binding = NULL; input_method->input_method_binding = NULL;
input_method->context = NULL; input_method->context = NULL;
} }
@ -906,12 +896,8 @@ input_method_notifier_destroy(struct wl_listener *listener, void *data)
if (input_method->input) if (input_method->input)
deactivate_input_method(input_method); deactivate_input_method(input_method);
if (input_method->input_method_binding)
wl_resource_set_user_data(input_method->input_method_binding, NULL);
wl_global_destroy(input_method->input_method_global); wl_global_destroy(input_method->input_method_global);
wl_list_remove(&input_method->destroy_listener.link); wl_list_remove(&input_method->destroy_listener.link);
input_method->seat->input_method = NULL;
free(input_method); free(input_method);
} }
@ -952,7 +938,7 @@ input_method_init_seat(struct weston_seat *seat)
seat->input_method->focus_listener_initialized = true; seat->input_method->focus_listener_initialized = true;
} }
static void launch_input_method(void *data); static void launch_input_method(struct text_backend *text_backend);
static void static void
respawn_input_method_process(struct text_backend *text_backend) respawn_input_method_process(struct text_backend *text_backend)
@ -988,28 +974,21 @@ input_method_client_notifier(struct wl_listener *listener, void *data)
client_listener); client_listener);
text_backend->input_method.client = NULL; text_backend->input_method.client = NULL;
respawn_input_method_process(text_backend);
if (!text_backend->compositor->shutting_down)
respawn_input_method_process(text_backend);
} }
static void static void
launch_input_method(void *data) launch_input_method(struct text_backend *text_backend)
{ {
struct text_backend *text_backend = data;
if (!text_backend->input_method.path) if (!text_backend->input_method.path)
return; return;
if (strcmp(text_backend->input_method.path, "") == 0) if (strcmp(text_backend->input_method.path, "") == 0)
return; return;
if (text_backend->input_method.overlay_keyboard)
setenv("WESTON_KEYBOARD_SURFACE_TYPE", "overlay", 1);
text_backend->input_method.client = text_backend->input_method.client =
wet_client_start(text_backend->compositor, weston_client_start(text_backend->compositor,
text_backend->input_method.path); text_backend->input_method.path);
if (!text_backend->input_method.client) { if (!text_backend->input_method.client) {
weston_log("not able to start %s\n", weston_log("not able to start %s\n",
@ -1029,7 +1008,9 @@ text_backend_seat_created(struct text_backend *text_backend,
struct input_method *input_method; struct input_method *input_method;
struct weston_compositor *ec = seat->compositor; struct weston_compositor *ec = seat->compositor;
input_method = xzalloc(sizeof *input_method); input_method = zalloc(sizeof *input_method);
if (input_method == NULL)
return;
input_method->seat = seat; input_method->seat = seat;
input_method->input = NULL; input_method->input = NULL;
@ -1072,9 +1053,6 @@ text_backend_configuration(struct text_backend *text_backend)
weston_config_section_get_string(section, "path", weston_config_section_get_string(section, "path",
&text_backend->input_method.path, &text_backend->input_method.path,
client); client);
weston_config_section_get_bool(section, "overlay-keyboard",
&text_backend->input_method.overlay_keyboard,
false);
free(client); free(client);
} }
@ -1098,9 +1076,10 @@ text_backend_init(struct weston_compositor *ec)
{ {
struct text_backend *text_backend; struct text_backend *text_backend;
struct weston_seat *seat; struct weston_seat *seat;
struct wl_event_loop *loop;
text_backend = xzalloc(sizeof(*text_backend)); text_backend = zalloc(sizeof(*text_backend));
if (text_backend == NULL)
return NULL;
text_backend->compositor = ec; text_backend->compositor = ec;
@ -1114,8 +1093,7 @@ text_backend_init(struct weston_compositor *ec)
text_input_manager_create(ec); text_input_manager_create(ec);
loop = wl_display_get_event_loop(ec->wl_display); launch_input_method(text_backend);
wl_event_loop_add_idle(loop, launch_input_method, text_backend);
return text_backend; return text_backend;
} }

View file

@ -0,0 +1,200 @@
/*
* Copyright © 2008-2011 Kristian Høgsberg
*
* 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.
*/
#include "config.h"
#include <stdint.h>
#include <linux/input.h>
#include "compositor.h"
#include "weston.h"
#include "weston-screenshooter-server-protocol.h"
#include "shared/helpers.h"
#include "weston-debug.h"
struct screenshooter {
struct weston_compositor *ec;
struct wl_global *global;
struct wl_client *client;
struct weston_process process;
struct wl_listener destroy_listener;
struct weston_recorder *recorder;
};
static void
screenshooter_done(void *data, enum weston_screenshooter_outcome outcome)
{
struct wl_resource *resource = data;
switch (outcome) {
case WESTON_SCREENSHOOTER_SUCCESS:
weston_screenshooter_send_done(resource);
break;
case WESTON_SCREENSHOOTER_NO_MEMORY:
wl_resource_post_no_memory(resource);
break;
default:
break;
}
}
static void
screenshooter_shoot(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *output_resource,
struct wl_resource *buffer_resource)
{
struct weston_output *output =
weston_head_from_resource(output_resource)->output;
struct weston_buffer *buffer =
weston_buffer_from_resource(buffer_resource);
if (buffer == NULL) {
wl_resource_post_no_memory(resource);
return;
}
weston_screenshooter_shoot(output, buffer, screenshooter_done, resource);
}
struct weston_screenshooter_interface screenshooter_implementation = {
screenshooter_shoot
};
static void
bind_shooter(struct wl_client *client,
void *data, uint32_t version, uint32_t id)
{
struct screenshooter *shooter = data;
struct wl_resource *resource;
bool debug_enabled =
weston_compositor_is_debug_protocol_enabled(shooter->ec);
resource = wl_resource_create(client,
&weston_screenshooter_interface, 1, id);
if (!debug_enabled && !shooter->client) {
wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
"screenshooter failed: permission denied. "\
"Debug protocol must be enabled");
return;
} else if (!debug_enabled && client != shooter->client) {
wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
"screenshooter failed: permission denied.");
return;
}
wl_resource_set_implementation(resource, &screenshooter_implementation,
data, NULL);
}
static void
screenshooter_sigchld(struct weston_process *process, int status)
{
struct screenshooter *shooter =
container_of(process, struct screenshooter, process);
shooter->client = NULL;
}
static void
screenshooter_binding(struct weston_keyboard *keyboard,
const struct timespec *time, uint32_t key, void *data)
{
struct screenshooter *shooter = data;
char *screenshooter_exe;
screenshooter_exe = wet_get_bindir_path("weston-screenshooter");
if (!screenshooter_exe) {
weston_log("Could not construct screenshooter path.\n");
return;
}
if (!shooter->client)
shooter->client = weston_client_launch(shooter->ec,
&shooter->process,
screenshooter_exe, screenshooter_sigchld);
free(screenshooter_exe);
}
static void
recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
uint32_t key, void *data)
{
struct weston_compositor *ec = keyboard->seat->compositor;
struct weston_output *output;
struct screenshooter *shooter = data;
struct weston_recorder *recorder = shooter->recorder;;
static const char filename[] = "capture.wcap";
if (recorder) {
weston_recorder_stop(recorder);
shooter->recorder = NULL;
} else {
if (keyboard->focus && keyboard->focus->output)
output = keyboard->focus->output;
else
output = container_of(ec->output_list.next,
struct weston_output, link);
shooter->recorder = weston_recorder_start(output, filename);
}
}
static void
screenshooter_destroy(struct wl_listener *listener, void *data)
{
struct screenshooter *shooter =
container_of(listener, struct screenshooter, destroy_listener);
wl_list_remove(&shooter->destroy_listener.link);
wl_global_destroy(shooter->global);
free(shooter);
}
WL_EXPORT void
screenshooter_create(struct weston_compositor *ec)
{
struct screenshooter *shooter;
shooter = zalloc(sizeof *shooter);
if (shooter == NULL)
return;
shooter->ec = ec;
shooter->global = wl_global_create(ec->wl_display,
&weston_screenshooter_interface, 1,
shooter, bind_shooter);
weston_compositor_add_key_binding(ec, KEY_S, MODIFIER_SUPER,
screenshooter_binding, shooter);
weston_compositor_add_key_binding(ec, KEY_R, MODIFIER_SUPER,
recorder_binding, shooter);
shooter->destroy_listener.notify = screenshooter_destroy;
wl_signal_add(&ec->destroy_signal, &shooter->destroy_listener);
}

View file

@ -30,44 +30,39 @@
extern "C" { extern "C" {
#endif #endif
#include <libweston/libweston.h> #include <compositor.h>
#include <libweston/config-parser.h>
void void
screenshooter_create(struct weston_compositor *ec); screenshooter_create(struct weston_compositor *ec);
struct wet_process; struct weston_process;
typedef void (*wet_process_cleanup_func_t)(struct wet_process *process, typedef void (*weston_process_cleanup_func_t)(struct weston_process *process,
int status, int status);
void *data);
struct wet_process { struct weston_process {
pid_t pid; pid_t pid;
char *path; weston_process_cleanup_func_t cleanup;
wet_process_cleanup_func_t cleanup;
void *cleanup_data;
struct wl_list link; struct wl_list link;
}; };
struct custom_env; struct wl_client *
weston_client_launch(struct weston_compositor *compositor,
struct wet_process * struct weston_process *proc,
wet_client_launch(struct weston_compositor *compositor, const char *path,
struct custom_env *custom_env, weston_process_cleanup_func_t cleanup);
int *fds_no_cloexec,
size_t num_fds_no_cloexec,
wet_process_cleanup_func_t cleanup,
void *cleanup_data);
struct wl_client * struct wl_client *
wet_client_start(struct weston_compositor *compositor, const char *path); weston_client_start(struct weston_compositor *compositor, const char *path);
void void
wet_process_destroy(struct wet_process *process, int status, bool call_cleanup); weston_watch_process(struct weston_process *process);
struct weston_config * struct weston_config *
wet_get_config(struct weston_compositor *compositor); wet_get_config(struct weston_compositor *compositor);
void *
wet_load_module_entrypoint(const char *name, const char *entrypoint);
int int
wet_shell_init(struct weston_compositor *ec, wet_shell_init(struct weston_compositor *ec,
int *argc, char *argv[]); int *argc, char *argv[]);
@ -88,12 +83,9 @@ wet_get_libexec_path(const char *name);
char * char *
wet_get_bindir_path(const char *name); wet_get_bindir_path(const char *name);
void * int
wet_load_xwayland(struct weston_compositor *comp); wet_load_xwayland(struct weston_compositor *comp);
void
wet_xwayland_destroy(struct weston_compositor *comp, void *data);
struct text_backend; struct text_backend;
struct text_backend * struct text_backend *
@ -102,15 +94,6 @@ text_backend_init(struct weston_compositor *ec);
void void
text_backend_destroy(struct text_backend *text_backend); text_backend_destroy(struct text_backend *text_backend);
/*
* Return value from wet_main() when
* weston_testsuite_quirks::required_capabilities are not met.
*/
#define WET_MAIN_RET_MISSING_CAPS 77
int
wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

12
compositor/weston.pc.in Normal file
View file

@ -0,0 +1,12 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
libexecdir=@libexecdir@
pkglibexecdir=${libexecdir}/@PACKAGE@
Name: Weston Plugin API
Description: Header files for Weston plugin development
Version: @WESTON_VERSION@
Requires.private: libweston-@LIBWESTON_MAJOR@
Cflags: -I${includedir}/weston

209
compositor/xwayland.c Normal file
View file

@ -0,0 +1,209 @@
/*
* Copyright © 2011 Intel Corporation
* Copyright © 2016 Giulio Camuffo
*
* 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.
*/
#include "config.h"
#include <signal.h>
#include <sys/socket.h>
#include "compositor.h"
#include "compositor/weston.h"
#include "xwayland/xwayland-api.h"
#include "shared/helpers.h"
struct wet_xwayland {
struct weston_compositor *compositor;
const struct weston_xwayland_api *api;
struct weston_xwayland *xwayland;
struct wl_event_source *sigusr1_source;
struct wl_client *client;
int wm_fd;
struct weston_process process;
};
static int
handle_sigusr1(int signal_number, void *data)
{
struct wet_xwayland *wxw = data;
/* We'd be safer if we actually had the struct
* signalfd_siginfo from the signalfd data and could verify
* this came from Xwayland.*/
wxw->api->xserver_loaded(wxw->xwayland, wxw->client, wxw->wm_fd);
wl_event_source_remove(wxw->sigusr1_source);
return 1;
}
static pid_t
spawn_xserver(void *user_data, const char *display, int abstract_fd, int unix_fd)
{
struct wet_xwayland *wxw = user_data;
pid_t pid;
char s[12], abstract_fd_str[12], unix_fd_str[12], wm_fd_str[12];
int sv[2], wm[2], fd;
char *xserver = NULL;
struct weston_config *config = wet_get_config(wxw->compositor);
struct weston_config_section *section;
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
weston_log("wl connection socketpair failed\n");
return 1;
}
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, wm) < 0) {
weston_log("X wm connection socketpair failed\n");
return 1;
}
pid = fork();
switch (pid) {
case 0:
/* SOCK_CLOEXEC closes both ends, so we need to unset
* the flag on the client fd. */
fd = dup(sv[1]);
if (fd < 0)
goto fail;
snprintf(s, sizeof s, "%d", fd);
setenv("WAYLAND_SOCKET", s, 1);
fd = dup(abstract_fd);
if (fd < 0)
goto fail;
snprintf(abstract_fd_str, sizeof abstract_fd_str, "%d", fd);
fd = dup(unix_fd);
if (fd < 0)
goto fail;
snprintf(unix_fd_str, sizeof unix_fd_str, "%d", fd);
fd = dup(wm[1]);
if (fd < 0)
goto fail;
snprintf(wm_fd_str, sizeof wm_fd_str, "%d", fd);
section = weston_config_get_section(config,
"xwayland", NULL, NULL);
weston_config_section_get_string(section, "path",
&xserver, XSERVER_PATH);
/* Ignore SIGUSR1 in the child, which will make the X
* server send SIGUSR1 to the parent (weston) when
* it's done with initialization. During
* initialization the X server will round trip and
* block on the wayland compositor, so avoid making
* blocking requests (like xcb_connect_to_fd) until
* it's done with that. */
signal(SIGUSR1, SIG_IGN);
if (execl(xserver,
xserver,
display,
"-rootless",
"-listen", abstract_fd_str,
"-listen", unix_fd_str,
"-wm", wm_fd_str,
"-terminate",
NULL) < 0)
weston_log("exec of '%s %s -rootless "
"-listen %s -listen %s -wm %s "
"-terminate' failed: %m\n",
xserver, display,
abstract_fd_str, unix_fd_str, wm_fd_str);
fail:
_exit(EXIT_FAILURE);
default:
close(sv[1]);
wxw->client = wl_client_create(wxw->compositor->wl_display, sv[0]);
close(wm[1]);
wxw->wm_fd = wm[0];
wxw->process.pid = pid;
weston_watch_process(&wxw->process);
break;
case -1:
weston_log("Failed to fork to spawn xserver process\n");
break;
}
return pid;
}
static void
xserver_cleanup(struct weston_process *process, int status)
{
struct wet_xwayland *wxw =
container_of(process, struct wet_xwayland, process);
struct wl_event_loop *loop =
wl_display_get_event_loop(wxw->compositor->wl_display);
wxw->api->xserver_exited(wxw->xwayland, status);
wxw->sigusr1_source = wl_event_loop_add_signal(loop, SIGUSR1,
handle_sigusr1, wxw);
wxw->client = NULL;
}
int
wet_load_xwayland(struct weston_compositor *comp)
{
const struct weston_xwayland_api *api;
struct weston_xwayland *xwayland;
struct wet_xwayland *wxw;
struct wl_event_loop *loop;
if (weston_compositor_load_xwayland(comp) < 0)
return -1;
api = weston_xwayland_get_api(comp);
if (!api) {
weston_log("Failed to get the xwayland module API.\n");
return -1;
}
xwayland = api->get(comp);
if (!xwayland) {
weston_log("Failed to get the xwayland object.\n");
return -1;
}
wxw = zalloc(sizeof *wxw);
if (!wxw)
return -1;
wxw->compositor = comp;
wxw->api = api;
wxw->xwayland = xwayland;
wxw->process.cleanup = xserver_cleanup;
if (api->listen(xwayland, wxw, spawn_xserver) < 0)
return -1;
loop = wl_display_get_event_loop(comp->wl_display);
wxw->sigusr1_source = wl_event_loop_add_signal(loop, SIGUSR1,
handle_sigusr1, wxw);
return 0;
}

793
configure.ac Normal file
View file

@ -0,0 +1,793 @@
m4_define([weston_major_version], [5])
m4_define([weston_minor_version], [0])
m4_define([weston_micro_version], [92])
m4_define([weston_version],
[weston_major_version.weston_minor_version.weston_micro_version])
m4_define([libweston_major_version], [6])
m4_define([libweston_minor_version], [0])
m4_define([libweston_patch_version], [0])
AC_PREREQ([2.64])
AC_INIT([weston],
[weston_version],
[https://gitlab.freedesktop.org/wayland/weston/issues/],
[weston],
[https://wayland.freedesktop.org])
WAYLAND_PREREQ_VERSION="1.12.0"
AC_SUBST([WESTON_VERSION_MAJOR], [weston_major_version])
AC_SUBST([WESTON_VERSION_MINOR], [weston_minor_version])
AC_SUBST([WESTON_VERSION_MICRO], [weston_micro_version])
AC_SUBST([WESTON_VERSION], [weston_version])
AC_SUBST([LIBWESTON_MAJOR], [libweston_major_version])
# We use minor as current and age since on ABI/API break/removal we bump major
# so minor will be reset to 0.
m4_define([lt_current], [libweston_minor_version])
m4_define([lt_revision], [libweston_patch_version])
m4_define([lt_age], [libweston_minor_version])
AC_SUBST([LT_VERSION_INFO], [lt_current:lt_revision:lt_age])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
AC_USE_SYSTEM_EXTENSIONS
AC_SYS_LARGEFILE
save_CFLAGS="$CFLAGS"
export CFLAGS="$CFLAGS -Werror"
AC_HEADER_MAJOR
CFLAGS="$save_CFLAGS"
AM_INIT_AUTOMAKE([1.11 parallel-tests foreign no-dist-gzip dist-xz color-tests subdir-objects])
AM_SILENT_RULES([yes])
# Check Weston and libweston version consistency
m4_if(m4_cmp(weston_micro_version, [90]), [-1],
[
dnl micro < 90
dnl A final or stable release, not a pre-release:
dnl Weston and libweston versions must match.
m4_if(weston_version, libweston_major_version[.]libweston_minor_version[.]libweston_patch_version,
[],
[AC_MSG_ERROR([Weston and libweston version mismatch for a final release])])
],
[
dnl A pre-release:
dnl libweston must be equal or greater than weston.
m4_case(m4_list_cmp([weston_major_version, weston_minor_version, weston_micro_version],
[libweston_major_version, libweston_minor_version, libweston_patch_version]),
[-1], [
dnl weston < libweston
dnl libweston must be weston_major+1.0.0
m4_if(m4_eval(weston_major_version+1)[.0.0],
libweston_major_version[.]libweston_minor_version[.]libweston_patch_version,
[],
[AC_MSG_ERROR([libweston version is greater but not (weston_major+1).0.0])])
],
[0], [
dnl weston == libweston, all ok
],
[1], [
dnl weston > libweston, wrong
AC_MSG_ERROR([Weston version is greater than libweston.])
])
])
# Check for programs
AC_PROG_CC
AC_PROG_SED
# Initialize libtool
LT_PREREQ([2.2])
LT_INIT([disable-static])
AC_ARG_ENABLE(autotools,
AS_HELP_STRING([--enable-autotools],
[Allow building with autotools]),,
enable_autotools=no)
if test "x$enable_autotools" = "xno"; then
AC_ERROR([
*** Autotools support will be removed after the 6.0.0 release ***
Please, try the Meson based build and report any problems you might have
with it. Instructions and references can be found in README.md.
If you still want to continue building with autotools,
use --enable-autotools configure option.
])
fi
AC_ARG_VAR([WESTON_NATIVE_BACKEND],
[Set the native backend to use, if Weston is not running under Wayland nor X11. @<:@default=drm-backend.so@:>@])
AC_ARG_VAR([WESTON_SHELL_CLIENT],
[Set the default desktop shell client to load if none is specified in weston.ini. @<:@default=weston-desktop-shell@:>@])
PKG_PROG_PKG_CONFIG()
# Check pthread
AX_PTHREAD
# Check for dlsym instead of dlopen because ASAN hijacks the latter
WESTON_SEARCH_LIBS([DL], [dl], [dlsym])
# In old glibc versions (< 2.17) clock_gettime() and clock_getres() are in librt
WESTON_SEARCH_LIBS([CLOCK_GETTIME], [rt], [clock_gettime])
WESTON_SEARCH_LIBS([CLOCK_GETRES], [rt], [clock_getres])
AC_CHECK_DECL(SFD_CLOEXEC,[],
[AC_MSG_ERROR("SFD_CLOEXEC is needed to compile weston")],
[[#include <sys/signalfd.h>]])
AC_CHECK_DECL(TFD_CLOEXEC,[],
[AC_MSG_ERROR("TFD_CLOEXEC is needed to compile weston")],
[[#include <sys/timerfd.h>]])
AC_CHECK_DECL(CLOCK_MONOTONIC,[],
[AC_MSG_ERROR("CLOCK_MONOTONIC is needed to compile weston")],
[[#include <time.h>]])
AC_CHECK_FUNCS([mkostemp strchrnul initgroups posix_fallocate])
# check for libdrm as a build-time dependency only
# libdrm 2.4.30 introduced drm_fourcc.h.
PKG_CHECK_MODULES(LIBDRM, [libdrm >= 2.4.68], [], [AC_MSG_ERROR([
libdrm is a hard build-time dependency for libweston core,
but a sufficient version was not found. However, libdrm
is not a runtime dependency unless you have features
enabled that require it.])])
COMPOSITOR_MODULES="wayland-server >= $WAYLAND_PREREQ_VERSION pixman-1 >= 0.25.2"
AC_CONFIG_FILES([doc/doxygen/tools.doxygen doc/doxygen/tooldev.doxygen])
AC_ARG_ENABLE(devdocs,
AS_HELP_STRING([--disable-devdocs],
[do not enable building of developer documentation]),,
enable_devdocs=auto)
if test "x$enable_devdocs" != "xno"; then
AC_CHECK_PROGS([DOXYGEN], [doxygen])
if test "x$DOXYGEN" = "x" -a "x$enable_devdocs" = "xyes"; then
AC_MSG_ERROR([Developer documentation explicitly requested, but Doxygen couldn't be found])
fi
if test "x$DOXYGEN" != "x"; then
enable_devdocs=yes
else
enable_devdocs=no
fi
fi
AM_CONDITIONAL(ENABLE_DEVDOCS, test "x$enable_devdocs" = "xyes")
AC_ARG_ENABLE(egl, [ --disable-egl],,
enable_egl=yes)
AM_CONDITIONAL(ENABLE_EGL, test x$enable_egl = xyes)
if test x$enable_egl = xyes; then
AC_DEFINE([ENABLE_EGL], [1], [Build Weston with EGL support])
PKG_CHECK_MODULES(EGL, [egl glesv2])
AC_CHECK_HEADERS([linux/sync_file.h])
fi
COMPOSITOR_MODULES="$COMPOSITOR_MODULES xkbcommon >= 0.3.0"
PKG_CHECK_MODULES(XKBCOMMON_COMPOSE, [xkbcommon >= 0.5.0],
[AC_DEFINE(HAVE_XKBCOMMON_COMPOSE, 1,
[Define if xkbcommon is 0.5.0 or newer])],true)
AC_ARG_ENABLE(setuid-install, [ --enable-setuid-install],,
enable_setuid_install=yes)
AM_CONDITIONAL(ENABLE_SETUID_INSTALL, test x$enable_setuid_install = xyes)
AC_ARG_ENABLE(xwayland, [ --enable-xwayland],,
enable_xwayland=yes)
AC_ARG_ENABLE(xwayland-test, [ --enable-xwayland-test],,
enable_xwayland_test=yes)
AM_CONDITIONAL(ENABLE_XWAYLAND, test x$enable_xwayland = xyes)
AM_CONDITIONAL(ENABLE_XWAYLAND_TEST, test x$enable_xwayland = xyes -a x$enable_xwayland_test = xyes)
if test x$enable_xwayland = xyes; then
PKG_CHECK_MODULES([XWAYLAND], xcb xcb-xfixes xcb-composite xcb-shape xcursor cairo-xcb)
AC_DEFINE([BUILD_XWAYLAND], [1], [Build the X server launcher])
AC_ARG_WITH(xserver-path, AS_HELP_STRING([--with-xserver-path=PATH],
[Path to X server]), [XSERVER_PATH="$withval"],
[XSERVER_PATH="/usr/bin/Xwayland"])
AC_SUBST([XSERVER_PATH])
if test x$enable_xwayland_test = xyes; then
PKG_CHECK_MODULES([XWAYLAND_TEST], x11)
fi
fi
AC_ARG_ENABLE(x11-compositor, [ --enable-x11-compositor],,
enable_x11_compositor=yes)
AM_CONDITIONAL(ENABLE_X11_COMPOSITOR, test x$enable_x11_compositor = xyes)
have_xcb_xkb=no
if test x$enable_x11_compositor = xyes; then
PKG_CHECK_MODULES([XCB], xcb >= 1.8)
X11_COMPOSITOR_MODULES="x11 x11-xcb xcb-shm"
PKG_CHECK_MODULES(X11_COMPOSITOR_XKB, [xcb-xkb >= 1.9],
[have_xcb_xkb="yes"], [have_xcb_xkb="no"])
if test "x$have_xcb_xkb" = xyes; then
X11_COMPOSITOR_MODULES="$X11_COMPOSITOR_MODULES xcb-xkb"
AC_DEFINE([HAVE_XCB_XKB], [1], [libxcb supports XKB protocol])
fi
PKG_CHECK_MODULES(X11_COMPOSITOR, [$X11_COMPOSITOR_MODULES])
AC_DEFINE([BUILD_X11_COMPOSITOR], [1], [Build the X11 compositor])
fi
AC_ARG_ENABLE(drm-compositor, [ --enable-drm-compositor],,
enable_drm_compositor=yes)
AM_CONDITIONAL(ENABLE_DRM_COMPOSITOR, test x$enable_drm_compositor = xyes)
if test x$enable_drm_compositor = xyes; then
AC_DEFINE([BUILD_DRM_COMPOSITOR], [1], [Build the DRM compositor])
PKG_CHECK_MODULES(DRM_COMPOSITOR, [libudev >= 136 libdrm >= 2.4.30 gbm])
PKG_CHECK_MODULES(DRM_COMPOSITOR_MODIFIERS, [libdrm >= 2.4.71],
[AC_DEFINE([HAVE_DRM_ADDFB2_MODIFIERS], 1, [libdrm supports modifiers])],
[AC_MSG_WARN([libdrm does not support AddFB2 with modifiers])])
PKG_CHECK_MODULES(DRM_COMPOSITOR_ATOMIC, [libdrm >= 2.4.78],
[AC_DEFINE([HAVE_DRM_ATOMIC], 1, [libdrm supports atomic API])],
[AC_MSG_WARN([libdrm does not support atomic modesetting, will omit that capability])])
PKG_CHECK_MODULES(DRM_COMPOSITOR_FORMATS_BLOB, [libdrm >= 2.4.83],
[AC_DEFINE([HAVE_DRM_FORMATS_BLOB], 1, [libdrm supports modifier advertisement])],
[AC_MSG_WARN([libdrm does not support modifier advertisement])])
PKG_CHECK_MODULES(DRM_COMPOSITOR_GBM_MODIFIERS, [gbm >= 17.1],
[AC_DEFINE([HAVE_GBM_MODIFIERS], 1, [GBM supports modifiers])],
[AC_MSG_WARN([GBM does not support modifiers])])
PKG_CHECK_MODULES(DRM_COMPOSITOR_GBM, [gbm >= 17.2],
[AC_DEFINE([HAVE_GBM_FD_IMPORT], 1, [gbm supports import with modifiers])],
[AC_MSG_WARN([GBM does not support dmabuf import, will omit that capability])])
fi
AC_ARG_ENABLE(remoting, [ --enable-remoting],,
enable_remoting=no)
AM_CONDITIONAL(ENABLE_REMOTING, test x$enable_remoting = xyes)
if test x$enable_remoting = xyes; then
if test x$enable_drm_compositor != xyes; then
AC_MSG_WARN([The remoting-plugin.so module requires the DRM backend.])
fi
PKG_CHECK_MODULES(REMOTING_GST, [gstreamer-1.0 gstreamer-allocators-1.0 gstreamer-app-1.0 gstreamer-video-1.0])
fi
PKG_CHECK_MODULES(LIBEVDEV, [libevdev])
PKG_CHECK_MODULES(LIBINPUT_BACKEND, [libinput >= 0.8.0])
PKG_CHECK_MODULES(COMPOSITOR, [$COMPOSITOR_MODULES])
# XXX: For minor version 2 of zwp_linux_explicit_synchronization_v1, we
# actually need a development version after 1.17, but there is no way to
# express such a requirement at the moment.
PKG_CHECK_MODULES(WAYLAND_PROTOCOLS, [wayland-protocols >= 1.17],
[ac_wayland_protocols_pkgdatadir=`$PKG_CONFIG --variable=pkgdatadir wayland-protocols`])
AC_SUBST(WAYLAND_PROTOCOLS_DATADIR, $ac_wayland_protocols_pkgdatadir)
AC_ARG_ENABLE(wayland-compositor, [ --enable-wayland-compositor],,
enable_wayland_compositor=yes)
AM_CONDITIONAL(ENABLE_WAYLAND_COMPOSITOR,
test x$enable_wayland_compositor = xyes)
if test x$enable_wayland_compositor = xyes; then
AC_DEFINE([BUILD_WAYLAND_COMPOSITOR], [1],
[Build the Wayland (nested) compositor])
PKG_CHECK_MODULES(WAYLAND_COMPOSITOR, [wayland-client >= $WAYLAND_PREREQ_VERSION wayland-cursor])
if test x$enable_egl = xyes; then
PKG_CHECK_MODULES(WAYLAND_COMPOSITOR_EGL, [wayland-egl])
fi
fi
AC_ARG_ENABLE(headless-compositor, [ --enable-headless-compositor],,
enable_headless_compositor=yes)
AM_CONDITIONAL(ENABLE_HEADLESS_COMPOSITOR,
test x$enable_headless_compositor = xyes)
if test x$enable_headless_compositor = xyes; then
AC_DEFINE([BUILD_HEADLESS_COMPOSITOR], [1], [Build the headless compositor])
fi
AC_ARG_ENABLE([fbdev-compositor], [ --enable-fbdev-compositor],,
enable_fbdev_compositor=yes)
AM_CONDITIONAL([ENABLE_FBDEV_COMPOSITOR],
[test x$enable_fbdev_compositor = xyes])
AS_IF([test x$enable_fbdev_compositor = xyes], [
AC_DEFINE([BUILD_FBDEV_COMPOSITOR], [1], [Build the fbdev compositor])
PKG_CHECK_MODULES([FBDEV_COMPOSITOR], [libudev >= 136])
])
AC_ARG_ENABLE([rdp-compositor], [ --enable-rdp-compositor],,
enable_rdp_compositor=no)
AM_CONDITIONAL([ENABLE_RDP_COMPOSITOR],
[test x$enable_rdp_compositor = xyes])
if test x$enable_rdp_compositor = xyes; then
AC_DEFINE([BUILD_RDP_COMPOSITOR], [1], [Build the RDP compositor])
PKG_CHECK_MODULES(RDP_COMPOSITOR, [freerdp2 >= 2.0.0],
[],
[PKG_CHECK_MODULES(RDP_COMPOSITOR, [freerdp >= 1.1.0],[])]
)
SAVED_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $RDP_COMPOSITOR_CFLAGS"
AC_CHECK_HEADERS([freerdp/version.h])
AC_CHECK_MEMBER([SURFACE_BITS_COMMAND.bmp],
[AC_DEFINE([HAVE_SURFACE_BITS_BMP], [1], [SURFACE_BITS_CMD has bmp field])],
[],
[[#include <freerdp/update.h>]]
)
CPPFLAGS="$SAVED_CPPFLAGS"
fi
AC_ARG_ENABLE([screen-sharing], [ --enable-screen-sharing],,
enable_screen_sharing=no)
AM_CONDITIONAL([ENABLE_SCREEN_SHARING],
[test x$enable_screen_sharing = xyes])
if test x$enable_screen_sharing = xyes; then
PKG_CHECK_MODULES(SCREEN_SHARE, [wayland-client])
if test x$enable_rdp_compositor != xyes; then
AC_MSG_WARN([The screen-share.so module requires the RDP backend.])
fi
fi
AC_ARG_WITH(cairo,
AS_HELP_STRING([--with-cairo=@<:@image|gl|glesv2@:>@]
[Which Cairo renderer to use for the clients]),
[],[with_cairo="image"])
if test "x$with_cairo" = "ximage"; then
cairo_modules="cairo"
else
if test "x$with_cairo" = "xgl"; then
cairo_modules="cairo-gl"
AC_MSG_WARN([The --with-cairo=gl option can cause increased resource usage and potential instability, and thus is not recommended. It is needed only for a few special demo programs.])
else
if test "x$with_cairo" = "xglesv2"; then
cairo_modules="cairo-glesv2"
AC_MSG_WARN([The --with-cairo=gles2 option can cause increased resource usage and potential instability, and thus is not recommended. It is needed only for a few special demo programs.])
else
AC_ERROR([Unknown cairo renderer requested])
fi
fi
fi
# Included for legacy compat
AC_ARG_WITH(cairo-glesv2,
AS_HELP_STRING([--with-cairo-glesv2],
[Use GLESv2 cairo]))
if test "x$with_cairo_glesv2" = "xyes"; then
cairo_modules="cairo-glesv2"
with_cairo="glesv2"
fi
if test "x$cairo_modules" = "xcairo-glesv2"; then
AC_DEFINE([USE_CAIRO_GLESV2], [1], [Use the GLESv2 GL cairo backend])
fi
PKG_CHECK_MODULES(PIXMAN, [pixman-1])
PKG_CHECK_MODULES(PNG, [libpng])
AC_ARG_WITH([jpeg],
AS_HELP_STRING([--without-jpeg],
[Use jpeglib for JPEG decoding support [default=auto]]))
AS_IF([test "x$with_jpeg" != "xno"],
[WESTON_SEARCH_LIBS([JPEG], [jpeg], [jpeg_CreateDecompress], [have_jpeglib=yes], [have_jpeglib=no])],
[have_jpeglib=no])
AS_IF([test "x$have_jpeglib" = "xyes"],
[AC_DEFINE([HAVE_JPEG], [1], [Have jpeglib])],
[AS_IF([test "x$with_jpeg" = "xyes"],
[AC_MSG_ERROR([JPEG support explicitly requested, but jpeglib couldn't be found])])])
AC_ARG_WITH([webp],
AS_HELP_STRING([--without-webp],
[Use libwebp for WebP decoding support [default=auto]]))
AS_IF([test "x$with_webp" != "xno"],
[PKG_CHECK_MODULES(WEBP, [libwebp], [have_webp=yes], [have_webp=no])],
[have_webp=no])
AS_IF([test "x$have_webp" = "xyes"],
[AC_DEFINE([HAVE_WEBP], [1], [Have webp])],
[AS_IF([test "x$with_webp" = "xyes"],
[AC_MSG_ERROR([WebP support explicitly requested, but libwebp couldn't be found])])])
AC_ARG_ENABLE(vaapi-recorder, [ --enable-vaapi-recorder],,
enable_vaapi_recorder=auto)
have_libva=no
if test x$enable_vaapi_recorder != xno; then
PKG_CHECK_MODULES(LIBVA, [libva >= 0.34.0 libva-drm >= 0.34.0],
[have_libva=yes], [have_libva=no])
if test "x$have_libva" = "xno" -a "x$enable_vaapi_recorder" = "xyes"; then
AC_MSG_ERROR([vaapi-recorder explicitly enabled, but libva couldn't be found])
fi
AS_IF([test "x$have_libva" = "xyes"],
[AC_DEFINE([BUILD_VAAPI_RECORDER], [1], [Build the vaapi recorder])])
fi
AM_CONDITIONAL(ENABLE_VAAPI_RECORDER, test "x$have_libva" = xyes)
PKG_CHECK_MODULES(CAIRO, [cairo])
PKG_CHECK_MODULES(TEST_CLIENT, [wayland-client >= $WAYLAND_PREREQ_VERSION pixman-1])
AC_ARG_ENABLE(simple-clients,
AS_HELP_STRING([--disable-simple-clients],
[do not build the simple wl_shm clients]),,
enable_simple_clients=yes)
AM_CONDITIONAL(BUILD_SIMPLE_CLIENTS, test "x$enable_simple_clients" = "xyes")
if test x$enable_simple_clients = xyes; then
PKG_CHECK_MODULES(SIMPLE_CLIENT, [wayland-client])
fi
AC_ARG_ENABLE(simple-egl-clients,
AS_HELP_STRING([--disable-simple-egl-clients],
[do not build the simple EGL clients]),,
enable_simple_egl_clients="$enable_egl")
AM_CONDITIONAL(BUILD_SIMPLE_EGL_CLIENTS, test "x$enable_simple_egl_clients" = "xyes")
if test x$enable_simple_egl_clients = xyes; then
PKG_CHECK_MODULES(SIMPLE_EGL_CLIENT,
[egl glesv2 wayland-client wayland-egl wayland-cursor])
fi
AC_ARG_ENABLE(simple-dmabuf-drm-client,
AS_HELP_STRING([--disable-simple-dmabuf-drm-client],
[do not build the simple dmabuf drm client]),,
enable_simple_dmabuf_drm_client="auto")
if ! test "x$enable_simple_dmabuf_drm_client" = "xno"; then
PKG_CHECK_MODULES(SIMPLE_DMABUF_DRM_CLIENT, [wayland-client libdrm], [have_simple_dmabuf_libs=yes],
[have_simple_dmabuf_libs=no])
PKG_CHECK_MODULES(LIBDRM_PLATFORM_FREEDRENO, [libdrm_freedreno],
AC_DEFINE([HAVE_LIBDRM_FREEDRENO], [1], [Build freedreno dmabuf client]) have_simple_dmabuf_drm_client=yes,
[true])
PKG_CHECK_MODULES(LIBDRM_PLATFORM_INTEL, [libdrm_intel],
AC_DEFINE([HAVE_LIBDRM_INTEL], [1], [Build intel dmabuf client]) have_simple_dmabuf_drm_client=yes,
[true])
PKG_CHECK_MODULES(LIBDRM_PLATFORM_ETNAVIV, [libdrm_etnaviv],
AC_DEFINE([HAVE_LIBDRM_ETNAVIV], [1], [Build etnaviv dmabuf client]) have_simple_dmabuf_drm_client=yes,
[true])
if test "x$have_simple_dmabuf_drm_client" != "xyes" -o \
"x$have_simple_dmabuf_libs" = "xno" && \
test "x$enable_simple_dmabuf_drm_client" = "xyes"; then
AC_MSG_ERROR([DRM dmabuf client explicitly enabled, but none of libdrm_{intel,freedreno,etnaviv} found])
fi
if test "x$have_simple_dmabuf_drm_client" = "xyes" -a "x$have_simple_dmabuf_libs" = "xyes"; then
enable_simple_dmabuf_drm_client="yes"
fi
fi
AM_CONDITIONAL(BUILD_SIMPLE_DMABUF_DRM_CLIENT, test "x$enable_simple_dmabuf_drm_client" = "xyes")
AC_ARG_ENABLE(simple-dmabuf-v4l-client,
AS_HELP_STRING([--disable-simple-dmabuf-v4l-client],
[do not build the simple dmabuf v4l client]),,
enable_simple_dmabuf_v4l_client="auto")
if ! test "x$enable_simple_dmabuf_v4l_client" = "xno"; then
PKG_CHECK_MODULES(SIMPLE_DMABUF_V4L_CLIENT, [wayland-client libdrm],
have_simple_dmabuf_v4l_client=yes, have_simple_dmabuf_v4l_client=no)
if test "x$have_simple_dmabuf_v4l_client" = "xno" -a "x$enable_simple_dmabuf_v4l_client" = "xyes"; then
AC_MSG_ERROR([V4L dmabuf client explicitly enabled, but libdrm couldn't be found])
fi
enable_simple_dmabuf_v4l_client="$have_simple_dmabuf_v4l_client"
fi
AM_CONDITIONAL(BUILD_SIMPLE_DMABUF_V4L_CLIENT, test "x$enable_simple_dmabuf_v4l_client" = "xyes")
AC_ARG_ENABLE(simple-dmabuf-egl-client,
AS_HELP_STRING([--disable-simple-dmabuf-egl-client],
[do not build the simple dmabuf egl client]),,
enable_simple_dmabuf_egl_client="auto")
if ! test "x$enable_simple_dmabuf_egl_client" = "xno"; then
PKG_CHECK_MODULES(SIMPLE_DMABUF_EGL_CLIENT, [wayland-client libdrm gbm egl glesv2],
[have_simple_dmabuf_egl_client=yes], [have_simple_dmabuf_egl_client=no])
if test "x$have_simple_dmabuf_egl_client" = "xno" -a "x$enable_simple_dmabuf_egl_client" = "xyes"; then
AC_MSG_ERROR([EGL dmabuf client explicitly enabled, but libdrm/egl/glev2 couldn't be found])
fi
enable_simple_dmabuf_egl_client="$have_simple_dmabuf_egl_client"
fi
AM_CONDITIONAL(BUILD_SIMPLE_DMABUF_EGL_CLIENT, test "x$enable_simple_dmabuf_egl_client" = "xyes")
AC_ARG_ENABLE(clients, [ --enable-clients],, enable_clients=yes)
AM_CONDITIONAL(BUILD_CLIENTS, test x$enable_clients = xyes)
have_cairo_egl=no
if test x$enable_clients = xyes; then
AC_DEFINE([BUILD_CLIENTS], [1], [Build the Wayland clients])
PKG_CHECK_MODULES(CLIENT, [wayland-client >= $WAYLAND_PREREQ_VERSION cairo >= 1.10.0 xkbcommon wayland-cursor])
PKG_CHECK_MODULES(SERVER, [wayland-server])
PKG_CHECK_MODULES(WESTON_INFO, [wayland-client >= $WAYLAND_PREREQ_VERSION])
# Only check for cairo-egl if a GL or GLES renderer requested
AS_IF([test "x$cairo_modules" = "xcairo-gl" -o "x$cairo_modules" = "xcairo-glesv2"], [
PKG_CHECK_MODULES(CAIRO_EGL, [wayland-egl egl cairo-egl >= 1.11.3 $cairo_modules],
[have_cairo_egl=yes], [have_cairo_egl=no])
AS_IF([test "x$have_cairo_egl" = "xyes"],
[AC_DEFINE([HAVE_CAIRO_EGL], [1], [Have cairo-egl])],
[AC_ERROR([cairo-egl not used because $CAIRO_EGL_PKG_ERRORS])])],
[have_cairo_egl=no])
PKG_CHECK_MODULES(PANGO, [pangocairo pango glib-2.0 >= 2.36], [have_pango=yes], [have_pango=no])
fi
AC_ARG_ENABLE(resize-optimization,
AS_HELP_STRING([--disable-resize-optimization],
[disable resize optimization allocating a big buffer in toytoolkit]),,
enable_resize_optimization=yes)
AS_IF([test "x$enable_resize_optimization" = "xyes"],
[AC_DEFINE([USE_RESIZE_POOL], [1], [Use resize memory pool as a performance optimization])])
AC_ARG_ENABLE(weston-launch, [ --enable-weston-launch],, enable_weston_launch=yes)
AM_CONDITIONAL(BUILD_WESTON_LAUNCH, test x$enable_weston_launch = xyes)
if test x$enable_weston_launch = xyes; then
WESTON_SEARCH_LIBS([PAM], [pam], [pam_open_session], [have_pam=yes], [have_pam=no])
if test x$have_pam = xno; then
AC_ERROR([weston-launch requires pam])
fi
fi
AM_CONDITIONAL(HAVE_PANGO, test "x$have_pango" = "xyes")
if test "x$have_pango" = "xyes"; then
AC_DEFINE([HAVE_PANGO], [1], [Have pango])
fi
AM_CONDITIONAL(HAVE_CAIRO_GLESV2,
[test "x$have_cairo_egl" = "xyes" -a "x$cairo_modules" = "xcairo-glesv2" -a "x$enable_egl" = "xyes"])
AM_CONDITIONAL(BUILD_FULL_GL_CLIENTS,
test x$cairo_modules = "xcairo-gl" -a "x$have_cairo_egl" = "xyes" -a "x$enable_egl" = "xyes")
AM_CONDITIONAL(BUILD_SUBSURFACES_CLIENT,
[test '(' "x$have_cairo_egl" != "xyes" -o "x$cairo_modules" = "xcairo-glesv2" ')' -a "x$enable_simple_egl_clients" = "xyes"])
AM_CONDITIONAL(ENABLE_DESKTOP_SHELL, true)
AC_ARG_ENABLE(fullscreen-shell,
AS_HELP_STRING([--disable-fullscreen-shell],
[do not build fullscreen-shell server plugin]),,
enable_fullscreen_shell=yes)
AM_CONDITIONAL(ENABLE_FULLSCREEN_SHELL,
test "x$enable_fullscreen_shell" = "xyes")
# CMS modules
AC_ARG_ENABLE(colord,
AS_HELP_STRING([--disable-colord],
[do not build colord CMS support]),,
enable_colord=auto)
have_colord=no
if test "x$enable_colord" != "xno"; then
PKG_CHECK_MODULES(COLORD,
colord >= 0.1.27,
have_colord=yes,
have_colord=no)
if test "x$have_colord" = "xno" -a "x$enable_colord" = "xyes"; then
AC_MSG_ERROR([colord support explicitly requested, but colord couldn't be found])
fi
if test "x$have_colord" = "xyes"; then
enable_colord=yes
fi
fi
AM_CONDITIONAL(ENABLE_COLORD, test "x$enable_colord" = "xyes")
# dbus support
AC_ARG_ENABLE(dbus,
AS_HELP_STRING([--disable-dbus],
[do not build with dbus support]),,
enable_dbus=auto)
have_dbus=no
if test "x$enable_dbus" != "xno"; then
PKG_CHECK_MODULES(DBUS,
dbus-1 >= 1.6,
have_dbus=yes,
have_dbus=no)
if test "x$have_dbus" = "xno" -a "x$enable_dbus" = "xyes"; then
AC_MSG_ERROR([dbus support explicitly requested, but libdbus couldn't be found])
fi
if test "x$have_dbus" = "xyes"; then
enable_dbus=yes
AC_DEFINE([HAVE_DBUS], [1], [Build with dbus support])
else
enable_dbus=no
fi
fi
AM_CONDITIONAL(ENABLE_DBUS, test "x$enable_dbus" = "xyes")
# systemd-login support
AC_ARG_ENABLE(systemd-login,
AS_HELP_STRING([--enable-systemd-login],
[Enable logind support]),,
enable_systemd_login=auto)
if test x$enable_systemd_login != xno -a x$have_dbus != xno; then
PKG_CHECK_MODULES(SYSTEMD_LOGIN,
[libsystemd >= 209],
[have_systemd_login_209=yes;have_systemd_login=yes],
[have_systemd_login_209=no;have_systemd_login=no])
# Older versions of systemd package systemd-login separately. Fall back on that
AS_IF([test x$have_systemd_login != xyes],[
PKG_CHECK_MODULES(SYSTEMD_LOGIN,
[libsystemd-login >= 198],
[have_systemd_login=yes],
[have_systemd_login=no])
])
else
have_systemd_login=no
fi
if test "x$have_systemd_login" = "xno" -a "x$enable_systemd_login" = "xyes"; then
AC_MSG_ERROR([systemd-login support explicitly enabled, but can't find libsystemd>=209, libsystemd-login or dbus])
fi
AS_IF([test "x$have_systemd_login" = "xyes"],
[AC_DEFINE([HAVE_SYSTEMD_LOGIN], [1], [Have systemd-login])])
AM_CONDITIONAL(HAVE_SYSTEMD_LOGIN, test "x$have_systemd_login" = "xyes")
AS_IF([test "x$have_systemd_login_209" = "xyes"],
[AC_DEFINE([HAVE_SYSTEMD_LOGIN_209], [1], [Have systemd-login >= 209])])
# Note that other features might want libxml2, or this feature might use
# alternative xml libraries at some point. Therefore the feature and
# pre-requisite concepts are split.
AC_ARG_ENABLE(junit_xml,
AS_HELP_STRING([--disable-junit-xml],
[do not build with JUnit XML output]),,
enable_junit_xml=auto)
if test "x$enable_junit_xml" != "xno"; then
PKG_CHECK_MODULES(LIBXML2,
[libxml-2.0 >= 2.6],
have_libxml2=yes,
have_libxml2=no)
if test "x$have_libxml2" = "xno" -a "x$enable_junit_xml" = "xyes"; then
AC_MSG_ERROR([JUnit XML support explicitly requested, but libxml2 couldn't be found])
fi
if test "x$have_libxml2" = "xyes"; then
enable_junit_xml=yes
AC_DEFINE(ENABLE_JUNIT_XML, [1], [Build Weston with JUnit output support])
else
enable_junit_xml=no
fi
fi
AM_CONDITIONAL(ENABLE_JUNIT_XML, test "x$enable_junit_xml" = "xyes")
# ivi-shell support
AC_ARG_ENABLE(ivi-shell,
AS_HELP_STRING([--disable-ivi-shell],
[do not build ivi-shell server plugin and client]),,
enable_ivi_shell=yes)
AM_CONDITIONAL(ENABLE_IVI_SHELL, test "x$enable_ivi_shell" = "xyes")
AC_ARG_ENABLE(wcap-tools, [ --disable-wcap-tools],, enable_wcap_tools=yes)
AM_CONDITIONAL(BUILD_WCAP_TOOLS, test x$enable_wcap_tools = xyes)
if test x$enable_wcap_tools = xyes; then
AC_DEFINE([BUILD_WCAP_TOOLS], [1], [Build the wcap tools])
PKG_CHECK_MODULES(WCAP, [cairo])
WCAP_LIBS="$WCAP_LIBS -lm"
fi
PKG_CHECK_MODULES(SETBACKLIGHT, [libudev libdrm], enable_setbacklight=yes, enable_setbacklight=no)
AM_CONDITIONAL(BUILD_SETBACKLIGHT, test "x$enable_setbacklight" = "xyes")
if test "x$GCC" = "xyes"; then
GCC_CFLAGS="-Wall -Wextra -Wno-unused-parameter \
-Wno-shift-negative-value -Wno-missing-field-initializers \
-g -fvisibility=hidden \
-Wstrict-prototypes -Wmissing-prototypes -Wsign-compare"
fi
AC_SUBST(GCC_CFLAGS)
if test "x$WESTON_NATIVE_BACKEND" = "x"; then
WESTON_NATIVE_BACKEND="drm-backend.so"
fi
AC_MSG_NOTICE([Weston's native backend: $WESTON_NATIVE_BACKEND])
AC_DEFINE_UNQUOTED([WESTON_NATIVE_BACKEND], ["$WESTON_NATIVE_BACKEND"],
[The default backend to load, if not wayland nor x11.])
if test "x$WESTON_SHELL_CLIENT" = "x"; then
WESTON_SHELL_CLIENT="weston-desktop-shell"
fi
AC_MSG_NOTICE([Weston's default desktop shell client: $WESTON_SHELL_CLIENT])
AC_DEFINE_UNQUOTED([WESTON_SHELL_CLIENT], ["$WESTON_SHELL_CLIENT"],
[The default desktop shell client to load.])
AC_ARG_ENABLE(demo-clients-install,
AS_HELP_STRING([--enable-demo-clients-install],
[Install demo clients built with weston]),,
enable_demo_clients_install=no)
AM_CONDITIONAL(INSTALL_DEMO_CLIENTS, [test "x$enable_demo_clients_install" = "xyes"])
AC_ARG_ENABLE(lcms,
AS_HELP_STRING([--disable-lcms],
[Disable lcms support]),,
enable_lcms=auto)
have_lcms=no
if test "x$enable_lcms" != "xno"; then
PKG_CHECK_MODULES(LCMS,
lcms2,
have_lcms=yes,
have_lcms=no)
if test "x$have_lcms" = "xno" -a "x$enable_lcms" = "xyes"; then
AC_MSG_ERROR([lcms support explicitly requested, but lcms couldn't be found])
fi
if test "x$have_lcms" = "xyes"; then
enable_lcms=yes
AC_DEFINE(HAVE_LCMS, 1, [Have lcms support])
fi
fi
AM_CONDITIONAL(HAVE_LCMS, [test "x$enable_lcms" = xyes])
AC_PATH_PROG([wayland_scanner], [wayland-scanner])
if test x$wayland_scanner = x; then
PKG_CHECK_MODULES(WAYLAND_SCANNER, [wayland-scanner])
wayland_scanner=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner`
fi
AC_ARG_ENABLE(systemd_notify,
AS_HELP_STRING([--enable-systemd-notify],
[Enables systemd notifications to
notify systemd about weston state
and update watchdog.
Also sockets provided by systemd
in case of socket-base activation
are added to wayland display]),,
enable_systemd_notify=no)
AM_CONDITIONAL(SYSTEMD_NOTIFY_SUPPORT, test x$enable_systemd_notify = xyes)
if test "x$enable_systemd_notify" = "xyes"; then
AC_DEFINE([SYSTEMD_NOTIFY_SUPPORT], [1], [Build the systemd sd_notify support])
PKG_CHECK_MODULES(SYSTEMD_DAEMON, [libsystemd])
fi
AC_CONFIG_FILES([Makefile libweston/version.h compositor/weston.pc])
# AC_CONFIG_FILES needs the full name when running autoconf, so we need to use
# libweston_abi_version here, and outside [] because of m4 quoting rules
AC_CONFIG_FILES([libweston/libweston-]libweston_major_version[.pc:libweston/libweston.pc.in])
AC_CONFIG_FILES([libweston/libweston-]libweston_major_version[-uninstalled.pc:libweston/libweston-uninstalled.pc.in])
AC_CONFIG_FILES([libweston/libweston-]libweston_major_version[-protocols.pc:libweston/libweston-protocols.pc.in])
AC_CONFIG_FILES([libweston-desktop/libweston-desktop-]libweston_major_version[.pc:libweston-desktop/libweston-desktop.pc.in])
AC_CONFIG_FILES([libweston-desktop/libweston-desktop-]libweston_major_version[-uninstalled.pc:libweston-desktop/libweston-desktop-uninstalled.pc.in])
AM_CONDITIONAL([HAVE_GIT_REPO], [test -f $srcdir/.git/logs/HEAD])
AC_OUTPUT
AC_MSG_RESULT([
Native Backend ${WESTON_NATIVE_BACKEND}
setuid Install ${enable_setuid_install}
Cairo Renderer ${with_cairo}
EGL ${enable_egl}
xcb_xkb ${have_xcb_xkb}
XWayland ${enable_xwayland}
dbus ${enable_dbus}
ivi-shell ${enable_ivi_shell}
Build wcap utility ${enable_wcap_tools}
Build Fullscreen Shell ${enable_fullscreen_shell}
Enable developer documentation ${enable_devdocs}
weston-launch utility ${enable_weston_launch}
systemd-login support ${have_systemd_login}
systemd notify support ${enable_systemd_notify}
DRM Compositor ${enable_drm_compositor}
Remoting ${enable_remoting}
X11 Compositor ${enable_x11_compositor}
Wayland Compositor ${enable_wayland_compositor}
Headless Compositor ${enable_headless_compositor}
FBDEV Compositor ${enable_fbdev_compositor}
RDP Compositor ${enable_rdp_compositor}
Screen Sharing ${enable_screen_sharing}
JUnit XML output ${enable_junit_xml}
Build Clients ${enable_clients}
Build EGL Clients ${have_cairo_egl}
Build Simple Clients ${enable_simple_clients}
Build Simple EGL Clients ${enable_simple_egl_clients}
Install Demo Clients ${enable_demo_clients_install}
Colord Support ${have_colord}
LCMS2 Support ${have_lcms}
libjpeg Support ${have_jpeglib}
libwebp Support ${have_webp}
VA H.264 encoding Support ${have_libva}
])

View file

@ -1,29 +0,0 @@
prog_gcovr = find_program('gcovr', required: false, disabler: true)
# Configure the build:
# $ meson configure -Db_sanitize=none -Db_coverage=true -Dwerror=true
#
# Ensure there are no stale .gcno or .gcda files around:
# $ meson setup --wipe ~/git/weston
#
# Run the test suite:
# $ meson compile
# $ meson test
#
# Generate the reports:
# $ meson compile gcovr-report
run_target(
'gcovr-report',
command: [
prog_gcovr,
'--root', '@SOURCE_ROOT@',
'--cobertura', meson.current_build_dir() / 'cobertura.xml',
'--html', meson.current_build_dir() / 'index.html',
'--html-nested',
'--html-theme', 'github.green',
'--html-title', 'Weston test suite coverage',
'--print-summary',
meson.project_build_root(),
],
)

View file

@ -33,7 +33,6 @@ home.png
icon_ivi_clickdot.png icon_ivi_clickdot.png
icon_ivi_flower.png icon_ivi_flower.png
icon_ivi_simple-egl.png icon_ivi_simple-egl.png
icon_ivi_simple-egl-vertical.png
icon_ivi_simple-shm.png icon_ivi_simple-shm.png
icon_ivi_smoke.png icon_ivi_smoke.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 737 B

After

Width:  |  Height:  |  Size: 915 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 525 B

After

Width:  |  Height:  |  Size: 653 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 B

After

Width:  |  Height:  |  Size: 161 B

View file

@ -9,7 +9,6 @@ install_data(
'icon_ivi_clickdot.png', 'icon_ivi_clickdot.png',
'icon_ivi_flower.png', 'icon_ivi_flower.png',
'icon_ivi_simple-egl.png', 'icon_ivi_simple-egl.png',
'icon_ivi_simple-egl-vertical.png',
'icon_ivi_simple-shm.png', 'icon_ivi_simple-shm.png',
'icon_ivi_smoke.png', 'icon_ivi_smoke.png',
'icon_terminal.png', 'icon_terminal.png',
@ -26,5 +25,5 @@ install_data(
'wayland.png', 'wayland.png',
'wayland.svg', 'wayland.svg',
], ],
install_dir: dir_data / 'weston' install_dir: join_paths(dir_data, 'weston')
) )

Some files were not shown because too many files have changed in this diff Show more