Compare commits
No commits in common. "main" and "5.0.92" have entirely different histories.
102
.gitignore
vendored
|
|
@ -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
|
||||||
|
|
|
||||||
710
.gitlab-ci.yml
|
|
@ -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
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
3
.mailmap
|
|
@ -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>
|
|
||||||
|
|
@ -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
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
|
|
||||||
37
DCO-1.1.txt
|
|
@ -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
318
README.md
|
|
@ -3,17 +3,38 @@ Weston
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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.
|
||||||
|
|
|
||||||
76
RELEASING.md
|
|
@ -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
|
|
@ -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" "$@"
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
610
clients/color.c
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
||||||
368
clients/image.c
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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, §ion, &name)) {
|
while (weston_config_next_section(config, §ion, &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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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')
|
||||||
|
|
|
||||||
|
|
@ -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 don’t 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
|
|
@ -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,
|
||||||
|
®istry_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
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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, ®istry_listener, &app);
|
registry = wl_display_get_registry(display);
|
||||||
|
wl_registry_add_listener(registry, ®istry_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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
3074
clients/simple-dmabuf-drm-data.h
Normal file
1014
clients/simple-dmabuf-drm.c
Normal 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);
|
||||||
|
|
|
||||||
|
|
@ -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, ¶ms_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, ¶ms_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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 don’t 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,
|
||||||
®istry_listener, display);
|
®istry_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;
|
||||||
|
|
|
||||||
|
|
@ -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 don’t 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,
|
|
||||||
®istry_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;
|
|
||||||
}
|
|
||||||
|
|
@ -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, ®istry_listener, touch);
|
wl_registry_add_listener(touch->registry, ®istry_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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
254
clients/tablet.c
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
1993
clients/window.c
169
clients/window.h
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
158
compositor/meson.build
Normal 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
|
|
@ -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 =
|
||||||
¬ifier->compositor_destroy_listener,
|
weston_compositor_destroy_listener;
|
||||||
weston_compositor_destroy_listener)) {
|
wl_signal_add(&compositor->destroy_signal,
|
||||||
free(notifier);
|
¬ifier->compositor_destroy_listener);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (add_systemd_sockets(compositor) < 0)
|
if (add_systemd_sockets(compositor) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
200
compositor/weston-screenshooter.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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}
|
||||||
|
])
|
||||||
|
|
@ -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(),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 240 KiB |
BIN
data/border.png
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.3 KiB |
BIN
data/home.png
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 737 B After Width: | Height: | Size: 915 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 525 B After Width: | Height: | Size: 653 B |
|
Before Width: | Height: | Size: 86 B After Width: | Height: | Size: 161 B |
|
|
@ -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')
|
||||||
)
|
)
|
||||||
|
|
|
||||||