Compare commits

..

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

769 changed files with 65198 additions and 206923 deletions

View file

@ -1,15 +0,0 @@
root = true
[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = tab
indent_size = 8
max_line_length = 80
[*.xml]
indent_style = space
indent_size = 2
tab_width = 8

89
.gitignore vendored
View file

@ -1,13 +1,100 @@
*.deps
*.jpg
*.la
*.lo
*.log
*.o
*.pc
*.so
*.swp *.swp
.*.sw? .*.sw?
.sw? .sw?
*.sublime-project *.sublime-project
*.sublime-workspace *.sublime-workspace
*.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
/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-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-egl
weston-simple-shm
weston-simple-touch
weston-simple-damage
weston-smoke
weston-stacking
weston-subsurfaces
weston-transformed
weston-view
weston-keyboard
libtoytoolkit.a
weston-desktop-shell
weston-ivi-shell-user-interface
weston-info
weston-screensaver
weston-screenshooter
weston-tablet-shell
weston-terminal
weston-multi-resource
weston-simple-im
git-version.h
version.h
weston
weston-launch
spring-tool
*.weston
*.test
*.ivi
wcap-decode
matrix-test
setbacklight
weston.1
weston-drm.7
weston.ini.5
/tests/weston-ivi.ini

View file

@ -1,656 +0,0 @@
# vim: set expandtab shiftwidth=2 tabstop=8 textwidth=0:
.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:
- "Merge request checks"
- "Pre Base container"
- "Base container"
- "Full build and test"
- "No-GL/Vulkan build and test"
- "Other builds"
- pages
# Base variables used for anything using a Debian environment
.os-debian-lts:
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:
- ci-fairy check-commits --signed-off-by --junit-xml=results.xml
variables:
GIT_DEPTH: 100
artifacts:
reports:
junit: results.xml
.debian-lts-x86_64:
extends:
- .os-debian-lts
variables:
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 TESTS_RES_PATH="$BUILDDIR/tests-res.txt"
- export VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation
- mkdir "$BUILDDIR" "$PREFIX"
- mkdir "$BUILDDIR_WESTINY" "$PREFIX_WESTINY"
.build-with-clang:
variables:
CC: clang-$LLVM_VERSION
CC_LD: lld-$LLVM_VERSION
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:
name: weston-$CI_COMMIT_SHA
when: always
paths:
- $BUILDDIR/*.png
- $BUILDDIR/meson-logs
- $BUILDDIR/dmesg.log
- $BUILDDIR/weston-virtme
- $PREFIX
reports:
junit: $BUILDDIR/meson-logs/testlog.junit.xml
# Same as above, but without running any tests.
.build-no-test:
extends:
- .default-rules
script:
- "${CI_PROJECT_DIR}/.gitlab-ci/build.sh"
artifacts:
name: weston-$CI_COMMIT_SHA
when: always
paths:
- $BUILDDIR/meson-logs
- $PREFIX
# OS/architecture-specific variants
.build-env-debian-lts-x86_64:
extends:
- .debian-lts-x86_64
- .fdo.suffixed-image@debian
- .build-env
needs:
- job: x86_64-debian-lts-container_prep
artifacts: false
.build-env-debian-x86_64:
extends:
- .debian-x86_64
- .fdo.suffixed-image@debian
- .build-env
needs:
- job: x86_64-debian-container_prep
artifacts: false
.build-env-debian-lts-armv7:
tags:
- aarch64
extends:
- .debian-lts-armv7
- .fdo.suffixed-image@debian
- .build-env
needs:
- job: armv7-debian-lts-container_prep
artifacts: false
.build-env-debian-armv7:
tags:
- aarch64
extends:
- .debian-armv7
- .fdo.suffixed-image@debian
- .build-env
needs:
- job: armv7-debian-container_prep
artifacts: false
.build-env-debian-lts-aarch64:
tags:
- aarch64
extends:
- .debian-lts-aarch64
- .fdo.suffixed-image@debian
- .build-env
needs:
- job: aarch64-debian-lts-container_prep
artifacts: false
.build-env-debian-aarch64:
tags:
- aarch64
extends:
- .debian-aarch64
- .fdo.suffixed-image@debian
- .build-env
needs:
- job: aarch64-debian-container_prep
artifacts: false
.test-env-debian-lts-x86_64:
tags:
- kvm
extends:
- .build-env-debian-lts-x86_64
- .build-and-test
needs:
- job: x86_64-debian-lts-container_prep
artifacts: false
.test-env-debian-x86_64:
tags:
- kvm
extends:
- .build-env-debian-x86_64
- .build-and-test
needs:
- job: x86_64-debian-container_prep
artifacts: false
.test-env-debian-lts-aarch64:
tags:
- kvm-aarch64
extends:
- .build-env-debian-lts-aarch64
- .build-and-test
needs:
- job: aarch64-debian-lts-container_prep
artifacts: false
.test-env-debian-aarch64:
tags:
- kvm-aarch64
extends:
- .build-env-debian-aarch64
- .build-and-test
needs:
- job: aarch64-debian-container_prep
artifacts: false
# Full build (gcov + perfetto) used for testing under KVM.
.build-options-full:
stage: "Full build and test"
variables:
MESON_OPTIONS: >
-Doptimization=0
-Db_coverage=true
--force-fallback-for=perfetto
-Dperfetto=true
-Dperfetto:werror=false
-Dwerror=true
-Dtest-skip-is-failure=true
-Ddeprecated-remoting=true
-Ddeprecated-pipewire=true
after_script:
- ninja -C "$BUILDDIR" coverage-html > "$BUILDDIR/meson-logs/ninja-coverage-html.txt"
- ninja -C "$BUILDDIR" coverage-xml
# Full build, (without gcov and perfetto)
.build-options-full-v2:
stage: "Full build and test"
variables:
MESON_OPTIONS: >
-Doptimization=0
-Dwerror=true
-Dtest-skip-is-failure=true
x86_64-debian-lts-full-build:
extends:
- .test-env-debian-lts-x86_64
- .build-options-full
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: $BUILDDIR/meson-logs/coverage.xml
x86_64-debian-full-build:
extends:
- .test-env-debian-x86_64
- .build-options-full-v2
aarch64-debian-lts-full-build:
extends:
- .test-env-debian-lts-aarch64
- .build-options-full-v2
aarch64-debian-full-build:
extends:
- .test-env-debian-aarch64
- .build-options-full-v2
x86_64-clang-debian-lts-full-build:
extends:
- .test-env-debian-lts-x86_64
- .build-with-clang
- .build-options-full-v2
x86_64-clang-debian-full-build:
extends:
- .test-env-debian-x86_64
- .build-with-clang
- .build-options-full-v2
aarch64-clang-debian-lts-full-build:
extends:
- .test-env-debian-lts-aarch64
- .build-with-clang
- .build-options-full-v2
aarch64-clang-debian-full-build:
extends:
- .test-env-debian-aarch64
- .build-with-clang
- .build-options-full-v2
# Docs should be invariant on all architectures, so we only do it on Debian
# x86-64.
docs-build:
stage: "Other builds"
variables:
MESON_OPTIONS: >
-Dwerror=true
-Ddoc=true
extends:
- .build-env-debian-x86_64
- .build-no-test
# Building without gl-renderer and/or vulkan-renderer, to make sure this keeps working.
.build-options-no-gl-no-vulkan:
stage: "No-GL/Vulkan build and test"
variables:
MESON_OPTIONS: >
-Dsimple-clients=damage,im,shm,touch,dmabuf-v4l
-Drenderer-gl=false
-Drenderer-vulkan=false
-Dwerror=true
.build-options-no-gl:
stage: "No-GL/Vulkan build and test"
variables:
MESON_OPTIONS: >
-Dsimple-clients=damage,im,shm,touch,dmabuf-v4l
-Drenderer-gl=false
-Dwerror=true
.build-options-no-vulkan:
stage: "No-GL/Vulkan build and test"
variables:
MESON_OPTIONS: >
-Dsimple-clients=damage,im,shm,touch,dmabuf-v4l
-Drenderer-vulkan=false
-Dwerror=true
x86_64-debian-lts-no-gl-no-vulkan-build:
extends:
- .test-env-debian-lts-x86_64
- .build-options-no-gl-no-vulkan
x86_64-debian-no-gl-no-vulkan-build:
extends:
- .test-env-debian-x86_64
- .build-options-no-gl-no-vulkan
armv7-debian-lts-no-gl-no-vulkan-build:
extends:
- .build-env-debian-lts-armv7
- .build-no-test
- .build-options-no-gl-no-vulkan
armv7-debian-no-gl-no-vulkan-build:
extends:
- .build-env-debian-armv7
- .build-no-test
- .build-options-no-gl-no-vulkan
armv7-clang-debian-lts-no-gl-no-vulkan-build:
extends:
- .build-env-debian-lts-armv7
- .build-with-clang
- .build-no-test
- .build-options-no-gl-no-vulkan
armv7-clang-debian-no-gl-no-vulkan-build:
extends:
- .build-env-debian-armv7
- .build-with-clang
- .build-no-test
- .build-options-no-gl-no-vulkan
aarch64-debian-lts-no-gl-no-vulkan-build:
extends:
- .test-env-debian-lts-aarch64
- .build-options-no-gl-no-vulkan
aarch64-debian-no-gl-no-vulkan-build:
extends:
- .test-env-debian-aarch64
- .build-options-no-gl-no-vulkan
x86_64-debian-no-gl-build:
extends:
- .test-env-debian-x86_64
- .build-options-no-gl
x86_64-debian-no-vulkan-build:
extends:
- .test-env-debian-x86_64
- .build-options-no-vulkan
# Expose docs and coverage reports, so we can show users any changes to these
# inside their merge requests, letting us check them before merge.
#
# This does not build the docs or coverage information itself, but just reuses
# the docs and coverage information from the x86-64 Debian builds as the
# canonical sources of coverage information; the docs themselves should be
# invariant across any architecture or OS.
docs-and-coverage:
extends:
- .default-rules
- .debian-lts-x86_64
- .fdo.suffixed-image@debian
stage: pages
needs:
- job: docs-build
artifacts: true
- job: x86_64-debian-lts-full-build
artifacts: true
timeout: 5m
script:
- mv prefix-weston-docs-build/share/doc/weston Documentation
- mv build-weston-x86_64-debian-lts-full-build/meson-logs/coveragereport Test_Coverage
- rm Test_Coverage/gcov.css
- cp doc/style/lcov-style.css Test_Coverage/gcov.css
- cp doc/style/*.png Test_Coverage/
- rm -rf build-* prefix-*
artifacts:
expose_as: 'Documentation preview and test coverage report'
paths:
- Documentation/
- Test_Coverage/
# Generate the documentation for https://wayland.pages.freedesktop.org/weston/
# Anything under public/ is published to this URL.
#
# Does not inherit .default-rules as it should only run in our default branch for
# the upstream repo.
pages:
extends:
- .debian-x86_64
- .fdo.suffixed-image@debian
stage: pages
timeout: 5m
needs:
- job: docs-build
artifacts: true
script:
- export PREFIX=$(pwd)/prefix-weston-docs-build
- mkdir public
- cp -R $PREFIX/share/doc/weston/* public/
artifacts:
paths:
- public
rules:
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_PATH == "wayland/weston" && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
when: on_success
- when: never

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,3 +0,0 @@
Faith Ekstrand <faith@gfxstrand.net> <jason@jlekstrand.net>
Faith Ekstrand <faith@gfxstrand.net> <jason.ekstrand@intel.com>
Faith Ekstrand <faith@gfxstrand.net> <jason.ekstrand@collabora.com>

View file

@ -1,386 +0,0 @@
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
----------------------------
Weston's development is [tracked on GitLab](https://gitlab.freedesktop.org/wayland/weston).
In addition to reviewing code submissions (see below), we use the issue tracker
to discuss both bugfixes and development of new features.
The '[good for new contributors](https://gitlab.freedesktop.org/wayland/weston/issues?label_name%5B%5D=Good+for+new+contributors)'
label is used for issues the development team thinks are a good place to begin
working on Weston. These issues cover features or bugfixes which are small,
self-contained, don't require much specific background knowledge, and aren't
blocked by more complex work.
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
it with the developers in the issue tracker, or on the
[mailing list](https://lists.freedesktop.org/mailman/listinfo/wayland-devel).
Many developers also use IRC through [OFTC](https://www.oftc.net/)'s
`#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
long time (potentially some hours due to timezone differences), then you
may want to send your question to the list or issue tracker instead.
Formatting and separating commits
---------------------------------
Unlike many projects using GitHub and GitLab, Weston has a
[linear, 'recipe' style history](http://www.bitsnbites.eu/git-history-work-log-vs-recipe/).
This means that every commit should be small, digestible, stand-alone, and
functional. Rather than a purely chronological commit history like this:
doc: final docs for view transforms
fix tests when disabled, redo broken doc formatting
better transformed-view iteration (thanks Hannah!)
try to catch more cases in tests
tests: add new spline test
fix compilation on splines
doc: notes on reticulating splines
compositor: add spline reticulation for view transforms
we aim to have a clean history which only reflects the final state, broken up
into functional groupings:
compositor: add spline reticulation for view transforms
compositor: new iterator for view transforms
tests: add view-transform correctness tests
doc: fix Doxygen formatting for view transforms
This ensures that the final patch series only contains the final state,
without the changes and missteps taken along the development process.
The first line of a commit message should contain a prefix indicating
what part is affected by the patch followed by one sentence that
describes the change. For examples:
compositor-drm: Support modifiers for drm_fb
and
input: do not forward unmatched touch-ups
If in doubt what prefix to use, look at other commits that change the
same file(s) as the patch being sent.
The body of the commit message should describe what the patch changes
and why, and also note any particular side effects. This shouldn't be
empty on most of the cases. It shouldn't take a lot of effort to write
a commit message for an obvious change, so an empty commit message
body is only acceptable if the questions "What?" and "Why?" are already
answered on the one-line summary.
The lines of the commit message should have at most 76 characters, to
cope with the way git log presents them.
See [notes on commit messages] for a recommended reading on writing commit
messages.
Your patches must also include a Signed-off-by line with your name
(or pseudonym) and email address which indicates that you agree to the
[Developer's Certificate of Origin 1.1](DCO-1.1.txt).
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,
that it was created under an appropriate open source license, or
provided to you under those terms. This lets us indicate a chain of
responsibility for the copyright status of the code.
**Agreeing to DCO 1.1 is mandatory.** Patches without a Signed-off-by cannot
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
changes compared to the previous revision in the commit message and/or the
merge request. If you have already received Reviewed-by or Acked-by tags, you
should evaluate whether they still apply and include them in the respective
commit messages. Otherwise the tags may be lost, reviewers miss the credit they
deserve, and the patches may cause redundant review effort.
Tracking patches and following up
---------------------------------
Once submitted to GitLab, your patches will be reviewed by the Weston
development team on GitLab. Review may be entirely positive and result in your
code landing instantly, in which case, great! You're done. However, we may ask
you to make some revisions: fixing some bugs we've noticed, working to a
slightly different design, or adding documentation and tests.
If you do get asked to revise the patches, please bear in mind the notes above.
You should use `git rebase -i` to make revisions, so that your patches follow
the clear linear split documented above. Following that split makes it easier
for reviewers to understand your work, and to verify that the code you're
submitting is correct.
A common request is to split single large patch into multiple patches. This can
happen, for example, if when adding a new feature you notice a bug in Weston's
core which you need to fix to progress. Separating these changes into separate
commits will allow us to verify and land the bugfix quickly, pushing part of
your work for the good of everyone, whilst revision and discussion continues on
the larger feature part. It also allows us to direct you towards reviewers who
best understand the different areas you are working on.
When you have made any requested changes, please rebase the commits, verify
that they still individually look good, then force-push your new branch to
GitLab. This will update the merge request and notify everyone subscribed to
your merge request, so they can review it again.
There are also
[many GitLab CLI clients](https://about.gitlab.com/applications/#cli-clients),
if you prefer to avoid the web interface. It may be difficult to follow review
comments without using the web interface though, so we do recommend using this
to go through the review process, even if you use other clients to track the
list of available patches.
Coding style
------------
You should follow the style of the file you're editing. In general, we
try to follow the rules below.
**Note: this file uses spaces due to markdown rendering issues for tabs.
Code must be indented using tabs.**
- indent with tabs, and a tab is always 8 characters wide
- opening braces are on the same line as the if statement;
- no braces in an if-body with just one statement;
- if one of the branches of an if-else condition has braces, then the
other branch should also have braces;
- there is always an empty line between variable declarations and the
code;
```c
static int
my_function(void)
{
int a = 0;
if (a)
b();
else
c();
if (a) {
b();
c();
} else {
d();
}
}
```
- lines should be less than 80 characters wide;
- when breaking lines with functions calls, the parameters are aligned
with the opening parentheses;
- when assigning a variable with the result of a function call, if the
line would be longer we break it around the equal '=' sign if it makes
sense;
```c
long_variable_name =
function_with_a_really_long_name(parameter1, parameter2,
parameter3, parameter4);
x = function_with_a_really_long_name(parameter1, parameter2,
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
=======
As a freedesktop.org project, Wayland follows the Contributor Covenant,
found at:
https://www.freedesktop.org/wiki/CodeOfConduct
Please conduct yourself in a respectful and civilised manner when
interacting with community members on mailing lists, IRC, or bug
trackers. The community represents the project as a whole, and abusive
or bullying behaviour is not tolerated by the project.
Licensing
=========
Weston is licensed with the intention to be usable anywhere X.org is.
Originally, X.org was covered under the MIT X11 license, but changed to
the MIT Expat license. Similarly, Weston was covered initially as MIT
X11 licensed, but changed to the MIT Expat license, following in X.org's
footsteps. Other than wording, the two licenses are substantially the
same, with the exception of a no-advertising clause in X11 not included
in Expat.
New source code files should specify the MIT Expat license in their
boilerplate, as part of the copyright statement.
Review
======
All patches, even trivial ones, require at least one positive review
(Reviewed-by). Additionally, if no Reviewed-by's have been given by
people with commit access, there needs to be at least one Acked-by from
someone with commit access. A person with commit access is expected to be
able to evaluate the patch with respect to the project scope and architecture.
The below review guidelines are intended to be interpreted in spirit, not by
the letter. There may be circumstances where some guidelines are better
ignored. We rely very much on the judgement of reviewers and commit rights
holders.
During review, the following matters should be checked:
- The commit message explains why the change is being made.
- The code fits the project's scope.
- The code license is the same MIT licence the project generally uses.
- Stable ABI or API is not broken.
- Stable ABI or API additions must be justified by actual use cases, not only
by speculation. They must also be documented, and it is strongly recommended to
include tests exercising the additions in the test suite.
- The code fits the existing software architecture, e.g. no layering
violations.
- The code is correct and does not introduce new failures for existing users,
does not add new corner-case bugs, and does not introduce new compiler
warnings.
- The patch does what it says in the commit message and changes nothing else.
- The patch is a single logical change. If the commit message addresses
multiple points, it is a hint that the commit might need splitting up.
- A bug fix should target the underlying root cause instead of hiding symptoms.
If a complete fix is not practical, partial fixes are acceptable if they come
with code comments and filed Gitlab issues for the remaining bugs.
- The bug root cause rule applies to external software components as well, e.g.
do not work around kernel driver issues in userspace.
- The test suite passes.
- The code does not depend on API or ABI which has no working free open source
implementation.
- The code is not dead or untestable. E.g. if there are no free open source
software users for it then it is effectively dead code.
- The code is written to be easy to understand, or if code cannot be clear
enough on its own there are code comments to explain it.
- The code is minimal, i.e. prefer refactor and re-use when possible unless
clarity suffers.
- The code adheres to the style guidelines.
- In a patch series, every intermediate step adheres to the above guidelines.
Commit rights
=============
Commit rights will be granted to anyone who requests them and fulfills the
below criteria:
- Submitted some (10 as a rule of thumb) non-trivial (not just simple
spelling fixes and whitespace adjustment) patches that have been merged
already.
- Are actively participating in public discussions about their work (on the
mailing list or IRC). This should not be interpreted as a requirement to
review other peoples patches but just make sure that patch submission isn't
one-way communication. Cross-review is still highly encouraged.
- Will be regularly contributing further patches. This includes regular
contributors to other parts of the open source graphics stack who only
do the occasional development in this project.
- Agrees to use their commit rights in accordance with the documented merge
criteria, tools, and processes.
To apply for commit rights, create a new issue in gitlab for the respective
project and give it the "accounts" label.
Committers are encouraged to request their commit rights get removed when they
no longer contribute to the project. Commit rights will be reinstated when they
come back to the project.
Maintainers and committers should encourage contributors to request commit
rights, especially junior contributors tend to underestimate their skills.
Stabilising for releases
========================
A release cycle ends with a stable release which also starts a new cycle and
lifts any code freezes. Gradual code freezing towards a stable release starts
with an alpha release. The release stages of a cycle are:
- **Alpha release**:
Signified by version number #.#.91.
Major features must have landed before this. Major features include
invasive code motion and refactoring, high risk changes, and new stable
library ABI.
- **Beta release**:
Signified by version number #.#.92.
Minor features must have landed before this. Minor features include all
new features that are not major, low risk changes, clean-ups, and
documentation. Stable ABI that was new in the alpha release can be removed
before a beta release if necessary.
- **Release candidates (RC)**:
Signified by version number #.#.93 and up to #.#.99.
Bug fixes that are not release critical must have landed before this.
Release critical bug fixes can still be landed after this, but they may
call for another RC.
- **Stable release**:
Signified by version number #.#.0.
Ideally no changes since the last RC.
Mind that version #.#.90 is never released. It is used during development when
no code freeze is in effect. Stable branches and point releases are not covered
by the above.
[git documentation]: http://git-scm.com/documentation
[notes on commit messages]: http://who-t.blogspot.de/2009/12/on-commit-messages.html

44
COPYING
View file

@ -2,8 +2,31 @@ Copyright © 2008-2012 Kristian Høgsberg
Copyright © 2010-2012 Intel Corporation Copyright © 2010-2012 Intel Corporation
Copyright © 2010-2011 Benjamin Franzke Copyright © 2010-2011 Benjamin Franzke
Copyright © 2011-2012 Collabora, Ltd. Copyright © 2011-2012 Collabora, Ltd.
Copyright © 2010 Red Hat <mjg@redhat.com>
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.
For libbacklight.c:
Copyright © 2012 Intel Corporation
Copyright © 2010 Red Hat <mjg@redhat.com>
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"),
to deal in the Software without restriction, including without limitation to deal in the Software without restriction, including without limitation
@ -15,16 +38,11 @@ The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the paragraph) shall be included in all copies or substantial portions of the
Software. Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 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. DEALINGS IN THE SOFTWARE.
---
The above is the version of the MIT "Expat" License used by X.org:
http://cgit.freedesktop.org/xorg/xserver/tree/COPYING

View file

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

1231
Makefile.am Normal file

File diff suppressed because it is too large Load diff

18
README Normal file
View file

@ -0,0 +1,18 @@
Weston
Weston is the reference implementation of a Wayland compositor, and a
useful compositor in its own right. Weston has various backends that
lets it run on Linux kernel modesetting and evdev input as well as
under X11. Weston ships with a few example clients, from simple
clients that demonstrate certain aspects of the protocol to more
complete clients and a simplistic toolkit. There is also a quite
capable terminal emulator (weston-terminal) and an toy/example desktop
shell. Finally, weston also provides integration with the Xorg server
and can pull X clients into the Wayland desktop and act as a X window
manager.
Refer to http://wayland.freedesktop.org/building.html for building
weston and its dependencies.
The test suite can be invoked via `make check`; see
http://wayland.freedesktop.org/testing.html for additional details.

159
README.md
View file

@ -1,159 +0,0 @@
Weston
======
![screenshot of skeletal Weston desktop](doc/wayland-screenshot.jpg)
Weston is a Wayland compositor designed for correctness, reliability,
predictability, and performance.
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,
industrial, kiosks, set-top boxes and TVs.
It also provides a library called [libweston](#libweston) which allows
users to build their own custom full-featured environments on top of
Weston's core.
Building Weston
===============
Weston is built using [Meson](https://mesonbuild.com/). Weston often depends
on the current release versions of
[Wayland](https://gitlab.freedesktop.org/wayland/wayland) and
[wayland-protocols](https://gitlab.freedesktop.org/wayland/wayland-protocols).
If necessary, the latest Meson can be installed as a user with:
$ pip3 install --user meson
Weston's Meson build does not do autodetection and it defaults to all
features enabled, which means you likely hit missing dependencies on the first
try. If a dependency is avoidable through a build option, the error message
should tell you what option can be used to avoid it. You may need to disable
several features if you want to avoid certain dependencies.
$ git clone https://gitlab.freedesktop.org/wayland/weston.git
$ cd weston
$ meson build/ --prefix=...
$ ninja -C build/ install
$ cd ..
The `meson` command populates the build directory. This step can
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
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
configuration with `meson configure build/`. If you need to change an
option, you can do e.g. `meson configure build/ -Ddemo-clients=false`.
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
how to build and install Weston.
More [detailed documentation on building Weston](https://wayland.freedesktop.org/building.html)
is available on the Wayland site. There are also more details on
[how to run and write tests](https://wayland.freedesktop.org/testing.html).
For building the documentation see [documentation](#documentation).
Running Weston
==============
Once Weston is installed, most users can simply run it by typing `weston`. This
will launch Weston inside whatever environment you launch it from: when launched
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
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
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
`man weston.ini`.
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.
Using libweston
===============
libweston is designed to allow users to use Weston's core - its client support,
backends and renderers - whilst implementing their own user interface, policy,
configuration, and lifecycle. If you would like to implement your own window
manager or desktop environment, we recommend building your project using the
libweston API.
Building and installing Weston will also install libweston's shared library
and development headers. libweston is both API-compatible and ABI-compatible
within a single stable release. It is parallel-installable, so multiple stable
releases can be installed and used side by side.
Documentation for libweston's API can be found within the source (see the
[documentation](#documentation) section), and also on
[Weston's online documentation](https://wayland.pages.freedesktop.org/weston/)
for the current stable release.
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.
Weston and libweston are not suitable for severely memory-constrained environments
where the compositor is expected to continue running even in the face of
trivial memory allocations failing. If standard functions like `malloc()`
fail for small allocations,
[you can expect libweston to abort](https://gitlab.freedesktop.org/wayland/weston/-/issues/631).
This is only likely to occur if you have disabled your OS's 'overcommit'
functionality, and not in common cases.
Documentation
=============
To read the Weston documentation online, head over to
[the Weston website](https://wayland.pages.freedesktop.org/weston/).
For documenting weston we use [sphinx](http://www.sphinx-doc.org/en/master/)
together with [breathe](https://breathe.readthedocs.io/en/latest/) to process
and augment code documentation from Doxygen. You should be able to install
both sphinx and the breathe extension using pip3 command, or your package
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
building the documentation. Installation will place the documentation in the
prefix's path under datadir (i.e., `share/doc`).
Adding and improving documentation
----------------------------------
For re-generating the documentation a special `docs` target has been added.
Although first time you build (and subsequently install) weston, you'll see the
documentation being built, updates to the spinx documentation files or to the
source files will only be updated when using `docs` target!
Example:
~~~~
$ ninja install # generates and installs the documentation
# 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
directives.

View file

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

9
autogen.sh Executable file
View file

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

View file

@ -1,45 +1,42 @@
/* /*
* Copyright © 2012 Intel Corporation * Copyright © 2012 Intel Corporation
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 "config.h"
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <cairo.h> #include <cairo.h>
#include <math.h> #include <math.h>
#include <assert.h> #include <assert.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/matrix.h"
#include <libweston/matrix.h>
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
/* 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 +114,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 +126,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 +135,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);
} }
@ -221,7 +218,7 @@ redraw_handler(struct widget *widget, void *data)
} }
static struct calibrator * static struct calibrator *
calibrator_create(struct display *display, bool enable_button) calibrator_create(struct display *display)
{ {
struct calibrator *calibrator; struct calibrator *calibrator;
@ -232,14 +229,11 @@ 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;
if (enable_button) widget_set_button_handler(calibrator->widget, button_handler);
widget_set_button_handler(calibrator->widget, button_handler);
widget_set_touch_down_handler(calibrator->widget, touch_handler); widget_set_touch_down_handler(calibrator->widget, touch_handler);
widget_set_redraw_handler(calibrator->widget, redraw_handler); widget_set_redraw_handler(calibrator->widget, redraw_handler);
@ -256,49 +250,21 @@ calibrator_destroy(struct calibrator *calibrator)
free(calibrator); free(calibrator);
} }
static void
help(const char *name)
{
fprintf(stderr, "Usage: %s [args...]\n", name);
fprintf(stderr, " -m, --enable-mouse Enable mouse for testing the touchscreen\n");
fprintf(stderr, " -h, --help Display this help message\n");
}
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
struct display *display; struct display *display;
struct calibrator *calibrator; struct calibrator *calibrator;
int c;
bool enable_mouse = 0;
struct option opts[] = {
{ "enable-mouse", no_argument, NULL, 'm' },
{ "help", no_argument, NULL, 'h' },
{ 0, 0, NULL, 0 }
};
while ((c = getopt_long(argc, argv, "mh", opts, NULL)) != -1) {
switch (c) {
case 'm':
enable_mouse = 1;
break;
case 'h':
help(argv[0]);
exit(EXIT_FAILURE);
default:
break;
}
}
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;
} }
calibrator = calibrator_create(display, enable_mouse); calibrator = calibrator_create(display);
if (!calibrator) if (!calibrator)
return -1; return -1;

View file

@ -3,24 +3,23 @@
* Copyright © 2012 Collabora, Ltd. * Copyright © 2012 Collabora, Ltd.
* Copyright © 2012 Jonas Ådahl * Copyright © 2012 Jonas Ådahl
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 "config.h"
@ -32,16 +31,14 @@
#include <cairo.h> #include <cairo.h>
#include <math.h> #include <math.h>
#include <assert.h> #include <assert.h>
#include <sys/timerfd.h>
#include <sys/epoll.h>
#include <unistd.h> #include <unistd.h>
#include <time.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/xalloc.h"
struct clickdot { struct clickdot {
struct display *display; struct display *display;
@ -62,7 +59,8 @@ struct clickdot {
int reset; int reset;
struct input *cursor_timeout_input; struct input *cursor_timeout_input;
struct toytimer cursor_timeout; int cursor_timeout_fd;
struct task cursor_timeout_task;
}; };
static void static void
@ -223,7 +221,14 @@ button_handler(struct widget *widget,
static void static void
cursor_timeout_reset(struct clickdot *clickdot) cursor_timeout_reset(struct clickdot *clickdot)
{ {
toytimer_arm_once_usec(&clickdot->cursor_timeout, 500 * 1000); const long cursor_timeout = 500;
struct itimerspec its;
its.it_interval.tv_sec = 0;
its.it_interval.tv_nsec = 0;
its.it_value.tv_sec = cursor_timeout / 1000;
its.it_value.tv_nsec = (cursor_timeout % 1000) * 1000 * 1000;
timerfd_settime(clickdot->cursor_timeout_fd, 0, &its, NULL);
} }
static int static int
@ -263,10 +268,15 @@ leave_handler(struct widget *widget,
} }
static void static void
cursor_timeout_func(struct toytimer *tt) cursor_timeout_func(struct task *task, uint32_t events)
{ {
struct clickdot *clickdot = struct clickdot *clickdot =
container_of(tt, struct clickdot, cursor_timeout); container_of(task, struct clickdot, cursor_timeout_task);
uint64_t exp;
if (read(clickdot->cursor_timeout_fd, &exp, sizeof (uint64_t)) !=
sizeof(uint64_t))
abort();
input_set_pointer_image(clickdot->cursor_timeout_input, input_set_pointer_image(clickdot->cursor_timeout_input,
CURSOR_LEFT_PTR); CURSOR_LEFT_PTR);
@ -281,8 +291,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;
@ -306,8 +314,12 @@ clickdot_create(struct display *display)
clickdot->line.old_y = -1; clickdot->line.old_y = -1;
clickdot->reset = 0; clickdot->reset = 0;
toytimer_init(&clickdot->cursor_timeout, CLOCK_MONOTONIC, clickdot->cursor_timeout_fd =
display, cursor_timeout_func); timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
clickdot->cursor_timeout_task.run = cursor_timeout_func;
display_watch_fd(window_get_display(clickdot->window),
clickdot->cursor_timeout_fd,
EPOLLIN, &clickdot->cursor_timeout_task);
return clickdot; return clickdot;
} }
@ -315,7 +327,9 @@ clickdot_create(struct display *display)
static void static void
clickdot_destroy(struct clickdot *clickdot) clickdot_destroy(struct clickdot *clickdot)
{ {
toytimer_fini(&clickdot->cursor_timeout); display_unwatch_fd(window_get_display(clickdot->window),
clickdot->cursor_timeout_fd);
close(clickdot->cursor_timeout_fd);
if (clickdot->buffer) if (clickdot->buffer)
cairo_surface_destroy(clickdot->buffer); cairo_surface_destroy(clickdot->buffer);
widget_destroy(clickdot->widget); widget_destroy(clickdot->widget);
@ -331,8 +345,7 @@ main(int argc, char *argv[])
display = display_create(&argc, argv); display = display_create(&argc, argv);
if (display == NULL) { if (display == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }

View file

@ -2,36 +2,31 @@
* Copyright © 2012 Collabora, Ltd. * Copyright © 2012 Collabora, Ltd.
* Copyright © 2012 Rob Clark * Copyright © 2012 Rob Clark
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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.
*/ */
/* 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 +44,144 @@
#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 "src/vertex-clipping.h"
#include "libweston/vertex-clipping.h"
#include "shared/helpers.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 +203,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 +239,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 +248,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 +303,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 +338,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 +349,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 +374,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 +420,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 +441,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 +511,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 +562,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 +619,7 @@ main(int argc, char *argv[])
d = display_create(&argc, argv); d = display_create(&argc, argv);
if (d == NULL) { if (d == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }

View file

@ -1,610 +0,0 @@
/*
* Copyright (C) 2024 SUSE Software Solutions Germany GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <assert.h>
#include <errno.h>
#include "color-management-v1-client-protocol.h"
#include "shared/helpers.h"
#include "shared/xalloc.h"
#include "single-pixel-buffer-v1-client-protocol.h"
#include "viewporter-client-protocol.h"
#include "window.h"
enum image_description_status {
IMAGE_DESCRIPTION_NOT_CREATED = 0,
IMAGE_DESCRIPTION_READY,
IMAGE_DESCRIPTION_FAILED,
};
struct pixel_color {
uint32_t r;
uint32_t g;
uint32_t b;
uint32_t a;
};
struct color {
struct display *display;
struct window *window;
struct widget *parent_widget;
struct widget *widget;
struct wp_color_manager_v1 *color_manager;
struct wp_color_management_surface_v1 *color_surface;
struct wp_single_pixel_buffer_manager_v1 *single_pixel_manager;
struct wp_viewporter *viewporter;
struct wp_viewport *viewport;
struct pixel_color pixel_color;
bool unmanaged;
enum wp_color_manager_v1_primaries primaries;
enum wp_color_manager_v1_transfer_function transfer_function;
float min_lum;
float max_lum;
float ref_lum;
uint32_t supported_color_features;
uint32_t supported_rendering_intents;
uint32_t supported_primaries_named;
uint32_t supported_tf_named;
};
struct valid_enum {
const char *name;
uint32_t value;
};
static bool opt_help = false;
static uint32_t opt_width = 250;
static uint32_t opt_height = 250;
static const char *opt_r = NULL;
static const char *opt_g = NULL;
static const char *opt_b = NULL;
static const char *opt_a = NULL;
static bool opt_unmanaged = false;
static const char *opt_primaries = NULL;
static const char *opt_transfer_function = NULL;
static const char *opt_min_lum = NULL;
static const char *opt_max_lum = NULL;
static const char *opt_ref_lum = NULL;
static const struct weston_option cli_options[] = {
{ WESTON_OPTION_BOOLEAN, "help", 0, &opt_help },
{ WESTON_OPTION_UNSIGNED_INTEGER, "width", 'w', &opt_width },
{ WESTON_OPTION_UNSIGNED_INTEGER, "height", 'h', &opt_height },
{ WESTON_OPTION_STRING, 0, 'R', &opt_r },
{ WESTON_OPTION_STRING, 0, 'G', &opt_g },
{ WESTON_OPTION_STRING, 0, 'B', &opt_b },
{ WESTON_OPTION_STRING, 0, 'A', &opt_a },
{ WESTON_OPTION_BOOLEAN, "unmanaged", 'u', &opt_unmanaged },
{ WESTON_OPTION_STRING, "primaries", 'p', &opt_primaries },
{ WESTON_OPTION_STRING, "transfer-function", 't', &opt_transfer_function },
{ WESTON_OPTION_STRING, "min-lum", 'm', &opt_min_lum },
{ WESTON_OPTION_STRING, "max-lum", 'M', &opt_max_lum },
{ WESTON_OPTION_STRING, "ref-lum", 'r', &opt_ref_lum },
};
static const struct valid_enum valid_primaries[] = {
{ "srgb", WP_COLOR_MANAGER_V1_PRIMARIES_SRGB },
{ "bt2020", WP_COLOR_MANAGER_V1_PRIMARIES_BT2020 },
};
static const struct valid_enum valid_transfer_functions[] = {
{ "srgb", WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB },
{ "pq", WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ },
{ "linear", WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR },
};
static bool
validate_color(const char *c, uint32_t *dest, uint32_t fallback)
{
char *end;
double value;
if (!c) {
*dest = fallback;
return true;
}
value = strtod(c, &end);
if (value < 0.0 || value > 1.0 || *end != '\0') {
fprintf(stderr, "Validating color failed, it should be between 0.0 and 1.0\n");
return false;
}
*dest = value * UINT32_MAX;
return true;
}
static bool
validate_option(const struct color *color,
const char *option, uint32_t *dest,
const struct valid_enum *valid_options,
int count, uint32_t fallback)
{
int i;
if (color->unmanaged && option) {
fprintf(stderr, "Option '%s' not valid in unmanaged mode\n", option);
return false;
}
if (!option) {
*dest = fallback;
return true;
}
for (i = 0; i < count; i++) {
if (strcmp(valid_options[i].name, option) == 0) {
*dest = valid_options[i].value;
return true;
}
}
fprintf(stderr, "Validating option '%s' failed, valid options:\n", option);
for (i = 0; i < count; i++)
fprintf(stderr, "'%s' ", valid_options[i].name);
fprintf(stderr, "\n");
return false;
}
static bool
validate_luminance(const struct color *color,
const char *c, float *dest, float fallback)
{
char *end;
float value;
if (color->unmanaged && c) {
fprintf(stderr, "Luminance not valid in unmanaged mode.\n");
return false;
}
if (!c) {
*dest = fallback;
return true;
}
value = strtof(c, &end);
if (value < 0.f || value > 10000.f || *end != '\0') {
fprintf(stderr, "Validating luminance failed, it should be between 0 and 10,000\n");
return false;
}
*dest = value;
return true;
}
static bool
validate_options(struct color *color)
{
color->unmanaged = opt_unmanaged;
return validate_color(opt_r, &color->pixel_color.r, 0) &&
validate_color(opt_g, &color->pixel_color.g, 0) &&
validate_color(opt_b, &color->pixel_color.b, 0) &&
validate_color(opt_a, &color->pixel_color.a, UINT32_MAX) &&
validate_option(color, opt_primaries, &color->primaries,
valid_primaries,
ARRAY_LENGTH(valid_primaries),
WP_COLOR_MANAGER_V1_PRIMARIES_SRGB) &&
validate_option(color, opt_transfer_function, &color->transfer_function,
valid_transfer_functions,
ARRAY_LENGTH(valid_transfer_functions),
WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB) &&
validate_luminance(color, opt_min_lum, &color->min_lum, -1.f) &&
validate_luminance(color, opt_max_lum, &color->max_lum, -1.f) &&
validate_luminance(color, opt_ref_lum, &color->ref_lum, -1.f);
}
static void
usage(const char *program_name, int exit_code)
{
unsigned int i;
fprintf(stderr, "Usage: %s [OPTIONS]\n", program_name);
fprintf(stderr, " --help\n");
fprintf(stderr, " --width or -w\n");
fprintf(stderr, " --height or -h\n");
fprintf(stderr, " -R (0.0 to 1.0)\n");
fprintf(stderr, " -G (0.0 to 1.0)\n");
fprintf(stderr, " -B (0.0 to 1.0)\n");
fprintf(stderr, " -A (0.0 to 1.0)\n");
fprintf(stderr, " Mode of operation may be:\n");
fprintf(stderr, " --unmanaged or -u: do not use color-management\n");
fprintf(stderr, " Or use the following:\n");
fprintf(stderr, " --primaries or -p:");
fprintf(stderr, "\n ");
for (i = 0; i < ARRAY_LENGTH(valid_primaries); i++)
fprintf(stderr, " '%s'", valid_primaries[i].name);
fprintf(stderr, "\n");
fprintf(stderr, " --transfer-function or -t:");
fprintf(stderr, "\n ");
for (i = 0; i < ARRAY_LENGTH(valid_transfer_functions); i++)
fprintf(stderr, " '%s'", valid_transfer_functions[i].name);
fprintf(stderr, "\n");
fprintf(stderr, " --min-lum or -m (0.0 to 10000.0)\n");
fprintf(stderr, " --max-lum or -M (0.0 to 10000.0)\n");
fprintf(stderr, " --ref-lum or -r (0.0 to 10000.0)\n");
exit(exit_code);
}
static void
supported_intent(void *data, struct wp_color_manager_v1 *wp_color_manager_v1,
uint32_t render_intent)
{
struct color *color = data;
color->supported_rendering_intents |= 1 << render_intent;
}
static void
supported_feature(void *data, struct wp_color_manager_v1 *wp_color_manager_v1,
uint32_t feature)
{
struct color *color = data;
color->supported_color_features |= 1 << feature;
}
static void
supported_tf_named(void *data, struct wp_color_manager_v1 *wp_color_manager_v1,
uint32_t tf)
{
struct color *color = data;
color->supported_tf_named |= 1 << tf;
}
static void
supported_primaries_named(void *data,
struct wp_color_manager_v1 *wp_color_manager_v1,
uint32_t primaries)
{
struct color *color = data;
color->supported_primaries_named |= 1 << primaries;
}
static void
done(void *data, struct wp_color_manager_v1 *wp_color_manager_v1)
{
}
static const struct wp_color_manager_v1_listener color_manager_listener = {
supported_intent,
supported_feature,
supported_tf_named,
supported_primaries_named,
done,
};
static void
global_handler(struct display *display, uint32_t name,
const char *interface, uint32_t version, void *data)
{
struct color *color = data;
struct wl_surface *surface = widget_get_wl_surface(color->widget);
if (strcmp(interface, wp_single_pixel_buffer_manager_v1_interface.name) == 0) {
color->single_pixel_manager =
display_bind(display, name,
&wp_single_pixel_buffer_manager_v1_interface, 1);
} else if (strcmp(interface, wp_viewporter_interface.name) == 0) {
color->viewporter = display_bind(display, name,
&wp_viewporter_interface, 1);
color->viewport = wp_viewporter_get_viewport(color->viewporter, surface);
}
if (color->unmanaged)
return;
if (strcmp(interface, wp_color_manager_v1_interface.name) == 0) {
color->color_manager = display_bind(display, name,
&wp_color_manager_v1_interface, 1);
color->color_surface = wp_color_manager_v1_get_surface(color->color_manager,
surface);
wp_color_manager_v1_add_listener(color->color_manager,
&color_manager_listener, color);
}
}
static bool
check_color_requirements(struct color *color)
{
if (!color->color_manager) {
fprintf(stderr, "The compositor doesn't expose %s\n",
wp_color_manager_v1_interface.name);
return false;
}
if (!(color->supported_color_features & (1 << WP_COLOR_MANAGER_V1_FEATURE_PARAMETRIC))) {
fprintf(stderr, "The color manager doesn't support the parametric creator\n");
return false;
}
if (!(color->supported_primaries_named & (1 << color->primaries))) {
fprintf(stderr, "The color manager doesn't support the primaries name\n");
return false;
}
if (!(color->supported_tf_named & (1 << color->transfer_function))) {
fprintf(stderr, "The color manager doesn't support the transfer function\n");
return false;
}
if (!(color->supported_rendering_intents & (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL))) {
fprintf(stderr, "The color manager doesn't support perceptual render intent\n");
return false;
}
if (color->min_lum != -1.f || color->max_lum != -1.f || color->ref_lum != -1.f) {
if (!(color->supported_color_features & (1 << WP_COLOR_MANAGER_V1_FEATURE_SET_LUMINANCES))) {
fprintf(stderr, "The color manager doesn't support setting luminances\n");
return false;
}
if (color->min_lum == -1.f || color->max_lum == -1.f || color->ref_lum == -1.f) {
fprintf(stderr, "To set the luminances it is required min-lum, max-lum and ref-lum\n");
return false;
}
}
return true;
}
static void
color_destroy(struct color *color)
{
if (color->color_surface)
wp_color_management_surface_v1_destroy(color->color_surface);
if (color->color_manager)
wp_color_manager_v1_destroy(color->color_manager);
if (color->single_pixel_manager)
wp_single_pixel_buffer_manager_v1_destroy(color->single_pixel_manager);
if (color->viewport)
wp_viewport_destroy(color->viewport);
if (color->viewporter)
wp_viewporter_destroy(color->viewporter);
if (color->widget)
widget_destroy(color->widget);
if (color->parent_widget)
widget_destroy(color->parent_widget);
if (color->window)
window_destroy(color->window);
if (color->display)
display_destroy(color->display);
free(color);
}
static void
resize_handler(struct widget *parent_widget, int32_t width, int32_t height, void *data)
{
struct color *color = data;
struct rectangle allocation;
struct wl_surface *surface = widget_get_wl_surface(color->widget);
struct wl_subsurface *subsurface = widget_get_wl_subsurface(color->widget);
widget_get_allocation(parent_widget, &allocation);
wl_subsurface_set_position(subsurface, allocation.x, allocation.y);
wp_viewport_set_destination(color->viewport, width, height);
wl_surface_commit(surface);
}
static void
set_empty_input_region(struct color *color, struct widget *widget)
{
struct wl_region *region;
struct wl_compositor *compositor;
struct wl_surface *surface = widget_get_wl_surface(widget);
compositor = display_get_compositor(color->display);
region = wl_compositor_create_region(compositor);
wl_surface_set_input_region(surface, region);
wl_region_destroy(region);
}
static void
buffer_release(void *data, struct wl_buffer *buffer)
{
wl_buffer_destroy(buffer);
}
static const struct wl_buffer_listener buffer_listener = {
buffer_release
};
static void
set_single_pixel(struct color *color, struct widget *widget)
{
struct wl_surface *surface = widget_get_wl_surface(widget);
struct wl_buffer *buffer =
wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(color->single_pixel_manager,
color->pixel_color.r,
color->pixel_color.g,
color->pixel_color.b,
color->pixel_color.a);
wl_buffer_add_listener(buffer, &buffer_listener, NULL);
wl_surface_attach(surface, buffer, 0, 0);
}
static void
image_description_failed(void *data,
struct wp_image_description_v1 *wp_image_description_v1,
uint32_t cause, const char *msg)
{
enum image_description_status *image_desc_status = data;
fprintf(stderr, "Failed to create image description: %u - %s\n",
cause, msg);
*image_desc_status = IMAGE_DESCRIPTION_FAILED;
}
static void
image_description_ready(void *data, struct wp_image_description_v1 *wp_image_description_v1,
uint32_t identity)
{
enum image_description_status *image_desc_status = data;
*image_desc_status = IMAGE_DESCRIPTION_READY;
}
static const struct wp_image_description_v1_listener image_description_listener = {
image_description_failed,
image_description_ready,
};
static struct wp_image_description_v1 *
create_image_description(struct color *color, uint32_t primaries_named, uint32_t tf_named)
{
struct wp_image_description_creator_params_v1 *params_creator;
struct wp_image_description_v1 *image_description;
enum image_description_status image_desc_status = IMAGE_DESCRIPTION_NOT_CREATED;
int ret = 0;
params_creator = wp_color_manager_v1_create_parametric_creator(color->color_manager);
wp_image_description_creator_params_v1_set_primaries_named(params_creator, primaries_named);
wp_image_description_creator_params_v1_set_tf_named(params_creator, tf_named);
if (color->min_lum != -1 && color->max_lum != -1 && color->ref_lum != -1)
wp_image_description_creator_params_v1_set_luminances(params_creator,
color->min_lum * 10000,
color->max_lum,
color->ref_lum);
image_description = wp_image_description_creator_params_v1_create(params_creator);
wp_image_description_v1_add_listener(image_description,
&image_description_listener,
&image_desc_status);
while (ret != -1 && image_desc_status == IMAGE_DESCRIPTION_NOT_CREATED)
ret = wl_display_dispatch(display_get_display(color->display));
if (ret == -1) {
wp_image_description_v1_destroy(image_description);
fprintf(stderr, "Error when creating the image description: %s\n", strerror(errno));
return NULL;
}
if (image_desc_status == IMAGE_DESCRIPTION_FAILED) {
wp_image_description_v1_destroy(image_description);
return NULL;
}
assert(image_desc_status == IMAGE_DESCRIPTION_READY);
return image_description;
}
static bool
set_image_description(struct color *color, struct widget *widget)
{
struct wp_image_description_v1 *image_description;
image_description =
create_image_description(color,
color->primaries,
color->transfer_function);
if (!image_description)
return false;
wp_color_management_surface_v1_set_image_description(
color->color_surface,
image_description,
WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL);
wp_image_description_v1_destroy(image_description);
return true;
}
int
main(int argc, char *argv[])
{
struct color *color;
if (parse_options(cli_options, ARRAY_LENGTH(cli_options), &argc, argv) > 1)
usage(argv[0], EXIT_FAILURE);
if (opt_help)
usage(argv[0], EXIT_SUCCESS);
color = xzalloc(sizeof *color);
if (!validate_options(color)) {
color_destroy(color);
exit(EXIT_FAILURE);
}
color->display = display_create(&argc, argv);
if (!color->display) {
color_destroy(color);
exit(EXIT_FAILURE);
}
color->window = window_create(color->display);
color->parent_widget = window_frame_create(color->window, color);
color->widget = window_add_subsurface(color->window, color, SUBSURFACE_SYNCHRONIZED);
display_set_user_data(color->display, color);
display_set_global_handler(color->display, global_handler);
wl_display_roundtrip(display_get_display(color->display));
if (!color->unmanaged && !check_color_requirements(color)) {
color_destroy(color);
exit(EXIT_SUCCESS);
}
window_unset_shadow(color->window);
window_set_title(color->window, "Color");
window_set_appid(color->window, "org.freedesktop.weston.color");
/* The first resize call sets the min size,
* setting 0, 0 sets a default size */
window_schedule_resize(color->window, 0, 0);
window_schedule_resize(color->window, opt_width, opt_height);
widget_set_resize_handler(color->parent_widget, resize_handler);
widget_set_use_cairo(color->widget, 0);
set_empty_input_region(color, color->widget);
set_single_pixel(color, color->widget);
if (color->unmanaged || set_image_description(color, color->widget))
display_run(color->display);
color_destroy(color);
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -1,386 +0,0 @@
/*
* Copyright © 2018 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <cairo.h>
#include <sys/time.h>
#include <linux/input.h>
#include <wayland-client.h>
#include "weston-content-protection-client-protocol.h"
#include "window.h"
#include <wayland-client-protocol.h>
#define WIDTH 500
#define HEIGHT 400
#define FRAME_H 18
#define FRAME_W 5
#define BUTTON_WIDTH 65
#define BUTTON_HEIGHT 20
enum protection_mode {
RELAXED,
ENFORCED
};
struct protected_content_player {
struct weston_content_protection *protection;
struct weston_protected_surface *psurface;
struct display *display;
struct window *window;
struct widget *widget;
struct button_t *b0, *b1, *off, *enforced, *relaxed;
int width, height, x, y;
enum weston_protected_surface_type protection_type;
enum protection_mode mode;
};
struct button_t {
struct window *window;
struct widget *widget;
struct protected_content_player *pc_player;
const char *name;
};
/**
* An event to tell the client that there is a change in protection status
*
* This event is sent whenever there is a change in content
* protection. The content protection status can be ON or OFF. ON
* in case of the desired protection type is accepted on all
* connectors, and Off in case of any of the connector
* content-protection property is changed from "enabled"
*/
static void
handle_status_changed(void *data, struct weston_protected_surface *psurface,
uint32_t status)
{
struct protected_content_player *pc_player = data;
enum weston_protected_surface_type event_status = status;
switch (event_status) {
case WESTON_PROTECTED_SURFACE_TYPE_HDCP_0:
pc_player->protection_type = WESTON_PROTECTED_SURFACE_TYPE_HDCP_0;
break;
case WESTON_PROTECTED_SURFACE_TYPE_HDCP_1:
pc_player->protection_type = WESTON_PROTECTED_SURFACE_TYPE_HDCP_1;
break;
case WESTON_PROTECTED_SURFACE_TYPE_UNPROTECTED:
default:
pc_player->protection_type = WESTON_PROTECTED_SURFACE_TYPE_UNPROTECTED;
}
window_schedule_redraw(pc_player->window);
}
static const struct weston_protected_surface_listener pc_player_listener = {
handle_status_changed,
};
static void
draw_content(cairo_surface_t *surface, int x, int y, int width, int height,
enum weston_protected_surface_type type, enum protection_mode mode)
{
cairo_t *cr;
cairo_text_extents_t extents;
const char *content_text;
const char *mode_text;
cr = cairo_create(surface);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_rectangle(cr, x, y, width, height);
if (type == WESTON_PROTECTED_SURFACE_TYPE_HDCP_0)
cairo_set_source_rgba(cr, 0, 1.0, 0, 1.0);
else if (type == WESTON_PROTECTED_SURFACE_TYPE_HDCP_1)
cairo_set_source_rgba(cr, 0, 0, 1.0, 1.0);
else
cairo_set_source_rgba(cr, 1.0, 0, 0, 1.0);
cairo_fill(cr);
cairo_set_source_rgba(cr, 0, 0, 0, 1.0);
cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cr, 15);
if (type == WESTON_PROTECTED_SURFACE_TYPE_HDCP_0)
content_text = "Content-Type : Type-0";
else if (type == WESTON_PROTECTED_SURFACE_TYPE_HDCP_1)
content_text = "Content-Type : Type-1";
else
content_text = "Content-Type : Unprotected";
cairo_text_extents(cr, content_text, &extents);
cairo_move_to(cr, width/2 - (extents.width/2),
height/2 - (extents.height/2));
cairo_show_text(cr, content_text);
if (mode == ENFORCED)
mode_text = "Mode : Enforced";
else
mode_text = "Mode : Relaxed";
cairo_text_extents(cr, mode_text, &extents);
cairo_move_to(cr, width / 2 - (extents.width / 2),
2 * height / 3 - (2 * extents.height / 3));
cairo_show_text(cr, mode_text);
cairo_fill(cr);
cairo_destroy(cr);
}
static void
redraw_handler(struct widget *widget, void *data)
{
struct protected_content_player *pc_player = data;
cairo_surface_t *surface;
struct rectangle rect;
widget_get_allocation(pc_player->widget, &rect);
surface = window_get_surface(pc_player->window);
if (surface == NULL ||
cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
fprintf(stderr, "failed to create cairo egl surface\n");
return;
}
draw_content(surface, rect.x, rect.y, rect.width, rect.height,
pc_player->protection_type, pc_player->mode);
cairo_surface_destroy(surface);
}
static void
resize_handler(struct widget *widget, int32_t width, int32_t height, void *data)
{
struct rectangle allocation;
struct protected_content_player *pc_player = data;
widget_get_allocation(pc_player->widget, &allocation);
widget_set_allocation(pc_player->b0->widget,
allocation.x + 20, allocation.y + 30,
BUTTON_WIDTH, BUTTON_HEIGHT);
widget_set_allocation(pc_player->b1->widget,
allocation.x + 20 + BUTTON_WIDTH + 5,
allocation.y + 30,
BUTTON_WIDTH, BUTTON_HEIGHT);
widget_set_allocation(pc_player->off->widget,
allocation.x + 20 + 2 * (BUTTON_WIDTH + 5),
allocation.y + 30,
BUTTON_WIDTH, BUTTON_HEIGHT);
widget_set_allocation(pc_player->enforced->widget,
allocation.x + 20 + 3 * (BUTTON_WIDTH + 5),
allocation.y + 30,
BUTTON_WIDTH, BUTTON_HEIGHT);
widget_set_allocation(pc_player->relaxed->widget,
allocation.x + 20 + 4 * (BUTTON_WIDTH + 5),
allocation.y + 30,
BUTTON_WIDTH, BUTTON_HEIGHT);
}
static void
buttons_handler(struct widget *widget, struct input *input, uint32_t time,
uint32_t button, enum wl_pointer_button_state state, void *data)
{
struct button_t *b = data;
struct protected_content_player *pc_player = b->pc_player;
struct wl_surface *surface;
if (strcmp(b->name, "ENFORCED") == 0) {
weston_protected_surface_enforce(pc_player->psurface);
pc_player->mode = ENFORCED;
window_schedule_redraw(pc_player->window);
}
else if (strcmp(b->name, "RELAXED") == 0) {
weston_protected_surface_relax(pc_player->psurface);
pc_player->mode = RELAXED;
window_schedule_redraw(pc_player->window);
}
else if (strcmp(b->name, "TYPE-0") == 0)
weston_protected_surface_set_type(pc_player->psurface,
WESTON_PROTECTED_SURFACE_TYPE_HDCP_0);
else if (strcmp(b->name, "TYPE-1") == 0)
weston_protected_surface_set_type(pc_player->psurface,
WESTON_PROTECTED_SURFACE_TYPE_HDCP_1);
else
weston_protected_surface_set_type(pc_player->psurface,
WESTON_PROTECTED_SURFACE_TYPE_UNPROTECTED);
surface = window_get_wl_surface(pc_player->window);
wl_surface_commit(surface);
}
static void
handle_global(struct display *display, uint32_t name, const char *interface,
uint32_t version, void *data)
{
struct protected_content_player *pc_player = data;
if (strcmp(interface, "weston_content_protection") == 0) {
pc_player->protection = display_bind(display, name,
&weston_content_protection_interface,
1);
}
}
static void
buttons_redraw_handler(struct widget *widget, void *data)
{
struct button_t *b = data;
cairo_surface_t *surface;
struct rectangle allocation;
cairo_t *cr;
surface = window_get_surface(b->window);
widget_get_allocation(b->widget, &allocation);
cr = cairo_create(surface);
cairo_rectangle(cr, allocation.x, allocation.y, allocation.width,
allocation.height);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr, 1, 1, 1, 1);
cairo_fill(cr);
cairo_set_source_rgba(cr, 0, 0, 0, 1.0);
cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cr, 10);
cairo_move_to(cr, allocation.x + 5, allocation.y + 15);
cairo_show_text(cr, b->name);
cairo_fill(cr);
cairo_destroy(cr);
cairo_surface_destroy(surface);
}
static struct button_t*
create_button(struct protected_content_player *pc_player, const char *name)
{
struct button_t *b;
b = zalloc(sizeof(struct button_t));
if (b == NULL) {
fprintf(stderr, "Failed to allocate memory for button.\n");
exit(0);
}
b->widget = widget_add_widget(pc_player->widget, b);
b->window = pc_player->window;
b->pc_player = pc_player;
b->name = name;
widget_set_redraw_handler(b->widget, buttons_redraw_handler);
widget_set_button_handler(b->widget, buttons_handler);
return b;
}
static void
destroy_button(struct button_t *b)
{
if (!b)
return;
widget_destroy(b->widget);
free(b);
}
static void free_pc_player(struct protected_content_player *pc_player)
{
if (!pc_player)
return;
destroy_button(pc_player->b0);
destroy_button(pc_player->b1);
destroy_button(pc_player->off);
destroy_button(pc_player->enforced);
destroy_button(pc_player->relaxed);
widget_destroy(pc_player->widget);
window_destroy(pc_player->window);
free(pc_player);
}
int main(int argc, char *argv[])
{
struct protected_content_player *pc_player;
struct display *d;
static const char str_type_0[] = "TYPE-0";
static const char str_type_1[] = "TYPE-1";
static const char str_type_off[] = "OFF";
static const char str_type_enforced[] = "ENFORCED";
static const char str_type_relaxed[] = "RELAXED";
struct wl_surface *surface;
pc_player = zalloc(sizeof(struct protected_content_player));
if (pc_player == NULL) {
fprintf(stderr, "failed to allocate memory: %m\n");
return -1;
}
d = display_create(&argc, argv);
if (d == NULL) {
fprintf(stderr, "failed to create display: %m\n");
return -1;
}
pc_player->protection_type = WESTON_PROTECTED_SURFACE_TYPE_UNPROTECTED;
pc_player->mode = RELAXED;
pc_player->width = WIDTH * 2.0/4.0;
pc_player->height = HEIGHT * 2.0/4.0;
pc_player->x = WIDTH * 1.0/4.0;
pc_player->y = HEIGHT * 1.0/4.0;
pc_player->window = window_create(d);
pc_player->widget = window_frame_create(pc_player->window, pc_player);
pc_player->display = d;
display_set_user_data(d, pc_player);
display_set_global_handler(d, handle_global);
surface = window_get_wl_surface(pc_player->window);
if (pc_player->protection == NULL) {
printf("The content-protection object is NULL\n");
return -1;
}
pc_player->psurface = weston_content_protection_get_protection(pc_player->protection,
surface);
weston_protected_surface_add_listener(pc_player->psurface,
&pc_player_listener,
pc_player);
pc_player->b0 = create_button(pc_player, str_type_0);
pc_player->b1 = create_button(pc_player, str_type_1);
pc_player->off = create_button(pc_player, str_type_off);
pc_player->enforced = create_button(pc_player, str_type_enforced);
pc_player->relaxed = create_button(pc_player, str_type_relaxed);
window_set_title(pc_player->window, "Weston Content Protection");
window_set_appid(pc_player->window,
"org.freedesktop.weston.weston-content-protection");
widget_set_redraw_handler(pc_player->widget, redraw_handler);
widget_set_resize_handler(pc_player->widget, resize_handler);
window_schedule_resize(pc_player->window, WIDTH, HEIGHT);
widget_schedule_redraw(pc_player->b0->widget);
widget_schedule_redraw(pc_player->b1->widget);
widget_schedule_redraw(pc_player->off->widget);
display_run(d);
weston_protected_surface_destroy(pc_player->psurface);
weston_content_protection_destroy(pc_player->protection);
free_pc_player(pc_player);
display_destroy(d);
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -1,24 +1,23 @@
/* /*
* Copyright © 2010 Kristian Høgsberg * Copyright © 2010 Kristian Høgsberg
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 "config.h"
@ -35,15 +34,12 @@
#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>
#include "window.h" #include "window.h"
#include "shared/cairo-util.h" #include "../shared/cairo-util.h"
#include "shared/helpers.h"
#include "shared/xalloc.h"
struct dnd_drag; struct dnd_drag;
@ -74,7 +70,6 @@ struct dnd_drag {
struct item *item; struct item *item;
int x_offset, y_offset; int x_offset, y_offset;
int width, height; int width, height;
uint32_t dnd_action;
const char *mime_type; const char *mime_type;
struct wl_surface *drag_surface; struct wl_surface *drag_surface;
@ -192,7 +187,7 @@ dnd_redraw_handler(struct widget *widget, void *data)
struct dnd *dnd = data; struct dnd *dnd = data;
struct rectangle allocation; struct rectangle allocation;
cairo_t *cr; cairo_t *cr;
cairo_surface_t *surface, *item_surface; cairo_surface_t *surface;
unsigned int i; unsigned int i;
surface = window_get_surface(dnd->window); surface = window_get_surface(dnd->window);
@ -212,13 +207,7 @@ dnd_redraw_handler(struct widget *widget, void *data)
for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) { for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
if (!dnd->items[i]) if (!dnd->items[i])
continue; continue;
cairo_set_source_surface(cr, dnd->items[i]->surface,
if (dnd->current_drag && dnd->items[i] == dnd->current_drag->item)
item_surface = dnd->current_drag->translucent;
else
item_surface = dnd->items[i]->surface;
cairo_set_source_surface(cr, item_surface,
dnd->items[i]->x + allocation.x, dnd->items[i]->x + allocation.x,
dnd->items[i]->y + allocation.y); dnd->items[i]->y + allocation.y);
cairo_paint(cr); cairo_paint(cr);
@ -274,38 +263,17 @@ dnd_get_item(struct dnd *dnd, int32_t x, int32_t y)
return NULL; return NULL;
} }
static int
lookup_dnd_cursor(uint32_t dnd_action)
{
if (dnd_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
return CURSOR_DND_MOVE;
else if (dnd_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
return CURSOR_DND_COPY;
return CURSOR_DND_FORBIDDEN;
}
static void static void
dnd_drag_update_cursor(struct dnd_drag *dnd_drag) data_source_target(void *data,
{ struct wl_data_source *source, const char *mime_type)
int cursor;
if (dnd_drag->mime_type == NULL)
cursor = CURSOR_DND_FORBIDDEN;
else
cursor = lookup_dnd_cursor(dnd_drag->dnd_action);
input_set_pointer_image(dnd_drag->input, cursor);
}
static void
dnd_drag_update_surface(struct dnd_drag *dnd_drag)
{ {
struct dnd_drag *dnd_drag = data;
struct dnd *dnd = dnd_drag->dnd; struct dnd *dnd = dnd_drag->dnd;
cairo_surface_t *surface; cairo_surface_t *surface;
struct wl_buffer *buffer; struct wl_buffer *buffer;
if (dnd_drag->mime_type && dnd_drag->dnd_action) dnd_drag->mime_type = mime_type;
if (mime_type)
surface = dnd_drag->opaque; surface = dnd_drag->opaque;
else else
surface = dnd_drag->translucent; surface = dnd_drag->translucent;
@ -317,17 +285,6 @@ dnd_drag_update_surface(struct dnd_drag *dnd_drag)
wl_surface_commit(dnd_drag->drag_surface); wl_surface_commit(dnd_drag->drag_surface);
} }
static void
data_source_target(void *data,
struct wl_data_source *source, const char *mime_type)
{
struct dnd_drag *dnd_drag = data;
dnd_drag->mime_type = mime_type;
dnd_drag_update_surface(dnd_drag);
dnd_drag_update_cursor(dnd_drag);
}
static void static void
data_source_send(void *data, struct wl_data_source *source, data_source_send(void *data, struct wl_data_source *source,
const char *mime_type, int32_t fd) const char *mime_type, int32_t fd)
@ -359,27 +316,19 @@ data_source_send(void *data, struct wl_data_source *source,
} }
static void static void
dnd_drag_destroy(struct dnd_drag *dnd_drag, bool delete_item) data_source_cancelled(void *data, struct wl_data_source *source)
{ {
struct dnd *dnd = dnd_drag->dnd; struct dnd_drag *dnd_drag = data;
unsigned int i;
/* The 'cancelled' event means that the source is no longer in
* use by the drag (or current selection). We need to clean
* up the drag object created and the local state. */
wl_data_source_destroy(dnd_drag->data_source); wl_data_source_destroy(dnd_drag->data_source);
if (delete_item) { /* Destroy the item that has been dragged out */
for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) { cairo_surface_destroy(dnd_drag->item->surface);
if (dnd_drag->item == dnd->items[i]) { free(dnd_drag->item);
dnd->items[i] = NULL;
break;
}
}
/* Destroy the item that has been dragged out */
cairo_surface_destroy(dnd_drag->item->surface);
free(dnd_drag->item);
}
dnd->current_drag = NULL;
wl_surface_destroy(dnd_drag->drag_surface); wl_surface_destroy(dnd_drag->drag_surface);
@ -388,58 +337,10 @@ dnd_drag_destroy(struct dnd_drag *dnd_drag, bool delete_item)
free(dnd_drag); free(dnd_drag);
} }
static void
data_source_cancelled(void *data, struct wl_data_source *source)
{
struct dnd_drag *dnd_drag = data;
struct dnd *dnd = dnd_drag->dnd;
/* The 'cancelled' event means that the source is no longer in
* use by the drag (or current selection). We need to clean
* up the drag object created and the local state. */
dnd_drag_destroy(dnd_drag, false);
window_schedule_redraw(dnd->window);
}
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)
{
struct dnd_drag *dnd_drag = data;
struct dnd *dnd = dnd_drag->dnd;
bool delete_item;
delete_item =
dnd_drag->dnd_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
/* The operation is already finished, we can destroy all
* related data.
*/
dnd_drag_destroy(dnd_drag, delete_item);
window_schedule_redraw(dnd->window);
}
static void
data_source_action(void *data, struct wl_data_source *source, uint32_t dnd_action)
{
struct dnd_drag *dnd_drag = data;
dnd_drag->dnd_action = dnd_action;
dnd_drag_update_surface(dnd_drag);
dnd_drag_update_cursor(dnd_drag);
}
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 cairo_surface_t * static cairo_surface_t *
@ -488,7 +389,6 @@ create_drag_source(struct dnd *dnd,
unsigned int i; unsigned int i;
uint32_t serial; uint32_t serial;
cairo_surface_t *icon; cairo_surface_t *icon;
uint32_t actions;
widget_get_allocation(dnd->widget, &allocation); widget_get_allocation(dnd->widget, &allocation);
item = dnd_get_item(dnd, x, y); item = dnd_get_item(dnd, x, y);
@ -503,11 +403,13 @@ create_drag_source(struct dnd *dnd,
dnd_drag->item = item; dnd_drag->item = item;
dnd_drag->x_offset = x - item->x; dnd_drag->x_offset = x - item->x;
dnd_drag->y_offset = y - item->y; dnd_drag->y_offset = y - item->y;
dnd_drag->dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
dnd_drag->mime_type = NULL;
actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; if (item == dnd->items[i]){
dnd->items[i] = 0;
break;
}
}
display = window_get_display(dnd->window); display = window_get_display(dnd->window);
compositor = display_get_compositor(display); compositor = display_get_compositor(display);
@ -515,30 +417,11 @@ 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) <
WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION) {
/* Data sources version < 3 will not get action
* nor dnd_finished events, as we can't honor
* the "move" action at the time of finishing
* drag-and-drop, do it preemptively here.
*/
for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
if (item == dnd->items[i]){
dnd->items[i] = NULL;
break;
}
}
}
if (dnd->self_only) { if (dnd->self_only) {
dnd_drag->data_source = NULL; dnd_drag->data_source = NULL;
} else { } else {
dnd_drag->data_source = dnd_drag->data_source =
display_create_data_source(dnd->display); display_create_data_source(dnd->display);
if (!dnd_drag->data_source) {
fprintf(stderr, "No data device manager\n");
abort();
}
wl_data_source_add_listener(dnd_drag->data_source, wl_data_source_add_listener(dnd_drag->data_source,
&data_source_listener, &data_source_listener,
dnd_drag); dnd_drag);
@ -546,11 +429,6 @@ 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) >=
WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION) {
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),
@ -662,6 +540,8 @@ dnd_enter_handler(struct widget *widget,
struct dnd *dnd = data; struct dnd *dnd = data;
struct pointer *new_pointer = malloc(sizeof *new_pointer); struct pointer *new_pointer = malloc(sizeof *new_pointer);
dnd->current_drag = NULL;
if (new_pointer) { if (new_pointer) {
new_pointer->input = input; new_pointer->input = input;
new_pointer->dragging = false; new_pointer->dragging = false;
@ -772,6 +652,7 @@ dnd_drop_handler(struct window *window, struct input *input,
message.x_offset = dnd->current_drag->x_offset; message.x_offset = dnd->current_drag->x_offset;
message.y_offset = dnd->current_drag->y_offset; message.y_offset = dnd->current_drag->y_offset;
dnd_receive_func(&message, sizeof message, x, y, dnd); dnd_receive_func(&message, sizeof message, x, y, dnd);
dnd->current_drag = NULL;
} else { } else {
fprintf(stderr, "ignoring drop from another client\n"); fprintf(stderr, "ignoring drop from another client\n");
} }
@ -789,8 +670,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 +730,7 @@ main(int argc, char *argv[])
d = display_create(&argc, argv); d = display_create(&argc, argv);
if (d == NULL) { if (d == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }

View file

@ -2,31 +2,28 @@
* Copyright © 2012 Openismus GmbH * Copyright © 2012 Openismus GmbH
* Copyright © 2012 Intel Corporation * Copyright © 2012 Intel Corporation
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and
* copy of this software and associated documentation files (the "Software"), * its documentation for any purpose is hereby granted without fee, provided
* to deal in the Software without restriction, including without limitation * that the above copyright notice appear in all copies and that both that
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * copyright notice and this permission notice appear in supporting
* and/or sell copies of the Software, and to permit persons to whom the * documentation, and that the name of the copyright holders not be used in
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* paragraph) shall be included in all copies or substantial portions of the * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* Software. * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* 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 "config.h"
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -38,18 +35,14 @@
#include <pango/pangocairo.h> #include <pango/pangocairo.h>
#include <libweston/config-parser.h>
#include "shared/helpers.h"
#include "shared/xalloc.h"
#include "window.h" #include "window.h"
#include "text-input-unstable-v1-client-protocol.h" #include "text-client-protocol.h"
struct text_entry { struct text_entry {
struct widget *widget; struct widget *widget;
struct window *window; struct window *window;
char *text; char *text;
int active; int active;
bool panel_visible;
uint32_t cursor; uint32_t cursor;
uint32_t anchor; uint32_t anchor;
struct { struct {
@ -69,7 +62,7 @@ struct text_entry {
uint32_t delete_length; uint32_t delete_length;
bool invalid_delete; bool invalid_delete;
} pending_commit; } pending_commit;
struct zwp_text_input_v1 *text_input; struct wl_text_input *text_input;
PangoLayout *layout; PangoLayout *layout;
struct { struct {
xkb_mod_mask_t shift_mask; xkb_mod_mask_t shift_mask;
@ -77,13 +70,13 @@ 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;
}; };
struct editor { struct editor {
struct zwp_text_input_manager_v1 *text_input_manager; struct wl_text_input_manager *text_input_manager;
struct wl_data_source *selection; struct wl_data_source *selection;
char *selected_text; char *selected_text;
struct display *display; struct display *display;
@ -187,7 +180,7 @@ static void text_entry_update(struct text_entry *entry);
static void static void
text_input_commit_string(void *data, text_input_commit_string(void *data,
struct zwp_text_input_v1 *text_input, struct wl_text_input *text_input,
uint32_t serial, uint32_t serial,
const char *text) const char *text)
{ {
@ -239,7 +232,7 @@ clear_pending_preedit(struct text_entry *entry)
static void static void
text_input_preedit_string(void *data, text_input_preedit_string(void *data,
struct zwp_text_input_v1 *text_input, struct wl_text_input *text_input,
uint32_t serial, uint32_t serial,
const char *text, const char *text,
const char *commit) const char *commit)
@ -280,7 +273,7 @@ text_input_preedit_string(void *data,
static void static void
text_input_delete_surrounding_text(void *data, text_input_delete_surrounding_text(void *data,
struct zwp_text_input_v1 *text_input, struct wl_text_input *text_input,
int32_t index, int32_t index,
uint32_t length) uint32_t length)
{ {
@ -305,7 +298,7 @@ text_input_delete_surrounding_text(void *data,
static void static void
text_input_cursor_position(void *data, text_input_cursor_position(void *data,
struct zwp_text_input_v1 *text_input, struct wl_text_input *text_input,
int32_t index, int32_t index,
int32_t anchor) int32_t anchor)
{ {
@ -317,7 +310,7 @@ text_input_cursor_position(void *data,
static void static void
text_input_preedit_styling(void *data, text_input_preedit_styling(void *data,
struct zwp_text_input_v1 *text_input, struct wl_text_input *text_input,
uint32_t index, uint32_t index,
uint32_t length, uint32_t length,
uint32_t style) uint32_t style)
@ -330,24 +323,24 @@ text_input_preedit_styling(void *data,
entry->preedit_info.attr_list = pango_attr_list_new(); entry->preedit_info.attr_list = pango_attr_list_new();
switch (style) { switch (style) {
case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_DEFAULT: case WL_TEXT_INPUT_PREEDIT_STYLE_DEFAULT:
case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_UNDERLINE: case WL_TEXT_INPUT_PREEDIT_STYLE_UNDERLINE:
attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
break; break;
case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_INCORRECT: case WL_TEXT_INPUT_PREEDIT_STYLE_INCORRECT:
attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR); attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR);
attr2 = pango_attr_underline_color_new(65535, 0, 0); attr2 = pango_attr_underline_color_new(65535, 0, 0);
break; break;
case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_SELECTION: case WL_TEXT_INPUT_PREEDIT_STYLE_SELECTION:
attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535); attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
attr2 = pango_attr_foreground_new(65535, 65535, 65535); attr2 = pango_attr_foreground_new(65535, 65535, 65535);
break; break;
case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT: case WL_TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT:
case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_ACTIVE: case WL_TEXT_INPUT_PREEDIT_STYLE_ACTIVE:
attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD); attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
break; break;
case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_INACTIVE: case WL_TEXT_INPUT_PREEDIT_STYLE_INACTIVE:
attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535); attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535);
break; break;
@ -368,7 +361,7 @@ text_input_preedit_styling(void *data,
static void static void
text_input_preedit_cursor(void *data, text_input_preedit_cursor(void *data,
struct zwp_text_input_v1 *text_input, struct wl_text_input *text_input,
int32_t index) int32_t index)
{ {
struct text_entry *entry = data; struct text_entry *entry = data;
@ -378,7 +371,7 @@ text_input_preedit_cursor(void *data,
static void static void
text_input_modifiers_map(void *data, text_input_modifiers_map(void *data,
struct zwp_text_input_v1 *text_input, struct wl_text_input *text_input,
struct wl_array *map) struct wl_array *map)
{ {
struct text_entry *entry = data; struct text_entry *entry = data;
@ -388,7 +381,7 @@ text_input_modifiers_map(void *data,
static void static void
text_input_keysym(void *data, text_input_keysym(void *data,
struct zwp_text_input_v1 *text_input, struct wl_text_input *text_input,
uint32_t serial, uint32_t serial,
uint32_t time, uint32_t time,
uint32_t key, uint32_t key,
@ -475,7 +468,7 @@ text_input_keysym(void *data,
static void static void
text_input_enter(void *data, text_input_enter(void *data,
struct zwp_text_input_v1 *text_input, struct wl_text_input *text_input,
struct wl_surface *surface) struct wl_surface *surface)
{ {
struct text_entry *entry = data; struct text_entry *entry = data;
@ -493,31 +486,29 @@ text_input_enter(void *data,
static void static void
text_input_leave(void *data, text_input_leave(void *data,
struct zwp_text_input_v1 *text_input) struct wl_text_input *text_input)
{ {
struct text_entry *entry = data; struct text_entry *entry = data;
text_entry_commit_and_reset(entry); text_entry_commit_and_reset(entry);
entry->active--; entry->active--;
if (!entry->active) { if (!entry->active)
zwp_text_input_v1_hide_input_panel(text_input); wl_text_input_hide_input_panel(text_input);
entry->panel_visible = false;
}
widget_schedule_redraw(entry->widget); widget_schedule_redraw(entry->widget);
} }
static void static void
text_input_input_panel_state(void *data, text_input_input_panel_state(void *data,
struct zwp_text_input_v1 *text_input, struct wl_text_input *text_input,
uint32_t state) uint32_t state)
{ {
} }
static void static void
text_input_language(void *data, text_input_language(void *data,
struct zwp_text_input_v1 *text_input, struct wl_text_input *text_input,
uint32_t serial, uint32_t serial,
const char *language) const char *language)
{ {
@ -526,7 +517,7 @@ text_input_language(void *data,
static void static void
text_input_text_direction(void *data, text_input_text_direction(void *data,
struct zwp_text_input_v1 *text_input, struct wl_text_input *text_input,
uint32_t serial, uint32_t serial,
uint32_t direction) uint32_t direction)
{ {
@ -536,13 +527,13 @@ text_input_text_direction(void *data,
switch (direction) { switch (direction) {
case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_LTR: case WL_TEXT_INPUT_TEXT_DIRECTION_LTR:
pango_direction = PANGO_DIRECTION_LTR; pango_direction = PANGO_DIRECTION_LTR;
break; break;
case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_RTL: case WL_TEXT_INPUT_TEXT_DIRECTION_RTL:
pango_direction = PANGO_DIRECTION_RTL; pango_direction = PANGO_DIRECTION_RTL;
break; break;
case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_AUTO: case WL_TEXT_INPUT_TEXT_DIRECTION_AUTO:
default: default:
pango_direction = PANGO_DIRECTION_NEUTRAL; pango_direction = PANGO_DIRECTION_NEUTRAL;
} }
@ -550,7 +541,7 @@ text_input_text_direction(void *data,
pango_context_set_base_dir(context, pango_direction); pango_context_set_base_dir(context, pango_direction);
} }
static const struct zwp_text_input_v1_listener text_input_listener = { static const struct wl_text_input_listener text_input_listener = {
text_input_enter, text_input_enter,
text_input_leave, text_input_leave,
text_input_modifiers_map, text_input_modifiers_map,
@ -579,10 +570,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) write(fd, editor->selected_text, strlen(editor->selected_text) + 1);
fprintf(stderr, "write failed: %s\n", strerror(errno));
close(fd);
} }
static void static void
@ -639,9 +627,6 @@ editor_copy_cut(struct editor *editor, struct input *input, bool cut)
editor->selection = editor->selection =
display_create_data_source(editor->display); display_create_data_source(editor->display);
if (!editor->selection)
return;
wl_data_source_offer(editor->selection, wl_data_source_offer(editor->selection,
"text/plain;charset=utf-8"); "text/plain;charset=utf-8");
wl_data_source_add_listener(editor->selection, wl_data_source_add_listener(editor->selection,
@ -699,19 +684,17 @@ text_entry_create(struct editor *editor, const char *text)
{ {
struct text_entry *entry; struct text_entry *entry;
entry = xzalloc(sizeof *entry); entry = xmalloc(sizeof *entry);
memset(entry, 0, sizeof *entry);
entry->widget = widget_add_widget(editor->widget, entry); entry->widget = widget_add_widget(editor->widget, entry);
entry->window = editor->window; entry->window = editor->window;
entry->text = strdup(text); entry->text = strdup(text);
entry->active = 0; entry->active = 0;
entry->panel_visible = false;
entry->cursor = strlen(text); entry->cursor = strlen(text);
entry->anchor = entry->cursor; entry->anchor = entry->cursor;
entry->text_input = entry->text_input = wl_text_input_manager_create_text_input(editor->text_input_manager);
zwp_text_input_manager_v1_create_text_input(editor->text_input_manager); wl_text_input_add_listener(entry->text_input, &text_input_listener, entry);
zwp_text_input_v1_add_listener(entry->text_input,
&text_input_listener, entry);
widget_set_redraw_handler(entry->widget, text_entry_redraw_handler); widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
widget_set_button_handler(entry->widget, text_entry_button_handler); widget_set_button_handler(entry->widget, text_entry_button_handler);
@ -725,10 +708,9 @@ static void
text_entry_destroy(struct text_entry *entry) text_entry_destroy(struct text_entry *entry)
{ {
widget_destroy(entry->widget); widget_destroy(entry->widget);
zwp_text_input_v1_destroy(entry->text_input); wl_text_input_destroy(entry->text_input);
g_clear_object(&entry->layout); g_clear_object(&entry->layout);
free(entry->text); free(entry->text);
free(entry->preferred_language);
free(entry); free(entry);
} }
@ -794,30 +776,25 @@ text_entry_activate(struct text_entry *entry,
struct wl_surface *surface = window_get_wl_surface(entry->window); struct wl_surface *surface = window_get_wl_surface(entry->window);
if (entry->click_to_show && entry->active) { if (entry->click_to_show && entry->active) {
entry->panel_visible = !entry->panel_visible; wl_text_input_show_input_panel(entry->text_input);
if (entry->panel_visible)
zwp_text_input_v1_show_input_panel(entry->text_input);
else
zwp_text_input_v1_hide_input_panel(entry->text_input);
return; return;
} }
if (!entry->click_to_show) if (!entry->click_to_show)
zwp_text_input_v1_show_input_panel(entry->text_input); wl_text_input_show_input_panel(entry->text_input);
zwp_text_input_v1_activate(entry->text_input, wl_text_input_activate(entry->text_input,
seat, seat,
surface); surface);
} }
static void static void
text_entry_deactivate(struct text_entry *entry, text_entry_deactivate(struct text_entry *entry,
struct wl_seat *seat) struct wl_seat *seat)
{ {
zwp_text_input_v1_deactivate(entry->text_input, wl_text_input_deactivate(entry->text_input,
seat); seat);
} }
static void static void
@ -888,27 +865,24 @@ text_entry_update(struct text_entry *entry)
{ {
struct rectangle cursor_rectangle; struct rectangle cursor_rectangle;
zwp_text_input_v1_set_content_type(entry->text_input, wl_text_input_set_content_type(entry->text_input,
ZWP_TEXT_INPUT_V1_CONTENT_HINT_NONE, WL_TEXT_INPUT_CONTENT_HINT_NONE,
entry->content_purpose); entry->content_purpose);
zwp_text_input_v1_set_surrounding_text(entry->text_input, wl_text_input_set_surrounding_text(entry->text_input,
entry->text, entry->text,
entry->cursor, entry->cursor,
entry->anchor); entry->anchor);
if (entry->preferred_language) if (entry->preferred_language)
zwp_text_input_v1_set_preferred_language(entry->text_input, wl_text_input_set_preferred_language(entry->text_input,
entry->preferred_language); entry->preferred_language);
text_entry_get_cursor_rectangle(entry, &cursor_rectangle); text_entry_get_cursor_rectangle(entry, &cursor_rectangle);
zwp_text_input_v1_set_cursor_rectangle(entry->text_input, wl_text_input_set_cursor_rectangle(entry->text_input, cursor_rectangle.x, cursor_rectangle.y,
cursor_rectangle.x, cursor_rectangle.width, cursor_rectangle.height);
cursor_rectangle.y,
cursor_rectangle.width,
cursor_rectangle.height);
zwp_text_input_v1_commit_state(entry->text_input, ++entry->serial); wl_text_input_commit_state(entry->text_input, ++entry->serial);
} }
static void static void
@ -970,7 +944,7 @@ text_entry_commit_and_reset(struct text_entry *entry)
free(commit); free(commit);
} }
zwp_text_input_v1_reset(entry->text_input); wl_text_input_reset(entry->text_input);
text_entry_update(entry); text_entry_update(entry);
entry->reset_serial = entry->serial; entry->reset_serial = entry->serial;
} }
@ -1019,9 +993,9 @@ text_entry_try_invoke_preedit_action(struct text_entry *entry,
} }
if (state == WL_POINTER_BUTTON_STATE_RELEASED) if (state == WL_POINTER_BUTTON_STATE_RELEASED)
zwp_text_input_v1_invoke_action(entry->text_input, wl_text_input_invoke_action(entry->text_input,
button, button,
cursor - entry->cursor); cursor - entry->cursor);
return 1; return 1;
} }
@ -1496,132 +1470,46 @@ global_handler(struct display *display, uint32_t name,
{ {
struct editor *editor = data; struct editor *editor = data;
if (!strcmp(interface, "zwp_text_input_manager_v1")) { if (!strcmp(interface, "wl_text_input_manager")) {
editor->text_input_manager = editor->text_input_manager =
display_bind(display, name, display_bind(display, name,
&zwp_text_input_manager_v1_interface, 1); &wl_text_input_manager_interface, 1);
} }
} }
/** Display help for command line options, and exit */
static bool opt_help = false;
/** Require a distinct click to show the input panel (virtual keyboard) */
static bool opt_click_to_show = false;
/** Set a specific (RFC-3066) language. Used for the virtual keyboard, etc. */
static const char *opt_preferred_language = NULL;
/**
* \brief command line options for editor
*/
static const struct weston_option editor_options[] = {
{ WESTON_OPTION_BOOLEAN, "help", 'h', &opt_help },
{ WESTON_OPTION_BOOLEAN, "click-to-show", 'C', &opt_click_to_show },
{ WESTON_OPTION_STRING, "preferred-language", 'L', &opt_preferred_language },
};
static void
usage(const char *program_name, int exit_code)
{
unsigned k;
fprintf(stderr, "Usage: %s [OPTIONS] [FILENAME]\n\n", program_name);
for (k = 0; k < ARRAY_LENGTH(editor_options); k++) {
const struct weston_option *p = &editor_options[k];
if (p->name) {
fprintf(stderr, " --%s", p->name);
if (p->type != WESTON_OPTION_BOOLEAN)
fprintf(stderr, "=VALUE");
fprintf(stderr, "\n");
}
if (p->short_name) {
fprintf(stderr, " -%c", p->short_name);
if (p->type != WESTON_OPTION_BOOLEAN)
fprintf(stderr, "VALUE");
fprintf(stderr, "\n");
}
}
exit(exit_code);
}
/* Load the contents of a file into a UTF-8 text buffer and return it.
*
* Caller is responsible for freeing the buffer when done.
* On error, returns NULL.
*/
static char *
read_file(char *filename)
{
char *buffer = NULL;
int buf_size, read_size;
FILE *fin;
int errsv;
fin = fopen(filename, "r");
if (fin == NULL)
goto error;
/* Determine required buffer size */
if (fseek(fin, 0, SEEK_END) != 0)
goto error;
buf_size = ftell(fin);
if (buf_size < 0)
goto error;
rewind(fin);
/* Create buffer and read in the text */
buffer = (char*) malloc(sizeof(char) * (buf_size + 1));
if (buffer == NULL)
goto error;
read_size = fread(buffer, sizeof(char), buf_size, fin);
fclose(fin);
if (buf_size != read_size)
goto error;
buffer[buf_size] = '\0';
return buffer;
error:
errsv = errno;
if (fin)
fclose(fin);
free(buffer);
errno = errsv ? errsv : EINVAL;
return NULL;
}
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
struct editor editor; struct editor editor;
char *text_buffer = NULL; int i;
uint32_t click_to_show = 0;
const char *preferred_language = NULL;
parse_options(editor_options, ARRAY_LENGTH(editor_options), for (i = 1; i < argc; i++) {
&argc, argv); if (strcmp("--click-to-show", argv[i]) == 0)
if (opt_help) click_to_show = 1;
usage(argv[0], EXIT_SUCCESS); else if (strcmp("--preferred-language", argv[i]) == 0 &&
i + 1 < argc) {
if (argc > 1) { preferred_language = argv[i + 1];
if (argv[1][0] == '-') i++;
usage(argv[0], EXIT_FAILURE); } else {
printf("Usage: %s [OPTIONS]\n"
text_buffer = read_file(argv[1]); " --click-to-show\n"
if (text_buffer == NULL) { " --preferred-language LANGUAGE\n",
fprintf(stderr, "could not read file '%s': %s\n", argv[0]);
argv[1], strerror(errno)); return 1;
return -1;
} }
} }
memset(&editor, 0, sizeof editor); memset(&editor, 0, sizeof editor);
#ifdef HAVE_PANGO
g_type_init();
#endif
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);
return -1; return -1;
} }
@ -1630,29 +1518,23 @@ main(int argc, char *argv[])
if (editor.text_input_manager == NULL) { if (editor.text_input_manager == NULL) {
fprintf(stderr, "No text input manager global\n"); fprintf(stderr, "No text input manager global\n");
display_destroy(editor.display);
free(text_buffer);
return -1; return -1;
} }
editor.window = window_create(editor.display); editor.window = window_create(editor.display);
editor.widget = window_frame_create(editor.window, &editor); editor.widget = window_frame_create(editor.window, &editor);
if (text_buffer) editor.entry = text_entry_create(&editor, "Entry");
editor.entry = text_entry_create(&editor, text_buffer); editor.entry->click_to_show = click_to_show;
else if (preferred_language)
editor.entry = text_entry_create(&editor, "Entry"); editor.entry->preferred_language = strdup(preferred_language);
editor.entry->click_to_show = opt_click_to_show;
if (opt_preferred_language)
editor.entry->preferred_language = strdup(opt_preferred_language);
editor.editor = text_entry_create(&editor, "Numeric"); editor.editor = text_entry_create(&editor, "Numeric");
editor.editor->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_NUMBER; editor.editor->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
editor.editor->click_to_show = opt_click_to_show; editor.editor->click_to_show = click_to_show;
editor.selection = NULL; editor.selection = NULL;
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);
@ -1676,7 +1558,6 @@ main(int argc, char *argv[])
widget_destroy(editor.widget); widget_destroy(editor.widget);
window_destroy(editor.window); window_destroy(editor.window);
display_destroy(editor.display); display_destroy(editor.display);
free(text_buffer);
return 0; return 0;
} }

View file

@ -1,24 +1,23 @@
/* /*
* Copyright © 2011 Tim Wiederhake * Copyright © 2011 Tim Wiederhake
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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.
*/ */
/** /**
@ -33,21 +32,15 @@
#include "config.h" #include "config.h"
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <cairo.h> #include <cairo.h>
#include "shared/helpers.h"
#include "window.h" #include "window.h"
/** 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 +49,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 +58,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
@ -98,8 +91,6 @@ struct eventdemo {
struct display *display; struct display *display;
int x, y, w, h; int x, y, w, h;
bool print_pointer_frame;
}; };
/** /**
@ -179,8 +170,8 @@ keyboard_focus_handler(struct window *window,
int32_t x, y; int32_t x, y;
struct eventdemo *e = data; struct eventdemo *e = data;
if (log_focus) { if(log_focus) {
if (device) { if(device) {
input_get_position(device, &x, &y); input_get_position(device, &x, &y);
printf("focus x: %d, y: %d\n", x, y); printf("focus x: %d, y: %d\n", x, y);
} else { } else {
@ -194,11 +185,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
@ -208,10 +198,10 @@ key_handler(struct window *window, struct input *input, uint32_t time,
{ {
uint32_t modifiers = input_get_modifiers(input); uint32_t modifiers = input_get_modifiers(input);
if (!log_key) if(!log_key)
return; return;
printf("key key: %u, unicode: %u, state: %s, modifiers: 0x%x\n", printf("key key: %d, unicode: %d, state: %s, modifiers: 0x%x\n",
key, unicode, key, unicode,
(state == WL_KEYBOARD_KEY_STATE_PRESSED) ? "pressed" : (state == WL_KEYBOARD_KEY_STATE_PRESSED) ? "pressed" :
"released", "released",
@ -231,16 +221,13 @@ static void
button_handler(struct widget *widget, struct input *input, uint32_t time, button_handler(struct widget *widget, struct input *input, uint32_t time,
uint32_t button, enum wl_pointer_button_state state, void *data) uint32_t button, enum wl_pointer_button_state state, void *data)
{ {
struct eventdemo *e = data;
int32_t x, y; int32_t x, y;
if (!log_button) if (!log_button)
return; return;
e->print_pointer_frame = true;
input_get_position(input, &x, &y); input_get_position(input, &x, &y);
printf("button time: %u, button: %u, state: %s, x: %d, y: %d\n", printf("button time: %d, button: %d, state: %s, x: %d, y: %d\n",
time, button, time, button,
(state == WL_POINTER_BUTTON_STATE_PRESSED) ? "pressed" : (state == WL_POINTER_BUTTON_STATE_PRESSED) ? "pressed" :
"released", "released",
@ -260,99 +247,25 @@ static void
axis_handler(struct widget *widget, struct input *input, uint32_t time, axis_handler(struct widget *widget, struct input *input, uint32_t time,
uint32_t axis, wl_fixed_t value, void *data) uint32_t axis, wl_fixed_t value, void *data)
{ {
struct eventdemo *e = data;
if (!log_axis) if (!log_axis)
return; return;
e->print_pointer_frame = true; printf("axis time: %d, axis: %s, value: %f\n",
printf("axis time: %u, axis: %s, value: %f\n",
time, time,
axis == WL_POINTER_AXIS_VERTICAL_SCROLL ? "vertical" : axis == WL_POINTER_AXIS_VERTICAL_SCROLL ? "vertical" :
"horizontal", "horizontal",
wl_fixed_to_double(value)); wl_fixed_to_double(value));
} }
static void
pointer_frame_handler(struct widget *widget, struct input *input, void *data)
{
struct eventdemo *e = data;
if (!e->print_pointer_frame)
return;
printf("pointer frame\n");
e->print_pointer_frame = false;
}
static void
axis_source_handler(struct widget *widget, struct input *input,
uint32_t source, void *data)
{
const char *axis_source;
struct eventdemo *e = data;
if (!log_axis)
return;
e->print_pointer_frame = true;
switch (source) {
case WL_POINTER_AXIS_SOURCE_WHEEL:
axis_source = "wheel";
break;
case WL_POINTER_AXIS_SOURCE_FINGER:
axis_source = "finger";
break;
case WL_POINTER_AXIS_SOURCE_CONTINUOUS:
axis_source = "continuous";
break;
default:
axis_source = "<invalid source value>";
break;
}
printf("axis source: %s\n", axis_source);
}
static void
axis_stop_handler(struct widget *widget, struct input *input,
uint32_t time, uint32_t axis,
void *data)
{
struct eventdemo *e = data;
if (!log_axis)
return;
e->print_pointer_frame = true;
printf("axis stop time: %u, axis: %s\n",
time,
axis == WL_POINTER_AXIS_VERTICAL_SCROLL ? "vertical" :
"horizontal");
}
static void
axis_discrete_handler(struct widget *widget, struct input *input,
uint32_t axis, int32_t discrete, void *data)
{
struct eventdemo *e = data;
if (!log_axis)
return;
e->print_pointer_frame = true;
printf("axis discrete axis: %u value: %d\n", axis, discrete);
}
/** /**
* \brief CALLBACK function, Waylands informs about pointer motion * \brief CALLBACK function, Waylands informs about pointer motion
* \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
@ -364,8 +277,7 @@ motion_handler(struct widget *widget, struct input *input, uint32_t time,
struct eventdemo *e = data; struct eventdemo *e = data;
if (log_motion) { if (log_motion) {
printf("motion time: %u, x: %f, y: %f\n", time, x, y); printf("motion time: %d, x: %f, y: %f\n", time, x, y);
e->print_pointer_frame = true;
} }
if (x > e->x && x < e->x + e->w) if (x > e->x && x < e->x + e->w)
@ -385,8 +297,8 @@ eventdemo_create(struct display *d)
{ {
struct eventdemo *e; struct eventdemo *e;
e = zalloc(sizeof (struct eventdemo)); e = malloc(sizeof (struct eventdemo));
if (e == NULL) if(e == NULL)
return NULL; return NULL;
e->window = window_create(d); e->window = window_create(d);
@ -399,7 +311,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;
@ -434,15 +345,8 @@ eventdemo_create(struct display *d)
/* Set the callback motion handler for the window */ /* Set the callback motion handler for the window */
widget_set_motion_handler(e->widget, motion_handler); widget_set_motion_handler(e->widget, motion_handler);
/* Set the callback pointer frame handler for the window */
widget_set_pointer_frame_handler(e->widget, pointer_frame_handler);
/* Set the callback axis handler for the window */ /* Set the callback axis handler for the window */
widget_set_axis_handlers(e->widget, widget_set_axis_handler(e->widget, axis_handler);
axis_handler,
axis_source_handler,
axis_stop_handler,
axis_discrete_handler);
/* Initial drawing of the window */ /* Initial drawing of the window */
window_schedule_resize(e->window, width, height); window_schedule_resize(e->window, width, height);
@ -513,21 +417,19 @@ main(int argc, char *argv[])
if (!log_redraw && !log_resize && !log_focus && !log_key && if (!log_redraw && !log_resize && !log_focus && !log_key &&
!log_button && !log_axis && !log_motion) !log_button && !log_axis && !log_motion)
log_redraw = log_resize = log_focus = log_key = log_redraw = log_resize = log_focus = log_key =
log_button = log_axis = log_motion = true; log_button = log_axis = log_motion = 1;
/* Connect to the display and have the arguments parsed */ /* Connect to the display and have the arguments parsed */
d = display_create(&argc, argv); d = display_create(&argc, argv);
if (d == NULL) { if (d == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }
/* Create new eventdemo window */ /* Create new eventdemo window */
e = eventdemo_create(d); e = eventdemo_create(d);
if (e == NULL) { if (e == NULL) {
fprintf(stderr, "failed to create eventdemo: %s\n", fprintf(stderr, "failed to create eventdemo: %m\n");
strerror(errno));
return -1; return -1;
} }

View file

@ -1,24 +1,23 @@
/* /*
* Copyright © 2008 Kristian Høgsberg * Copyright © 2008 Kristian Høgsberg
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 "config.h"
@ -30,7 +29,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>
@ -111,7 +109,7 @@ resize_handler(struct widget *widget,
{ {
struct flower *flower = data; struct flower *flower = data;
/* Don't resize me */ /* Dont resize me */
widget_set_size(flower->widget, flower->width, flower->height); widget_set_size(flower->widget, flower->width, flower->height);
} }
@ -173,8 +171,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 +184,6 @@ int main(int argc, char *argv[])
flower.window = window_create(d); flower.window = window_create(d);
flower.widget = window_add_widget(flower.window, &flower); flower.widget = window_add_widget(flower.window, &flower);
window_set_title(flower.window, "Flower"); window_set_title(flower.window, "Flower");
window_set_appid(flower.window, "org.freedesktop.weston.flower");
widget_set_resize_handler(flower.widget, resize_handler); widget_set_resize_handler(flower.widget, resize_handler);
widget_set_redraw_handler(flower.widget, redraw_handler); widget_set_redraw_handler(flower.widget, redraw_handler);

View file

@ -2,24 +2,23 @@
* Copyright © 2008 Kristian Høgsberg * Copyright © 2008 Kristian Høgsberg
* Copyright © 2012 Intel Corporation * Copyright © 2012 Intel Corporation
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 "config.h"
@ -30,13 +29,12 @@
#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-client-protocol.h"
struct fs_output { struct fs_output {
struct wl_list link; struct wl_list link;
@ -47,6 +45,8 @@ struct fullscreen {
struct display *display; struct display *display;
struct window *window; struct window *window;
struct widget *widget; struct widget *widget;
struct _wl_fullscreen_shell *fshell;
enum _wl_fullscreen_shell_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 +77,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 +119,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 +145,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 +250,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 +277,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 +284,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;
_wl_fullscreen_shell_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 */
_wl_fullscreen_shell_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;
_wl_fullscreen_shell_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);
_wl_fullscreen_shell_mode_feedback_destroy(
_wl_fullscreen_shell_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 +418,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 _wl_fullscreen_shell *fshell,
uint32_t capability)
{
struct fullscreen *fullscreen = data;
switch (capability) {
case _WL_FULLSCREEN_SHELL_CAPABILITY_CURSOR_PLANE:
fullscreen->draw_cursor = 0;
break;
default:
break;
}
}
struct _wl_fullscreen_shell_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);
@ -363,15 +459,27 @@ output_handler(struct output *output, void *data)
if (fsout->output == output) if (fsout->output == output)
return; return;
fsout = zalloc(sizeof *fsout); fsout = calloc(1, sizeof *fsout);
if (fsout == NULL) {
fprintf(stderr, "out of memory in output_handler\n");
return;
}
fsout->output = output; fsout->output = output;
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, "_wl_fullscreen_shell") == 0) {
fullscreen->fshell = display_bind(display, id,
&_wl_fullscreen_shell_interface,
1);
_wl_fullscreen_shell_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 +489,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 = _WL_FULLSCREEN_SHELL_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 +504,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 +512,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);
_wl_fullscreen_shell_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 +554,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);

500
clients/gears.c Normal file
View file

@ -0,0 +1,500 @@
/*
* Copyright © 2008 Kristian Høgsberg
*
* 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 <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;
}

1062
clients/glmatrix.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -2,24 +2,23 @@
* Copyright © 2008 Kristian Høgsberg * Copyright © 2008 Kristian Høgsberg
* Copyright © 2009 Chris Wilson * Copyright © 2009 Chris Wilson
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 "config.h"
@ -36,32 +35,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 +62,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 +80,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 =
@ -142,7 +92,7 @@ clamp_view(struct image *image)
image->matrix.x0 = allocation.width - sw; image->matrix.x0 = allocation.width - sw;
} }
if (sh < allocation.height) { if (sh < allocation.width) {
image->matrix.y0 = image->matrix.y0 =
(allocation.height - image->height * scale) / 2; (allocation.height - image->height * scale) / 2;
} else { } else {
@ -154,45 +104,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 +146,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 +213,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 +235,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 +277,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 +308,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 +347,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 +379,51 @@ image_create(struct display *display, const char *filename,
} }
image->window = window_create(display); image->window = window_create(display);
image->widget = window_frame_create(image->window, image);
window_set_title(image->window, title); window_set_title(image->window, title);
window_set_appid(image->window, "org.freedesktop.weston.wayland-image");
image->display = display; image->display = display;
image->image_counter = image_counter; image->image_counter = image_counter;
*image_counter += 1; *image_counter += 1;
image->initialized = false; image->initialized = false;
window_set_user_data(image->window, image); window_set_user_data(image->window, image);
widget_set_redraw_handler(image->widget, redraw_handler);
widget_set_resize_handler(image->widget, resize_handler);
window_set_keyboard_focus_handler(image->window, window_set_keyboard_focus_handler(image->window,
keyboard_focus_handler); keyboard_focus_handler);
window_set_fullscreen_handler(image->window, fullscreen_handler); window_set_fullscreen_handler(image->window, fullscreen_handler);
window_set_close_handler(image->window, close_handler); window_set_close_handler(image->window, close_handler);
widget_set_enter_handler(image->widget, enter_handler);
widget_set_motion_handler(image->widget, motion_handler);
widget_set_button_handler(image->widget, button_handler);
widget_set_axis_handler(image->widget, axis_handler);
window_set_key_handler(image->window, key_handler); window_set_key_handler(image->window, key_handler);
widget_schedule_resize(image->widget, 500, 400);
image->frame_widget = window_frame_create(image->window, image);
widget_set_redraw_handler(image->frame_widget, frame_redraw_handler);
widget_set_resize_handler(image->frame_widget, frame_resize_handler);
image->image_widget = window_add_subsurface(image->window, image,
SUBSURFACE_SYNCHRONIZED);
/* We set the input region of the subsurface where the image is draw as
* NULL, as the input region of the parent surface is automatically set
* by the toytoolkit. But as the window that finds the widget in a
* certain (x, y) position looks for surfaces that are on top first, it
* will call the image_widget handlers for input related stuff. */
set_empty_input_region(image->image_widget, display);
widget_set_redraw_handler(image->image_widget, image_redraw_handler);
widget_set_resize_handler(image->image_widget, image_resize_handler);
widget_set_enter_handler(image->image_widget, image_enter_handler);
widget_set_motion_handler(image->image_widget, image_motion_handler);
widget_set_button_handler(image->image_widget, image_button_handler);
widget_set_axis_handler(image->image_widget, image_axis_handler);
wimage = load_cairo_surface_get_user_data(image->image);
assert(wimage);
if (wimage->icc_profile_data && render_intent != -1) {
verbose_print("Image contains ICC file embedded, let's try to use the Wayland\n" \
"color-management protocol to set the surface image description\n" \
"using this ICC file.\n");
ret = widget_set_image_description_icc(image->image_widget,
wimage->icc_profile_data->fd,
wimage->icc_profile_data->length,
wimage->icc_profile_data->offset,
render_intent, &err_msg);
if (ret) {
verbose_print("Successfully set surface image description " \
"using ICC file.\n");
} else {
fprintf(stderr, "Failed to set surface image description:\n%s\n",
err_msg);
free(err_msg);
}
}
/* TODO: investigate if/how to get colorimetry info from the
* PNG/JPEG/etc image. Then use that to create a parametric image
* description and set it as the widget image description. Also, if
* clients do not enforce us to avoid setting an image description (i.e.
* render_intent != -1) but no colorimetry data is present, we can
* create a sRGB image description (through parameters) and set it as
* the image description to use. For now Weston do not support creating
* image description from parameters, that's why we've added only the
* code above that depends on ICC profiles. */
widget_schedule_resize(image->frame_widget, 500, 400);
return image; return image;
} }
static void
print_usage(const char *program_name)
{
const struct render_intent_info *intent_info;
const char *desc;
unsigned int i;
fprintf(stderr, "Usage:\n %s [OPTIONS] [FILENAME0] [FILENAME1] ...\n\n" \
"Options:\n", program_name);
fprintf(stderr, "-v or --verbose to print verbose log information.\n\n");
fprintf(stderr, "-h or --help to open this HELP dialogue.\n\n");
fprintf(stderr, "-r or --rendering-intent to choose the color-management rendering intent.\n\n " \
"The rendering intent is used when an image file has colorimetry data embedded,\n " \
"and the compositor should present this image taking this into account. We use\n " \
"the Wayland color-management protocol extension to set the image description\n " \
"and a rendering intent, which is up to the client to decide. This is optional,\n " \
"and if nothing set we'll use 'perceptual'. Supported values:\n\n");
for (i = 0; i < ARRAY_LENGTH(cli_ri_table); i++) {
/* "off" option does not have a corresponding render_intent_info
* object from which we would be able to get the description. */
intent_info = render_intent_info_from(cli_ri_table[i].render_intent);
if (intent_info)
desc = intent_info->desc;
else
desc = "No render intent (do not set image description)";
fprintf(stderr, " %s: %s.\n", cli_ri_table[i].cli_option, desc);
}
}
static int
get_render_intent(int *render_intent, const char *opt_rendering_intent)
{
unsigned int i;
/* The default, if client does not set anything. */
if (!opt_rendering_intent) {
*render_intent = RENDER_INTENT_PERCEPTUAL;
return 0;
}
for (i = 0; i < ARRAY_LENGTH(cli_ri_table); i++) {
if (strcmp(opt_rendering_intent, cli_ri_table[i].cli_option) == 0) {
*render_intent = cli_ri_table[i].render_intent;
return 0;
}
}
fprintf(stderr, "Error: unknown rendering intent: %s.\n\n",
opt_rendering_intent);
return -1;
}
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
struct display *d; struct display *d;
int i; int i;
int image_counter = 0; int image_counter = 0;
int render_intent;
bool opt_help = false;
char *opt_rendering_intent = NULL;
struct weston_option cli_options[] = {
{ WESTON_OPTION_BOOLEAN, "help", 'h', &opt_help },
{ WESTON_OPTION_BOOLEAN, "verbose", 'v', &verbose },
{ WESTON_OPTION_STRING, "rendering-intent", 'r', &opt_rendering_intent },
};
parse_options(cli_options, ARRAY_LENGTH(cli_options), &argc, argv); if (argc <= 1 || argv[1][0]=='-') {
printf("Usage: %s image...\n", argv[0]);
if (argc <= 1 || opt_help ||
get_render_intent(&render_intent, opt_rendering_intent) < 0) {
free(opt_rendering_intent);
print_usage(argv[0]);
return 1; return 1;
} }
free(opt_rendering_intent);
d = display_create(&argc, argv); d = display_create(&argc, argv);
if (d == NULL) { if (d == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }
for (i = 1; i < argc; i++) for (i = 1; i < argc; i++)
image_create(d, argv[i], &image_counter, render_intent); image_create(d, argv[i], &image_counter);
if (image_counter > 0) if (image_counter > 0)
display_run(d); display_run(d);

View file

@ -1,32 +1,28 @@
/* /*
* Copyright (C) 2013 DENSO CORPORATION * Copyright (C) 2013 DENSO CORPORATION
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and
* copy of this software and associated documentation files (the "Software"), * its documentation for any purpose is hereby granted without fee, provided
* to deal in the Software without restriction, including without limitation * that the above copyright notice appear in all copies and that both that
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * copyright notice and this permission notice appear in supporting
* and/or sell copies of the Software, and to permit persons to whom the * documentation, and that the name of the copyright holders not be used in
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* paragraph) shall be included in all copies or substantial portions of the * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* Software. * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* 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 <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <linux/input.h> #include <linux/input.h>
@ -35,16 +31,10 @@
#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 "../shared/cairo-util.h"
#include "shared/cairo-util.h" #include "../shared/config-parser.h"
#include <libweston/config-parser.h> #include "../shared/os-compatibility.h"
#include "shared/helpers.h"
#include "shared/os-compatibility.h"
#include "shared/xalloc.h"
#include <libweston/zalloc.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 +133,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;
}; };
@ -165,10 +153,29 @@ hmi_homescreen_setting {
char *cursor_theme; char *cursor_theme;
int32_t cursor_size; int32_t cursor_size;
uint32_t transition_duration; uint32_t transition_duration;
uint32_t surface_id_offset;
int32_t screen_num;
}; };
static void *
fail_on_null(void *p, size_t size, char *file, int32_t line)
{
if (size && !p) {
fprintf(stderr, "%s(%d) %zd: out of memory\n",
file, line, size);
exit(EXIT_FAILURE);
}
return p;
}
static void *
mem_alloc(size_t size, char *file, int32_t line)
{
return fail_on_null(calloc(1, size), size, file, line);
}
#define MEM_ALLOC(s) mem_alloc((s),__FILE__,__LINE__)
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
/***************************************************************************** /*****************************************************************************
* Event Handler * Event Handler
****************************************************************************/ ****************************************************************************/
@ -310,10 +317,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;
} }
@ -594,10 +603,6 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
wl_registry_bind(registry, name, &wl_shm_interface, 1); wl_registry_bind(registry, name, &wl_shm_interface, 1);
wl_shm_add_listener(p_wlCtx->wlShm, &shm_listenter, p_wlCtx); wl_shm_add_listener(p_wlCtx->wlShm, &shm_listenter, p_wlCtx);
} else if (!strcmp(interface, "wl_seat")) { } else if (!strcmp(interface, "wl_seat")) {
/* XXX: should be handling multiple wl_seats */
if (p_wlCtx->wlSeat)
return;
p_wlCtx->wlSeat = p_wlCtx->wlSeat =
wl_registry_bind(registry, name, &wl_seat_interface, 1); wl_registry_bind(registry, name, &wl_seat_interface, 1);
wl_seat_add_listener(p_wlCtx->wlSeat, &seat_Listener, data); wl_seat_add_listener(p_wlCtx->wlSeat, &seat_Listener, data);
@ -612,8 +617,6 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
ivi_hmi_controller_add_listener(p_wlCtx->hmiCtrl, ivi_hmi_controller_add_listener(p_wlCtx->hmiCtrl,
&hmi_controller_listener, p_wlCtx); &hmi_controller_listener, p_wlCtx);
} else if (!strcmp(interface, "wl_output")) {
p_wlCtx->hmi_setting->screen_num++;
} }
} }
@ -757,7 +760,7 @@ create_cursors(struct wlContextCommon *cmm)
cmm->wlShm); cmm->wlShm);
cmm->cursors = cmm->cursors =
xzalloc(ARRAY_LENGTH(cursors) * sizeof(cmm->cursors[0])); MEM_ALLOC(ARRAY_LENGTH(cursors) * sizeof(cmm->cursors[0]));
for (i = 0; i < ARRAY_LENGTH(cursors); i++) { for (i = 0; i < ARRAY_LENGTH(cursors); i++) {
cursor = NULL; cursor = NULL;
@ -807,8 +810,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 +819,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 +832,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;
} }
@ -1034,7 +1036,7 @@ create_launchers(struct wlContextCommon *cmm, struct wl_list *launcher_list)
if (0 == launcher_count) if (0 == launcher_count)
return; return;
launchers = xzalloc(launcher_count * sizeof(*launchers)); launchers = MEM_ALLOC(launcher_count * sizeof(*launchers));
wl_list_for_each(launcher, launcher_list, link) { wl_list_for_each(launcher, launcher_list, link) {
launchers[ii] = launcher; launchers[ii] = launcher;
@ -1052,7 +1054,7 @@ create_launchers(struct wlContextCommon *cmm, struct wl_list *launcher_list)
for (jj = start; jj <= ii; jj++) { for (jj = start; jj <= ii; jj++) {
struct wlContextStruct *p_wlCtx; struct wlContextStruct *p_wlCtx;
p_wlCtx = xzalloc(sizeof(*p_wlCtx)); p_wlCtx = MEM_ALLOC(sizeof(*p_wlCtx));
p_wlCtx->cmm = cmm; p_wlCtx->cmm = cmm;
create_ivisurfaceFromFile(p_wlCtx, create_ivisurfaceFromFile(p_wlCtx,
launchers[jj]->icon_surface_id, launchers[jj]->icon_surface_id,
@ -1065,32 +1067,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
*/ */
@ -1100,12 +1076,11 @@ hmi_homescreen_setting_create(void)
const char *config_file; const char *config_file;
struct weston_config *config = NULL; struct weston_config *config = NULL;
struct weston_config_section *shellSection = NULL; struct weston_config_section *shellSection = NULL;
struct hmi_homescreen_setting *setting = xzalloc(sizeof(*setting)); struct hmi_homescreen_setting *setting = MEM_ALLOC(sizeof(*setting));
struct weston_config_section *section = NULL; struct weston_config_section *section = NULL;
const char *name = NULL; const char *name = NULL;
uint32_t workspace_layer_id; uint32_t workspace_layer_id;
uint32_t icon_surface_id = 0; uint32_t icon_surface_id = 0;
char *filename;
wl_list_init(&setting->workspace_list); wl_list_init(&setting->workspace_list);
wl_list_init(&setting->launcher_list); wl_list_init(&setting->launcher_list);
@ -1125,70 +1100,56 @@ hmi_homescreen_setting_create(void)
weston_config_section_get_uint( weston_config_section_get_uint(
shellSection, "workspace-layer-id", &workspace_layer_id, 3000); shellSection, "workspace-layer-id", &workspace_layer_id, 3000);
filename = file_name_with_datadir("background.png");
weston_config_section_get_string( weston_config_section_get_string(
shellSection, "background-image", &setting->background.filePath, shellSection, "background-image", &setting->background.filePath,
filename); DATADIR "/weston/background.png");
free(filename);
weston_config_section_get_uint( weston_config_section_get_uint(
shellSection, "background-id", &setting->background.id, 1001); shellSection, "background-id", &setting->background.id, 1001);
filename = file_name_with_datadir("panel.png");
weston_config_section_get_string( weston_config_section_get_string(
shellSection, "panel-image", &setting->panel.filePath, shellSection, "panel-image", &setting->panel.filePath,
filename); DATADIR "/weston/panel.png");
free(filename);
weston_config_section_get_uint( weston_config_section_get_uint(
shellSection, "panel-id", &setting->panel.id, 1002); shellSection, "panel-id", &setting->panel.id, 1002);
filename = file_name_with_datadir("tiling.png");
weston_config_section_get_string( weston_config_section_get_string(
shellSection, "tiling-image", &setting->tiling.filePath, shellSection, "tiling-image", &setting->tiling.filePath,
filename); DATADIR "/weston/tiling.png");
free(filename);
weston_config_section_get_uint( weston_config_section_get_uint(
shellSection, "tiling-id", &setting->tiling.id, 1003); shellSection, "tiling-id", &setting->tiling.id, 1003);
filename = file_name_with_datadir("sidebyside.png");
weston_config_section_get_string( weston_config_section_get_string(
shellSection, "sidebyside-image", &setting->sidebyside.filePath, shellSection, "sidebyside-image", &setting->sidebyside.filePath,
filename); DATADIR "/weston/sidebyside.png");
free(filename);
weston_config_section_get_uint( weston_config_section_get_uint(
shellSection, "sidebyside-id", &setting->sidebyside.id, 1004); shellSection, "sidebyside-id", &setting->sidebyside.id, 1004);
filename = file_name_with_datadir("fullscreen.png");
weston_config_section_get_string( weston_config_section_get_string(
shellSection, "fullscreen-image", &setting->fullscreen.filePath, shellSection, "fullscreen-image", &setting->fullscreen.filePath,
filename); DATADIR "/weston/fullscreen.png");
free(filename);
weston_config_section_get_uint( weston_config_section_get_uint(
shellSection, "fullscreen-id", &setting->fullscreen.id, 1005); shellSection, "fullscreen-id", &setting->fullscreen.id, 1005);
filename = file_name_with_datadir("random.png");
weston_config_section_get_string( weston_config_section_get_string(
shellSection, "random-image", &setting->random.filePath, shellSection, "random-image", &setting->random.filePath,
filename); DATADIR "/weston/random.png");
free(filename);
weston_config_section_get_uint( weston_config_section_get_uint(
shellSection, "random-id", &setting->random.id, 1006); shellSection, "random-id", &setting->random.id, 1006);
filename = file_name_with_datadir("home.png");
weston_config_section_get_string( weston_config_section_get_string(
shellSection, "home-image", &setting->home.filePath, shellSection, "home-image", &setting->home.filePath,
filename); DATADIR "/weston/home.png");
free(filename);
weston_config_section_get_uint( weston_config_section_get_uint(
shellSection, "home-id", &setting->home.id, 1007); shellSection, "home-id", &setting->home.id, 1007);
weston_config_section_get_color( weston_config_section_get_uint(
shellSection, "workspace-background-color", shellSection, "workspace-background-color",
&setting->workspace_background.color, 0x99000000); &setting->workspace_background.color, 0x99000000);
@ -1196,35 +1157,21 @@ hmi_homescreen_setting_create(void)
shellSection, "workspace-background-id", shellSection, "workspace-background-id",
&setting->workspace_background.id, 2001); &setting->workspace_background.id, 2001);
weston_config_section_get_uint(
shellSection, "surface-id-offset", &setting->surface_id_offset, 10);
icon_surface_id = workspace_layer_id + 1; icon_surface_id = workspace_layer_id + 1;
while (weston_config_next_section(config, &section, &name)) { while (weston_config_next_section(config, &section, &name)) {
struct hmi_homescreen_launcher *launcher; struct hmi_homescreen_launcher *launcher;
char *command;
if (strcmp(name, "ivi-launcher") != 0) if (strcmp(name, "ivi-launcher") != 0)
continue; continue;
launcher = xzalloc(sizeof(*launcher)); launcher = MEM_ALLOC(sizeof(*launcher));
wl_list_init(&launcher->link); wl_list_init(&launcher->link);
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",
@ -1250,8 +1197,8 @@ hmi_homescreen_setting_create(void)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct wlContextCommon wlCtxCommon; struct wlContextCommon wlCtxCommon;
struct wlContextStruct *wlCtx_BackGround; struct wlContextStruct wlCtx_BackGround;
struct wlContextStruct *wlCtx_Panel; struct wlContextStruct wlCtx_Panel;
struct wlContextStruct wlCtx_Button_1; struct wlContextStruct wlCtx_Button_1;
struct wlContextStruct wlCtx_Button_2; struct wlContextStruct wlCtx_Button_2;
struct wlContextStruct wlCtx_Button_3; struct wlContextStruct wlCtx_Button_3;
@ -1262,11 +1209,12 @@ int main(int argc, char **argv)
int ret = 0; int ret = 0;
struct hmi_homescreen_setting *hmi_setting; struct hmi_homescreen_setting *hmi_setting;
struct wlContextStruct *pWlCtxSt = NULL; struct wlContextStruct *pWlCtxSt = NULL;
int i = 0;
hmi_setting = hmi_homescreen_setting_create(); hmi_setting = hmi_homescreen_setting_create();
memset(&wlCtxCommon, 0x00, sizeof(wlCtxCommon)); memset(&wlCtxCommon, 0x00, sizeof(wlCtxCommon));
memset(&wlCtx_BackGround, 0x00, sizeof(wlCtx_BackGround));
memset(&wlCtx_Panel, 0x00, sizeof(wlCtx_Panel));
memset(&wlCtx_Button_1, 0x00, sizeof(wlCtx_Button_1)); memset(&wlCtx_Button_1, 0x00, sizeof(wlCtx_Button_1));
memset(&wlCtx_Button_2, 0x00, sizeof(wlCtx_Button_2)); memset(&wlCtx_Button_2, 0x00, sizeof(wlCtx_Button_2));
memset(&wlCtx_Button_3, 0x00, sizeof(wlCtx_Button_3)); memset(&wlCtx_Button_3, 0x00, sizeof(wlCtx_Button_3));
@ -1304,9 +1252,6 @@ int main(int argc, char **argv)
exit(1); exit(1);
} }
wlCtx_BackGround = xzalloc(hmi_setting->screen_num * sizeof(struct wlContextStruct));
wlCtx_Panel= xzalloc(hmi_setting->screen_num * sizeof(struct wlContextStruct));
if (wlCtxCommon.hmi_setting->cursor_theme) { if (wlCtxCommon.hmi_setting->cursor_theme) {
create_cursors(&wlCtxCommon); create_cursors(&wlCtxCommon);
@ -1316,6 +1261,8 @@ int main(int argc, char **argv)
wlCtxCommon.current_cursor = CURSOR_LEFT_PTR; wlCtxCommon.current_cursor = CURSOR_LEFT_PTR;
} }
wlCtx_BackGround.cmm = &wlCtxCommon;
wlCtx_Panel.cmm = &wlCtxCommon;
wlCtx_Button_1.cmm = &wlCtxCommon; wlCtx_Button_1.cmm = &wlCtxCommon;
wlCtx_Button_2.cmm = &wlCtxCommon; wlCtx_Button_2.cmm = &wlCtxCommon;
wlCtx_Button_3.cmm = &wlCtxCommon; wlCtx_Button_3.cmm = &wlCtxCommon;
@ -1324,23 +1271,11 @@ 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_background(&wlCtx_BackGround, hmi_setting->background.id,
hmi_setting->background.filePath);
create_workspace_background(&wlCtx_WorkSpaceBackGround, create_panel(&wlCtx_Panel, hmi_setting->panel.id,
&hmi_setting->workspace_background); hmi_setting->panel.filePath);
for (i = 0; i < hmi_setting->screen_num; i++) {
wlCtx_BackGround[i].cmm = &wlCtxCommon;
create_background(&wlCtx_BackGround[i],
hmi_setting->background.id +
(i * hmi_setting->surface_id_offset),
hmi_setting->background.filePath);
wlCtx_Panel[i].cmm = &wlCtxCommon;
create_panel(&wlCtx_Panel[i],
hmi_setting->panel.id + (i * hmi_setting->surface_id_offset),
hmi_setting->panel.filePath);
}
create_button(&wlCtx_Button_1, hmi_setting->tiling.id, create_button(&wlCtx_Button_1, hmi_setting->tiling.id,
hmi_setting->tiling.filePath, 0); hmi_setting->tiling.filePath, 0);
@ -1354,21 +1289,23 @@ 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);
UI_ready(wlCtxCommon.hmiCtrl); UI_ready(wlCtxCommon.hmiCtrl);
while (ret != -1) while(ret != -1)
ret = wl_display_dispatch(wlCtxCommon.wlDisplay); ret = wl_display_dispatch(wlCtxCommon.wlDisplay);
wl_list_for_each(pWlCtxSt, &wlCtxCommon.list_wlContextStruct, link) { wl_list_for_each(pWlCtxSt, &wlCtxCommon.list_wlContextStruct, link) {
destroyWLContextStruct(pWlCtxSt); destroyWLContextStruct(pWlCtxSt);
} }
free(wlCtx_BackGround);
free(wlCtx_Panel);
destroyWLContextCommon(&wlCtxCommon); destroyWLContextCommon(&wlCtxCommon);
return 0; return 0;

View file

@ -2,49 +2,44 @@
* Copyright © 2012 Openismus GmbH * Copyright © 2012 Openismus GmbH
* Copyright © 2012 Intel Corporation * Copyright © 2012 Intel Corporation
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and
* copy of this software and associated documentation files (the "Software"), * its documentation for any purpose is hereby granted without fee, provided
* to deal in the Software without restriction, including without limitation * that the above copyright notice appear in all copies and that both that
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * copyright notice and this permission notice appear in supporting
* and/or sell copies of the Software, and to permit persons to whom the * documentation, and that the name of the copyright holders not be used in
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* paragraph) shall be included in all copies or substantial portions of the * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* Software. * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* 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 "config.h"
#include <stdbool.h>
#include <stdint.h>
#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>
#include "window.h" #include "window.h"
#include "input-method-unstable-v1-client-protocol.h" #include "input-method-client-protocol.h"
#include "text-input-unstable-v1-client-protocol.h" #include "text-client-protocol.h"
#include "shared/xalloc.h"
struct keyboard; struct keyboard;
struct virtual_keyboard { struct virtual_keyboard {
struct zwp_input_panel_v1 *input_panel; struct wl_input_panel *input_panel;
struct zwp_input_method_v1 *input_method; struct wl_input_method *input_method;
struct zwp_input_method_context_v1 *context; struct wl_input_method_context *context;
struct display *display; struct display *display;
struct output *output; struct output *output;
char *preedit_string; char *preedit_string;
@ -59,9 +54,6 @@ struct virtual_keyboard {
char *surrounding_text; char *surrounding_text;
uint32_t surrounding_cursor; uint32_t surrounding_cursor;
struct keyboard *keyboard; struct keyboard *keyboard;
bool toplevel;
bool overlay;
struct zwp_input_panel_surface_v1 *ips;
}; };
enum key_type { enum key_type {
@ -223,7 +215,7 @@ static const struct layout normal_layout = {
12, 12,
4, 4,
"en", "en",
ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_LTR WL_TEXT_INPUT_TEXT_DIRECTION_LTR
}; };
static const struct layout numeric_layout = { static const struct layout numeric_layout = {
@ -232,7 +224,7 @@ static const struct layout numeric_layout = {
12, 12,
2, 2,
"en", "en",
ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_LTR WL_TEXT_INPUT_TEXT_DIRECTION_LTR
}; };
static const struct layout arabic_layout = { static const struct layout arabic_layout = {
@ -241,7 +233,7 @@ static const struct layout arabic_layout = {
13, 13,
4, 4,
"ar", "ar",
ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_RTL WL_TEXT_INPUT_TEXT_DIRECTION_RTL
}; };
static const char *style_labels[] = { static const char *style_labels[] = {
@ -276,10 +268,11 @@ static void __attribute__ ((format (printf, 1, 2)))
dbg(const char *fmt, ...) dbg(const char *fmt, ...)
{ {
#ifdef DEBUG #ifdef DEBUG
int l;
va_list argp; va_list argp;
va_start(argp, fmt); va_start(argp, fmt);
vfprintf(stderr, fmt, argp); l = vfprintf(stderr, fmt, argp);
va_end(argp); va_end(argp);
#endif #endif
} }
@ -345,8 +338,8 @@ static const struct layout *
get_current_layout(struct virtual_keyboard *keyboard) get_current_layout(struct virtual_keyboard *keyboard)
{ {
switch (keyboard->content_purpose) { switch (keyboard->content_purpose) {
case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_DIGITS: case WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS:
case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_NUMBER: case WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER:
return &numeric_layout; return &numeric_layout;
default: default:
if (keyboard->preferred_language && if (keyboard->preferred_language &&
@ -377,7 +370,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);
@ -433,11 +426,11 @@ virtual_keyboard_commit_preedit(struct virtual_keyboard *keyboard)
strlen(keyboard->preedit_string) == 0) strlen(keyboard->preedit_string) == 0)
return; return;
zwp_input_method_context_v1_cursor_position(keyboard->context, wl_input_method_context_cursor_position(keyboard->context,
0, 0); 0, 0);
zwp_input_method_context_v1_commit_string(keyboard->context, wl_input_method_context_commit_string(keyboard->context,
keyboard->serial, keyboard->serial,
keyboard->preedit_string); keyboard->preedit_string);
if (keyboard->surrounding_text) { if (keyboard->surrounding_text) {
surrounding_text = insert_text(keyboard->surrounding_text, surrounding_text = insert_text(keyboard->surrounding_text,
@ -462,18 +455,18 @@ virtual_keyboard_send_preedit(struct virtual_keyboard *keyboard,
uint32_t index = strlen(keyboard->preedit_string); uint32_t index = strlen(keyboard->preedit_string);
if (keyboard->preedit_style) if (keyboard->preedit_style)
zwp_input_method_context_v1_preedit_styling(keyboard->context, wl_input_method_context_preedit_styling(keyboard->context,
0, 0,
strlen(keyboard->preedit_string), strlen(keyboard->preedit_string),
keyboard->preedit_style); keyboard->preedit_style);
if (cursor > 0) if (cursor > 0)
index = cursor; index = cursor;
zwp_input_method_context_v1_preedit_cursor(keyboard->context, wl_input_method_context_preedit_cursor(keyboard->context,
index); index);
zwp_input_method_context_v1_preedit_string(keyboard->context, wl_input_method_context_preedit_string(keyboard->context,
keyboard->serial, keyboard->serial,
keyboard->preedit_string, keyboard->preedit_string,
keyboard->preedit_string); keyboard->preedit_string);
} }
static const char * static const char *
@ -505,12 +498,12 @@ 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, wl_input_method_context_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, wl_input_method_context_commit_string(keyboard->context,
keyboard->serial, keyboard->serial,
""); "");
/* Update surrounding text */ /* Update surrounding text */
keyboard->surrounding_cursor = start - keyboard->surrounding_text; keyboard->surrounding_cursor = start - keyboard->surrounding_text;
@ -577,10 +570,10 @@ keyboard_handle_key(struct keyboard *keyboard, uint32_t time, const struct key *
break; break;
case keytype_enter: case keytype_enter:
virtual_keyboard_commit_preedit(keyboard->keyboard); virtual_keyboard_commit_preedit(keyboard->keyboard);
zwp_input_method_context_v1_keysym(keyboard->keyboard->context, wl_input_method_context_keysym(keyboard->keyboard->context,
display_get_serial(keyboard->keyboard->display), display_get_serial(keyboard->keyboard->display),
time, time,
XKB_KEY_Return, key_state, mod_mask); XKB_KEY_Return, key_state, mod_mask);
break; break;
case keytype_space: case keytype_space:
if (state != WL_POINTER_BUTTON_STATE_PRESSED) if (state != WL_POINTER_BUTTON_STATE_PRESSED)
@ -621,38 +614,38 @@ keyboard_handle_key(struct keyboard *keyboard, uint32_t time, const struct key *
break; break;
case keytype_tab: case keytype_tab:
virtual_keyboard_commit_preedit(keyboard->keyboard); virtual_keyboard_commit_preedit(keyboard->keyboard);
zwp_input_method_context_v1_keysym(keyboard->keyboard->context, wl_input_method_context_keysym(keyboard->keyboard->context,
display_get_serial(keyboard->keyboard->display), display_get_serial(keyboard->keyboard->display),
time, time,
XKB_KEY_Tab, key_state, mod_mask); XKB_KEY_Tab, key_state, mod_mask);
break; break;
case keytype_arrow_up: case keytype_arrow_up:
virtual_keyboard_commit_preedit(keyboard->keyboard); virtual_keyboard_commit_preedit(keyboard->keyboard);
zwp_input_method_context_v1_keysym(keyboard->keyboard->context, wl_input_method_context_keysym(keyboard->keyboard->context,
display_get_serial(keyboard->keyboard->display), display_get_serial(keyboard->keyboard->display),
time, time,
XKB_KEY_Up, key_state, mod_mask); XKB_KEY_Up, key_state, mod_mask);
break; break;
case keytype_arrow_left: case keytype_arrow_left:
virtual_keyboard_commit_preedit(keyboard->keyboard); virtual_keyboard_commit_preedit(keyboard->keyboard);
zwp_input_method_context_v1_keysym(keyboard->keyboard->context, wl_input_method_context_keysym(keyboard->keyboard->context,
display_get_serial(keyboard->keyboard->display), display_get_serial(keyboard->keyboard->display),
time, time,
XKB_KEY_Left, key_state, mod_mask); XKB_KEY_Left, key_state, mod_mask);
break; break;
case keytype_arrow_right: case keytype_arrow_right:
virtual_keyboard_commit_preedit(keyboard->keyboard); virtual_keyboard_commit_preedit(keyboard->keyboard);
zwp_input_method_context_v1_keysym(keyboard->keyboard->context, wl_input_method_context_keysym(keyboard->keyboard->context,
display_get_serial(keyboard->keyboard->display), display_get_serial(keyboard->keyboard->display),
time, time,
XKB_KEY_Right, key_state, mod_mask); XKB_KEY_Right, key_state, mod_mask);
break; break;
case keytype_arrow_down: case keytype_arrow_down:
virtual_keyboard_commit_preedit(keyboard->keyboard); virtual_keyboard_commit_preedit(keyboard->keyboard);
zwp_input_method_context_v1_keysym(keyboard->keyboard->context, wl_input_method_context_keysym(keyboard->keyboard->context,
display_get_serial(keyboard->keyboard->display), display_get_serial(keyboard->keyboard->display),
time, time,
XKB_KEY_Down, key_state, mod_mask); XKB_KEY_Down, key_state, mod_mask);
break; break;
case keytype_style: case keytype_style:
if (state != WL_POINTER_BUTTON_STATE_PRESSED) if (state != WL_POINTER_BUTTON_STATE_PRESSED)
@ -756,7 +749,7 @@ touch_up_handler(struct widget *widget, struct input *input,
static void static void
handle_surrounding_text(void *data, handle_surrounding_text(void *data,
struct zwp_input_method_context_v1 *context, struct wl_input_method_context *context,
const char *text, const char *text,
uint32_t cursor, uint32_t cursor,
uint32_t anchor) uint32_t anchor)
@ -771,7 +764,7 @@ handle_surrounding_text(void *data,
static void static void
handle_reset(void *data, handle_reset(void *data,
struct zwp_input_method_context_v1 *context) struct wl_input_method_context *context)
{ {
struct virtual_keyboard *keyboard = data; struct virtual_keyboard *keyboard = data;
@ -785,7 +778,7 @@ handle_reset(void *data,
static void static void
handle_content_type(void *data, handle_content_type(void *data,
struct zwp_input_method_context_v1 *context, struct wl_input_method_context *context,
uint32_t hint, uint32_t hint,
uint32_t purpose) uint32_t purpose)
{ {
@ -797,7 +790,7 @@ handle_content_type(void *data,
static void static void
handle_invoke_action(void *data, handle_invoke_action(void *data,
struct zwp_input_method_context_v1 *context, struct wl_input_method_context *context,
uint32_t button, uint32_t button,
uint32_t index) uint32_t index)
{ {
@ -811,7 +804,7 @@ handle_invoke_action(void *data,
static void static void
handle_commit_state(void *data, handle_commit_state(void *data,
struct zwp_input_method_context_v1 *context, struct wl_input_method_context *context,
uint32_t serial) uint32_t serial)
{ {
struct virtual_keyboard *keyboard = data; struct virtual_keyboard *keyboard = data;
@ -828,19 +821,15 @@ handle_commit_state(void *data,
layout->columns * key_width, layout->columns * key_width,
layout->rows * key_height); layout->rows * key_height);
zwp_input_method_context_v1_language(context, wl_input_method_context_language(context, keyboard->serial, layout->language);
keyboard->serial, wl_input_method_context_text_direction(context, keyboard->serial, layout->text_direction);
layout->language);
zwp_input_method_context_v1_text_direction(context,
keyboard->serial,
layout->text_direction);
widget_schedule_redraw(keyboard->keyboard->widget); widget_schedule_redraw(keyboard->keyboard->widget);
} }
static void static void
handle_preferred_language(void *data, handle_preferred_language(void *data,
struct zwp_input_method_context_v1 *context, struct wl_input_method_context *context,
const char *language) const char *language)
{ {
struct virtual_keyboard *keyboard = data; struct virtual_keyboard *keyboard = data;
@ -854,7 +843,7 @@ handle_preferred_language(void *data,
keyboard->preferred_language = strdup(language); keyboard->preferred_language = strdup(language);
} }
static const struct zwp_input_method_context_v1_listener input_method_context_listener = { static const struct wl_input_method_context_listener input_method_context_listener = {
handle_surrounding_text, handle_surrounding_text,
handle_reset, handle_reset,
handle_content_type, handle_content_type,
@ -865,8 +854,8 @@ static const struct zwp_input_method_context_v1_listener input_method_context_li
static void static void
input_method_activate(void *data, input_method_activate(void *data,
struct zwp_input_method_v1 *input_method, struct wl_input_method *input_method,
struct zwp_input_method_context_v1 *context) struct wl_input_method_context *context)
{ {
struct virtual_keyboard *keyboard = data; struct virtual_keyboard *keyboard = data;
struct wl_array modifiers_map; struct wl_array modifiers_map;
@ -875,7 +864,7 @@ input_method_activate(void *data,
keyboard->keyboard->state = KEYBOARD_STATE_DEFAULT; keyboard->keyboard->state = KEYBOARD_STATE_DEFAULT;
if (keyboard->context) if (keyboard->context)
zwp_input_method_context_v1_destroy(keyboard->context); wl_input_method_context_destroy(keyboard->context);
if (keyboard->preedit_string) if (keyboard->preedit_string)
free(keyboard->preedit_string); free(keyboard->preedit_string);
@ -891,15 +880,15 @@ input_method_activate(void *data,
keyboard->serial = 0; keyboard->serial = 0;
keyboard->context = context; keyboard->context = context;
zwp_input_method_context_v1_add_listener(context, wl_input_method_context_add_listener(context,
&input_method_context_listener, &input_method_context_listener,
keyboard); keyboard);
wl_array_init(&modifiers_map); wl_array_init(&modifiers_map);
keysym_modifiers_add(&modifiers_map, "Shift"); keysym_modifiers_add(&modifiers_map, "Shift");
keysym_modifiers_add(&modifiers_map, "Control"); keysym_modifiers_add(&modifiers_map, "Control");
keysym_modifiers_add(&modifiers_map, "Mod1"); keysym_modifiers_add(&modifiers_map, "Mod1");
zwp_input_method_context_v1_modifiers_map(context, &modifiers_map); wl_input_method_context_modifiers_map(context, &modifiers_map);
keyboard->keysym.shift_mask = keysym_modifiers_get_mask(&modifiers_map, "Shift"); keyboard->keysym.shift_mask = keysym_modifiers_get_mask(&modifiers_map, "Shift");
wl_array_release(&modifiers_map); wl_array_release(&modifiers_map);
@ -909,31 +898,27 @@ input_method_activate(void *data,
layout->columns * key_width, layout->columns * key_width,
layout->rows * key_height); layout->rows * key_height);
zwp_input_method_context_v1_language(context, wl_input_method_context_language(context, keyboard->serial, layout->language);
keyboard->serial, wl_input_method_context_text_direction(context, keyboard->serial, layout->text_direction);
layout->language);
zwp_input_method_context_v1_text_direction(context,
keyboard->serial,
layout->text_direction);
widget_schedule_redraw(keyboard->keyboard->widget); widget_schedule_redraw(keyboard->keyboard->widget);
} }
static void static void
input_method_deactivate(void *data, input_method_deactivate(void *data,
struct zwp_input_method_v1 *input_method, struct wl_input_method *input_method,
struct zwp_input_method_context_v1 *context) struct wl_input_method_context *context)
{ {
struct virtual_keyboard *keyboard = data; struct virtual_keyboard *keyboard = data;
if (!keyboard->context) if (!keyboard->context)
return; return;
zwp_input_method_context_v1_destroy(keyboard->context); wl_input_method_context_destroy(keyboard->context);
keyboard->context = NULL; keyboard->context = NULL;
} }
static const struct zwp_input_method_v1_listener input_method_listener = { static const struct wl_input_method_listener input_method_listener = {
input_method_activate, input_method_activate,
input_method_deactivate input_method_deactivate
}; };
@ -944,56 +929,23 @@ global_handler(struct display *display, uint32_t name,
{ {
struct virtual_keyboard *keyboard = data; struct virtual_keyboard *keyboard = data;
if (!strcmp(interface, "zwp_input_panel_v1")) { if (!strcmp(interface, "wl_input_panel")) {
keyboard->input_panel = keyboard->input_panel =
display_bind(display, name, &zwp_input_panel_v1_interface, 1); display_bind(display, name, &wl_input_panel_interface, 1);
} else if (!strcmp(interface, "zwp_input_method_v1")) { } else if (!strcmp(interface, "wl_input_method")) {
keyboard->input_method = keyboard->input_method =
display_bind(display, name, display_bind(display, name,
&zwp_input_method_v1_interface, 1); &wl_input_method_interface, 1);
zwp_input_method_v1_add_listener(keyboard->input_method, wl_input_method_add_listener(keyboard->input_method, &input_method_listener, keyboard);
&input_method_listener,
keyboard);
} }
} }
static void static void
set_toplevel(struct output *output, struct virtual_keyboard *virtual_keyboard) keyboard_create(struct output *output, struct virtual_keyboard *virtual_keyboard)
{
zwp_input_panel_surface_v1_set_toplevel(virtual_keyboard->ips,
output_get_wl_output(output),
ZWP_INPUT_PANEL_SURFACE_V1_POSITION_CENTER_BOTTOM);
virtual_keyboard->toplevel = true;
virtual_keyboard->overlay = false;
}
static void
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
display_output_handler(struct output *output, void *data) {
struct virtual_keyboard *keyboard = data;
const char *type = getenv("WESTON_KEYBOARD_SURFACE_TYPE");
if (type && strcasecmp("overlay", type) == 0) {
if (!keyboard->overlay)
set_overlay(output, keyboard);
} else {
if (!keyboard->toplevel)
set_toplevel(output, keyboard);
}
}
static void
keyboard_create(struct virtual_keyboard *virtual_keyboard)
{ {
struct keyboard *keyboard; struct keyboard *keyboard;
const struct layout *layout; const struct layout *layout;
struct wl_input_panel_surface *ips;
layout = get_current_layout(virtual_keyboard); layout = get_current_layout(virtual_keyboard);
@ -1002,14 +954,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);
@ -1022,38 +969,26 @@ keyboard_create(struct virtual_keyboard *virtual_keyboard)
layout->columns * key_width, layout->columns * key_width,
layout->rows * key_height); layout->rows * key_height);
display_set_output_configure_handler(virtual_keyboard->display,
display_output_handler);
}
static void ips = wl_input_panel_get_input_panel_surface(virtual_keyboard->input_panel,
keyboard_destroy(struct virtual_keyboard *virtual_keyboard) window_get_wl_surface(keyboard->window));
{
if (virtual_keyboard->ips)
zwp_input_panel_surface_v1_destroy(virtual_keyboard->ips);
if (virtual_keyboard->input_panel) wl_input_panel_surface_set_toplevel(ips,
zwp_input_panel_v1_destroy(virtual_keyboard->input_panel); output_get_wl_output(output),
WL_INPUT_PANEL_SURFACE_POSITION_CENTER_BOTTOM);
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[])
{ {
struct virtual_keyboard virtual_keyboard; struct virtual_keyboard virtual_keyboard;
struct output *output;
memset(&virtual_keyboard, 0, sizeof virtual_keyboard); memset(&virtual_keyboard, 0, sizeof virtual_keyboard);
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;
} }
@ -1065,12 +1000,10 @@ main(int argc, char *argv[])
return -1; return -1;
} }
keyboard_create(&virtual_keyboard); output = display_get_output(virtual_keyboard.display);
keyboard_create(output, &virtual_keyboard);
display_run(virtual_keyboard.display); display_run(virtual_keyboard.display);
keyboard_destroy(&virtual_keyboard);
display_destroy(virtual_keyboard.display);
return 0; return 0;
} }

692
clients/matrix3.xpm Normal file
View file

@ -0,0 +1,692 @@
/* XPM */
static char * matrix3_xpm[] = {
"512 598 91 1",
" c None",
". c #020202",
"+ c #020602",
"@ c #020A02",
"# c #061606",
"$ c #071E07",
"% c #061206",
"& c #020E02",
"* c #061A06",
"= c #0A220A",
"- c #0B310E",
"; c #0E3E12",
"> c #0A260A",
", c #0E2A0E",
"' c #134A16",
") c #0E5A0E",
"! c #104616",
"~ c #124E1A",
"{ c #166A12",
"] c #127212",
"^ c #1E921A",
"/ c #168A16",
"( c #1A5E2A",
"_ c #165626",
": c #227232",
"< c #3A965A",
"[ c #268A3E",
"} c #227A37",
"| c #1E662F",
"1 c #1E6A32",
"2 c #227E3A",
"3 c #16320E",
"4 c #36822A",
"5 c #4A9E72",
"6 c #4AAA6E",
"7 c #42862A",
"8 c #4DAE7B",
"9 c #1A3612",
"0 c #224616",
"a c #264E16",
"b c #32621E",
"c c #1A3E12",
"d c #265A1A",
"e c #367622",
"f c #3E7626",
"g c #5A8636",
"h c #4A962E",
"i c #669A3E",
"j c #82AE52",
"k c #3E9222",
"l c #4AA232",
"m c #66AA3E",
"n c #6ABA3E",
"o c #82BE4A",
"p c #76AA4A",
"q c #96BE5E",
"r c #1A9E1A",
"s c #22BE22",
"t c #2AD62A",
"u c #6AEE8A",
"v c #4AEE4A",
"w c #50CE94",
"x c #26CB26",
"y c #26D226",
"z c #1EAE1E",
"A c #2ADE2A",
"B c #2AE62A",
"C c #2EEE2E",
"D c #56F24A",
"E c #66F65E",
"F c #127E12",
"G c #42EE42",
"H c #3AEE3A",
"I c #2B9F4D",
"J c #3EBA6E",
"K c #2AAA4E",
"L c #56F262",
"M c #66C29E",
"N c #68D6B2",
"O c #52BE8A",
"P c #3CAE67",
"Q c #2A9646",
"R c #6AC6AA",
"S c #6ACAA2",
"T c #C2D672",
"U c #B2D26A",
"V c #4EAA2E",
"W c #9ECE5A",
"X c #5EB632",
"Y c #62C299",
"Z c #8ACA4A",
"..............................................................................................................++@@@@@@+++....................+@@@@@@@+........................................................................................................................++@@@@@@+....................+@@@@@@@+................................................................................................................................................................................................+@@@+.......",
".............................................................................................................+@##$$$$$#%@+..................+&##$$$$#&+......................................................................................................................+&#$$$$$#%+..................+&#$$$$$#&+..............................................................................................................................................................................................+&#$#%+......",
"............................................+@&%#***%&@+...................+@@@@@@@@@+....................@##=--;;;;;;;->$%@...............%#>-;;;;;-,*&+...................+&%&&@+............................................................@&@@+.......................@%*--')))!;-=%@+..............%*-;;!!!!;-*&+.....................+&%###%@+............................................................................................................................................................@#$-;;;-=*@+...",
"............................................%**==,-->=*%@.................@%*$$$$$$$*##%&+................%$--;~'))){))!;-=*&.............&#--;)){)~!--=#@...............+&###$$**%@+........................................................@%**$*##&@....................&=,;']^^/])';,*@.............&$-;)){//]);-=#@+...................@#*==>=*#%@.........................................................................................................................................................&*>;!~))!->*@...",
"...........................................+%**===,,>**%%+..............+@&%************%@+..............@#*,;!~~))())_';-=*@............+%*=-;~({_~;-=**%+.............+&%*$**$**%@+........................................................&&#*$*#$%%+...................@*=-!:<<[_~!-,#@.............@=-;'(}[<}_-=*#@+..................@%#**>>>*%%&+.......................................................................................................................................................+%$=-!)))!-,$@...",
"..........................................+&*$>,-;;-->$$%+..............@&$$$$>$$$$$>$$*#%&@.............@#>-;'((|(||1(~!--$%+..........+&**,-;_:}2(~;->$#&@............@%*$=>>=>$$#%+......................................................+&$*>=>=**%@..................@&*>3_456<:(~;,*@............+&=;!(:786<(;,$*%+.................@&#*>---,>$##@+......................................................................................................................................................@%*-;_|1|(;-*&...",
"..........................................@*=,90abbba3,*$&+............@%#*,333333333393>$#@+............&*,cdbbeeff4febd0;=*+.........+@%>-cabfghifbdc9=$#&+.........+&%$,39c09c3,=$@.......................++@@@++.......................+&#,39c993=*%+................+&*=3;bijjifbac,*@............@&=;adfijjifc9>*#@................+%*>,9abdac3*$&+......................................................................................................................................................&*>9aefggfa;=%...",
".........................................&*=;abgijjigbc9=#@...........@%*,c0db{b_0_db:bdc3=$&+..........&%=9de47kkklllk4ebac=#........+%$>c'be7mnonphebd03=*&+.......+&%=3cd:eeee(a3=*@....................+&&*=*$*##%@+..................+%*30d:1e(d09=%+..............+&$>9cdfmqom7bd09*&............@*>9db4ioqpgbac3=%+..............@#*>;afgmiifac,*%+...................+@&%#&@+........................................................................................................................+&*,;abipnpif03#+..",
"........................................&$-~]rstuuuvws/{;-*+........+&#-;)]rsxyszrrssysz/{';$&........+%=-;{/yABCCBCACCtyz^];,+......+%,;!{/sABDvuEvBAsrF{~-$&......@#=-;)/zxBBAAs^{!-*&.................@%$,-;;;!;;;-,*&+...............@*-;)/zytAsr/{;$%+............+%>;~F^sxAvGAs/]);>*+...........@*-~F^sxGvHAsrF);>%+...........@%$-;~]IxDuvDJ/{';>$%@...............&%$>----,$&+......................................................................................................................&=-~]^sADEDtKF',@..",
"........................................&=;~FIyHDEvDAsr]~-$&........+#,;)]/zsABxszssAAysrF);-#+.......@#--!]ryBCBCBCCCBBxsrF~,%.....@#>-!)]ryAHGEuELHBxzrF);-#.....@#*-;'{/yBACBByr]!;,*&...............@#=--!!)))))~!;-=%+.............+%=-!]rsBBBtz/];,*@............&=-;]^zxABCByrF);-=%@...........+#=;)FrsACBBysrF~-=#@.........&#>-;!{/KyDDDGAz])';-,=&.............&%=>;;!;;->=%@.....................................................................................................................&=;~]rJAGLDGs])>&..",
"........................................&#=-~][6MNNOP[{!->#&........+%*-;)(F^rI^/FF/IrQ/])'-=%........+&>,;~]^rIzKzKsKzr/F(~;=@.....&*>,;!)][IKOwNwOPKQF|~;,*&.....@#$>-;~]/rrzKr/F)->*%@..............+&*=--''~___~';,=*%@.............+&*,-']/rKr/F_!-*%@............@*=-!{2QIIIQ/(;->*&+.............&%=-!(}^IIr/[]);>$&@.........&*>,-;!(1<ONwO<}_!;--=*&.............@%$=-;!!;-=*%&.....................................................................................................................@*=-~{[POwO5}!-%...",
"........................................+*>-a|75RNNR5}('-*#@........@&$-!__:[55<}1}}5554|~;-=%+.......&#*,-_1[QQQIIIIIQ[}1('-*@....+&$=-!(:}[QI68OOO66<}(_;-=&.....+%*=;;_|[[QQQ[2|~!->#&.............+@%$-;~(:f774e1_;,$%@.............@#$,;_:<865[1_;,$&@............@#>-~|}}[QQ[|~;>*%@...............&**-'(}[Q[[}|_;=*%@........+&*,;;c~(e<OSSO5:((_!--$&............+%$=;~b2e|a->#@+...................................................................................................................+&$>3~|}<P65[(c=#+..",
".......................................+@*=9afgjTTTUjge0-=%@.......+&%=9cbbgiqqjg7ggjqqggba;=&.......+%$=-;a17khkhhllkh7feb09>@....@#>-abe7khhlmVmmjqqjgedc9>&.....@*>;adbe47k4k77ebac,*%+...........+&#*,9a:gijqqqjgea3=#@.............@*=;0bgpqUqifdc,$&+............@*,cde7kk777ba3>#&+...............@**,0de4kh7hfb0,$%@........&*,;abbbefiqUUqi4bbbba;,#............@&$3afjjjifc,*&+...................................................................................................................@%=,;df7hhh4fd3*@...",
"........................................%*9c:kiqTTTWjl7bc>$&........&$>0d:4ijWqoikhmqTqp7eb0,#+......&*=9cde4hlVVVVmVXVVk72b',&...+&*3a14klVVVVVVVXqWWoi7bdc>#+...+&$3cde4k<lllllkk4ea9>*&+..........&*=3;d:75jqTTWomk:03=%+...........+&*30b4iqqUWpgba3*%+...........+%=30e[llVVlke_9=*&+...............+#=3cb4kllVlked;,$@.......@%=3d1e47hlpWUUWjhkk44ed9$@..........+%$,cbgqUWqgbc,$&...................................................................................................................&*,9dehllllheac=%...",
".......................................+$-~]zxCDuuEEvAyr{;,*+.......*-!{rsxADEEGABBGuEuGsz/{;=@....+%$;~]/zsAACGHvGvGGHCCAyz/~$...%>;~FzAABCCCBCCCCGvDHtsz/{;$@...&$-~]rzxBCCBCCCCBAs/{;-$%.........@*-')FrstCGLuDvGHtzF~->&...........&=-~FzyBGDEGAs/{;,*@...........&=-~FztACBABxr]'-=@................+*-'{^stBCBCBs/);,*+.....@#,;)/zytBHHDEEEEvvBBtyz^{-#..........@$-;{IxDEEDyI{!-*@.................................................................................................................@$-'{rxAGCAtsr]~-%...",
".......................................@#;~]ryADEEEEvBs^]!-#@......+%-;]^zyBHLLvCAAHvuDHsz/{!*+.....#-;{/zsACCBGLLLLLLGCCBBs/)=+.+*,;~FstCCCBCBtyxytBAAysz/{;*+..+%=-~]rstAABACBBBCtxr]'->*&........@=-)F^syBCCAAxyAAAzF~;=%..........+%-;)FsBACCBAs/]~->#+...........@=;)FzACCCBBs/{;,#+.................@$;)FsABCCCAs/{!-*&.....+$-;)/syBHLLEEuEuELGCBxs/);*.........+#,;~{IALLLDyzF);=%+...................................................+...........................................................@#>;~]IAGvHysz/{;-*+..",
".......................................+@*-;12IOSNSS8I});,*@........@*,;{F2IPwwPI[QIOwO<2|);,%......&=,!{F^IKKJwwNuNwwwJsKr}_;%...@*>;~FIKzKrI^/2F/[QQ^2]|);=&....&*>-!(]/^IKrKrKrrr^]'-=*%@........@*=;)]}^IKIQ2}}/[/]'-**@..........+@*=;(/QIQQ[[]);-*#+............+#>-~2PJwJK[]~;=#@...................&$-!{/IJJwP[(;,=#@......&$,;)F[QPwNwNuNNuNwJI^F);,#.........&**,;~:5wwNO<1_;,$%+............................................+@+++@@&@@@@@@@@+++................................................@#$-;):5wJP[F_!->#+...",
"........................................&*=;_2g8RNNR6[:(;=*&........@#=-~(1[5OO6[2}<6M6<|_;-=@......@*,;_1}[QKKOwNNNNSw6KQ[:_-#...@#*-':[IIIQ[[21::}22}:__!->&....+&*,;_(12[[QQQQQQ[2|~->$#@........+%>9'(}}QQQ}:1111|~;>$%&...........@#>-'|[2}}:(~;,*#+.............@%=-_26OYO<:_;,$%@...................@*,3~|[8YS6<(->$&+......@%=-'(14KONNNSNNNSO5[}(~-*&........@&#>,3_|<YRN6<1!;>*$%@...........................................&%###%#%#%#####%##%@...............................................&#=,9_1<OO<}(';=#+....",
"........................................&*=9aegjTTTqpgea;>#@........@#=3adb4impifffgpjigdc9>$&.....+&*-;d:4kimpoqWUUUWoplkkea-%...@$*3c:7hhhhhg7feef4febbac3=%....+&*,;a(be7k7h4h7<44ba;>=$%+.......@#>9abe4hik7ebbbbba-=$%%+..........@&*-cde4ebddc->%@+.............@#=9dgjWWjiea3=*&....................+&=-cbgqqUqgb;,$&+......@%*,cd:fijqUTTTTUqji4eda-*&......+@%**>3caegqWWjiba;9==**@........................................+@%$>>>=>=========***%@.............................................+&$>90dfippgba;3*&+....",
".......................................+%*30|7ijTTTUpl4d0=*&........&*>c_be4hiig4ee7iiifdc3=%@......&=3abfhlXqZZZoZWUUZnXVk4d3#...@%$3aehVVlnnnVllhkkk4eba09=%.....@*>3ad:4khllIlVllk7eda9=*&+......&*>0db4hmnmh4}ee:(ac3=$#&.........+@#>,0debdaa93,*#@..............&*>9dhoWWZifd0,$@.....................%,cabgqUWqifa3=#+......@#$,cab4hmoqTTTUZnmk4bdc,*@.....+#*=,c!a(b7mqUUqi7bdcc33=#+.....................................@%#=,333;0cc0;0c;cc;c9,>*%...........................................@%$,;de4hlnmhedc,*%.....",
"........................................#-']rxBLuEuEvts/);=%........&$3)F/rzssszrrzsyxs/{!-,#+.....+#-~]rxAGvEEGHHvLEEEGCCts^)$...&$-;{rxCCHvvDGBBCCBAysr/{'-=+....@#,;~F^sACCCCCCACCtyz/]',#@.....+*,;{/zsAGDvtyszrr^F{~;-,=@.........@#=;)F/^])';;-*&..............+*-;(^JvEELtK/{;>#....................+#-~2IyEEEEtK]~3=@......+*-;~]^zxACLEEEELGByz/]~;=&....@*--~)F^rzsxGEEEEHssr^F])!,#....................................@*-;~){]{/^^////////FF]{);=@.........................................@*>;)FzsxABCAs/]_;$%.....",
".......................................+*-;_^stDEEELGAs/)-=&.........%,'{F^/rrr/FF/rzz^]);-*@+.....@*-~{rsAAGLLvCBCHLLLGCCAsF'*+..@#,;)/stBBHvGHCCCCCCBsz/{);>%....@#=-!{/stCCCCCACBBAxz/]!-$&....+@*>;{/zsAvLDBxsszr//F]~!-=#.........+&=-!]]])!;-$%++..............@*-;)^xGEEuAs/);-&....................@$-'{IxGEEDAz]~-#+.......#=;~]^zyBHvLEuLGCBxz^]~;$@....%--!{/IzsJyAvEuELGAtyssr/);*...................................+#-;']/rKzzzsssKszszszzK/])-#.........................................%*-;)/sABCCBys/)!-$+.....",
"........................................+*-;~:[PSNNOP}|!-=#@.........+&$-;;;~!!;;;;!'~'-,$#@.......@%>-'(][QPwwJKKKJwwOIQ}F{;>@....+*>-~{F2[QPPKKKKKJJKI/})!-*@....+&*=,;)FQrKKKzKzrr/F{~;>*%+....++%*=;~:2<OwwPII^[F]|_)~!-=&...........@%*--;,=*#@+................+&>-;([OwNO<:~;=*@....................+%>-!(<OwNO5:~-=%........&*>-;_]QPOJ86PPJJPQ}{);,#.....&$-;|[68OJOYSNNNNNOOO665[_-*...................................+&=-!1<588866666O6666668<}_,%.........................................&*=;~]/IrIQQ2{!-=*@......",
"........................................+&*=;_:<ORN6<|~;,$&...........+&**>==,>====>,,*$%&+........@%*>;~(|[5OO6<[[<OY6<1|_;-$@....+&#--;_(:2[QIIIKPOO8<[}('-*+.....@#$=-!|}QQQPPIQQ[2(_;,*#@......+&$=;~(1g8MM6KQQ}1||11(~;=%............@@@&&%%@....................@#=-a46YSO<1;,$#@....................@#*,;d26YSO<|;,*@........+%*,;_|<6O6<24<5Y8<:(!;=%+...+%>-ab5RRRRRNSNNSNNNRNNRM5b9#....................................#=3af6MMNMNNRNNMNRNNNRRMg(-#.........................................&$,;_:[IIQ2:(;-$#&+......",
"........................................+&*>30biqUUjgbc9=*@.............@&*##**$#$*$#$#%@..........@%$=9cdbgpqqmg7giqqjgbbac,%+.....%*>>30dbef7hhlmmoZoik7e09#.....+@#$=90:7hhVmmlkh4edac-=#@......+&$=cabfiqUUjmll74eeeeb_c=#...............+++++...................+&*,9agpWWqgb;,>#@...................+@#*,;dgjWWjib;,$&.......+@#*,cabijqpg7fgjqjibdac=&+...+%>3agjqTTTTTTTTTTTTTTTTUifc#...................................+#>;dgjTTTTTTTTTTTTTTTTTUibc&........................................+#=30b4hhkkeba-=#@@.......",
".........................................@$=3abiqUUqib03>#&..............+@@@&&&%&&&%&&@...........&*,9abe7kpqWjlkipqWoi7e|a3$+....+&*=3c0|e47klVVXXZZoXVk7ea>@.....&*,3cdeklVmXXmVlkke|dc3=%......@#=90d:7iqWWZonXlhk7kk71a9#+......................................+%$-0bgjWUWifa9>*&+...................%*,90eioWUqibc3*%........@#>-0dfioZp57kipWqi4bac>*+...@#>!cgjTTTTTTTTTTTTTTTTTTjf0*...............+@%%%%%@+...........+%30agqTTTTTTTTTTTTTTTTTTjb0#.......................................@#$9a14kVVVk4(c3$&@........",
"........................................+%=;~FIADEDDyQ);-*@..................+@@@@@@@@+...........&=-!{^xtvDEEEEvGHDuEDHtyz^)-%...+&=-;)F^sxxxtACCCHGLGHCBAs/!#....@$,~{FzsABCHCHCCCCtxszF);$+....+#,;)FrsxHvvvDvvDGGCHABts/'>@.....................................+&*-!{ryuEEEtKF)'-$@..................+$-;)FrtLEELAK{!-$@......+%=3!{^ztvvHxssyHvGAs/]~3>@...&=30|<YuuEuEuEuTuuEuEuuuNXQ_>.............+&*>--;-->$%@+........+#,~e5wuuuuuuuuuuEuuuuuuSX[0$...............+&##**%&+..............+$-!{^sAACCCAs/)!-*@........",
".........................................&--'{rwvLLGy/{;>#+......................+...............+%>;)FKGLuEEuEuELEEEEEGCAyr);%...+*=-~]rzxAAyAAytBACCCBCCBs/)$....&>;{FrsxBBCBGBCCCBCBtsr]!,%....&*,;)/syBACHHvLLLELLHCBBs/),@......................................&=-;)[stvvDAs^{!-=#+.................+*-!)FIyGLLDxr{'-$&.......&$-~{/rsyAyzzrzxAxsr/{~-=&...+#,;~]rsXxwvLEEEEEEGtxxss^]!*+...........+#*,;!~~!;--=*@.........&>;~FrVsXsXxxXxXxxxXsssz/{;#..............@#*=>-,-=#@.............&$;)]zAACCBByzF);,#@........",
".........................................+%*-;|QJYw6[(;>#@........................................&*>;(<8NNNSNNNNNNNNNwJKI/|;=&...+%$=-~]//^^/////^[QIKKKKrF'-#....+*=;~{]F/QIJJKKKzKzIr/|!-*@....@#=-'1/QIIKKJJwwwNNNwKKr/(;*.......................................+&$,;_25PJPI[]~-,$&+.................+&*,;(2<PJPP[(;-$%@.......+&#>;~(:]11_~_)|2](~;->#@.....+%=,-c~(||e[6wNSR542:b(a!->&...........+&#$>-!~)~'-,*#&..........@$>3!!))()d|((|(dd)0_!';-%+.............@&**>=,==*$%+............&*>;~F^IrrQ/F(;-*#@.........",
"..........................................@#*-cb<55<1;,*%+........................................+%*-0:58OMRSRRRwMMRO85[}|~-=+...+&*>;_1}[Q<<<[[}[[Q5KIIQ[(!,&....+&*-;!_(|}[QKIIQQQQQ[}|;,$@....@#$-'_}[QQQQIPJYORNSO5[2:~-#+......................................+&%*,!([<I<Q}|~->#&@.................@#$-0(1[<I<Q:~;=*&..........&=,-;!!';----;';;-,=*@+......+&*=>--c_(:5RNSO<:d~!;->=%+...........@&#=-'(|1|_!->*@..........+%*=>,3,-3c;c-33----,,>=*%+............+&$=,-;;;-,*#&...........+&*=-!|[QQ}}}(~-$#@..........",
"..........................................@#*>cabebb0->*&.........................................+%*,;dfg5i5mm8mm8m5ig7:da9=#+...@%*,cd47<imjpi5hhijopmkh4bc=&.....@&*,90_db4khlhk747774ba-$@....@#=9ae4hhhhhhhilmjWqjge1b0-%........................................@#=,cbf7khh7eac=$&+.................@**3abf7hhh7ba3=#@..........+&>>,,-,,==>,,3,=*$#%+........+&**>,39afiqUUjiba09-=$%+...........+&*$,9~bee:bd;,*%+..........+&***>=>=>=,=>===>=>*$*#@.............@%>ccadbda;,$%+.........+&#>=cae4hhfebd0,*%+..........",
"..........................................+%$,-0dbbd93=$&..........................................@=,3df7hlVVXXXVmVlVh4ba;3=%....+*>30ekVlXoZWommXnZZZmVh4b0,@.....@&**-99_b4hVVVkkk<llked9=&....@*>cd4lVVVllhhhlmoWUol7f1d9$+.......................................@#$9'b4klllk7eac=$&................+%=3017klllk7:a9>#@...........&&#*$>$*$$#$*=$$*%&+..........+&#*,90dfiqUUqifd;3=$&@............@*$-9d:kkkk4bac>$&...........@&#$*$*$*$***$*$#*##&@@+............+#=;abe474ed9=*%+........+#>30~ehmpl7eda9=$&+..........",
".........................................+@*,;_{/^^2{'3,#.........................................+#=c_}zxtAHHCCCCCCCCts^F';>#....+$-'{^yCCCvLvvvGGvGvGBtxrF',%.....+&*>;')]^stCACAyAACBAs/)3%...+#-;{/sCCCBCBCBBCCvLEDHysz^];&.......................................@#,'{^stAACCAs/{;-=&..............+%>;~FzAACCBts^]!-$&...........@&##$>,=*#&##$=*%&+............@#$3!|[KwEEEvAKF);->%+...........+$-;)]ryBHHBAs/{;-#+...........+@%%#%##*=#%#&&&&#%&..............+%-;)FrsABAsr{!-$&.......&=-~]/rsALGtJ/F);-*%...........",
"..........................................@*-;'FQzr/{!;,%+.........................................%,;'FryACBHBCCCBCBAyzF)'-=&+....%=;)^sACCBHGLLLLLGCAtzrF)',@.......@#-;)]^sAACBAABCABAz/);*+..@#>;)/stBCCCCCCCBGGLLGHCAsr{;%........................................%=;)FzyBCACAs/{!-=*&.............&=-;)/zACAABAz/);>#&.............+@&%%%&&@.@%%%+...............@*-;)FztLELDxr{~-=#@............&$;~]^sAvLvHts/);,=&..............+.+.+@+++..+.+++...............+*-!{/zxACBAzF~;=%.......#=;~FrzxtGvAz/{~;$%............",
"..........................................+&*-;|[I<[(-=*@..........................................&*>-'{F[IKPKKKKzKrQ/]'->$%+.....@%=-)]F2/QIKOwNNwPQ[])';=*&.........+#=-!)F^KzKrrrrKr/F'->@....+#=;)F^KKKJJwwOwOOOOJJO6P2~-&.........................................&*-')F/rIzI/{~;>#@@............+@#=-!(FrKz^//]'->*@...................+.........................+#>-!1<ONwOQ(;,*%+.............@%>-~1[6wNSJI2(;,$&+..............................................@*-!{FQKJJP[_->*@.......&*>;~:2QIPI<:~;,>%+............",
"...........................................@#=c15O8<|;>#@..........................................+%*-;_|2}QIIKIIIQ[}|_;-*&+.......@$=-;~_((:[8RNN6<:(!-=**%@..........+#*=;(2QIIIQQQ[[2(;-*@....+@*>;(}[<5YRMMNMMO6P6YRR62a,&.........................................+*=-'(:2QK<[1~;-*#+............+%*,;~|}<<<[:_~;,*&+..............................................@*>9_78YR840->$&+.............@#=-~1[56O852(!-*&+...............................................+#>;(2<8YR6ea-=%@.......@#=-_:2[[<[:(;,*&+.............",
"...........................................@#=0bijjib3$%@..........................................+%*>9abe47hlllhh<7ebd9>$&+.......+%*=-339cafiqqqpfd0->$&@............+%$*3_e47477744ebd3=$@....+&*=9a:47ijUUqTqqjiimjqqjg0-+..........................................&*,9cdfgjpieda;>#@............+%$>;dbgppi7ba;,$%@...............................................@#=3agiqjifc3*#@.............@%#=9af7giig7ba3>#&.................................................#=9aegjqqpfa,*%@.......@*=cdf77h77ba;>*&+.............",
"...........................................@#>9agggfa9*#&..........................................@#$3c(e4klVVVVlVVlkea9,*&........+@&%#*>>9abhmooifa3>*%&.............+%#>3cdee44ee:bbd03$%@.....@#>,0dbfggiijjjiih4ggjggb3=&..........................................@#=-caemoom7eda3*@............&#,cdb7loZp7ba9,*%+...............................................+%$,9dggggd0,$&+.............+&*-c|4ll5hhfd09=*@+................................................%=9cbggiggb0,$%+.......&$,0|7klllke_3=$@..............",
"...........................................&$30ab1bd09>#@..........................................+$-'{/zxtCCCCCCCBBtzF~-=#........@@@&#$--!{/xtHCxK]~-=#@.............+%$,;!)]F///F]()~'->#@.....@#>-!(]}[4hhhkhkQ^^Ik7fbd0,@..........................................@*,;!{rtvvtJz^])-%...........+&=;{/zsADLGK^{!->#@...............................................+%$30_|::(a;-$&+.............%=-'{rxCBBAxzF);-=@.................................................%>;~{:474bdc->#+......+%-!{rxAAAAs/{;-*@..............",
"............................................%$-;;'';--$&...........................................+&>;)/rsAACCCCCABByzF~-=@.............+#>;'FzAAxs^]~-=%................%*,;!~'))))~';;->#&+......@#,;;~))){){{]{F]{){(__;,*@..........................................+%=-'(^JGGAsr/{!>#+...........@*;)F^syBwAzF);-#&+................................................+*,-;!'~;;-$%+..............@*,;]rtABxsz^]!;>%+.................................................+#-;!))))~;--#+........*-;{rsyByszF);>#+..............",
".............................................+%*====%&+..............................................%=-~{]FQrKKrIrr^F|'-*&+..............@#=-!{//2]';,$#@.................+&%*=====,,=***@+..........@#$>,--------;-,-,-=,=#+............................................+%*>;~1241(~'-,%+.............@=-;!(14}:~;,#&+...................................................+&#*>=>*#&@.................&*=;)FFFF1)!;>*%+....................................................&#$>-,,==#&+.........&=,;)]FFF{);->*@...............",
"..............................................+&&%%&@+...............................................+#-;;~(|}}2}221(~!-**@................@**-'_(_!->#&+....................@&#*&%%&&%#&+.............+@&##*****==*=>***$#&+..............................................+@**-99'c-->$%&+.............+@*=,,-cc3-=#&+......................................................+&&#%&@+.................+@#>>;_(_!--,$%%+......................................................+&&&%##&@...........@#=-;_((_!-->%@+...............",
"................................................+..+.................................................+@#,-3cc_db_d_0!;-,*@+.................@#=-9;3-=$%+......................++++.+@@++.................++&%%%%%%#%%%&&@@@+................................................+%**>>,,=**%@+..............+@&#*$>>>**%%@..........................................................+@+....................@&*=3ccc9,>*#@+.........................................................+++@++............+%*39ca_cc,=*&.................",
"......................................................................................................+&**=,,3993,>>==>*%&..................+@%*>=>**%&+..................................................++@@@@@@+++@@.......................................................&***$*#%&+.................+%%#%#%%*%&@+.................................................................................+%*=-9c->=*%@+............................................................................+&#>3999c,,*#&.................",
"........................................................................................................&#*$$>>$#&&@%#*#@.....................+%***#&@+.......................................................................................................................+&%%#%&@+...................@@&@%&&@++....................................................................................@&*$>>>*%#&..............................................................................+@&#$>>==**%@+.................",
"............................................................................................................++++......+...........................+......................................................................................................................................................................................................................................................+.++++++..................................................................................+.+++++.+....................",
"................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................",
"................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................",
".............++@@@++..........................................................++@@&@@++....................+@@&&&&&@@@@@+.......................+@@@@@++...................++@&&&%@@@@++........................+@@@@@++................++@@&&&&&&&&&@@++....................+@@&&@@@++....................+@@@@@@@@+...........................................................................................................................................................................................................",
"..........+&&#*====####@+.................+@%#######@+...................+@####==,=>=*##&+...............+&#*$===>===**%&@.....................@&**$*$*#%@+............+@###==>>,,,>>=*##%@+.................+@#****===###&@........+@###==>,,,,,=,,=>=*#&+...............+@#*====>$**&&@.................@%%**$>$=**#&++................................................................................................................................................................................++@@@@++...............",
".........@#=>-;!~~)!!;-,$*%@+..........@%*$>-;;;!;;;>$#&@..............+&#>-;;;)){)~!;;-,$%@+..........+@$>-;!){{))~!;;-,=#+.................+&*,-;;;;;--$#@.........@#$,-;!)){)))))))!;;-$#@..............+&$=-;;!!~))!;--=%+....+&$>;;!')){{{{))){)~!!;,=%@..........+%*$-;;!)))~';;->=#&+............+%$,-;;!~~~!;--$$%@+...........................................................................................................................................................................+@#$=>>,>$****&+.........",
".......&%#*-;!))]F]])~!;--=*@.........%#=-;;'))))()~';>*&@............@#*,-;'){]//F]{)'!--=*%@.......+&#=,-;'{F//^F]{)~;;->$%+..............@%=--!~))))';-=*&.......@#=;;~)]F///////F]{)';-=%............@%#=,;;!)){]]]]));-=&....@#>;!)]FFFF////F///]{)~!-=*&........@#$--;~)]F/F]{)~';->*%@..........+#*,;!))]]]]))!;--,*&.........................................................................................................................................................................@&#*=---;-;-;---=#&........",
"......+&#*$>;;~{]1]1(~;;,>**@+......+@%$*=-;!))(({{);,$%&+............@**=--~){]}/}]|)~;-,>$#@.......@&#*>-;!)]1F}F:{();-,=*#@..............&#$,;!~)~)~!;,*&@......+&$=-;')(F}:}11F:]|_)~;-*&...........+&#*>>-;!)(]F1]()~;-*&...+&$=-')({:F}F}F}F}F}]_)~;-*#@......+@&#*>-;!~(]1F1{)!;-,>$#&.........+&**>-!)({{]|)~!;-=>#%+.......................................................................................................................................................................+&&*$>,----;--->=>*#+.......",
"......@%**--;(_:}[}211_!-=>$#+......+&**,-;!((1}2}}(~3=#&+...........@#$>--!_|}}[[[}}2(~;-,=*@.......+%*>-;;_|}}[[[}}:(!;-,=*&.............@#*=-'_((111(!->$&+.....@%*>;!((}}[[}[[[[22:1(!->%+..........@%*$=-;'_(}}[[}21(!-=@....&*>;_(|}}[[[[}[}[[}}:1(!->#+......+&%*,-;;_|:}2}21(_';--=*&+........+%*>-;_(}}2}:11_'-,=*#@......................................................................................................................................................................++%#*=,;;;!!!!;;3-=$*#@......",
".....+&*>,cabff77hk77ebba9,=*@......&#>3;adbeggghigeb;,*%+..........+&*=9cabf7ghhhhhhg7bda;,>&......+&$=3cabf7g7h4hh4g7bda9,=&.............@$>-cbegggg7eb;,=&+....+&#=,;abfghhhhhh7k77eeba-=*+..........@*=3;0befgghhh77fba;>%....&*3cbef77k7hhhh7hh774ebd9=*@.....+&#>,;adbefgkh7k74fbba;3=*@........&$,cabff74k74febba09=*&........................................................................................+..................................................+@++.......................+@#$,3cdbbebeebbb0;,=*&+.....",
"....+&=-cabegmmmVVVVmpm7ebac>#.....+%=-'b47kmmoononm7d9>#&..........%*>cd:47lmnmVlVVXnml7eba,#+.....%*,0(e77lpmnVVVmXmmh7eb03$+...........+#=cabgijjjjji7b9>*&....@%$-0de7lpnXlVVlVVVlkk4b0,*&.........@#>9abgipppoonXVVk4b0,#+..+*,c{4hIhlVVVhVVVlVVVllkea9=&.....&#>3abe4hmmmmVVVmpml7eedc>%.......@#=9dgiimlVVVlVlkk7}d0,#+....................................................................................+@%%#%%@+.........................................+@&%*%#&@+.....................&#>90bgippjjppppi7bac,>#+....",
"...+%>;)FrzyHvvvHCHHHDGtysrF~-&....&=;)/sABHvEuEuEuvs^);,*+.......+@=-~]zytHGDvvHCHGvvvHBAsr{-%....+$-)FzyBBvDLDGCHGDDvHAys/)-%..........+#-;{^swEEuEEEDy^{;-%....#=-)]rstHDEDHCCCBCBCCAsr{!-%.......+&$-~{^syuuEvEvDGCCBy^]!=+.+%-']zxCCCCCCCCBCCCBCBCCts/);=+...@*-!]rsAAHGDGHCHHHvvGCtsr]!>.....+%*-'{rxDvGCCCCBCCCCBtz]',&.................................................................................@%*$>----->$*&.....................................&#*=---;-->*#@+.................+#-!{/zxDuuuuEuDuHtsrF);,#+...",
"...@#-;)/zstHDLvBCBCGLDCtxz/);#...+&=;)ryBCHDEEuEEEuA/{;,*@.......+#=;)/sACBGLLGCBCHDLvHCAyr];*....@*;'/sABHGLLvHCCvLLGCCBsr(;#..........@$;~]rstuEEEELDA/{!-#+..+#,;)/zsyHLLvGBCCCCCCAAxr{;-%.......@*,;)FKsHEEEuLLLGCCBxr]!$+..&>!]ryBCCCCCCCCCCCCCCBCBs/);>&..+%=-)FzyACGvLvHCCCvDLGCCAz/'=@....@#,;'FIAGvvCCBCCBCCBCBs/);*...............+@&&&@+............................+@%%&@+.....................+&##,--;!~~!!;->%..........@&&&&&&&&&&&&&&&&@........&#=--;!'!~!;-,=##&...............&$-!{^sADEEEuEuELEAsz/]~-=%...",
"...&*=-!(F[QPJwJJKKJJwOPI/F|;>#....+#=;)2/IPOSNSNSNOQ|!-*&+........&*=;)F^IKJwwJPKKJJwwPKI^]'-&....@%>-)F^IKJOwJPKPJwwOPKr^]!-&..........&*>-~:[6YNSNNwO<1;,=@....&*,;~][QPOwOPKKKKKzrr^F);,*&......+&*$-!)2Q6MNNNNwwJKI^F);,%...+&=;{FrIKQKKKKKKKKJJsKKr});>&....@*>;)F[rIJJwJJKKJJwwJKIrF(;*.....&#=-;(25wwJKKKKKzKsKKK/(!-#..............+@%###%&@..........................+@&&##%&+..................+@&%**=--;!!~'';->#.........+@&&%%%%%%##%%%%%%&+.......@%*,--!'~'!;-,=**#@+.............%*,-!(25OwNNNNNSwOP[2]);-*&...",
"..+&*>-'(}[QQ66<Q[[QIPP<[[}(!,&....+%$>;_1:[<88RNNS67(;-=&.........&#=-_}[Q<5665Q[[Q586PIQ[1~-%....@%*-'_}[Q<55<[[[<K6PI<Q[{'>%.........+&*>;~|2<6ORMRS8<(;=*&....@$=-__1}<6JPI[[2[[[[}|(!-=#@.......@#>-~:7<88OOO65<Q}}|_;-*@....&*,;_|}}2}}}}[[[II5KIQ[:~-=%+...&#=-~|[Q<I6P5QQ[Q<K6IIQ[}(;*+...+@%>9~(}<66<Q[2[[Q<6JP5[(;,&.............&%*$*$*##%&........................+%*$$$*##&+................@&%%$>,-;!_{2ee1_c-$+.......+&%%###$$$$$$$$$$###%@......@#>-ab1e:1(~!-->**#&@+..........+&*>-!(1Q5O866868O8<[21(',*@...",
"...&*,;de7khhh77ebef4ghhhhhed9%.....@**3c~abffgjqUWjgbc-*&.........@$=-aehhhh77feebe77ihlhhea3%....@#*,0df474eeebeef7hllkh4ba,&.........@#=,0behhihimjZqgb9=*%....@*=3abf4hhik7eeeeee:bba;->*@.......%*,;agpjjmiig44febda93=#&....&*=3c0a_dddbbbee7hklkh4e03*@....@*=3de7hhlkh4fef47hhilkh4b;%....@#*-cdbehhl4eeebe4ipqZpiba9#...........+@%$*>,,>=$*#@......................@&$*==>,=$#&+..............+&#$==-9cabfgjjjpgd9,@......+@&$$>>======,=====**$*&.....@#,cgipjpg7bbacc,,=$%@+..........&*,;abf7hihgffghhlihh7e09>%...",
"...&*9a|kVVVlhk4eebe4khVVVlkbc$+....@#*=,90adffpqUWqgb03=%.........@*>3d4klhk4f1b|eekhllVll4b;#....+%$,cdef4eebee1e7hllVVVl4d3#........+&*,;aehlVVV6XoZqibc3>&+..+@$,cde7kllVlhk444444e|d!9=$@......%#30dfioZoV5l<k4ee1(a;3>*@....@%$=,3c090!a(b14klVVVlkea9=%....%$30_7VVVVVhk4ee4khlVVVlke0>+...@*,0de47lVlk4e1ee7loWWqm7d9*+..........@*=33aadd09,=#@....................&*=39cadda93*#@...........+%*==3c'd(147hmoWZjifa9#.....@&#,3c0c0aadadadaaaa0c9,$&....&*3agqqZnXlk4e:bdcc,=$#@.........&=3ade4kVVh7fe4klVlVVl71a,*+..",
"..+$-'FrtCBCBBxszrrzstBBCBByz{,+.....%#--!_|/QsGLEuDyI{;-#+.......+&=-!{rsxszzrrrrzstACCCCCxr(>....+#>;)]//rzrzrrzsxAHHHCCAs^)=.......&*=-~]rsAHHBCBHvLDAK];-#+..+&,;)/zyAHGGGGGGHHHAAysrF);-%.....&>;)FQxGuLGGBCBAtxsz/F{!->%....+&*=--;;!'){F^rxtBCCABxr{'-*+..@$-;{rsCCBCCAtxsssxCACCCAyz];&...#-'{^zxtCCCtsszzssCvEEvts^(-.........+%$-~{/rxxsz/~;,*@.................@#>;~]/rsyys/);-*@........+%*--~)]/rsyyAACHvGGHsrF!*....@*-;)F/rrrzzzsszszzzzr/F{;$+...&=c1KAGGGCCBHtAAsrF{!;->#@......@#-~]^zstACtxsssACCCCBCAr]',@..",
"..+*;~]zyCCCBBysrrrrzyABCCCxr{-+......@#--!){^KtLLELxr)!-=&........&$-;'{F////^^//rsABCCCCAyr)=+...+@#-;)){]F/^/rzsAGvGCCABs/)=+......&=-!)/ztvvGCBBCGLLtz]~-=@...#=;)/zsACLELELLLLLGHAxz/{;-#....@#-']^zxHvLvBCBCCBAyzr/]';,#.....+@**>-;-;''{/rsACAABts^)!,#...+#-'{/sBCCCACAysssAACCCCCtz];%..+#-!]rzyABBBAszzrsstGLELHs/{=@........+*-!{/ztHLLtK]'-*#.................@$-;]/sxGGDAK]!-,%......+@%#-;!)FrsxBABCCCCAAysrF)-#...&*=-!]rsyAAyyAAABAAAAtAsz/)-%...@=-!{^zsyBCCLLLvAxrF)!;--=&+....@*-!]/rzyAAAsszsytBBCCCxzF'>&..",
"..+&=-!][KzKI^/]_)({]F^IKzK^|;*........+%*=-'(25SwwOQ|;-*%+........+@#$=--;;;;!'~){F^IzKKKr2(;*......@%*=,--;~)(|12IJwwJKK^F)-%.......&*>-!(2KOwJIQQIJwO<1!-=&....@*>;)][IPwwNNNNuNNwJIQF(!-*&....+&=;'{2[PwwJKKIrKrQ/2()!->*&.......+&&#$**>-;~{FrKzr^FF~;=$+....@*>;)FQrKKKrQ/FF/^rKzKIr^1!$+..+&*-!{F/rIKK^2]1112IOwwO52(;*..........%$-'{[<wwwO[_->#@..................%=-'|[POwwO4_-=*&.....+@&**=--!{F[rKzKzKKI^}}1_;>%+...+%*>-)F//rrrrrrrKrr^rrrQ/(;=@....&==-c(]}QKJwNNwJQ}{~;;,=$%+....+&#=;~)]FF//}]]2/^rKKKK^{~-#...",
"...&$-!([QIIQ[|(~';_(|}[IIQ2(;*+........@%*-9_1<YSR84_;,$&+.........+@&%*===>,,;;'(|}QQIIIQ1~-%......+&%#*==-;'_(11<6OOPIQ[|!-%......+&$,-'(|<6O8<}}[5O8<1'-*%+...@%*-;(1[6MNSNNSNNNY6Q[}(;-*&.....&*-'_|[<OwO<QQQQQ[}:((;-=#@..........@&&%*=-!_:2QQ[2:_'->@+....@%*-;|[[QQQQ[}1:12[QQQQ[}_;*....&*,-_(}}QIQ}:|((1:<6RSO<:~;*+........+@*=;(2<OSR84~-=%@.................+&$-;(}5OSR84~-$#@.....@&%$>--;!(1}QIIKIIQ[}((';>*@....@%$=-_:[QQQQQQQQQQQQQ[Q[}(!,%....+&*=-;~1}Q8YNNR8<}((~;-,=*%....+&#>=;!_(1||((((:2[QIIQ2(;>%+..",
"..+&*3cb7hkhk4ba!ccadb44hhk4d;#.........+&#=30biqWWjgdc,*@...........+@%%#*$=>,;aab17khlhh4d9=&.......+&&%*=,;abffgiqqomk7fd9=&......@%*39abfipomh77gpqjib09=&....@%*,;abeioqWUUUqWqopih7fa;=#....+%=3abb7pqqomikhkhk77fbd;,*@...........@&%$*3cde75h7b|a;=$@.....+#$3cb47khikiggeggiklkh7e03#....&*,;abe4hkh7bbbbbfijWWqifa3*.........+&*,cdfijZqpga9>$@.................+&*-0bfijZqpea3*&+.....@#*=9aadbf77hhhhhh7fbaa;9=#+....@#>-9df7<k<kh<kk5k<k5kh77ba-&.....@%#>,9ae7ijqqqpg4febba0,=#+....@&*>99aadbbb(bbe77khhk4dc=&...",
"..+*=9_e<VVllk41a00d14klVVVke0*+........+@*=9afiqUUjib03>#+...........+@##$>>-ca|e4hmnnVlk4b0=&.......+@%$=-9dfgijjqWUZmlk4ba3%......&*-;be7klmmmh7klnZqiedc,#....@%$30db4hmMnppjoonZXopmib09#+...+#=c(e7hmZWZooonmVlmmpigd9,%..........+@&#*,c_b7mnmhfda3=*@.....@#>9~b4khmnooojjjjoomlk4ed9*+...@*>0d:4hmnnk7ee47hpZUTqpgdc*+........+%>3ab7hXnnm7d9=%&.................+%*3a14lnnnm7a9>$@.....&*>;de77hmpXmVVVkk41d0c9=*&+....@*=9deklVVVVVVVVVVVVVVVVk4d9#......@#$=900e7ipppmVVimiigedc>@.....@#=,9c0_d1ee4hlmnXVVh4bc3#...",
"..&=;~/ztCCCAAsr/F]/zstCBCBxzF,+.........&>-_:IAEEEvyQ{;-$@............+%*=-;~{^zyAAvvvAAszF);&........&*>-~]rsHuuuuEEvGtysrF'$....+#>-)]zyBACCCBBAAAGLDts/]!>@...&*,;)F/zxBGHtAxtHBGLLDDtKF',&...%-!{^sxCGDEEELLDGHHGDvvyK]!=+.........@&#>;~{/zxGvvtz/{;-=&.....&>;)]^zxtGuEuuuEEuEDGHxxz^(>+...+=;{/zxAvDDHysyyBBGEEEuDs^(-.........&#-']rsACHHyr]'-=%+................@*-!]rsABHHxK]~-=@....+*;~FzxCAHGvDHBCBxs^F{!;;-$@.....&,;)/ztCCCCBCCCBCBCCCBCCBs^(>......@%>,;~{FrssAAHHHHDvDHxz/~$.....+%=-;!)]/zsxttGDDGHCts/)-*+..",
"..@=;'FzACCCCtsrF]]/zsABCCBAr{,+.........&=;)FKxLLELyr)!-=%.............&*>-~)/rxABHGvvAsz/]'>&.......+@*,;~]rJxuuuuELvAAxsrF)=+...&$-')/sACCCBCCAAtBGLLHsr]);%...@*=;!)F^stAxszsyxCCGLLDGzF)-#...&-;{rsAAGLELLvvGHCHvLLEtz]'>+.........+%>-;)F/syHGGyz]);-#+....+%>;)FzsABHGvDLuDLLLGHAyyz^{-+...+%;)FzsAHGGHtAABCHvEEuuGs^),@........+*>;)FzstAts/)!-*&+................+%=;)/zsAAxs/);-#@....+=;)FsACCHLLLGCBBsr/]~';-=#+....+#,;)FsAACBCCBCCCCCCBCCCCBxr)=+.....+%*=-;']/rssxACCGLLLGAs/)=+.....+%>-;)]/zxBCCGGGACAyr]'-*...",
"..+%>-']QKKKr[F|_;'_]/QzKKK/:!*..........@%=-!:5wNNOQ|'->#@.............@%=,;~:[6OOJ8P<[1)'-,#........+@&#>-;_:4h5lPPJPKIQ/})-%....+#>-!:QJwOJJzKrIIKOww6[})!-&....@&$=-;'){]:|(1]F[IJwww6}(;,&..+@=>;)F[IPwwO6PPIQIKOwww5[_;*...........@%>-!(:}QPPI}(;-=*&......@*,;)}^IIKPJ66P6P6JJPKr^/|;$.....@=-')12IPJOJJJJPJJwNNR5}(;*.........+@%>-;~){{{)!->#@+...................&=-;~){]{)!-=#@.....+%-;)/IKKJwwwPK^/F|';-=$%&+......@*=;)F^IrKKKKKzKKzKKKKzIr2);%.......+&%$>-;_(]2/QKJOwNwOI2{;%.......+%*=-'([IJJJ6PPQ[F{);,*&...",
"...&*-'|[QII[}1_;-;__:}QIIQ2(;*+.........@$*-0(<OSR64(;,*&@............+&#$,!_|58MR85[:(!-=>%@.........+%#*==9'_b124<<IIIQ[|'-%....+&*,;(<OMwOPIIIQI5OYY5[:|!-&.....@%#*=,-;;;;;!_(|}5YSY6f~;>%...@%>,_(}[6YM6<[}[22<6YSY51~;$+..........+%*-'(:}[Q<[1!-=#&+......@#>;_1[QQ<II<[[}[Q<II<QQ}(;*+....@&$,c~|}<6YRRRO6P8RSNO5:~;%..........+&%*=------>$#&+....................@&*=------>*#@+......&=;~1QIKPOYO6[}}|~;;==*%@.......@#>-!(2[Q[QQQIQIIQQQQQQQ[:~-#........+&#*=-;'~|:[IPOSNS8<:_-%........@%#=-_28YRO6<}|(~;,>*&+...",
"..+%*,cd4hhlk4bbaccad:77hlh4b;#..........@$=30bgqWWjgd;,$%@............@#*=9abfiqTUqigba;,*$%@.......+&%*$$>=,90abbe7hhllkhea-#.....&$-cbiqUqomhhhhlmjqqpkfba9%....+@%*$=>,,,,-39aabfiqWqp7d0,&..+&$>90bfgmqqjffbfbf7pqWqpfd9=@..........@#*3abe77h47bc9$*&......+@*=3dekhlhhhhefff7hhlllk7bc$+....@&#$-cdfhiqTTTqpmnqWWqifa;#..........++&%*$>>==**#&+.....................+@%*$>>=*=$$%@......+&=cae4lVnoqomg4fbbc;,$#&@.......@*,cabf7khhhhhhhhhhkhhhk4ea3#.......+@&$*=3cadbe7hmoWTUjiea3%........+%$>3agjUUqi7bdcc,=*&+....",
"..+#=9~ekVVVlk4:dd(bb4kVVVVk|0*+.........@*>3aeiqWWqiba9=$&+..........+#*-c_b7ijqTUqm71dc3>*&@.......+%*>=,3-3c0dbe4kVVVVVl7b9%....+#>caepqUWZXXVVVVXZWWolh7b0*....+%*>,,3--3,-90_bbhpZWWpgba,%...&*-0(e4lpWqjif4eefhpZWZpgb03&..........&*30(47khllk:a3=#@.......%*30(7VVXVVVhk444klVVlVVkea,@....+&#=,cd4kmqTTTZnXXZWWZi7d9*+..........+@%#*=,>=>$#&@.....................+&%#$==>>$*%@+.......#>cd4hVVXZZoXlh74:ba;3>*%+......&*3cbeQllllVVVVVVVVVlVVlh4d9%.......+&*=,90dbe44hVXoWUWoi4d9#........@#*,9bgqWWZp7edc-,$%@.....",
"..&=;)FztCBCAAszr/^rzxACBCBtz],+........+#-;(FKtEEELtK/);=#&.........+%-!)]rstGLLELGtsrF);->#@......%=-;)){))~)]//zyACBCCBBs^{=...+%=;{^KtEELvCCBCCCGLEEvHByz]-...+%>;!)({~~~'!~{/rzyGEEEvyrF!*...%-;)^sxAvEvvtsssssyGEEEHsr];%.........@$-~FzxACCCAyr]~;=#......+*-~]ryCBCCCBAyssstCCCCCCBzF;&....@%$-;)/zyAGDEEEGHvLEELHK^(>+..........+&#>,-;---=$*@....................+&#$=,---;-,=@........#;)FzxABHGvGGHHBAyzr]{!;>*&.....%,;)/stACCCBCBCCBCCCCBCCBsr(>......+*=-')F/zytHAHBHGvDGGxzF!*........@=-;(^yGvDDCsrF~;-=%+.....",
"..&>-~FzyCCCCByzr^^rzytCCCCyz{,+.......@#=-!{/sALLEGAs/);->*&.......@#-!)F/KAGvGGHHBys^]);-,%+.....+#>;)]//^]{{]/^zsxBCBCCAy/)=+..+#,!{^sABHHCCCCCCCGLELGCBtsF-@..%>-!{F//F))~~){/rKxGLLLDxz]'*..+%>!)/zyBHLvGyszzssyGLLuGyr];#.........&>-)FzABAACBxr]'-#@.......*-!{rxBCCCCBAxsssyBCCBCCtz];&....+%#>-!{^zsAtHACBCCGLLDts/)=+..........+%**>--;--,*#%+....................&#*>---;---=%........@=;)FrzsxACCvGLvHBBsrF{~;-=%....%=;)/zACCCACCCCCCCCCCCCCBx^(=+....&#=;;)]ryAGLLGHCCBBtssr/)-%........+%-;)}sAHHAxs/]~->%+......",
"..+#=-~]QKKKK/[F|{(]F2/IKKK/]!*......+@&%*,-!_25wNNO<1(;-=*%@......@&%=;~(][8wwJPII[2]~;-,**@......@#*-!):]|(~'))(]F/rIzKKr[);#....@#,;_][IKKJKJJJJsJwwwJPK/F)=...&*>;~{]|(~'';!'(1:Q6SNS8[|!-#...+#>;):2IPwYPQ}2F:}Q6wNw6[|'=+.........&*=;)F^rKKrQF(;=$&+.......&=-;(^IzKKrr//FFFF/IzKKKr:'=......+&$>,;~1:22[[Q^QPwwww5}~-%...........+&$**=>=,>$*%&+....................@%#$>>,>>=$$%+........%=-;!)(]2QIOwwwwKK^])~;-,*&....&$=-']^zKzKzKzKKKKKKKzKrI/);%....+%*=,-!(FQPONNNJPI[2]_~;;-*+........+@*,;_:QIII2{!;,*%+.......",
"..+@>,;(}QIIQ[}:1((_:22QQIQ2_-#+......@%$>,-0_15YSS8<1_;->$*&+.....+&$>-~(|}5YR6<Q[}:(~;->>$&+.....@#>-c(|:1(~_~__(1:[QQKIQ2~-%....+%*,c_:[QIIQKIPKPPOSROI[[1'$+..@*=-__|:1(~~~___(1[8YNR8}(;=@....&=-!(145YY5}1(|(:48YSY5e_;*+........+@*>3!|[[QQ[2:~->%@........%*,;_}QIQIQ[}||||}2QQIIQ[1;*+.....+@**=-;_((||:2}[56SS87(;=#...........+%#>>-,-===$%@+....................@%**=>--->**%@........+&#>,-;~(:<6wwwJPQ[:(~';,>%....+%$-'(}[QQQQIIIQQQQQQQQQ[{~-#....+%*>-;'_:[5OSNS8<2:_!c-=$*&..........@*$-!|}[Q2|~->*%+........",
"..+@*,;de4hhhh7feb:bf77hkh7ea,%.....+@#**,;cabfiqTUqiebac3>=#@.....@%*3cdffgjqUjih74fbba;3==%@.....@*=9abf7ff1bdbdbf4ghhlkkea-%.....@#=9abe77khlllmmoqWqjihfb0>...@*=3_beeeebbbdbbffgjqWqpfdc>@....@*,;abgiqqigebebfgpqWqmed9*..........&*,;af75hhkfb'-$%@........&*=caekhlhhg7febf47hhllh7bc*......+&*>=3cdbeeef77gmjZqogd9=%..........+&*=-;0a0!c3>$%@...................+&*>,9;a~c0,=*%+........+&#*>39ab7iqqopmkh7fbd0;,*+...@%*,;a:f44747777k4k74774fba,%...+@$,cabbf7kmjqqqp7fd03-,*#&+..........@*$9cb77k4ba3>#&+........",
"...@*>9aekhVVmmikkkhlmmVlhkb03#.....&#*-0ad:4gijUTTqph7e1dac,#+....&*,0bgimjqWWomVlkkk4ebdac>#+...+#=-aeimmmikk4[4khmXXXVVh4d3%.....+%>-0dbe7khllXVXZZUWoVlk4a$+..&$-'b4khilihk7kkimpnZoqifa9=@....@*>cad4pqWjlkhhklmoUWWpgb0=+........+%*,cbgmXnmh4bc3=%@........&*-c(4hVVXXmmh<khinnnlVlk:a$+.....@#>,0a1477kkhlmmnonomgbc>&..........+%>9abeggged9=$%@.................+%*,;_b7gigedc>%&.........@%#$>90df4iimVVVVmmiifbc3#...+#*=3adbe4e4e44e4e4e4eeeba;>&...+#>0bgiiihlVmjjihfba3,=*#&+..........+&*=3_eklh7:a;=*#+........",
"...&*-!]^sxBGGvGBBBHGvvHAxs/{;*.....#,;)/zsyBBHvuEuEvHABxsr]~,&...&$-~2swDLLEEEGHCCCBCAtsz^]!,&...%>;)/sHDDGHABCCABHvDvGCCAzF!*......&=;!)]/rzxBBBCBvLELGCCAs]*..+#-!]zxACHvGHHBBHGDDGGHHAI]'-&....%=-;_FItEELvCACACGLEEvtJ/{-&.........*-!{rxDDvvyz/);-#@........%>;)/sABHHLGvCCACHvDGHCAxr{,@....+#,;)]rsAABACBHvGDGBHAz2)9$.........+#-!{rsAvDvwV]!-=%................+#>;~FzxAvDDwz1;-#@........+#*=-;~|:/rKsxAHGDDGGyzF'*....%=-;!)]F///F/////F//FFF{!;-&...%>!2yGDGvHHBtysKr/{~;--$#@...........+#,;~FzxBBxzF);,*+........",
"...@=,;)/zstAGvvBCCCGGvAAsz/);*+...+*-;]/zyABCCvEEEDGCCBAxz/);*...%>;~FsHGLLLLLvCCCACBCBAxzF)-#...&=;)}swGLvGCCCCCCHGvGBBtxr{-#......+*$;;)]FrsxBCCCCvLLHCCyr)*..+#,']ryBAHvvGBCCHGLvGCBAs^)!>@...+@#=;;{IyGvvHHHCCBHGGLDAzF),@........+%-;{QyvLvGs^{~-=#+........@>-!]ryABBvvGHCCCGGvHCBysF)>@....%$;'{/ryACCCCCHvvHCCtxr{!-&.........@#-~]rxtGvDHy/)-=#+...............%=-;{/sAGHDDGsF'-=%........++&#*>-;){F/rstttGGDGyzF)$+...+@*=;;'_)){{){({{{){))~;;-*+...#,'FJtvvHCAyszr/F)~!->#&+.............%=-!]ryBByzF~;>%+........",
"....&%*-;~(:[<PPKKKKPPIQ2{)!-#@....+&>-'{F/QrIKPJOOOPKzrr/});=%...+#>;_2<8JOwOJJJzKzKzzr^/F);=&...+%*-~1QI5PKKKKKKKPJPPI[F{'-$+.......@&#==-!)]/^IKKJJJJKKr[];#...@%=;~{/[IPJPKKKKPJJIQ[F{~-$%.....+&%$=-_1<IPKJPKKKPPPP<[(!-%..........@=,;([PP6I2_;,*&...........@$=;~]F[IPJPPKKKPJPI[/]);-%.....&*-;!)]^rKzKKKKPPIQ[F(~-=%+.........@%$-~1[IPJJI4_;=*@...............+&$,-~2I8JPPP<2_-$&+............+@#*=>,;')12[<<<}:_;,@......+@#**,-=,-,->>>->-,,==*#@....&*,014<<[Q}:(~';;->=*@+...............@*>-!{//r2{!,=%+.........",
".....&#*=-;_(2[QQQIQ<[21_!->*%......&*=;(:2[QIIIIPPPIIQQ[}:~-$@...+@=-c|[<IKIPIIIIIIIQQQ[2|~-=&....@*=3~(:2}[QQIIIIII<[:('-->&.........+%%==-;_1}[IIIIKI<Q[2(;#....@#$-;~(}[QIII<II<Q2:__;-=%+.......@#>>3a(:}QQIIII[Q}}:(!-=%..........@%=3!|[<<2(;,>#@...........+&*=-;!(1[QQIIIQI<Q21_;->*&.....@*>;!(|}QQIQII<[}1(_';,=#&..........+%*,;(1[<<<[|!->#@...............+%*=-_45O65Q4:_;=*&...............+&#$>=,,;cca_a_9->#+.......++&%%%**%**$$$%$#%%#%&@+....+&*,90_____;;->=**%@++................+@#=-!:22}_->*&..........",
".....+&#$>,3abe4hhhh7ffdc9,**&......@*=9(ee77hhlkhkhkhk77f:a3$&...+&*90b4khhhhlllhlk5kh47f1a-*&....+%*-9adbf7hhhkhhhh4eda9-=#&..........@&$$-0_b47khhlhhk77eb3%....+#$>-9ab47hhlhhhh4bd03,>*@.........@#=-cabf7hhhhh74bbda9,*&..........+%*,cdf74fdc=*&@............@#*=39ab47hhhlhhh7e003>*%@.....@*=90dbf4hhhhkk7edcc-=$*&+...........&*=cdb47hh4b0,*%+...............+%$=9agjqpk7fb03=#@.................+@#**$>-33999,$*&..........@+++@@@@@@@&@&@+++........+@#=,399333,==$*&&@....................@#=3a14fb_3$*@..........",
".....+@%*>,9cde7kllk74:dc3=*@.......&*-0be7kllVVVVVVVVllk4edc=@...+%=-cb4hlVVllVVVVVVIl<k4ea9=@....+@#,9ab1e7kllVVVlkk4dc-,*%+..........+@%*,9d:4klVVlVVlhk4bc#....+@#*>9a|7klVVVVlk7|ac9,*%+.........+#*=3ade4kklllh4ebd03**@..........+&*,cde44e0;,$#@............+@%*=90d4klVVlllk7|a33=$#@.....@#>3cd:[klVllhk4ed03>>*%&+...........@*,cae4kkk4b;,$&@...............&#=9afioZol7e|a3>#@...................+@***===,*=**#&............++.+.....................@&#=9993,,,$**&@+.....................@*>3ab44ea9=*&..........",
"......+%#>-')F^zxxtxzr/]'-=#+.......#=;~FrsstttBAABBtAAyyzr]'-&...@$-')/zxtAAAAtBtBABtAysz/]!-&.....@*9'{F^rsxtAtAAAyzrF~;3$@...........+@*=-~]^zsAtBttAxszrF~*....+@#>-')/zsttAAtAxzF)!;-=%...........%=-;)]rzxtAtxsz^/]_;=*@...........#,;~F^zr^{'-=#+..............@*-;)FrsxABAAtyz/)!;-#&......@#-')F^zxxAttysr^F);->*&@............+$;)]/zsxsr/~;=#+..............+*-!{FztvvHtsz/{;-=@....................+&%*$>,,=$$%&@.....................................@#*=----->,=#&+......................+&$-!{/rr/{!-=%..........",
"........@#--!)]F/rr^F{{~;=#+........+#-!){/rrzszzzszzzzr/F]);$@...+%,-~)Frzzszzszszszzzr^F]';*+......%$;!){{Frzzszzzr/]);->%+............+@*-;'{F/rzzzzzr/F])-@......@%>-~)F/rzzrrr^F)'->*%+..........+&%*-;){F/rrr^/F])';-*&+...........&$>;'{]]{~;,%+................@$;;)]/rrzzzr/F)';-##+......+%=;!){Frzzrr/FF));;$#@+..............&>;){F///]);-$@...............@$-']/syBBtz/F{';$%+......................++@%&%#&+++.......................................@%%*=>=*=#@+.........................+%>;')]])~-=#@..........",
"..........&**=--;;;;-->=*@+.........+@*=--;''~~))')~)!!;;-->*&.....+&*>--;~~~)~~~)'~)~'~;;-=*&........+%*=---;!~~)~~!;-,=*%+...............@%$=--;'~~)~'!;;-,%.........@%$>-;;!~';!;--$#@+..............++@*=---!;!;-,--$#&+..............@#==---,=*&...................@#*>--!!~~!!;--$#%+..........+##---;'~';;;--=##+.................+@%=---;-->=#@+...............+%*-'(1}[[2)!--$#+...........................................................................++.+@&@++.............................@#$>-->=$@+...........",
"..........+@@%%%**#%%%&@++...........+@&#**=,,,=$>$>>,===**%&........@%*>>=,-,---$$=$==$=**#&..........+@&##=>,>-,>>=$#&&@+.................+@%#====,>>>=**#%@..........+&***$=$$**%%&@+..................@@@%*%***#*%%&@..................+@%%%*#%@.....................+&%*=>=>$*#%%&@+.............+&%*>>=>>==**%%&.....................@&#**#%%%&@@.................+**-;;~((!;,=*&+...................................................................................................................+%#*%**&+............",
"...........+..++@@@++++...............+@@&&%#%%&++@@&#%&&&@+..........@&%#####%%%&@+@+@%&&+...............+&&%%&%###%&&+......................++%%#%%###%&&@+.............@%%%#%@+@+++.....................++.+++++++.+......................@&@@@++.....................+@+@@#&&@@++++.................+@&%%#%&&&&&++......................++&@@++.+...................+@&*=>,,,=*%%&+.....................................................................................................................@@&@@+..............",
".............................................++.....+++...+.............+.....++........+.....................++....................................+....+..................+...............................................................................................+..+............................+.+++..............................+.........................+++.+++++++++..........................................................................................................................................",
"...........................................................................+................................................................................................+.+.................................................................................................................................+..............................+................................................................................................................................................................................",
".............++@@&@@@@....................................................+@@+.+.........................................................................................++@@@@&@@@@++...................++@&&@@@@++@+.....................................................................................+@@@@@@@+........................+@@@@&@@+................................+..........................................................................................................................................",
"............+@%#&%%&&%@...................++++.........................+@&+&@@@@@@+.........................++++@+++++++++.............+@@@@@+@+.......................++&&@&&&%%&&&@@@+..............+@@@@&&%&&&&&&&&+.......................++.+@+....................++@@++....+.+@&@+...............+++@&&&&&&&&+.......................+&@&&&&&&++...............+@@+@@+++++++@++@@+................++@@@+++............................................................................................+..@+..............",
"..........+@&%#*$*###%@+................+@&&%&@@&&&@+.................@&%&%&%%&&&&&%&++....................++@&%&%&&&&&&&++.........+@@%&&%&&#&&&@@@+.................@&%&&%%&%%%#%%&%@&@+...........+@&&%%%###%%%%#*#%&@+..................+@&&%%&&&@@@++............+@&#%%%&@@@@&%&&&%&@@@.........+&&&&&&&&%%%%&&&&@+...................&%&%%&%%%%%&@+...........+@&&&%%&&&&&&&&&&%&&%&+............+&&%&%&##&@@@@+...............@@@+............@&&@@@+..........@@@@@@+.....@&@@@@++..................@&&%@&@.............",
".........+%%#*$=>===$**&+..............+@&###$****##&@..............+@%#$$*$$$$$****#%&@+.................+&%%#$$$$**#####&+.......@%#%*$*$$*$*$**#*&@+.............+@&#**$$$**=*=*$$$$#%&++.........&%###*******$>$=****#%@+.............@&%%##*$$$***#%&++........@&#*$*$*#$#%#%#*#*##$%%#@........@%%#$$****$*$*$*###@@+..............+@&*#******$$*#%%&@......+@@%##***$#$###$####$#*#&+..........&%*#**$**$$*%%%&+.............@%%%#%&@+......+@@##%%#%+.......+&#%#%%%&@@+@@&#%%#*%%@@.............+@&%$####*&@@..........",
"........&**=,990aaa0c9,**@+...........+&#*==,3333,,==#%............+&*>>33c9cc0cc33,,>*$%@+.............+@#*=,>,,3933,,=,>$*&.....+#=>3339ccccc3933=>*#&+..........+&*>=3393c99c;ccc9933,=*&+......@%*=,,-39ccc0009c9cc933==#+..........+@#*=>,3333333,,>=*#@......&#$=>=333-,=,=>>>,,,3,-,=*+......@%*>>,,339cc9cc333>=$*%&............@##>>33c9ccc939-3>>*#+....@%$==,,3933,,,>==,,,,,,>=*@.......+%*=,3399cc93,=>*#&+..........+%*=>,=>==##&@@@@%*$=>,,=*#+.....@#*=>,,>***%#*$==>,,,>=>#&...........+&**>=,,,===$*%+........",
"......+#,;'){]/rrzzr^F{;-$#@.........@#>;;~))]F]]{{~!--&+.........+#=-!){]FFF/^^/]]{))!;,$#&+.........+&#>-;')){{]FF]{{)))';;#+...#-;))FFFF///FFF]{)~;--*&+.......&*,;~)]FFFF/F/^/^/FF]])~;,#+....@*-;~){{FFFF//^^//FF//]{)!-$+......+&%$-;'~){{FFFFF]{))~!;=@....@=;'){{{F]]{))~~)){{{{{{{);$+...@%=;;)){)]]////FFF{{))!;,=@..........&$-;~){]/F////FFF{));,#...+#-;~){{]]]]{))~~)){{{{{)'-*+.....&*-;~)]FFFF^/]])~;-$%.........+#,;!~{{{)~;->=*==--')){{)!-*...@%=-!)))))';;---;'){){{))';=@.......&#*=-!!)){{{{))!;>$%@+.....",
"......%=-')]/zxtBHHAxr/);,=*&........@=;~{]F/rzzrr//{'->%.........&$-;{Frzzzzsssszrr/F{~;--*&........@#*,-~)]F/rrrzzz///FF]]~-&..@>']F^rzzzssszzzrr/F)'--=%+......%=-']/rzszszszssszzzzr^F~;$&...+#>-)]//zzsszzssssszzszz/F]),%......@#==;!{]//zzszzr///F]]);=+...#-']F/rrzzrr/F]]]F/rrrrr//]-@..+**-~]F^/rzzzssszszr//F]~;=#+........+#=!)F//zzzzssszzzr/]]!$...+$;)]//rrzzr//F]]F//rrr//]'-%....+%>-)F/rzzzzsszr/F)!-$#+.......#>!)]//r//]);;,-,-;~)F^r//F),&..%=-!{F/^/F])~;;!)]F/rr//F]);%......&#*,;))F/^rr^//F)!;-=*#@....",
".....+&*=;!(F[KJwwwOI}{'-=#%@.......@%*-;)(]}}/2/[F]~;-**+........@*=-)]}/2/[/^/Q/[/2{)';,=*&........@#$=-;~_F}/2^Q/[/}]1{_)'-&..&=;){F/2//Q//[/[/}/|);-=$#@.....+&=,;)]}//Q/Q/Q^/rQ//[/F{!-=&....&*-;(F//[//Q/Q//Q//[/[/F])!>&.....@%#>=-;)_F}/[/Q^[F]1]_)~;$@..+%,;)(]}//[/2F|_)|]}//^[/F]_-@..+%*,;)]F2//Q^I/Q/Q//}]|);-*@.........+#$-~{FF[//[/Q/^[//]|~-*...@#-!):F[^[^[}]|(({]}/[//]);=&....+&*-;(F/2^/[/Q/[F_~;,*@+.......&>;~(]:F/})';->>>,-!)]2/2F(~-&++%=,;)]}F:](~!;--!)]1F[FF|);-%.....+&**=-;)(FF}/2F1{~;->$*#&+...",
"....+&$*-;~(}Q56MSSO5[|_->*%@.......+*=-'~|:2[Q[Q[[1(;,>#&........@*=;_1[[Q[Q[QQQ[[[}1(~;->*%+......&**=>-;~1:}[[Q[[[}1}1|((!-%..@,'_(:[Q[[Q[QQ[[[}}:(!--,$*%.....%*-;(1}[[[[QQQ[Q[Q[2[}1|~-=%....&*,!(:[[[QQQ[[QQ[QQQQ[[}|(;-&....+&*$=--!_12}QQ[[[[}}:11(_;=&..+#>;~1}}[[Q[[:|(((:}[[[[2}|(-@..+%$=;_|}}}[[Q[QQQ[[}}1|(!,*%.........@%=-~(::[[[[Q[Q2[[}1(~-#...&$-;(1}2[[[[21(|(|:22[[[1(;=&....+&*>!(}[[Q[QQ2[}}1_;,$%+.......%=-~|:}}}}|_'--=>-;~(1}2}11~-&.+%*,;_122}1|(!;-;'_|2[2[}|('-&.....&#$>,-!_|:}[[[}21('--,$*%+...",
"....@%>,;adb4hloqWqqpgfbc->%@.......@$>-adee77hkhgheba-=*%+......+&>,cdf77hhhhh7hh7k74bbba;,*@.....@%$>9;adbf77kkkhk7h77ffeba;%..@>adf47hhhhhk7hhh77febaac,=*+...+#>3abf7khhkhhhhkkhhhkh7fdc=#....#=9aefhhhhkhhh<kkhkhhhh7fba-&....&*=,9cabbf477hk7h7777ffbb0>&..@*30de77hhh74febbbe7hhhhh7ed3@..+&$-cdbe77kkhhghhhh77fbdc9*%.........&*=3a:f7hk<hhhhh777ebd9#...&=9ade77hhh77febbe7ghh77fba,%....&*=,0bf7khhhhh774bd0-*#@.......%,;abf7g77fbdc;9-;ade7gh77bd,&++#=3ab7g77febdac0dbf7gh77fba-&...+&**,9c0dbff7kkk74fbb~c03>*&...",
"....&*,cde4khllnoZqqoml7b03>#+......&*30(e4klXpppnpm7bac>*&+......#=9d4klVVmXmVllVVlliligfbc,#+...+%=-!d:e7hilllllVlVlmimlkkea$+.&>de7hmpXmVVVllllllhhhg7fdc=#...+$,0|4<llmpnmlVlVVVVmjmmked9$+..@*-!b4<hlVXmXVVVllVlmmmmVh7:0*...&*=;~b:fkhillVVlVVVmimllk4|c%..&=9_e7kmmmmVlk42e4khhVmmmihe0%..+#=9ab4kkllVmnnpmVlVlk[ed9=&+........&$,0b4khllVmmpmVVVlk4ba$+..#>9de7lXppmVlk4447ippmVVk4dc*....&*,c(4<llmpmmVllk7:a9>#&......+#3a14hmnpmh7eb_a~db47mmppl7bc#.@$;abhlXXmmihebb|e7hlmmmiked9#...@#=ccd:f4hihllllVllhhg7fa9,#+..",
"..+%=-!]ryBACCCHGHHGGvGxz/{;,#......%>!]rxtBGDLEEuEvAyrF~-$@.....+>;{^sACAGGLGHCCCCBCGGvvAJF),#...%-;{/syBHGDvHBCCCHHHGvvvHAx/-&.&;/stvDLvvHBCCBBBBCCHGvGwzF'>@.+%-~]rtCCHvDLGHCCCHHGvLDDtJr];%..&,~FzyCCHvvGGHCCCCHHGLLvGCtsF-..+*-~FrsABGGGGHACCCHGvDuvGAAs)*.+*;)/stGGLDvHCBxssyACHGLvDGtsF>+.&=-~FzsAACCGvuvEDHCACCxzF);$@........%-;{ryBCCCBGDLvGCBCBxz{,+..$!]rstGLDLDHCCBAtBvuLvHBBxr(-...&$3~]rxACHGLDHHCCAsz/~;*#+.....+=!]zxBDELvGCAsr^rzxAHvELEvAz(=+@-{/ztvuDDvGtyzzzstHDELLGAyr(>..+#-']rsyBHGvGHBCCCCHHDvGwz]~,&..",
"...%>;~]zxBCBCBCCCBCGDLAs/]~;*+....+%,;]rsAAGGLLELuuvts/);,%.....@>!{rxBBCGvLvHCBCCCCGLLDvs^);%..&$-!]zxCBGGvvCCCABCCGLLLvHBy^;+.&;/sBGLLLGHCCCCCCBCHGDDDts/{;#..%,~FryACBvLvGCCCCABHvEuEGyr];#..&,']zyACHGLLGBCCCCCCGGLvGCBsF-@.&>;)/sBBHGvGGBCCAACGvDDLGHAs)%..%;)/zAGLLLvCCAAysxBCCvLLLvHsF-++@$-']rsABACHvLELLGBBBAyzF'-#+.......+%-;]rsAAACCGGLvHCCBByr]-+.+$;{/sAGLLLGBCABABHGLuvCBtsr)=+...*-!]ryBCHLLLvCBBAsrF)-$&+.....+>~FzyGLuELHBAxzrrsyAGLuEuvtz]$+@,(/JAGLDuELGAszsyBAGLELvHsr)=+.+*-)FztCCGvGGCCCABBCGLDvtzF);#..",
"...%*-;)FrIKzIrIrQIIJwOP}|';=#......+#=;)][QIJOwYwwOPI[{~->#.....+#=;)FQKKJJwJPIIQIKKJwwwOQ(;,%..@*,-_2KJJJJJPIQQQQQQPJOOJPK/)=..@>_}QPOwOJKIIrIrIQrIJwNw8<|'-&..@#>')/QKKJJJPIQQrIIIJwNSP[|'-&...#-!{/IQKJOJPIQIQrQIJJOJJKIF~#+.&*-!1QPJJJJPPIQQQQQIPJOOJKI};&..@=-~:[PJwOJPK^/FF2^IKJOwO8<2_$...@*,;){F/[QIJNNNOII^/F]);-#+.........+#=;)]F/[QKPJJJPKIr/F_;*...%>;(2QPOOJJKKzrIIKPwJPIQ/:);#....@*-;)F[/IJSwOKQ^/]);-*&........*-~1[6YNNNOKI/F]1/QIJwNNN8<1!%.+$;)2<JOwwww8I[2/[QIJwNNOI2{;*..+#,;1[KPJJJPPQQIQrQIJwww8Q(;-&..",
"...&*=;(2[QQQQ[[2[[<8OO5}(_;,&+.....+&*>9!(|Q<PPP6PPIQ}|;-*%+.....&=-'(:[Q<5IQQ[}2[}Q8YSR84(;,&..@*-9([6OO6<<}}:|(||:[<<5IQQ}!%...#;(1Q<P6IQ[}::1:1:[5OSY6[|_-#...&>-'(}[QI5P<22:::}[8YSY64(c=@...%=-!|}[Q<P5Q2:1:::2[Q<<QQ[|-@..@*,01<OOO85Q2:||||:2<<I<K<[1-@..@%-'_1[5PPIQ[}1||:}[<<PPP<2(;%..+@&*>-;!~|:[6YSY8<:|(!;->*@..........+@**-;~((:}QKPQQ[[2_~;>&...@$-'(}QIP6K<QQQQ<I<K5[2{(!-$@....+&*,;!(:25OO8[21_!3-*%.........%>;_1<MNNNOPQ[||1:[<6RNNM82(,%++%-c([<P6OYY6<2}1:}[6YSY871~,%..+#,;1<6OO8<Q}::1:1}[5YSR84|'-%..",
"...%$,;d4khhh4k777hipqoi7bbc9*+......@*=-cab7hhlhlllkh4bc3=%@.....@*>;_b47hlhh4eeeefgmoWWjgba-&..+*>cbiqqqpg7bbd_0aade77hhk7e9@..+*9ab45lmi74bb(ddbbgiqWWoied3%...@*3cdef4hlihf:b:bfgpqWqpfd;=&..+@*,cdefkhlk7e:bbbbef7k4h74b,+..&*3agpqWqmgfbb_a_adbf7hhhk7e3@..@%=9ab4klllk74:b|be7kkllhhed9#...+@%$=,39abfiWUqpgbd0;>=*#@...........+%#=,9c~db7hhhk4f:d0-=&...@$39df7llmih4hlmmVlhhfdac-=#+.....@&$,30dfiqjpfbdac,=*&.........%,cafgqTTTqik7eb1fkimqTTTjfd3@.+*3ab7hlmoWqji774ffgiqWqjgba3#..@#-cfiqWqpgfed(ddbbgiqWqogfd3%..",
"..+&=3cekVVVllQkkkkmnWopk4ea9=%......&*>90de4lmXXXVVVlhed03$&+...+%*,9de7klVVlk74444hpZWWoiea3%..&*9afpZWWoV7ebd_000ae4kkhhh49&..+$cdekVXXml74bdddde4pZWWomkb0#...&>9'bekkllXlk44e44hnZWWpgb0,&...&=30bekhlVVl7e}eee4khkhllk13@..&=9dgoWWZnl4eddaaad:7kllllke9@..@$>cdekhVVVlhk4ee4[klVmVlh4d;#....+@%$,9cdbgpWUWjg:da3,$$&+...........++%$>,90de7lVlhk4ed09$&...@*30d4lVXXVlllVnXXVVl4d03,>%.......&*=90dfmoqmgeba;,$#@........+#-0dgiqTTTWnVk774klXoUTTUjgb9&.+*;aekVXXqWUomlhk74inWWWohed9%..+#3afpZWZnl7eb0addb7nZWWomke0*..",
"..&$;~]zyCBCCCCBCCHHvEDGAyz/);#.....&*=-)]^zxCHHGHHCCCBsr])-$@...+$-;)/ztBCCBCAAtAtABHEEELtsF'%..*,)FKAEELGAsz/{))~){/zsxyxxz)@.+&-)FzxCCBCBysr/]{F^sHDLLGHtzF=..+%-!{rsACCHHAtxssxtAGLLDAK/'-%..+#-!{rstCBCCAxsssyxyABAAttyr;@.+*;(^xDLLvGtsr/{)){FrstAABAy^'@..@>;)FzACCCCCCtyxsxAACHGHBts/)*.....+#,-;~FrsvuEEvyI/('-=*@.............+&$-;!)/zxBCCAAxzF);-&..+*-;(/stCHCHCCHHHGHBCts/(;;>#+......&=-!)2KALDGsz^]_;>*%........@,!]rswEuuuEvHAAABBCHDEuuuus/;&.+=)FzxCCHDEEGHBCCtytvEEEGAz/)$..@>)/JtEEEGtsr^]{)FrsHvELGHts/-+.",
"..@=;)FztCCCCCCCGvGLLLLHtxz/);*+...+@*,;']^zAHGGHCCCGGCyz/);,#...+#-;)/zyACGvGCBBBBBCvLLLLAz/;&..#;)^sHDLLvAs^F)'!;!'{F^^rrrF;&..%-)FzABCCCtxz^F{){/zAAHGBCBs]-@..%-!]/syACBCCAyxABHGHHCAs/{!,@...#-;]rsAABCAByyxytCCAAtszrr{-@..*;FryGLLDHyz/]))')]^zsyyxyz/;@..&=-~FzxCBCCBCBBBBBCCCBCCCBs/)$......&*>-~{^stLELGsrF);,*@+..............@#=-!)]ryACCBtszF);=%...#>;)/sABCBCGvGGvGvCtyrF);-=&.......+*-;)/KtGLtyr]]~->$@........@$!]^stEEEELLHCAAACHvEEEEDGs/;@.+=!FzyCCHvGGCCCCABAAHLLLLAsF)$+.@-(^sGLLvGyz^])'){FzACHHCCBsF-@.",
"..+&=-):rKKzKKKJwNNNNNw8Q2]);=&.....@%*=-'|}PJwJIQIKJwOQ1(!-=%....+*=;)]/IKwwwJKzrKKJwNwNO<}~>@..%,;([6www6Q:);->=>>,-;;;;;;-*+.+&*-_]QIKKr^F|);;--!(2IIKIIr[)=...@*,;)F/QrKKKQ^[I8wJKQ2}(!-=%....@=,;)F^rIzKrQ/}IPOJI/]()!;-*...%-':<Owww5[]_;---;!){]]F]{)!>....#=-~:/KKKKzKKrIrIzKKJKKKI2)-%.......&*$-;_26wNS6[_'-=%@................+@#*=-;)/IKzI^F|'-=%@...&*=-'FQKJJwwwwvwwwK[]);-=*%.........@#,-_:5OwP[1~;>*#&+........+%>!(2<ONwNwwwPI^IKJwNSNNYP[_$..+#-!]/KKJJKJKJzKzI[Q6wNwJ<:_,%..@,!(46www6[:';-,,-!(}IKKIIr2)=..",
"...%$-!|[QQII<I8ONNNNYO5[}(~->%....++&$,;~(}<OO5Q2}<6O6[:~';=&....+&=,!(1[<OYOK<QIQI5ONNRY<1~>+..@,9_15YSY6}_;-=*$###$$$>>>$*#...@*-;(}QIIQ2|_;->=,;_:}QQQQ[}_$+..@#=-!(:[<I<Q<[<<6YO<}(_;->#@...+@#=;_(2[<K5<[4[<8Y8[1~;-,>*&...%-0|[8SSO5:_9-,--3;_((|((~!-*+...@$-;(2QIIIIIQIQIQQQKIIKI[:!=@........@*=-c15YSY5}~-=$%+.................&%$$>-~|[QQ221(;->#+...&*>-'(}IIJwNNNNNSO<1(!-=#%+.........+%*-;b<8O<:(;-$$%@+.........%>-a:[ONNNNwO6<[<<OOSNNSY5:!#+.+%>;([QIKIIIPPJP<[[[8YNM6[_;-%..@$c(26YSO5:_;->*=,9_12[QQQ[:!*..",
"...&*,0b4hlllllppoojoomi4fba3=&.....@&$-0dbfkmmkgffgipmgfba;,#+....%*30bb7ijWqplhlhVmjUUUjgfa>+..&,cdfpqUqpfd9->#%%%%%##$*$$&@...&*30b4hhh74bac,,==3cbf7kkh7fd$..+&*=9abe7ijqjjjjjqqqifda9,*#@...+@*=;_bf7iqqjjjjjqqjgbac,=*&+...&3abgjWUqibdc-,,;0dbeeeebda3*...+@*30d4hlmmllklhllhlVmmlh7e0$+.......+@%=90biqWqpea9*#&..............+@@@@%*$3c_e4hk4ebdc,*%....@*=9ab7hmmZZUUUUWqifdc-$#&@.........+&*,cbijqiea9-**#%+.........&>9abgjWUWqoppjjjppooWUWqif0*..+#3;b7hllhhhmjoopi7gpqWqjgbc3&..@=cbfpqWqiea33>$=,3adf77kk7e0$..",
"..+%=9~ekVVXVXlXXXXnXXXVk4edc=%....+&$,cd14klVVlkkkhlVVlke:ac=@...+#=;a:4hmZWZoXVVXVXZWUUqp7b9&.+&3ab7pWUUjgdc9*#%&&&%%%#$*%%@...@=ca:kVVVlk}d;3,>33a:7khlll7b>+..&$3c_e4ijUTUUWUTUWqifb09,>#@....&$=0dekijWUTUUUUUWoiea9,$#@...+%;afioUUqp4bac99a14kkkhk74|a,@...%=9_bklXXXXXVVlVVVVXnnXVhea>+........@$>3aepqWWpgd;3*&...........+@&%#$*$*$,9ab4hllk7eba9=&+...@#3;dekVXnZUTTTUUqm7bac,*#@.........+%*-0eioqp7ba9,>$##%@+.....+#,9d4ioWUWZXnoqUUqnnoWWUZp7a=+..#,a1kVVVhhlmZWZonlmnWUWogea3%..+>abhpWWZpfac3==>,3a:4kllVl7d=+.",
"..&=;~FzABHGHHCBHHGBGGGHAys^{;*....@*-'{^sxBBHCCBAtACHCBAys/);#...&>;)/zxtHvEEGHBCCBHGEEELGxz(%.+*!]rsGDEEtJ^]~-,*%%%#$#*$*$$&...#-)FztBBCAAs^{~!;;)]zyACCCAx^;+..%-;{/zxHDEEEuEEEEEvGs^]);-,%...+%-;{/stHDuEuuuEEEELyI{'-=%+...+=)/ztDEEDAJ/]))]^sACCBCCByz/;&..+*;)/ztBHHHBCCCCCCCHCCHCCtz];@........%,;_:KHuEEGs[{!,#.........+&#>---;--;-!)]rsABBBxsr]'-*+..+&=;)/stCHvLEEEEEELGys^{';=#+........%>3!{ItEGGszF(!;----=*&+...@='{/stDuDLvHGLEEEEvGvLEELGJ/-@.+>!]zxCCCCBBGLEEvvHHvLELvAKF~*..@;FKyGLELGs/_~;;;')/zxtCCBCx^-@.",
"..&>-)FzACBCBCCGBLLLvLvCCBxr{;*+..@#-;)FzsAACCCCBtABCCCCBxs/{;*+..&=;)FzsAHLLGHCCBCCCvLEEGHyr{#..*']IsGLELHsr]~;,$#%###*$*>*%&..+&;'FzyCCCCxs/{!;;!)FzxBBBBCy/;+.+%-!)/sttGEuEEEELELLtsr/)~;-*+...*-!]^sytEEEEEEEEEEGx^)!-=&+....>~[sAGLELAs^]{)]rsAACCCCAxz/'*...%;)FzyCCBGCCCCBBCCCBGBCCAsF-&.......+%>;)FItELuHs^);-%+........&$--;!)~~';;')]rsBBCAysrF~-*....%,;)FzABCCLLEEEEELHtzr]~;-$@........%,;)FKyGLtyr/{~;;;----=&...+*;)^sBLLLLvCHLEuELvBGLLEvts^;@.@>!FryCCHCCCCGLLLHBBGLLLvtzF)$+.&-FrxGELuHs/{';-;~{/zABACBAy^;+.",
"..@*=-_]QKKJKKPJwNNNNwwJKr/|'-&...+&=-!)2^rKKJJJKKPPJJJKK/}{;-%...&%=;_]}[IOOJPKIIIIKJOwOOPI}'*++%-!([8www6Q|!-=*%&&%##*$###&@...@=-~FQKKKI/F(;-,,--!]/rrrKr/)>...@*-;)1^QPORSMYwwwNOK[1{~!-,%....@*,;(F[Q6YRSMMMSwwOQ(;-*#+.....#;~:<Owww5[|''!'{/IKKJKKKQF|;#..+&=-~]^KJJJJKKKKIKKKJJsPKr})>+........@$=;_25SNw6[(;-$&.........&*,-!!)~!;----!{/IKr^^F|'-=%....@%=;)FQKKJJwwSwwwO8KQ1);->$@........@#>-~:5OO6[|)';->--;--=&....%>;_:IOwNwJII6wOYOPIPwwww6[)=+..$-'F[KKJKIIKJJwJPKPJwNwJ<2),&..@=~1[6wNw52);->=,-;)F^rrKzI/_>..",
"..&#=-;|[QIIIIIPOwwNwwOP<[}(;$%...@%$>;(2[<I6OMYYYOYMRY6KQ2|'-%...+%$,!(:}Q<PQ[2:}}}}[I56IQQ1_$..@=;(15MNM8}(!->$#%%##$$**$$#&...@>-!|}QIQQ2|~;->>,-'(:}[QQ[2'*+.+@$=;_1:[<PP6P5<5OYO5}1((~!3*+..+&*,;_(}[<PP55<55OR8f~-*$@......%>~|[6SSO<:(_!'_|}QIPOO8PQ}(;%...&*-;(}QIIIIQ[22}}[[<IQIQ[:!=+.......+&*>-~15YSY8}(;=*&+........&=-;_1:}(!;---;_1QQQ[:|('-*%+...+$,-!|[IIII5I55686665[(!-=*&........+%=-c|<8O51(~!---;~~!;,#+..+&=,a|7OSNY8<[<58P<[[<6SSO5}~>+.@#>;(2QII<QQ<<I5II<POSNR84(!,&..+*;d}8YRY52_;->$=-;_:}QQQQ[2~=+.",
"..@#=-0b4hhlhhhVmpojjomlkh4bc$@...@&=,cb7hlmoqUUUUqTUUqjmlhfd,%...+%*-0bef7hhhf1bbbbe7hhhkhkfa,++&=cafiqUqpfba3,***#*==-3==>*&...@=9cb4klhhf1a0-,,-9abf7<hh7:0*...@*=3abe44hkhh47imoji7fbbbdc>....&*=9abe4khlhk77ipjpg0-*#@......%,0bgjWWqifbdaaab4hmoqZqpi4ec*..+&*90bfkllhh74eb:bf47hlhhkea,%.......@&*=9cfiqWqifd;3*&+........%,;de4hk7ba;;9cdekhk7eba;-*%+...+#=cab7hmmlhh<hh5mnqjieda9=#........@#=90biqjpfbda00a_bbbac>@...%>9abgjWUqige7khkh7fijWUqif0>..+#30d7hhlhhkhhhhhhlpoWUqjgbc,+..+$0dgiqUqieba;3=,3cde7h5hk7e0*..",
"..@*>3a1kVVVVVlVVVXXXXXVlhk:a>@..+%$,cdfhmnoqWUqUUUqUUWqnmVke0#...&$,9d14klVVk7e:e:e47<llVVlkb>+.&,cbfpoZojh4bdc;,>,9cdddda'0>+.+&>c_ekVVVhk4ed~c;0a17hmlllhfa$..+@*-cde4klVVlhkklmonmhk[44e(,@...@*-01e7klVlVhQ4hmppfa,$#@......%9dbhjWWqmhee|b1e4lVnZZZnVh4a*..@#99d:kVVVllk44eee4klVVXlhedc%......+@$>3cdfpqUWjgba9>$%@.......%9ab7lmml7:bb(bekm6Vkke|03$%+...&*3cdekVXXmlhhhklmnonmh4|dc$@......+#=3cdfmoZphebb{de7hhhfd9*..+&-0(fmoWWZpk47khhk44ioUTqp7b,+..#-0:kVVVVlhkhkhlmXnZWUWohfa>@..@>cbgpqWWphe1d!09~dehVmmVVke0*+.",
"..%>;~]ztCBCCCBCCCCCBCCCBCyz/!$...*3)]rxGDDLvDDvvvvvvvDvDvvts]>+.@#-')^zyAACCByszzzzstCCCCCBy/;++%;)}stvvvHCAsr/])))]/zxyyszF~&+@*;{^zACBCCAxsr///^rstGvDGAxz{-..+%-'{/sxACCCAByxABHHBBCCBAAz~&..+#-']rstACCCCtyxxAAs[(;,*&.....+*;FrxHGDHHAyszzrzstCCGGBvCAs]*..#>'{/zACBCCCtxszzsxACCCCCAsr{=......#$-;~F^sHEEEGxr/{!->$&+....+>)/stGGvGtszr^rsAGvGBysr]!,*+...#-!]rstCHBCBCAtytCHGGBBAsr];#.....+#=;'{/KAEDHxsszzzsADHGyI{=+.+$;{rsALEEDGysssssssxtDEEEGs/;+.+='FzxCCCBCCBxxyACGDLEEEvyKF;@..%!{^zAGGGHCxsr/F]/rstDGvHByz]-..",
"..@$-)FzyBCCCBCCCCCCCCBCCBtzF'$+..#;)FzyvLELvCCBBABBCCCvLELGz]=..+*-!]^syBCCCBAyzzzzyAAACACBx^-@.#-~FryCCCBCAAz//F]F/zABBABxz~&+@*;]rstCCBCBysr^//rssHvLLvAy/{=+.+%-!]rsABCCCCAxyyytABCACBBAz)&...#-)FrsACCCCAAxssssrF~;=*@......*!{/sACCCBCAyszzzssxCCCCCCAs)%.+%-!]rsACCCAAByszrzytBCCCCAsr{-+....#>-;~{/IsGLEuvyr/{)'->*@....+=)/sAvLLvAyzzrzstvvvAxzr]!-#+..+#;~]rsACCCCCBByxyxCBCCBCtzF'=+....&$-;){/JAGLHAszzzsytDLDtz{-+.+$!]rstvLLLBxszzrzzssBHLLvGs/;@.@=)FzACCCCBBxyssxALLEEEuvtzF;%..%-)/zyCCCCCByz///rzxHLLLvAsr{,+.",
"..+%=-~]QKKKKrIrIrIrIKrIr^/|!-&..+&>;_:<OwNwJII/[^^QQQKwNNS8[!%...@=-~{F^IrKKr/2F:F1/^IzKzKK/(>+.@>-'{^KzKKKr//|_({(F//rrrr[];@.+#,!{FQKKKzI//1|{1|}QPwwwJI2);%..+&=-']/^IIKPKQF//2/^^rKrzIr};&..+%=;)F}^IrKKI^F2::1)!-*%@.......&=3_]QKKKKKr[F1F:F2/rKKzKIr};&..&$-;)F/KKzKr^/F]]]/^IKKKKI/|;*...++%=,-;'_:[6RNw8Q1(';-,*#@.....*;_25wwww<Q:2]2[5wwJI[]_',*@...+&=;'{/IKKKKr^/FFF/IKKKrIr}{;%.....&*=-!~{}POOPI[}}}2<8wwwP[_=+..#-'1[5JNwOP[:]|(({:2IJwNw6[(=+.+*;']^KJJKIr/F}2[PwNNNuNOQ:_>@..+*-':^KKsKKr^211||2[6wNwJ<2)-%..",
"...&*-;(}[QIQQ[[[222[[[[}:(~-=&...%>-_1[8SNRO5[[2}}}[<5OMNR5e!&..+%>-!|}[Q<I5<[2e1e:2[<<IIQ[}!#..@%=-_1[QIQQ[[2::1|1}}QQQQ[}),+.@&,;(:QKPI<<[}2:11:275OYO82(!-%...%=-_|}[Q<PI5[4}}4[}QQ<<<I[};@...%=3_:2[<I5K<[2:||_!-=$%+.......@#,c_}QIII<Q[}::}:e}[QQQQ[2_,+..@*-;_:[I5PI<[}||(11}QP6PP<}(;#...+%*>-;~(b:45MNR872|(~;->*%+...+&,~|<8SRO5[2e:1[56O5[|('-=%@....&>-'(}QIPI<Q[}:1|:2QI<<<<2|;$+...@%*-9_b175OY6<[422f<6MSY51~>..+%>;_2<OSSO5}|(_~_~(:78MSY5}_>+..#-~|[IIP5<[2:(12<OSNSNR87(;,&..+%=;_}[<QQ<<[2:1:e2<5YRY52(!$@..",
"...%*>3a17khh<h4ffef474f:bd0-$@...%>9afiqTTUqjmg7f47imjWUTUjg0%...&=;dfipjjqqjjijiijijpppmhf|9%..+%*,0be47kkhiiiiiiiiikhh7eea-+.+%3abgijqqjjpppiiijijjjpmiba9>@...%>9bgipjjjqjpjijijipppppi4f9@...#>9bgipjjqjjjiigebac=*@........+%=9ab47himmiiiiipiiiihh44ba>..+&*9abgijqjjpigfbbfgipjZojpge0*...@#*9adbfgijqTTTqjigfeba9=*@...+%,0dgmjojpjpiiiippmieba;,*%@....&=;aegpjqjjpigebbee7lmpjpied=+...@*=9afgijqUUqjimippjqUUqjf0$...#3cbgiqTUqig:bacade4iqUUUjgb,+.+%3abgjqojjigfbbfgmjWTTTjgbc,&...&*30be7himppiiiiijjpppmgba;#+..",
"..+@*>-0b4kllmVl5ihhihh7f|dc3#@...%-afhjqTTTWWZmhk7lpZUTTTTqhb#..+#,0biqqUUUUUTqUTqUWWZWZXifd9#...&$,cd1e4hlVnqqUUWqonmVll7|a,@..#;b4mqUTTUWUqUTUUUUWonmlhba9$+..+#3afiqqUUUUTqUUUUUWWWWWonl40%..+%9afpqWUTUUUUUqoifbc,$&.........&$9!be4hmoWWWWqqUUqXXllk410$@..%,cd4ioUUUWWZph447moWWUWWqp4b=+.+&*-a1khiqqTTTTTTUZpmhked9*&....%>9afkmXnqqUUWWZoXmked03>$@+....#,ab7pqTTTUWom4e1e4hioWWWqm4c&..+%$9agjqUqTTTUWWqWqUUTTTUjg0=+.+%,_ehjWTTUol7ed~ab7hjqTTUqmf9+..$9d7pqUUUTqjhfefkljqTTTqiba3#...&$,9de4kmoZZWWWqWqWomVl7bc3*+..",
"...&=-;)/zsAHGDvvvvvvvHtsr/{!>+..+$!FzxvEEEEEEDGAxxBGDEEuEEEA^-+.@=;|IwEEEEEEuuuuuEuEEELEvxz:'$...&*-!{^zzxACGDEuEEELvCCAxs^{-@..*)rsGvEuEEEEuEuuuuuEDCAts/(;>+..+>~2stEEEEEEEuuuuuEEEEEEvHts]*..@=~}zGuEEEEEEuEEvAs/{3>*+........&>;)F/zsHvEEEEEEuEEvHCBxz/(-+.@*;{^xBDEEEEELHxssxGvEEEEEDHxF>..+*-)FsABGDuuEEuEuEEGHAAs/)-*....#,'{rxBHHDEuEuEEGCBsr]);>=@.....$;]zxGEEEEEEvAJrrrzsADuEEDtsF=..+%-!1VNEuEuEEEEEEEEuEuEuuZz:-..+>~FsAGEEEDDHxz/]F^sAGEEEEDts)#.@>~/zHEEEEEuGJrrzytGLuuuuXI];*...&=;~]/rstDDEDEEEEEvvHAyzF~;=@..",
"...&*>;~{/zytvvvuLuLLvvAsrF);#+..+$;{rsAtDvDGHHtszsxAtGuvuvAx^;@.@=;{/JtvtHvvDvDvHGGGGHGAAz/]!*...+&>;)]/^zsxBtHGGGAHBAyyz/])-@.+%!FzxyvvGDAGDtDvHvtCBtyz^]~;$+..@=!{rwtGGGNvDDDGGGvtHHAHBtsr(=+.+$!{IytGGvGGvvGHwsr])-$@+........@#-!)F/rsxGtGHGGGGBABtsz/]~=@..&-)/zxAHDvGHGxyzzJytHGHHHBtz]>+.+*-~]rsxttGDDEuDvGGBBAsr]!-#+...%-;)FzsxttHHHHHGHAxz/);,$&+....+%;{^sytvvNGvAsr/F//zsxGtGtyz(*...#>;]zXHvDDGuGGHHHGGDDDDAy^(=+.+$;]rsAHvvGAxs/]){FzyAtDHNAyr)%++>;{^JtvNvHGxz^/^zyytGGGxzF{;*...+%-;)]/rsytGtHGtHGAAszrF{!-#+..",
"...+&&$,-!_:Q5JOJOOOO66[|_;-*+....%=;~(:}e}}}}::{(((:}}4}2221~=+.+%=-~{e2442}4}}ee}e2}2}:1(;-*&.....&*=-;;))1:2e}}2}22]()~;;>%+..+*;'|ee24[44[eee24}e:{();-=*&...+%=-'{ee}4}4}}4}4}[4}2}}:](~-&..+&=-!1e}f[}4}}e2:1~;,$@...........+#=,-;!(|:ee}4}}}2:{))';-=%...+%-'(|}42}}e2:1(({:}f}}}22:);%...&*,;)1]2}e:}424[4[}F]{';,#@.....%=--~)1:e}}4[[}2:(~;->#@......+&=-~{:e4[}}}e1~;;;'~(|e1e:|_-@...@$>-~{:ee}}}}[}2}4}4}}}e1'-#..+%>;~{::e222:(~;;;;~(1ee}}:|'>+.+#=,~{e}}ee2:(~!~)({:e}e|_;-=&.....&=,-;;)11:e}24}}2:(~'--=#@...",
".....@%*>,-0_::4[[[[22:_;->*&+....@*>-;0____(__!;9;c'_______'-%...+#>3c~__(((((_((_(___a!;-,*%......@%##*>-9;;'_d____'!;-,=**&...+%*-3c__(((({((d___!!;->=*$&+....@%=-c~__(((((((((((d____';-*+...&*=-c__((((d(_~!9-**@@............+&**>>-9c_~_(((_'!;--==#%.....%=-9a__d(__a!;-990__((_(_!;$+...+%*,-c~~__|(((((|((~!;-=*&+.....@%$>=-;!___((|(~;;-=*%&........@*=-9~__(d__~;-==>>-9;00~!;-#+...@&#>-9'___d((((((((((__~;-=@...@*>-9!____~';-===--30'__~!c-#...@$>-c~___'_!;-,--3;!'_~!-=*&......+@&**=--cca_____~;-,==*#@....",
"......+@**=-30aabbbba009,,*#+......&$,3390a00cc93>-339000c9c;,%....&*=330c00aaa000c009cc3,=$%@......+@@%#$==,39c000ccc3-=$$#&@....&*>-39900aaaaa0c0c93->>$#%@.....+&*,39ccaaa0aaaaa000909c;3$#....@#$>9990a0a0a0c9>>$%+...............&&#$=-,99cc090c93>>$$&+.....@#=-3900a00;39,>33909000993#+....@#$,-9cccaaaaaada00;3>*#@......+@%$$>3390aaaaac-=>$#@+........@*$-339cacc9c-,>*$*>>,9993,=&....+@%*-93900caaaaaaaaaacc;3=#+...+&$=,339ccc9->$**=>,-39cc3,=&...+%$>99c0c993=>*>>=,93c93,*%@.......+@%$*>=-,999cc9;3,>$%&+.....",
".......+@**=,3300a00039>=$#%@......@%$>9933099-,==>=>3333999,$&....+#$=3,9339993,3cc999,>=**&+.......+@@&#$$>,,333399,==**&@+.....@#*=,999cc90ccc939->,***@@+......&%*-93990;99990c33393-3,=*&.....@*$,-93ccc9c93,,*%@.................@&#**,,99999-3=>***&+......+&*>-93999333==>==399,3393=#.....+@**>3,9999cc0ac0c-3,=#%+.......+&%**>,999cc0c->=*#%@..........&#*,99ccc9-,,**$#$*===-3,>*&.....@&**,93339990c000;cc99,=*&+....@%$,,399,-,==*#*$=,,-9,3,>*@....@&==9339-3,,*$**>*=,,,>$$&.........++@%*$=>3993-3,=**%&.......",
"........&**>-3;!'__'!9->*#&&+......+&$>--;;!;;,>>$$---;-;;-;-*+.....@#$>=>----,----;;;--$$%#@............@#=>--;-;;-;-$*##&@......+%*$,-;;;!!;!;;;-;--=$#%@+.......+&*,-;;;;;;;;;!;;;-;,-3-,*&.....@#$=-;;;;;;;';-,=%+..................+&*$=,-;-;---,=##%@+......+&#>--;;'';--,=,,--;;-;---$&.....++#*>-3-;;'!!'~!;;;--=#@.........+&#%$=,;'';!;--**%@...........+%$>-;;;;;--=$%%%##==>,-->%+.....+&#$-->-;;;;!;!;;!;!;--=$&.....+%#>-,-->-=**##%#$=-,----$%.....+&$,--;---$$*#$*=>>=-,>=%&............+%=,----33->$##&@.......",
".........@##*$===>----$%@+++........+&%*==$=>**&@@@&#*$=**=*#&+.....+@&@&@&@@&&@@%==$#*#&++.+............+&&%#$>-,>>##@++.+.......+++%#$$$>>=>===*=$**%+............+@&$=>--->=>=>---,==**%%&@......+&%**$==>==$#*%@+.....................+.@#$=-,->=%@+...........+&%**$$=,=>***##%*$=-,>$%&+......+@%#*>>=>$>>---->,>*&+.............++%$>>--==$#&++.............+&#*$===$*%&++++.@@#%%%*&+........+&**#%*==========$*$%#@+......+%#==$%&@@@++++@&#%**$$*%+.......+%*=$-=*%++++@%&%%%%#&&+.............+&%**=$**%@@...........",
".............++@+@%&&@+................+..+.........+..++++++.....................+.+++......................+.+@&+@......................+++@++++.+....................@@&&&@.+.+@&&@+..++..............++++@++..............................++@@&++.................+...+@@++.....++++&@++.............++.++@&#%&&@&@@...................@+@@++....................+.+++++++........+...+.................++++++.++++.+.+.............+............++................++@@.......+.++......................+.....+.............",
"................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................",
"................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................",
"...........................................................................................................................................................................................................................................................................................................................................................................++@+@@+@++.................++@&@++............................+@@&%%*#*##%&+...........................+.............................................",
".......+@&&&&%####&&&&@+....................+@&&&&&&&@+................@&&&&&@+++@&&@@+.....................+@&%%&&@++..+.............+&&&&%%#&&&@+++@&&@+................+@@+.......+@&&@+..............+@&@+.........................+@&&&&@+.....+@@&@+..............+@+...+++...+&%&&@@+..........+@&&&&@+...+&&&&&&&%@+.............+@&&&&&&&&&&&&+................+%$--;-;-;---$*&+..........+%*=>>-,$#&@+........................@#>-;!'''''!;-$&+..................+@&%*#**#%@..........................................",
".....+%#*==$>===$>$=>=*#%&@...............@%#**=*=*=*%&@.............+%**=**==$*#*=*$*&@.................+&#$*=*>>==##**%#@+.........&##=$>$>=>==*$%$$**$#%@+.......@%##*#$**#%%#####$==*$##&.......+%#*#$==*##&@@@&%####*##@........@#$***=**&@@@@&&*=**$##&+......@%##*#$#*##*#####$=*==*#&+.......+%*=>=*=######*===$>**#@..........+%#==$>=>=>====*$$##&+..........@#,-'){]]F{{);;,*%+........@#$--;;;--==*&@.....................+&*,-!)]FFF]])~;-$&+................@#*=,,-,>=*%&.........................................",
"....+@%*$$=**=$===>*$>**#%%+............+&&%*$$>$>*$$##%@+..........@&%$$>>>=>=>=$>=*$#&+...............+@&%*$=*=$=>=$$**$&@.......++%$$**=**=>>>>>=$>>$$*#@+......+@%*$**==**&&%%*****>$**%%+.....@@%#****$$#%%&%&&**==$==*&+.....@&&%*>>$$*$%%&&&%%$$>$=*$%@.....+&%*$=*=$=******>*$>$$>**%+......+&***$>*>=**#$$*$*=*>>**&........+@&**$=*$=>*>>$>>$*=*$#@..........@#=-!){]]1](~;->$%@........&*=---;;-->*#@+.....................@%*>-;){]}F({)!-=#@.................@#$>=,-->$$%&+........................................",
"...+%*$>==,------,-,,=>***%%+..........+@&%*$===,=,,=>**#%@........+&#$=,,-,---->,=>>***#@.............@%#$$>=>-----,,=>=*$%&......+#**=>,>--;-------====$$%@......@#$$=>,>>>$$$*$*>=>>==>=$#@.....&#*$>=,>===*#$##$*>>>=>>>=@.....&#$$>===,>***#$#$$====>==*&.....&#$>=>>>,>,=>>>>=>==,,=,=*%.....&**=,>,=,=>>$=*=>=>>,==,=#+......+&%%**=>--,--,---,,=>=**%..........&*=;_|}}[221(!-=*%@.......+&*,;_((~~;->$%@.....................@%$=-;_|}}}2}|_-,*&+................@#*,-;';;-*#%@........................................",
"...@#*=39cc00c000cc9c9c3,=*#&+........+&#$>,3cc9cc9933>=$*%@+.....+&*=,3ccc0c0;9cc9993>=$*&+..........@%*==39cc0c0c0ccc93,=*#@....+&*>,399c;0aaacaac0ccc33=$%+....+%*=>3399933=>=>,9399c93,==&....+*$=339cc9933=*>*>=33c39933%....@%*=339c9393>=*=*=339c9c93=#....@*==9ccc;999933339c999c993=%....@*=,399c99c3939339c39cc993=&.....+@#$$>339c0c0c0c0ccc9993=*@........+%>3abgiimk7fba;>*&+........%*3abe7ebdc3$%&+...................+&*>-;0bf7iiiigb0-=%+...............@%$,;a_bba0,*#%+.......................................",
"..+#=c0_bbeeeeeeeeeeb|bdd09>#@.......+#=,99adb|eebe:bdac33>*&+....@$3c_bbbeeeefeeeb|bdcc3=*#@........&*=39ab1beefeeeeeb:bda3=#+...@#-9db:eeeefeefeffeeebbd03=%....%#3c_bb:b:bda9c!a(b1eb1da09$@..+%=-'db1beb{b~0c39c!d|b:b|b03&..+#>c'db:be1b_acc9c~db:b1bbdc>@..+#=9~d|beeebe|bd_db|be1be1b0>+..+%=cadb:b:eb:b(ddd1be1beb1b0,+....@%*,cc~dbeeeeeeeeeeeb:bd03%.......+@*>9bgoqZonVl4bac>$&+......+#,0|7kkk7e{03>*&...................+#*,ca14<VXnoopibc3*&..............+&=3cde777eba9=%&.......................................",
"..%-~FzyHtGtGtHtHAAHABtyzr]~;$+.....&$-!)F^syAtHHtGAtyr^F{~-,%...+$;{^sxBHAGGtGHAHHAAsz/{';-=&......@*;~{FzxHtHAGAHAHtGGtyr{!,&..@>;{^stAGttGtHHGHAGtGAGty/{;$+..@-;{/sAtGtGtsz^^rzyyABGAtszF;#..@=']rsABtHtAys/]{]^zyAAGHAAsF,+.@,!FrytAHtAtsr/FF/rsxBBHAAyz],++#,)FzytHtAGtAtsszsyAGAHtGAyz)&..@-'FzytBGtHtHyszzsxAAGtGtAyz{=...@$-;)/zsxxtHAGGAGHtGAHHAx/{=+......&#-;{rwvuELGHBxr])->%@......&>;{^sCCCAys/);,=@.................+@=-'{/zyACGvEEvxI{'-$+............+*-!{/zxGGGts/{'-*&+.....................................",
".+*;(/xGLLELuEuLEELELHCBAs/{!>@....&*-;)]^zyACGLLLELLAxzrF)'-*+..+$!FzyCLLLLuLEELLLLHByz/{);-$+....&*-!)/ryHLLLLLELELLLLDHs/);*..&,)FKALLEuLEELLLELELELLLts/)-+..%-)/KtDLELLGCszrzyBBGDLLHBxr)=+.%,)/sBHLLLGCByz/F/zxAHDDLGHyr;@+*-)/sAGvLLvCByzr/rsACHDLLvHy^;@+#;)/stHLLEEELHAxsxHDLEELLGAx{#..@-(ryBGDLEELvHtssxGLELLELGCx/-+..%>-!]zyBCHLLLuELuEELLLLLAz];@......@=-~{IxEEELGBBsr]~;>%+......&$;)/zyBBCBxr]'-=&..................&$-!]/zyBCGLLLDAr{!-#&............%$;~]^JALLLGyrF~-=*@.....................................",
".+%-'1<OwNNNwNNNwNNNwJKKr^]'->@....&*=-;){FrKJwwNwNwwPI[F('-=&...+#-)}QPwwNNNNNNNNNwJKQF_~;-=*+...+&*>-!|}<OwNNwNNwNNwNww8[_',%..&=;_[6wNNNwNNNNNNwNNNwNw8[_;>...&=;([8wwNNNwPQ1FF[IKJwNwJP^]!%..%=;(/IJwwNwJI^F_)|FQKJwNNwJIF-++&,;{[IJwNwwJK^2]{F[IKJwNwwJI]>+.&,'{[KOwNwNNwJI[[IPwNNNwNwK[~&..+*;{[IOwNNNNwJI}[QPwNNwNwwP/(=...&*--~FQKKwwNwNNNNNNwNNww8[_-@......@%>;':<YNNwJKIF_!;=#+.......+#=;)]//rrI/]'-=$@..................+%*=;)(FQKJwNNO5}'->%+............&*=;~:[8SNw8Q:);,*#@.....................................",
"..#=c(<OSNNNNNNNNNSwROIQQ21_;-#...+&*--!_|}[<POSSSNSO8Q}1(~;=#+...%>!|Q5YNNNNSNNNSSO8[Q11(!;>*&...+&*=;~(1<8YSNNNSNNwNNNR67(;,@..&=c_e5YNNNNNNNNNNNNNNNNS841;*+..&=3a28YNNNSO5}1(|}Q5OSNSO<[|;*..@>-~}<8YNSOPQ}|___1[<PYNwO6[(,+.&*;_}<8SNSOPI[}1||}QIOwNSO6[(>+.&=3(}<6SNNNNR8<}}46ONNNNSOP[!&...*;(2<OSNNNNY8[22[6ONNNNSO5[_>+.+&*>;_1[IIPYNNNNSNNNNNNNY84_,@......+%*-a1<OSSR5[1_;-=*&........+@=>'_:2[QQ[('->*&...................+%$>-!_:}5OSSO<1!-*#@...........+&*>-~_[5YNR6[|~;>$&@.....................................",
"..#>cbfijqoooooojojojpih574ba;#...@*=3abbf7hhmpjqjqojpiiieba3*+...#,0b4iqUUWWoqqjjopmhh4eeba3*@...@#>3abe7hpoqjqjqjoqqWUWjgbc3&..&=0dgmqWUWqqTTTTTUqqWWUWjgdc$+..@>3aepqUWWqmgebdbe4hjWUWji4bc$..@>9afgpqUUqi7fbd0dbfhpqUWqmgb>+.%=3dehpWUUomh7feeefkipqUUqigb>+.&=3degjqUUWqqigfegijqWUTUji4c&..+*;dfgjWUUUqqigff7ijZWUUWjif0>...&*=;deklVmoqqjqqqqqWUUUqpfd=+......@#*-cbgqUWqgfd03>$&@........+&$=;a|e4iikfa3=$#+..................+&%$=39degjWWqibc9$#+...........@#=3;dfgijqqpgebc3$#@.....................................",
"..&,cdeimXnnnnmmVlmlmmVVVVhkea$+..%=9d1kklllllmlmVmmmnoqojhba>+..+%-cd7ioWUWonXmmmlVVVVllh710,%..+&*,c17klVXXXmmmmXmnZUUUqhfa9%+.@3cb7pZUWqojqTTTUqpnoWUWogea>+..&=9d7pWWWZml7eb|be7hnqUWol4bc%..&=cdehnWWWom4ebddb:ehpWWUZmh|,++&>cdehnWWWomhkkkkkkklnWUWZm7b,+.&>caehoWUUWonVk444lnoZWUUoi40&..+#9aehjWWWWonlk74klXnZWUUolfd$...&=30bklVVXmmmmlmmpooWUWWjgd,+......@#>90eiqUUqifdc3=#@..........+*>30aehmomgea03=%...................+%$>-0aeiqUTqifa3=%&...........&=-9deklXnnXXVk4b03=%+....................................",
".+*3':rxBCBCBCBBAAtACCBCCCCAxF=..+$!{^sBBCBCBCBAtyAACHDEEvAs/;&..+$!{/stvELLGHBCABBBBCBCBCBs/'$..+*;)/sACCCCCCBAtBBCCvEEEDyK/'$.+*!]ryDEELvGHvuEEEEGGDLELGxKF-@..%;_/sGEEDDHtsz^^rrsyDDEEGts^)>+.%-~FzyHDEEGByzr/F/rsyBDEEvHs/;++%;)/sAGEEEDHABBABBBtBGEEEvHs^;@.%-~]^sGEEELGHBAxAtAHGLEEEDtz0%..@-)]ryGvEEvvHAtyytBHvDEEEGAz(-...#-!]rxCCCBCBCCABCCHGDEELGs2!&......@$3)FKtEEEDts/{'-=@..........+*-;~]^xGDvtsrF);-#+.................@#=-;{FzxvEEEAKF~-=%.........+&$-'{rsACGvHHCCByz]);=&....................................",
".+%-!)^sBACCCCBtyyyyABCCCBCCxF$..+>;]zyCGHCCBAxyssxytHGGvvAsr~%..+*;{/zAHvGvHCCtAxyBBBCCCCBy/)=+.+>;{/sACBCCCCAAyxxtBHGLvHxzF'*+.*!FzJGLLLvHAGEEEEGCCGLELvyz];@..*;)}zAGGGHCBsr/F/rzxBLLLvys/)$..@>'FrsBGGvGtsz^F{FrzyAGGGGtsF-@.*-)FzxHLLLGCBACGGHBBAvLLLLAsF-+.&>!{^KxGLvvvHCBBBCCBHvvGvHx^~&..@=;]/ztGvvGCBCBxyACCCGGGDAs/)$+.+%-!]ryBBCCCCBABABBHGvvvHtzF-&......@$;~FKAGLLLAz/);-*&...........&=-!)}stGCByzr]';$%+................+&*,;)FItGLEEtzF~;=#+........@*,;)]zACHHCCBHCHBzF);-*&...................................",
"..@$,;)][IIzKK^FF]]]F^rIKrKzQ~%...$-~2IOwwJKQFF1{{]F[QPPPPIQ};@...&=-~|[KPJJKI^//}F/^IrKzKr[{;%..+#,'{/IKKKKrQ//2FF[/IPPP<2{~-&..&-;1[6wNwJI<PwNNw6IIJSwwOQ1'>+..@>;(:IPJKIQ/2)';!~1[Pwww8Q:);%...#>'(1IKJPKQ[]_~!'(12QPKJK[:!*+.&=-~{[PwwNJPIIJwwwPIIJwwNOI2)>@.+%>-'{}[IPJwwJJKKKJwwJP<<[:'=+...#=;~1}Q<IPKKrQ^^IPwwJP<Q4:~,@...@*,;)FQrIr^Q^/[^IJwwJ5IQ[('$........&=-!:<ONwO<1_;=*&.............%*=;':QIIII/});,*&+..................@%*-!|QJwwO51_-,*@.........@#=-;)}IJOPIIIKJOP[_!-=&@...................................",
"..@%$-;(}2QQQQ}:(((_(1}[QQQ[2~%..+%-~1<YSSO<}1~';;!_|}QIIIQ[};&...@*-c_}[IIIQ[[211||}[QI<QQ2~-#...%,-_:QIIQQ[[1|111|}}QQ[[|~;=&..@=9_}6OSY6[[5RSNR54[5RSY64(!$+..&=9'|[QIIQ21(!--;c(:5OSY621!-&..+&$-'(}QIQQ[|(_'9;~(:[QQ<Q}_,%..&*-c(15YNSO<<<OSNM6<78MNS8<1!*...@*=-c_|2[<OYOII<KJYM6[}1|~-*+...@#=3c(|}[QIQQ[}}[POO5[}|(!-#+...@#=-'_:[[}}212:}[<OY5[}:(!-%.......+&=-0(<ONR8[_;,$%@.............+%=-c_:[[Q[[1(;,$#@..................+&*=c_e8MSO<1!->#@.........@#$,!_:<OO5[2}<6O6}(;-$#+...................................",
"..@*$9cd144hhhebbdddbe477hhh40&..+*9afiqUWjifda;9-90bfhhllhkfa*...+%>3ae4hlik44ebb:bf47hlhhed3#...&=9de7hlhh47ebbbbbefhk74bcc$&..@>;afpqqqpggiqUTqiggpqWqpfd0*...@*30b7hhhkfbd;3,-cafiqWqpgdc3&..+%*,;dfhhhhfedacccabe4hlh7eac#..&*30dfiqUWqigiqUTqjiipqUWjgbc*...+%$=90df7ijWqpllmoqqpgfbdc,%....+%*,9abb47hhk4f7gppqmgfba9-&....+&*,cdbf44eeeeefgpqqpgfba9>%.......+&*3abiqUUjgd3,$&@..............&*>cab77h47fba9=*&...................@*>9dgjUWqib0-=%@.........+%=-9dfiqjifffipjpfbc3>*@...................................",
"..&#=9ab4klV6lk4:bbb:4klllll7d#...*cd7mqWUoi4bac399c(4lVVVVlkb=+..&$=9aellXXmlkk7447hklVVll7d9%..+#>9dellVlVVhhk77447kllh4edc,%..&*3abioZZm7gpqUTUjghmoZqpgdc$+..&=30ekVlVlk4bac99cd4mWWZjhba,#..@#$30d4lVVVk4f1dd_be4lVVVl4d3%..@=9cb4pZUWoXVjqTTUjmljZUWZifa*....&*>30de4moZZnmmnqWZphfbdc>%....+&*=3abe4hVllhhhlnZomhebdc>%.....%*,cd|4f444447kloqoj7fbac=&........%=caeiqTTqib0,=$@..............+&=30b4kllVk41a9>#+.................+&$,cbgjWTqjfa9>$@.........@#>90b7moom7e4inopgbac=*@...................................",
"..@=;~FzstACBBxszzrrzxtCBCCCyF$..+-{^sHEEEGts^{~''~)/sACCBCAxr;@.+%-;)/sACHHHBBCBtACCHHCCCAs^)=..+$;~FzyACCHvGHGHAABAAAAtsrF(;%+.#-;(^JtHGtxywEEuuGyxAHGAsQ{~>+..#-~FztCCCCAsr])~~{/JtEELvyKF'*..@=-;{^sBBCBCAxzr^rzxtCCBCts/'*++#-~]^sHvEEDHGvEEEEEHHGEEEvAz}-....&=-!)F^stHDDvGvDvDvAsz/]~;#.....@$-!)/rsACCHGGvvDvGtsr/]'-%.....#>;!{F^rzzsxABCBHGvtsr/{!-&.......+$;~FKtEEEDxI{;-$@..............+&=;)FzsACCCxsr]';#@................&#-;([JDEEEwz4);>%.........&=;_]^ztHHtszzxCGAsr])3,&...................................",
"..@*;~FryABCCBAxzzzzsyBACCBBt]*..+-(/stGLLGAzF)!;;;{/ztCCCCCAr;@..*-!)/sBBBCCCBCACCCGLGHCCAz/'*+.+#-!{/sABHGLLuEELGBBBBAyzrF~-*..@>;~)/rsssssGLEEDwxssssz^]';=@.+%-)/zACCCBxs/]~'){^sAvLDGxrF'$+.+#>;)/stCBCBBAsrrrzyBBBCABzF'*..#-~]rJtLLLLGHLuEuEGGCGLLLLtz],+..+&*=-;{FrsACGLLELvGBxz^]);>%+....+@#-~)/zxBBHLLLLvGAyz/{~-$&....+&*-;')]F/rzABCCCBCByz/{~;$@.......&,-~{IyLLEDyr)!-$@...............@%-;)/zAABCBts/]!,$#@..............@>-;{^sHLDDHz]!;,#.........@$-']/zstxszrrzsAyz^]~;$&...................................",
"..+&>-~{F^IKKKIQ2[2[^QrKrKzIF~&...$'([6wwwOQ|';,>,-;)][/IrIrQ]-+..@*,;)}rKKKJsKKKKKJwwwJIr/]~-&..+&*=;)]FQIJYwwwNwOJKr^^[F(!-*&...&>=-;'(1::[5ONSwP4:|((_!;,*@...@$-)FIKzKr^F(~---!(26wwYP[|~-%...+#=-)F^rIzIr^/]1]F^rKKzI/F~-@..@=-!{[PwwNwJJOSNNNwJwwwNwOK2~*.....&*>=-!(F[IPwNNwJPQ2]~;->*+.......+%$-;)}IKJwNNwOPI2(!->*@.......+#$,-;~)|F^KKJKKKQ}(!;>$#........&*>-!1<OwwO<(;,*@.................+%=-!{/rIzIz[]);=*&@..............+#=-!|Q8www51~->%@.........+&=-;~((F1(___(]1](~;-$%+...................................",
"...&*-;(|}Q58O85<5<5<<IIIQ[}|-@..+*3_:<OSR84(;->,>=-!(}[[QQQ2),+..&#=-~:QKIIPPOJJ8PJ6PKQ[:1~3*&...+*=-;'(|[<5888O888855<<f|c-*@...+&$*>-9'~(|[OSRY5:('!;-,=*&@...+#-;|[<QIQ21~;---ca15OSY84(;>&....@#-;_:}[[QQ[:(((}[Q[[[2:_,#+..@*-c_:5OwNwOO86M86OJOYNNSO7|!*.....+@*>,-~_}QP66O65<[1_'-=*&+........+#=-'(:Q5YNNM6Q:(!-=*@.........+%*=,;~(1Q6JJ8I[}1~;,>*&........&*==cd<OSR87~;=*%..................@%*-;(|}[<<5}~-,*%+...............@$-c(46RRY51'-*#@..........@%*,--;;;;----;';;-=$%@....................................",
"..+%*9cdefijWUUWqWqqqpmhhk4:d,@..+*3afiqWWjgba;3-33cabf7kkhkfd=+.+&*=3ab7llmnqqWWWWopmh4ed00-*@...@#=>30abbf77h5imnqZqqqqifc9$&....+%#*==99afgqWUjib_09->$%&+.....%-cb4hh54fba9->3;afiqWqpfb0=@....&**3a|f44hkhfebbe7hk4feda-#....&>9afiqWUWWqjmgiipqWUWUWjgba*.....+&*=-9ab7hhm6m6lhkfdc9=*%.........+&*>9abfiqqUqifba;,$#@.........@&#=-;ab7ijWqjifbda;3=*%........@#>,cbijUWjgdc,*&..................@%*,9adbeijjgbc,$*@+..............@*,;bgpWWqibc9>#@..........+&%*>>,-=>,>==,-==>*#&+....................................",
"...&=3ae4kmqUTTTUTUUWZXXVl7ed,@..+*0d7pqUUql7:da'00db[kVVlVhkb,+.+%$,9_4hVXXZZWUUUUWnll41bac3=&..+@*>330d|e47kklVXoWWUUWWjga9=&.....+&#$>-cdfiqUUqpfdc3>$#%@.....@$3~ekVVVlke(c9399afpZWWpgea3%....@#>3ab44klV<k4e4klVlkke|a3#+..+#30b7pWUUUUWZm6hmoWUUUUWqmf0>.....+%*,9abeklVVVVVVVl4edc3=#+.........@*=cab4iqUTqpebac,*&+........+@#>>3a:7hnZWUom4e|d03,=#@.......&*=9abiZUUoibc9=#+..................@*=90d:7moomfdc3>*+.............+#*30dgjWUqjfa9=*@..........++&%#*$$$$*$***$>$#%&+.....................................",
"..@$;~FryAHDEEEEEEEEELCCCAsrF-&..&-(^sGvEELHxszr///rsAACCBCAxr'&.+*,!)/stHHHGEEEEEEEGHAAsrF)'-%...#>;~{F^zsxytCCCBGLELEELGsQ{;#......+#>9')FztLEELAK^{~;=$&+.....%,~FzABCCBAsr]{~)]^stEELvyzF'*...+&=-!]^sxACCBAxsxACCBtysr{!,@..@=!{^stEEEEEELGBBADEEEEEEGAK]-...+%$-;~{/rxACHHHCCBCCxs^]);-&........+#,-~]^sGuEEEGK^]~;,*+........@*,;')FztAGLEEvHssz/F{~!,#.......&=;~FKAuEELyK]~-=%..................+#-;(F^stGvAs^F{!-$@...........+#-;~{rxGEEvAKF!;>%............+&#%#**###*##*==*%+..........+++++&&&&%@+++&&&&%@+.......",
"..&$;)FzxtHvLEELLELLGGCCAAzF)-@..@>)/KyvvGHHHAssrzzsxCCGGCCCsF;@+@*-'(^sBBHHCvvvvLvLvGCAsz/]!-#..+%-;{FrzssyxABABCCvGLLLLvyr]'*......+%>-;_]IyLEEEts/]~-,#&+.....%-)FzyCCCBtsr/]{{F^JHLLLHxrF'*....@#=;)/zsACCCAyyABCCCysr/{!*@..@>;{/sAvLvuELLHBBCHLELLLvvxz]=+..@*>-!)]rzyCHCHCCCCCCBsz/{!-*.........&=;!{^KtLEELts/]~->%+.......+#=-;'{^sBCGDLDvAxszsr/])!$+......+*-~{ItLvEDAr]~;=*&..................&$;;{/ryBCBsz/]);-#...........+#-;)FKyvDEutz]~;,#...............+@@@+.+++@@@&&@.........+@&*#%##$$$**#%##$$$**####+...",
"..@%>-~1//IPKJ6KI5I5<Q[2F]_;-*+..+#-!|[IPJJJJJI[[/[^IPwwwOI[]_>..+&$-!)2IKJJKJKPQKPPOwJK[F|~;=%...%>;'F[Q/^/F/F^[QIIPJwNw8<1~-#.......@*=-;~:<OwNO<}_!->#&@......@=-~]QKzKrQ/F__~~(1[Pwww8Q|~-%.....@#=-!)]QPJJK^^QKJJK[])!->&...+#=-_:QPJJwwNwPIQIJwNwwJPP[{;%...@$=-;)(F[IJwJPIIIPJwKQ/|);-#.........&#=-;_:<ONNw52(!-=*@........+&#=-;'|QPwJJKPIQ2}/Q/}{~;%........&$-!1<wNNO<1~;,*%@...................@*=-!(2IKI[F|';,*&...........+&=-;_:<OwwO5}_;>%@......................................+@&%#$$$*=*$$$$>$==*>>$**%#@...",
"..@$=-!(:2QI5I<[[[222|(_;;-,*%+..+%=3'|[QI5OOJ5Q[[QQ<6YSN6<:_;%...&*-;_:QIII<Q[42}[56OO<[:1_;,&..+#-;(1Q<Q[2111|:122<6YSY84(!-&......+&%$=;_|<OSNO5|_;-**%@......@%-;(}QQQQ2}|((_((|}5YSY5}(;=@......@#=-;_}5O85[}[5OO5:~;,*&+...+@*-9(}IIPOYY6<[}[5YSOPPIQ}'-%...&*>-'(:}Q5OY8<[}Q6OOP<}2|'-$+........@%>-!_1<OYSO5:~;->*&.......+@%*,-!(:<OOO<<<[2}2[QQQ}_;=+......+&*-;(7OSS6<(_-=$#@...................+#$=-_1[[[21(_;,*&...........+%$=-0|78RSY5b!-=#@......................................+%##$*==,---,==,-,,--,,>$>*@...",
"..@*=9ab44hiVih777ffeda933**%&....&*=9affhimqomiiikhipqqqjgf09#...%$90bfhmmmi44feffipjjphg7ba;%...%3ab4immh7eeeeeeffgpZWWjgbc3&......+%*=3;dfijUUjifac9>*&@......+&=;dekhhk74febbbbfgiqqoifd;,@......+%$>-0fippmiiimjpgbc3>$&+...+%$-cdfhlmmoophf77ioqqmmk7ea>&...&=-cdfgiijqqpg7fgiqqpmigfbc,@........&*=9abfgqTUqifd0->$#+.......@*$90dbgiqqjmhh74f7hmlihfa,+......+#*30bgqWWjied0->*&+...................@*>-0b4474eeda-$%..........+@%>-9abgqWWqiba-$%+.....................................+@*=,339c0aac0c;9000c0cc99,>#...",
".+%>;a:khVmnonmlhkk4ed09,>$#&@....@$>9ade4lmXoZqoqoXVmppppi4b0*+.+#-0b4inooonmh74efhmonoXopifa>+.+=9bfmoqqjmkhkkkkklmoWUWniea3%.....+&*>30begjWTUWph4dc3>$&+.....+#=90eklllllhkkkhkhlmnnXifa9=%......+@*=3abhXnopqooXmkea9=#%+....%*30b7VlXonnmhk4kVnoonXXlfa3&..@#30bfijqqqqnmlkkhmnoooqqphea*.......&*=9ab4ijqTTUjgeb03,*%+.....+&$-a17hmjWWomVllhhlmoZom7b9%......@&$3cfiqUUqmh4{a3>*@...................@#=3~b4klllk7|a3#+.........@#=-0dekmqWUqpea9=#@......................................#,;ad(b1ee2ee:e:eeee4ee:bdc>@..",
".+*;)/stCCHvDvvCCCtxz/('--#%+.....&=3~{FrsxBHDEEEuvGCCCCCAAsrF=+.&>!]rsADEEEGHAtszsxAHGDLvvts/;@.@-]rJGuEEuGCCCBACACCDEEEDyKF'*.....%=-~{/zyBvuEEEvttzF{;-$&+....+*-~]rxACBCBCCCCBBBBHHHCtz]~,&......+&>;~FryCGLEuEDGBxrF_;=%....+*-!]ryCCGHGBBBxsxBHBGGHCts/!*..&,)/zxuuEEEvHBtAttBHHvEuEvAsF-.....+&=-;)/zxADEEEEGBxz/)'-$&.....%>;~/stBCvEEDHCCBCCHGLvDHxr{*.....+%=3'{ItEEEEGAtz/{!->&..................@*-'{/zxACCByz/),#........+$-!{/zytGLEEEwz:~;=&.....................................@-)FrzsyxAABtxtyxtyBtBBByxz/~#..",
"..#;)/sACCCvLLGBCABsz/);-$#.......&=;!(/rsyBCvLELLLvBGBCCCAyr{,@+&-!]rxHGLLLGCCAszzsBBHvLLLGxr;@.@-{rsGuEELGCCBCCCCCHLEELGtr]!*....+%,;)]^stCGEEEuvCxz/{!->*@....+$-']rsAACACCBBBCCCCCCCCyr]',&.......@$-!{ryABvEELvHAs^{~-=&....+%-~]ryCCBCBCBysytBCCCBCCBzF!#..#-)/sAvEEELGBBAyytBBCvLEuDAs/-+....@#=-~{/sACDuEuLvByz/{!->#@...+#>;)^sBCCHLLLBCCCCBHLELDvyr)=......&*-!{IAvELLGCAsrF);-*&..................%=;)FzyBCCCBs/);%........&$;)]/zyCGLLEDtzF~-=@.....................................#;(/zyyABABCCBBABBABBCCABysr)>..",
"..&=;_FrKJJwwwJKKr^}{';=$&+.......@&$-;)12KJwwOOJOwwwwwwJJI[]!*..+*-!{2IJwwwJKI/F|]}^IPJwwOP[|-+.+$;([6YNNwPKKIKrKIKKJwwOP[(!>&....+&*>;~{FQKJwNNSJKQ/(~;=*%+.....&*,;)]/^rKzKzKKrIKKKKKI^|'-%.........@*,;':QKOwSwOKQF'--*&@.....&=-;{/QKsKKKI/}FFQzKsKKK/F~>@..@=-_1<6SNNwJKI^//^IKJJwNwOI[)$.....+&*,;!)2^IJwNNwOKQF_~-=#@.....&*,;)FQKKwwwOPKKzIKKJwww6[|;&......@#$-;1<OwwwPKQF|);,=%@..................@%=-!)/IJwwKQ_;=&........&*,;)1}QKPwwwO<|!-=%+.....................................%-~)F//rrrrrrrrrrrrrrrzrr^/|;$..",
"..&=-':}QIKKJPI<QQ}|('-$&@+........@#>;_(}<6MMOPPJYwNSSYYO<}(-&..+%=;_1<P8OJPI[2((((:2QP8J8<}~,+..%-a128686PIQQQQQIIIK565[1!-#+.....+*=-!_1[<66OO85<2:(~->#&@.....@#=,;~(1[QIIIQQIQQQQ[[}|~-=%.........@&*,;(}[P8OO5[}_;=*%@......@#*-!|[QQIIQ[:((|}[QQIQQ2(;*+..&*3!12<OOOOPI[211}2QK8OO88[1'$......&$=-'(|[I56OM8P<[}(~;,*&.....@#$,;(2QQK6O8IQQQI<I66O6<1~>@......+%*>,_25OOPPQ[}('-,$%+..................+&#$-0|4OwY84_->&........@*>-'(1[QP68O6[d;,*&......................................&-!(1}[QQIIIQIQQQQIQIQQQQQ}:!*..",
"..&=9ab4hlllmVllhh41ac,$@+.........@#=3abfijWqqmmpZWUUWWWjied3&...&=cdb7kllmlhkfdaa_dbehhli7fd>+.+%>;dfg5i5hkllllhhhhh74fba9,#......+%>-0a:7hlm5mPlh7eda;,*%+.....+&*$,-c_e75hlhllhhh74ebd;=*&........+@&*>9ab4h5l5hfba9>#@.......+%*=cde47777ebdade777k77e0c*...+*3abfh5mmllh4:bb:7hlllmlh7ba*......@*,30be7kllmmmlk7fba;>*&.....@#*-cde47hlmllhlhlhlVllh7ba>........&*>9abhhmlhhkfba;=$#@..................+&%$=9dgpWWpga-*&........@*,90(e4hlVllhea3>*&+.....................................&3abe7h5lihl5ll5h5l5lk5khh4e0$..",
"..&=9d:kllVlVVVVVh7ed0,*&..........+%>c_bfhqWWoXXnZWWUWWWom7b3@...%>cde4hVlVVhked00c0b:7llkked,+.+%-9de7khllVllVlVVVlk4fbba9=&......@%$99dbklVVVVVVlk4ba9,$%+......+%*=-9abkhVVVlVlVhk4eba9,*@.........@%$=9abfkllh74|ac=*@.......@&*>9de4k7k4ebaaab47774eba3%+..+%3~bf4hVlVllkebbe4hVVVVVk7b0*......@#=;adekVVVVVVVlk4bac3*&.....@&$,0de7klVVVVVVVVVVVVVl7b0$+.......@*-9aehVVXVVkke(09=#@...................@%*>9agoqZjga9=&.......+%=,cd:4lVVVXVl7d0,$#+.....................................%9(eklVXXXXVVVVXVlVlVXVXVVl4d$..",
"..%,!]/zsAytyAAtAsz/]);=&..........@*-~{/rxtvvHABBHvLvLGvtJrF-&..+*-~]/rzyxtysz/])~){{^zsssz/{,+.@$9_{/rzssxxyAAtBBtysr^F{~;=#......@#>;'{/zsttBtAtxsrF{~;$%+.......&*--')FrsxAABBAAxsr/]);>#+.........@#>-;)F^zsssz^F)!-=%.......+&$;!{/rzzrr/]{)]F/rrrr^F);#...+*;(F^zsyAAtys^/F/rsxtAtysrF~=......@=-!{F^sxttAtAtyz^]{';=#+....@%=;'F/rsxAABABAABtAAAtyz/)=+.......&=-~FzxACCBCBxz/{~-=&...................@#=-!|IxvGxI{~,&.......@*-!{FzsACCCCBtsF);>*@.....................................*'/zxBCCHCBCBCCCCCCCCBCBCCBsF-..",
"..@$;')F/rrrrrrrr^F)~;-%+...........%,;~)FIzsssssxyAAByyyz/])-@..+&,;~){F/rrr/F)~;;;!){]F/F]{!=+..#-;~_{]/^rrrrrrrrrr^F{)!;,=&.......&$-;!)]/rrrrrrr/])!;=%+........+@*,-!)]/rrrrrrrr/F)~'-$@...........&#>;!){F/F/]{~!-*#@........@*,;'){]F]{)'!!!))){{)));,%+..@#-!))]//rrrr/]))){F/rrrr/])-@......+&>-!']/rrrrrrr/F))!;,$&+.....@&=-')]/^rrrrrrrrzrrrr^F);=........@%-;)^yABBBBtsrF{!,*@....................+*=;~F^rzrF);,&.......+%-;)F/sAAABAByr]!-=#@.....................................*'FrstAACCCCCCBCCCCACBCBCAtz{=+.",
"...@#=>-;;'''!'!;;;,=*#+.............@#=,-~(|(()()]]]F]:{)!-$%.....@#=>--;;';;--,>>>>=--;-;->*&...+%*,,--;;''!'~~~'!!;;-=**&+.........+%$=>-;;'''''!;-,##&+...........@&*=,-;;'!''''!;--==%+............+@&**>--;-;--==*++..........+&$=,---,-,>====->>->,=$%.....@#$>,-;;'';;;--->-;;;';!;-,%.........%*>=-;;'!~!'!;-->$*&+.........@#$--;;!!'~~~)~'~~'!;;-$&.........+*=-')]FF]]{)~;->%+......................@#==;!__';,=%.........+%*-;!)]F}F2]{~;=*@+......................................&=;~){]F}F2/2//[/[/[/2F2FF{)>@..",
"....@%***>>>,>>>=>$$#&+..............+@**=-;;!;;;;'~_'~!'c-=*&.....+@%**=>>=>=>*%&&%%$***=*=#&......&&*$===,=,,>=>,>==**#%+............+&#$*>>,,,>=>=*#%+...............&%%*>=,>,,>=>=*#&@+...............++&*#*$=***#%@.............+@%%***$%#**#&#%**##&%&+......+&%**$=====*=**$**>==,==$%@.........+&%$*$>,,>,=>=**#%@............+&%**=>,,=------==>=*#@...........@%>=--;;;;-,=**%+.......................+@#$=,-9->$&+..........@#*$,-;;;';;-,=*&+.......................................+#$>--;;!!!~~_~~_~_'__~!';;>#...",
".....+@##**$***$*#%@@+.................&**=,99->>-9;c9c33>>$%@.......+@%###$###%@..+@@%&%*##%+......++@%#**$***$***$*#&@@+..............+@&%**$**$*$$%@+.................@@&$*$$**$%%%&@+...................+@%&#**#&&@@...............@@&#&#&@+++..+@@+++..........+@&%#####&&&&@&&&##%#%%&+...........+@&%##$*$$*$$#&&@+..............+#**$*$*$*$******#&&+...........@&$*==,-,>>$*#%@+........................+&#$==>=#%@...........+@%#$*,,,-,,=$#&+........................................+%***=,,-33-339-9333,333-,>=#...",
".......+@&%&##%%%%&@...................@@%#**>**$*,>,,,>>=#&@.........@%%%&&%%&&+....@+@@@&&@.........+++@@&&%%&&@&@@@+.....................@&&##%&&&&@...................+++&&@&&@@@@+......................++@@@@@@@@..................++@+........++...............++..++++++.+.++.++.+...............++@&&@&@&&@&&@+.................+@&@%&&&%&&&%%&@@+.............+@%##*==*=*#%&+..........................@&%&###%&+..............+&&%*$=$**#%&@..........................................+@%***>$*=$========$=**=**%+...",
"..........+@&&@&&&@....................+.@%#&%%&%%#****%%#&+..........+&&%@&@@+@+....+....................++.++..............................+@&&&@@%&@.......................+++++.+.........................+.++.+..+.......................................................................................++@+@+.++....................++++++@@+++.+................@&%##%#*#%#&+++..........................+&&&&&@+..................++@%%*#%&@+.............................................+&%%**#*##%*%#*#*#**#*#%&....",
"..............+.....................................+..+..............+++++++..................................................................+..+++++.................................................................................................................................................................................................................+++.++++.................................+.+...........................+........................................................+....+.+.+...+..........",
"................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................",
".................................................................................................................................................................................................................++++@+++.......................................................................................+...............................................................................................................................................................................................................",
".....................................................................++@%%&%@++..................................................................+@&&&&@@+....................................................+&%*#$#$*##&+.........................................++&&&&&@++..............................+&%%%&@+...........................+@&&@+.................+@&%&%&@+..........................++&%%%&%&&+............................................................................................................",
"..............+&&%&&@@.............................................@%#===>,>=*&@...............................................................+&*$=====*#%&@..............................................@&#*=,,3-3,3,,=*%@.....................................+&#*=,,3,=*#@+..........................+@#*===>=*%+......................+@#*=>=*##@+............@%#*=,3,=*#%@......................+@&*==,,3>==*%...........................................................................................................",
"...........+%$$,----=$&+..........................................%=-;;~){)));->%@...........................................................+%=,;;~){))!;->$&...........................................@%=-;')){{{]{{{)';,$@...................................+#--;!)){)~;;,*&+......................+@*>-;;'~~~;>$&+..................+&$-;!)))!;-,*&+........+%$,;!~){))!;-=&...................+@#--;)){{{{)~!-#@.........................................................................................................",
"...........%$--;!~'!-,*&+.........................................%>;~)]//^^])!->#@..........................................................%$-;!{F/^/F]);-=#..........................................+#=-!~{F//rrrr//F)~;=%...................................+#-!))F^/^F)!;-=%+.....................+*=;!){]FF])'-=%..................&$-;)]F//])!--=&+.......&*-;~{F^//F)!;-$%+................+&*--!)]^/r^^/F);-#&........................................................................................................",
"..........+%*--;!''!-,$#@.........................................&=;~(2[5<Q:_;-*#&+.........................................................%*,-~|[Q[}}{);>*@.........................................+@*=>;!(F}[QPPP<<Q1~->&...................................+%-;)|}<<<[('-,$%+.....................@#=-!~1[<Q}(;=*#+................@%*>;(4<<Q}('-=*&+.......@*>;~}[5QQ}(!->*&+................+&#=-;(1Q<I5K<[_;=*&........................................................................................................",
"..........@$=-!~(((_'-=#&.........................................%,;(}[8OO6<|~3>#&@........................................................+%=,c(4565Q[}(;-*%.........................................+%#$-;(}[QI8OOYYO67(;=@...................................+$-~1[58O652~;,=#&....................+&#>;~:[5Y65e;-$%@...............+@%$-!f58O6<:~;>$%@......+&$-c(<O8O5Q1(;=$%&+...............+@*-;~1<8OMYM651c,*&........................................................................................................",
".........+&>9;abe4fbd0-*#+........................................&>cb7ijqqjgfa;,$%&+.......................................................@#=3cbijomih4ea3*#........................................+&*==;ae4iimjqqoqqpgb9>&...................................@$9afgmqZoigbc->*%+....................&*=cdfipqqjga3>#@...............+%#$-agjqqjifdc,*&@.......@*-0fgjqjmi4ba->#%@...............+&=39abgjqqWWqjf09*%........................................................................................................",
".........&*,cdegmppi4b09=#@.....................+@@@+............+#30bflXnZnl4:ac,**&+...............................+.....................&*=,cabhmnXVVl4b03#+...................+++.................&%>9cd7hmnnonnnnnpiga3>#....................++@+...........&=9dekmnoXmkedc3>*%+...................#*9ab7lXoYmgdc=*@...............&%=,cd4mnZnl7:a9>$@......+%*30binnXXVk4ac,=#&@+..............@*,0ab7mnZWUWpgdc,#+......................+@++............................................................++...............",
".........*-']rsHDuEDxz/);=*@.............+&%%%*%$=*$#&+...........*;{/zxHHHHCxs/{~;->$%%@+..............+@&###*****$**$*%&@..............@%$,-')/KxACBCCCxr]'-&..........+%#*#***%#$*#@+............@#=-!{/ztGvELvGHHBBAsQ{'-*+.........+&%###**#*$*$$*##%%&+....#-)FrsCCGCHAyr]);--*%@+..............+@=-~FrxBCHBHs^{;,&.............&#=-;~]QyAHHBHxzF~-=%......+$,!(/sBHBHCAs/)';,=#$#%%@..........&$3'(/KxADLELDx[{;-&............+%###*#***$=$$****%%%@........+&###****#*#*#*##*&+..................+%##*$*=$#*%&+.........",
"........+#-!]rytDuEuAs/{;-=&...........&%#*=,--->----=#&@+.......+*;)/zyBBBCABsrF)';--,**%@+...........@%*==,----;-----,-=#%@..........@%#*,;;~]FryACCCCBAzF),&.......+&&#$>,-------->=#@..........@%*,;)]rxAGLELLHCAAysz/{;-#.......+&%##=>,-------------,*#@..+&-!FryACCBBBxs/{~!---=#&@+...........@#-;)FrtABCCAs/);-#+...........@%*,-!)FryCBCCAyzF);,%......+#-;)FzxBCCCByr]);;-->-,=*&.........@#-;)]rsAHLLLGyr]!-#+.........+%#$=,----;;----;----,*#&......+%#=>-,-,--------->=$%&@+..........@&%%$$----->--,,=#%&+......",
".........&*-!1[5wNNw52|!-*#@.........++&%*$>==,-=,,==$$$%@+.......@=;'][rKKKIr^}{~;-->,=*$%&..........+&*#=>=>,--;-----===*%@+.......+&%%*$=-;;~{][^IKKKK/]!-$+.....+@&###$=,>---->,>=**#+.........@%$=-;)][IJwNwwPI^^[F1);=*&......+@&#$$>>,>--;;----->==>$*@...@*-!(FIKzKKr^F|)';-,=*$#%@+..........@%*-;~]2rKKKIF(;,*&............@#$>-;~(][IKzKQF]~-=*&.......&*>-_]}^IKKK^F_;--,,=>>**&+.........+%$-;(1QPwNwO[_!-*@.........+&**=>==>-----;------,>$*@......@%#$=,,,,=>=>>>=>,,>**%&+........+@%%*#==>,,---,,,=$*%%@+.....",
"........+&*=3!b<6OY6<2('->%@.........+&%$>---;;;;;;;--=**%@.......&=-!_:QIIIQ[}:((~;;;->$*$#&+.......+&*$>>--;;;!!~~~;;;-,=*%@......+&%*$=--;;__(:}[QIIIQ[(!-#+.....@%#$*>---;;!!;;-;-,>*#@........@#=,-;_:[Q5OOO6<[}}1|(!-=*@.....+@%$**=,--;!!!~~!!;;;;--,$&...+#=;_|[QIIQQ[2:(_~!;--=$#%@..........&$>,;_|}[[IQ[:~-=*@...........@#*=-c!_(:}QIIQ[}(!->#@.......@#>,;(:}[[QQ[|~!;;;;;--,>*@..........&%=-;(}5MNR87_;=*&.........+*=,---;;;!'~!!!;!!!;;-,*#+.....@*=---;;3;-;;;;;;---=*$%&+.......+&#$$=,--;;'!;;;--,=$*%@.....",
".........&%$39afgipig7ea-*%@........+&#*=9;aaa|bbbdda0c,>#&+......&*,;de7hllhh74febb_aa;3==$%@.....+&#$==3;aa_bbbbbbbbdda0->*@.....+&#$=,-;adbbeef7khhllh7bc-%.....@%$*>,3;aadbbbbdda0;,=$*@......+%$,cadb47llmXmmhh74eeba9=#@.....@%*$>,3caddbbbbbbbbbddacc3#...+&*30b4hllhh744eebbda;3=$*&+........+&*=30db47hk74ba->*&+.........+&$>3cadbee7khh47fbd9=*@.......@&$=ca1e4kkh4bbda~dad0a03=&..........+&*>9cbiqWWjgdc,*&........@%>9;aadaddbbbbebbbbbbda;,=&....+#,30a~d_ddaaddbddda09==*%@......@%#*=,-;aa_dbbbbb~cc,>$%&.....",
".........@%*>90b7llVlh4bc3*@........@%>-cab1e444k774eeda3=*&......@*3cb4lVVVVlllkhkk74ed~093=%+....%*=,ca(be4444kkkkk7444bac,#+....%$,;'a(be47kkhhlllVVVVke_3*+...+%*,;'0_b4444k74k44:da03==%+....@*=cd1ekhVlXXnXXllhkk4ed;,*&....@%=99!ad1e4477kk7k7k7k74:d0$+...%>9_bklVlVllhkhkk74eba09,$@........&*>c0(e7kllll4edc,$%+.........@#>9a1e4[kkllhllkk4ba9=#+......@#*30b44kllVk4eee447ee:ba3$+..........&*,9afmqWWogbc9>%+.......&=9_be44747khhkkkk77474eda3$+...%=9_be47744e4474744e|dac3=*&....+%*,;'a_be4447kk74eedac3,#&....",
".........@*=-;~/KxtAABsr{!,%.......&*,;)/rsxAAHBHBBAAAs/{!--%+...+#-'{rxBCCBHHHHHHHBBAAyzr/{!,&...@$;!{/rsxyBCCBBBBCHAHAByzF)-%...&>;~FrzsAtCBHHBHHHHGBCCtzF'>+...&,;)/rzsxABCBCCBBBtxsr/]~;>&....%-']rsxACGHHvvvGHCCBBts^{;,*...+#-;{/rzsAACBCBBCCHACHABtyr];+..+$;)FzxCCCHHGHHHHABBAsz^F)!>&......&$-!{/rytCCHHHts^{;-*&........@#-;{^zxtACACHHHHHAAz/);>&......%=-;{^stACBCByxsyAACAysz/);%..........#=;~]KtEEELyI{!-$@......@=;{/zytBBCBHBCHBCBCCBAAAsr]!#..+>!]rsxABABtAyABABAAAxzrF]~-$+..+%-;)FrzsytBBBBBACCAysz/]);>&...",
".........+&*,-')]rzsyxs/);,#+......&=-~]zytBHGGLGLLLGLBs/)!-$&....&>!{^sACCHvvLLvGLLLLGCBts/);*...%-!)/sxBCHvHCCCBGvLLELuGs^{;*..+%-;]rytBCvGLLvLLLLLGHBCAzF),@..+$-!]rytBCvvHCBCBvDGCBAsr]~-*+..+*-!FzxCCHHLLLLLLGBCBCAxr{'-#+...*-~FzyABBvGCCCBHvLLvLLGHts/-@..+$;)FzyCCCGLLLGLGLLGHAyzrF);*......+=-'(/zxBCHvLLHxr{!-=@........+#-;]rxABCCCBGLvLvGHs/);>#......@*-;{rsyBCCCBBABCHLvHBAxr{;*.........+&>;~]IAvEuvyr]!-=&......@=']zyCHLLLLGLLGLvLLLLLGGBxr{>+.+='FzxCGLLGCBCCCCCCvHHAsr/]!>&..+*-!{rytBCGGHCBCCHGGCBtsr]'-#...",
"...........+%*=-;'~{]F]);=#@.......@*>-~FQKKJwwNwNwNwwOQ|!->*&....@$=;)/IKKJwNwNNNwNNwwJKK/F!-%..+%=-~F^KKJwwwJJKJwwNwNNw8<|~-&...&=-)F^KKJwNwNwNwNNNwJJKIF'-*...+%=;)2^IKJwwwJsKJwwwJJz/}';,%....&=-~F^IKJwwNuNwwJJzKzr/|;-*&....%>;(/IKKwwwwJzJJwNwNNNwJK[)-+...%>;_]QKJJwwNNNNwNNwwPI}F(;,#.......%>-;)]/IKwONNOI|;-*%+.........@$-;{/rIzKJJwwNNwwOQ1;,*&.......&$,;)F/^IzJKrQ/PJwwJPr2{!=#..........@#>-':5wNwOQ|'-$#+......+#-)FQJwNwNNNNNNwNNwNwNwwPIF~$..+*;)2IJwNNwJsKsKsPwwwJK^}]~-=@..+%=;)FQrPJwwwJsKJwwwJKKr1);,%...",
"............+@**>--'_(_;,*&+.......@#*-~1[QPJwwwNNNNNRO41';-*@....@%>-~:[QI6ONNNwNNwNNYPK<[1~-%...#=;_1[<IJYSYPIKKONNNNNRM7b;>%...#,9_1[QPPwNNNNNNNNSOJPP[|!-%+...#=;_1QIPJYSO8PKPOSOOII[:_;,#+...@*='(}QIJwNNNNNROKIQQ[}(;=#@...+#-;(}[IKJYwJPKP8RNNNNNw8Q}_=+...&>-'_}QIJONNNwNwNNNR6Q[1(!,%.......&#--~(}QI8SNNR<1;,*&..........@*=;(}2QQIKJwwwNNSO7_->*@......+@*=;_(:}Q<K<Q[[<ORR8<[}(;=@..........+%$,c_<OSR64_;=*@+......+#-'|[5ONNNNNNwNNNNNNNNwOPQ}~*+..&-!|[PONNSOKPIPIIPYMO<[}|~-*@...#,;_:QIPOwSOPIIPOSYJPIQ2_;=%...",
"..............@#*>=3c_a9>$&........&*=9de4hinqZWZZZWZqogeac9>&....@#=3a:7lVmoWUWWqZWqqommlhfd3%...%,;dfhlmXqqqmlhmpqUTTTTjgb0>&...%,;bfkimpqWZqZoWWUWjXmk7bc-#...+#-cbfkmmooWqpmlmoqopmlh7d;,%....@*=;de7hpoWWUUUqpi<77e1a9=%@...@*-ab7himqqqqphmpqUUTUWqphf0=....@*30d4hlmnqWWWZWqWWqmh7f:a3#.......&*,30df7ipWTUqgbc9$%+.........@$=9d1447hlmoZqZWWjgd3>*&......+@#=3ab:4hiVihhiijqqp77bd9>&..........+&*,cbgqWqjgd;,*&........%>cb4mnqWUUUUUUWWUUUUUZjmgea>..+%-0b7pqWUWqnmmmlmmoqoi47eb0,@...%>9bfkimpoqpmhlmpqopmlh4dc,#...",
"..............+@#*>999;3=%@........@$3'dekklXnooZooZZWqm7edc3#+...@*>c04hVXnnqZooppnXooonomhea>+.+$9aehmnonZopmhhhmnqTTTTqiea9#..+$9dfhXnonoononnooZooXVVhe_3*+...$9dflpnonooXXmlVXnoooonkfd9*+...@#>cabfklnooZWqqmhk4eeda3>*+...%,cb7innooooXmllmoZZZZZnmked>+...%=3a1kVlXnXZononnnooXVlh4:c$+......@*=9cd:7kjqUTUifa3=%+.........+&>30dbe4khlpnooZWqib0,*&+.....+&*>0_e7klnooXpnjqoolkeba3=&..........@$>9afiqUWqgb03=%.......+#3ab7lnZZZZZZZZZZZZZZZoXVVkb,+.+#,ab7loZZZonXmmllmnnnVVkked,#..+$cdeiXXonZoXlhklXnoonomifdc=+..",
"...............+%#>---;-=*@........%,!]/zxtBCCCCCHCDLLvAysrF',&..+&>;)/sAHHvGvCHAyyAHBHGLDDtsF;+.+-{^sGDDLvGHBtxxsAAvLuuuuxKF;$..+-(rsGvLLvHHAtxtCCvCHHCBAzF'=+..+-]rxGvEEDGHHAAABCBHGvDDGxr]-+...%*,;)FrsxHHGGvGCAssr/F{~;-$+...$~FztHDvDvHHtysAAHHGGGHCAs^(-@..+*-~]zABCBCCBHBAtAHBHHBCCxzF-+......@=-;~{/zsGEuEuwz{'-=&.........+%=-'){F^rzsytBCvLvtI]'-*+.....&*-;{^sxBGvLLEvLDvHAys^]);>&..........@$;)FztEEEvxI{'-*.......&=;{FzxCHBGHGHHvCHCGvGGHHBCyr;@.+=!{/ztHHHGBHCCtxtAHHCHCBAs^)$..@-{rsHDEDGCHBxysAACCGvLDHyr];#..",
".................@%#$**%#@+.......+#-;]^zsyBCCCCCCCCLLLHxszF)-%...#>;)/stCBCCCCtssssxACLLELGs^-@.+-(/sHLLLvCttzzzzsytGEuEGy/{!*+.@-]rxHLELvBBysssxACCCBCCtzF)-@..&-{IyGLLLLHCBBABCCCCLLEuGyr{-@...@*,;~{/rsACBCCCCyz/F])!;-$@...+$'FzAvLLLGCtyszsyACCGCCCxzF),+...%;)]zyCCCCCCBxssyxBBCCCCAz]-@......+%$-;){^sAvEDvtr]~-=&..........+%>-;!){F/rzsytGLLyz])-#@.....+$-!)^zyBHLLEEEELGAAsr/{!-$@..........&=-~}KAvEEvyr]'-#+......+=;~{rtABCCBCCCCBCCCCCBCCCCt^;@.+=;)]rtACBCCCBAysstABBCCCBy/)=+.@-]rxGLELvBAxszzsytCvEDLGyrF~*..",
"...................+@.+............@=-'{F^/KKJJJsKJJwwRPQ2]_-=@...@$>;~/IKKKKrI/2]1F2[IOwww6}(-...$'([6wNwJQ}F{)_){:}QP65<2_;=@..+=!([6wNwJQ[2]1]2^rKKKKKQF)-*...@>'1<8NNNwwJJPJKJOJwwNNR8[|'=.....@%*-;!1F^IrKzKI/:);;,=*%&.....#-_:<JwwwJKQ/}]}/IKJJJKK/|!-#...+@*-']QKJJJKI^2:]:/^QrKKzI]~$........+%*>-;(:5ONwO5|!->*+...........@&##=>--'_(]2[POO<1!->%.......@=-;)F[IJwNNNNNw8Q}|_;;,*%............%>-~:5wNwO<('-=@........&=-'(2IJJsKKKKKKzKKzKKzIKrQ],+..%=-'(/IKsKKrI/F]}F^IrKKKr[);%..+=;1[6wNwPI2]]|{]2}Q8www6Q|~-%..",
"...................................&$,;(2QIKPOOP6IKPYSM5[:_!-*@...@%=-~1[IIQQ[21((((|:48RSO5:'=+.+*9_15YNR841_~;;-;~_|1}}1_;,*&...*c(}POSY541(__(_:[[IIIQ[|!3*+..+=;(g8NSNNMYYRRRSSSSNNNR64(;*+.....@#*=;~1}QQQQQ[1_;-=*%@+......%-;(78SNY8<[}1|1}QIIKIIQ2(;,%....%$>;(1QIK<Q2:(_((1:}QIIQ[1;$+........+%*-9'b[OSSO<1;-*%@..............&&#*=,;'_125O8<|;,*&.......&$=;_(}[PMNSNNNR5[|_!-=*#@...........+&=-c|<ONR64(;,*%........&$-;_:QKPKQ[[QQIIIQQQ[QQQQ2)>..+&*-;(:QIIIQ[}1_(((:2[III[:~-%..+*0d}6YSY52((~~~~_1[5RSY84(;-&..",
"..................................+&*-0b4hlmoWWqnmmpqWqigfba3$@...@#=-ab7hlhg4fbbaaddbgpqWqie0>..+$9depqWqpfbaac93990dbbbd0c,*@..+$cdfpqWqpfbbdaddb47hllh7ba,#...+=cbgjTTTTUUUUTTTTUUTTTTjgbc=......@%$>9a174hhkk4ba;,$#&+.......@=;dgpqWqnih4fffghmpmmlhfd;=#....&$,;d4hlli4febaadbe4hhlh7b0*.........@%*=3;bgjWWqgb0-=%@...............+@%#*,;0bfpqjgd9,*&......+@*=30bf7pqTTTTTqigba0-$#&@...........&*>90bgqUWjgdc>*&+.......@$=;0ehlmhhk7khhhhhhhh7hhhfd>...&*,;0e7hlhh4:bdadb:47hhlhea3%..+*cdgiqWqifbaacccadfiqWqpfbc,&..",
"..................................+#=9~ehVXXZWWZonnoWUWph7:dc=&...%*30d4lVVXVk7e:bbb|fhpWWZpgd,+.+=0b7pWUWogeba09-3cadb:bbac3$&..+=abgjZWZpkebdbb:4klVXXlhe_9*+..@,0fgqTTTTUUTUTTTTTTTTTTqgb0=+.....@%*,cdekllVllked9,=$%@.......&>3a7poqZonpmmimmnZZnnXVkb03%....&=3aekVVlVk4e|bbbe4klVVlh4a>@........+#$39abioWUqpfdc,*&+...............@&$>,cab7pZqib09$&+.....@#$3'be7hnWTTTTUWp74b_93=%@..........+&*,9afiqWWoieac>*@.......&*,cd4hVlVlllllVVVVhllllllkb,+..@*3ab4lVVVhk4ebdb:fkkVVVl7b9*..+=0bhnWWWphbbda_ade4pZWWpiba3#..",
"..................................%-;)^stHvvDvDvBCHvLEEGBxz^{;%...*-~]rsAHHGHCAyzrrrssHGEELGs/;+.@,]QsHvELGtsr/])!~){/rzrrF)!-%..@-FryGEEEGAszrrrsxtACHGHts/)=+..@-2IwuEEEEEELELEEEEEEEEuuJr:-@.....%=-;(^sACBCBCts^{'-->#@......#9~FrAHHHGDDuvDEDEDDGGGHyr{!>+..+*-']zxCCCCAtsz^/rzstACCCts/;#........@=-!(/zyEEEDtK^]~;=#+.............+&*=;!{/rsHDvtKF'3$@.....&*-;{^stAGLEEEEEEGAtz/{!;=%+........+#>-'{[stEEEvxK/{;-=&.....+%-;{/sACCCCCCBBCBCCCBCCBCCtr;@.+#-)FrxACCBBBxzr^rzxABCCBCyr(>..@-FIxvLELHysr^^/^rzxGLEEGyKF'$..",
".................................+%-~]rxHvLLvGHCCCCHLELGCys/);*+.+#;)FrsACBCBCBxsrrzsxCvELuGs/;@.@-{rJGLELLAyz^])~))F/rzzrF{~;*..&-{IsHLuLvAyszzzsyBCCBHCAsF)-@..@;]rxuEEELvvBHCHCGGvLDvGts/(-@....+%>-!)/sAABCBCAs/])!-=*%&.....%,;{^sABCGvLLDuvELLvvHCBtr]'=+..+*;)FzyCCBCByzrr^/zsACBCBBs/~*.......@#=;~{/KtGDEEAs/]~;-=*+...........@&*=-;){/zJtGDyr]~-*&.....&=-'{rstCBGvLLvvvvGCxrF)'-$@.......@&$-;~]^JALEuvAzF{!;,*&.....*-;)^sBCBCCAACCCCCCACBCCACxz;@.+#;)FryBCCCCtysrr/zttBCCCBtr{=+.+-{ryGLEEvAxzr^^rzyAvLLLGxr]'*..",
".................................+&=-~1QJwwwJI[^[/QIJOwPQ[F_!,&...&=;'{/QKKKKzK^FF]2^IPwwNwP}(>+.+$;([PMNNOIQ}|)';'!)1F2]]_~;=&..+>;1[8wNNOII/2FFFrKzKKKKQF_;*+..+>~:QJwNNwJKKIIIQIQIIIIKQ:);*......@*=-!)FIrKKKrIF|~;->$$&@.....+#=-'{F}QI8886O8JOOJJKKK^]!-%...+%=-~]/KKKrQ/F1){(F/QrKKKr[);%......+&**,;!(2<YNww52(~;-=*#@..........+@%#$=-;~(:Q8OO<|!-=&+.....@#=-;)F^IKJJJKKPJJwJI}(!-,*@.......&#*>-;'_2PwNNO<}_!-,=*@.....&=-;_/KKJKKrrIzKKzKzIrKzKK/F,+.+&,;)][rKJKK^2F(((]F^IKzKK^]'*..+=;1[8wNNOPQ/](||}[POwNwJQ|',&..",
"..................................&$-;148wSO54}::1}[6OO<[}|(;-%...%=-'_:[IIPI<Q[:||:}Q<OYYY5:;=..+#;_:5OSYO<[}|_~~~__(1111(~;,%..+*c_}5YNR8<[:||(}2<IPIIQ[|_;*...+*9_f8RNSO5I[[[}[}[[QQQ[}('-*+....+&*>-;(:[QQQQQ[2(~;--=*#&......@%>,3!(|2[[<[[[[<<IIIIQ}~;=#+..+#=;~(2QIIQ[2|(__(_:2QIKI2:(-#......&#$>-;'~1<YSSO<:(~;->$#@.........@%$$$=>-;~(1[6M67|;-*@......&*$,;(1}[QIPPI<IPOY8<}(_;-=@.......@#>>-;_(:<MNS8[|(~;->$#+....%==;_}[IPP<Q[QQQQQQQQQQQQQ[_>+..&*-;(1QIPP<[2()_((}}[QIIQ2|;$+..$;_28YNYO<[}:1(1:[QORSM52(;$+..",
"..................................&*9cbgpWWqpgf7ffggjqqphffbc,%...%=-0dfhmmpXmihffffghmoqWqib0$...%,abiqZqnmh7ffbbbbff7f7fbba-@...*9afiqqWjikffff7hmmnmmi4fdc>+..+$3afpqWqqmihg77g7ghhilhfbc,#.....&*=,;abf7hhlikh7bbdc09,*#+.....+&*=-30dbffff7777hhhlhhedc=&....#>;db7ilihgffb(dbef7hiVihfd9*....+@**,-0adbggqTTqigbbaa;3$&........+%**,,9;cadbfgmjjgd;,$&......@*=9abf7hhlmikhhmoWqigfbd09%......@%*-;cabffiqTUqifb_ac9>*@....&=-0dfhlmmlh4hhhhhhhhh4hhhhb,+..%=;abehmmmi47bbddbf7hilik7ba=...%3afiqqqjmg4feff7gipWqqpfd9$+..",
"..................................&=3aegoWUWommimmmoqWWopmi7d;%...%,0b4hmnoZZooppmimmpooZqjif0$+.+#3aeiXoZoXmmiiiiiiiiimmhkeb9#..+%;aeinZoonmmmiimpoZooonmked,+..+%9afioZZooonpppmXmmXnnmhea9*+...@*=9_beklmjononpmih74eda3*&+.....@#$,c0de4k<khkhlllVVVl7d;,#...+$9de7mooonpmh7ee4glpnoonmhea$....@**3c(e4ggpqqTTUjmi44:ba9$@......@%=-0!d(be44kklnnngb0,*&......%=9ab7immXlVllllmoWUjmii7ed>+....@&=3_be7gijqWTTqjih74eda,#+...%,0d4hmoonmVlllVlnnnnVVVnpm49+.+#,ab4hmnonnmiheee7lmXooonh4b,@.+#3afmnZZonXmliiimXXoqZqifac*+..",
"..................................&,']ryDuEEuvLDuvvuEEEEDDHxI(>+.+$!]zABDDEEEuLEuvuDEvDGGGAs[)=..+>;{/yBHHvLvLDDGLvGLDLDGGByr{=..@=~{rsCHHGLLuvvvDDEEEvEEvAs^'&..@>!{rxHHDvvEEDuDuDDDDDvDAsF'=+..+%-!]rxAHGLEuEuEDDDGHtAs^);$@.....&=-'{/rsxtCACCCCCCCCBBs^);$+..@-)^xtvuLuEuvGxssxtDvEEuEvty/;+...%,;)^stBHGuuuEuEuuDHAAxr{-#.....+$-']/rzsyxBBBACHHCs/);-#+....+$;'FsADLDGHCAtxtAEuEEEGGtxz~%...+#-;{rytBvuuuuEuEuEvABts/)-%..+=;FrtHvEELvHCCCCCGvuvGHHvDDJ(@.@>'/ztHDuEEvDGtssstvDuEuEEGtz~@.+>!{rxBHBGLvuvvvDvuDvHGHtr1~,@..",
"..................................@>;{^sGvuEuDuLDuLLEEuLGuDyr{-..+>;FrxHGLLELuDDLDDLLLGHCByzF'$+.+*;)FzyACHvLLLLvuDLGuDuDvtxr{>+.+$;)FsxBCGGDLLuLuLLLLLuuvBxr;&..+*;)/sxACHvDvLDLvuLuDDDutzF'>@...*-~]zyBBHvLLEEuuuDGCCAyr);-%.....%=-~]/zsBBBCCBBCCCBCBxzF';*+..+>)rsAGuEuvuDGyssyAvDLvuuDHxr-+..+#>;)^xBBHvEuEEuEEDGHCAyz]!$+....&$;)FrsxAABCBCCCBCts/);>#+....@$;~}zwvGvHCBAtssxvEuuvuDGAz]$...@$-']zxBAGvEEuuEEuvvHCAyr)-*..+$~FzAAGLLLGCBCCCBGvvvHCHvvvx)&.+>)/sAHGDLuuLLAxsxAGvvuEuLHAr~&.@*;)/ztACHGLLLuLuDLvvCCxs/);$@..",
"...................................%=-!|[5P666J68O666JO86P<4(;%...#,!1}<588O666686668PIQ[2]_;=&...&*-;):/[<56P8P6K8668P8P<[:~-%...&$-;)]}[I6686JO8O8O6O6P<Q:)=+...&=-;(F}[IP8666OJ6666PP<4|;-%....&=-!{F[IIP6O6OJOPPPIQ/F)-=&+.....&>,;~|/^rKzKzKzKKKr^/F);,=@...+*-(:Q<6O6J65<[::2Q566J665Q})>....@$>;)F[[IP6OOY6O66PII/F(;=%.....&*>;_F///rIzKKKKIQ[|!,$#@......&>-'1QP6PII^/F::4<668OPPI[];&....&$-!{F[Q<66OYY6OO8PIQ/]);#@..+%>!12<6686IIQ^QQQIPPPQQIPP<4;+..%-'][QP66J6PP[}:2[<PJ6J66<[1-+.+%$-;(F2[<P68686888PI[[F);-$@...",
"...................................@*=-0(:}}[4[[[[[[4}[[2}1_;=#...%*-;(12}[[[[2[[[[[[}21(_;-=#+...@%$>-;'_1:2}}}[[[[}[}2:1(;-=@...+&*,-'_(|22[[4[[[[[[4[[:(';*+...@#*--;_(|}}[[[4[[[}}111_;,*&+...@#=-!(|:}42[<[[[[[}:1(~;,*&.....@#=-;_1}QQQII<KIIIQ}|_!-=*&@...+%-;_(}[[[[[}1(__~|[[[4[[:|_9%+...@&*=;~_|:e}477[7[[4:1|_!-$&....+&#>;(1[[QIIIIIIQ[:(!-=%@.......&*>-!b}2}21(__~__:2}}[4[:_!>@....@**-;_(|}}}}727[4[21|(~;=#+...@$-!(:2[[[2:11|1}}4}}2::}}}_,@..&=-!(:}[[[[4}:___|2[4[[[}:(;=...@#*,-;__|:}[}[[[[}e1(_;9-*#@...",
"...................................+%*,300dbbbbfbfbbbbbfbba0,*&...&*,90abbbbbfbbebbbbbda9c-=*&....+&*=,,390dbbbbbbbfbbbdda;-=*+...+&*>=390abbbbfbfbbbbebbba9-#.....&#>,33cadbbbfbfbbbddaac3=#@....@%>-9addbbfbffffbfbbda;9=&+.....@#=3ade45llhllmmlh7edcc,$*@.....&=3cabbffbbbd000adbbfbbbbd0-&....@#$$3c0adbbb1fbfbebbda09=*@.....@*>cdf7hhhhllllk4ba;>$&+.......@%$-;abbbbdaaa9c0abbbfbbba;*.....+#$,30addbbbbfbebbbbdac3$%....@*,cadbbfbbb(b(dbbebbbbbbbba=..+@*,c0dbbbffbbd000abbbfbbbda9#....&#$,-3cadbbbbbbbbba0;3=>#&....",
"....................................&#*,ca_dbbbb:bebfb:bbba9-=&...@$>3;adb1bb(bb|b:bbdac9,=$*@.....+&#*,-9c0bbebe:b1bbdacc3,=%+....+%**>-cadbbb:bbb:b|b:bdac3#+....@##$,,30ad:b:bbebbdaac3,$#@....@%*>c0ab1b:eeeef1bbaa09,*%......@*>c_b4kVVllXXXXml4ed09>*%+.....%*,cadbeef1ba'9c0ab|be:bda0>&....@&%>,9caab1bbb:b:bbdac;3=%+.....&*=0b4<lVVXVVVVh4|a9,*%........+%*=3ddbbd_a0c;99abbb::bda9*+.....&*>3;0adbb:b:bbebbaa0;,=&...+&*>-cab1be1dbddddbb:bdddb:dc$+..@*=30adb:bb:ba0330db:b1bd_0,%....@%*$=399abbfbbb1b003,=>*%+....",
"....................................&$=3;_(]//[//[///[///F{~-$@...@$-;~(]2/2F]F}////2]_';3,*%+.....+&#$>-;!)]2//}^//2F:{_';->%......&#*--;)]/[////[//}///](';=@....+&#$33;~(]/}////2F1_~';-=#+....@#,-'))F2/^/rzr^^/F{)~!;-%+....+&=-)F^sxBCCCABCBAAsr]~;-*#@.....%-3!){F/^^/](~';~{F//}//F)!,&....+%#-;'~){F2^/[F[//F{)~!;-#+....+#-;)/sxAABCCBABxzF)!-*&........@%*-!{F/F])_!;;;'_]/^^^F]);*......@*>-!~)]F[/[/////F{)!';>%...+%=-;~(F^^^/F]]]]]F//F{{{]F:)=...@#>;~{F}//[FF{)'~)F}/[FF()~;#.....&#>--;_)]F[//[/]{';;-$#&+....",
".....................................&$=-;!))))_){{{{{()))!;=%+...+&*,;!))))))){)()))~;--,#&..........@*>>;;~))){){){))!;;-=%+.......+&*$-;))))_({))){){)~!;-$@.....++%*>,;!)){({){))~;;--$&+......@#--;!))|)]]{F]]{)~;;-$%%+.....&*,;)]/zsysxysyssr/]);,*&+......+#,-!))(]{)~!;;;;!_{){)));;*+......@%=-;!~){){{{_{))~';->#@......%$-~]^zzsyyxyyzrF{~-=#+.........@*>-~)))~!;----;'~)(]){);,%.......@#>,;!~)){){({)))!;;,$%+....&#=-;~){{)))~'~!))())'!!)))-#+...@*-;!))){)_)!;;;!)_))))~;;$@......+&%$,-!))_){)~);-=#*%@......",
"......................................+@@&#==-,->-=,>--===##@.......+@#*==,==>=>->>==>*%&&+.............@&#$$>>>>=>>>$**%&&+...........@@@&$=,,>=>,>=>====#&@+.........++@%#$=>=>$>$$$%%%&@+........+%***>>->--,-,->>=##&++........@#=>-;~)))))))));;,=*&+..........&#$=,,>>==>****==>=>==>*%+........+@@##==>==-,>>>===#&+........+&*=--'~))))))';-,=*&@...........+%*====>*$$*#**>=>,->$*%%+.........&#*==>>->-,-=>>=**%+......+@@#*==->->=>====>>>,===$**&......+&**=>>,,,==****>>->===##@...........@##=,-$=$**%@@..........",
"........................................++@@@@&@&&%@%&&%@@@+..........++@&@&&&&&&%&&@@+....................+@&%&&&%&@++...................++&@%%%%%%&&&@&@@+..............+@@@&&&%&@+.+.............+++&&&%&&&&%%%&&%&@+.............@%%%**$====>=**%%&@.............+@&&&%&&@@@@@&&&%&@&@@+............+.+@@&&&@&%&@&@@@............@&&%%##$$***$#%&&@..............++@&%&@@@+@@@&&##%%%@++............+&&&#%%##*%#&&@&+..........+.@&%&*#%%%%%&&&&@&%%@@+++.......++@&%%&%@&@@@&&@&@&&&@@+..............@@@@%@+++.............",
"..............................................+...+..........................+........................................................................+...........................+........................+++...++...................++..++++++++++......................+....................................+...+...................++++..+++.+++.............................+@@@@@++.................+..+@&@&&@@@.+..............+++@&&@@+@++.+...+....................................................+...................",
".....................................................................................................................................................................................................................................................................................................................................................................................++............................+............................................................................................................",
"................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................",
"................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................",
".................................................................................................................................................................................................................................................................................................................................................................................+@@++..........................................................................................................................................",
".............................................................................................................................................................................................................................................................................................................................................................................+@&#*$==#&@.....................+%#***%@...................+@#***##@+..............................................................................",
"............................................................................................................................................................................................................................................................................................................................................................................@%%*$3c99>=*&+.................+&#=3999=*&.................@%#=9c;,=#%@@............................................................................",
"........................................................................................................................................+@@&%#&@+..........................................................................................................................................................................................................................&**>,30dda9>=*%+...............@%#,;addac,*%...............&*=>3cdd093=>*%+..........................................................................",
"......................................................................................................................................+%*=>----=#%&@.....................................................................................................................................................................................................................+%>-!~)]Frr/)';,#&..............+#-;)]/rr/{!-=@.............@*-;')Frr/])~;->%@.........................................................................",
".....................................................................................................................................@&*>-;;!'!--$*%&....................................................................................................................................................................................................................%>-!)]F/rzr/)!--*@.............+%$-!]rzssr]~;-#.............@*--!)/zsz/F])!--#@........................................................................",
".....................................................................................................................................@%$,-;;'~'-,$%&@...................................................................................................................................................................................................................@#=,;~|F}}/}(;-=*&...............&*>-_2IPIQ|;-*%..............&*>,;)F2/}F|);,*#@........................................................................",
"....................................................................................................................................+&$=-;!~(1(!-*$%@...................................................................................................................................................................................................................@#*,'(}[[[}:~;=#&+...............&*=9_48OO5:!,=%+.............+#*=-_|[[[[}1~->#&........................................................................",
"..........++@++................................+@++@@@++@++..............++++...................................++++...............+@#>-ca(beeea;,$*#&++................++..............................................................................................+@@+++.....+@@++..................................................+@+++@@++++++++...............%$>;dfhhhhfea9>$&+...............@$>9dgqqqjea-=%+..............&$=3abfhkihed;=*%+.......................................................................",
"......+@&#***######*##&&@+...............+&&%###********%##&+..........@&%*#&##%*#%#%%%&&@+................+@&&##*##%#&&&@+........+%*30d:44kkkedcc,=*#&@............+@%%#%@+.....+@&%%@+............+@%#%#%%%%&&%&&%##*%#%%@........@@&%%%#&&@++...+@&%%%%@.........+@%#%**#&&&&&%#%**#&+..........+@&%%%&&&@++..+&%%%%%%&+...........+@&#%************%@+............+&=3abhmonV7:d;=*&+..............+%*,0biqWWqgdc>*&.............@%#>3d:7innXifa9>*@.......................................................................",
"...+%%=----;-;;;;;-;-;->$#%&@+........+%##=---;-;;-;-;---,,$#+.......@%*=,-;------;-;-;--$*@+............@%$=,--;-;;-;--->$%@......&$-~]rzytBBBsr/{)!;-=$%+.......+%*=>----$##%%##$----,=*%%@.....+&%$>-;>-;---->--,--;;--;->&.....@%$=,--;-->=*=###$-------*@.....&*$$--;----,->---;--;-$*@+....+%%$>------==#$#$$>-------$%+.......@&#>---;-;;;;;;-;--->*&+.........+%$;'FstEvvHs^]);>%..............+&=-'1KtEEEDxI{!-%.............&*=;!{^stDDDGs/)3,%.......................................................................",
"...@#,-;!!~~~'))''~!!!!--,>*#@.......@#*=-;;!!!~'~~~~'~'!;;->%.....+%$>--;''!!!!!!!!!!!!;-,=%+.........@%*>,-;;''~!!!!!;;;--=&.....#,;)FzsyBBCAyz/F{)!;-,=#%+....@*--;;;;;;-->,>$---;;;;--,*#&....@#=-;;!~'!~!!;;;;;!!!!~!!;-=@...&$>--;!!!!;--->----;;!!!;;,#+...&$>-;;''~'';;;;;;'!~';;-==#+...@$,-;!!!!;;---=-,-;;!!!;;--=&......@#>--;'''~'~))~~~''!;--=#@.........%,-~FJAvuvHs/{';=&..............+*=-!{IAGELGyr]!-#+............+&=-')FJALLLGs/);=#.......................................................................",
"..+%*=-;'!!~~~'~'~~'';;--=$$%@......+&*$>>-;;'!!'~!!~~~'!';-,#.....+%*,-;;;;;;;;;;!''';;--=*%+.........@#$>,-;!!!~!';';;;--=*&....+%*,;)F/QrKzK^/:{)~!;-=$*%@....@*=,-;;;;-->==>*>--;;;;-=>$%@....@#*,;;!'!!'';;--;;!!'!'!!;-$@...@*>,--!'';;-->==>>--;!!!;;-*@...&*=,-;!!!!;;---;!''!!!;-=$#@...&*=,-;';!;-->===>,-;!!!!;--=&......&#=,-;;!!~~~)_~'~!;;;-,>*@.........@*,-~[6www5}_;-=%+..............+&#>-'15wNwO<('-=&..............+&*,;!2IOwwO[_;>*@.......................................................................",
"..+%=-;_(1111|({:1:1(((';--=*%+.....&$*,-;;~((1::111({:1{|(!;*@...+#*>-;~_)|{1)__)(||(((~;->#@.........&*=--!~(1{::|)((__~;->%+...@%>-c|}<<I5P5<[4}e:1_;-,*%@....&*-;0~||b~;-,>=--c_|)(~!;,*#@....&*>;!(b|{b1||_!!!_b{1b1{1_'-#..+&*,;;_(b||(~;;---;;~(1b1)~;-&..+&=-!~(b:1b1)~!!_)|b:1b|~;=#@..+%,;;~1b11(_;-->,-;~({11b(!;,#.....@%*>-!~((1:1e1e:11{1(~!;=*@.........&*,3ae5MSY5:~-=#&...............+@#*-;(<OMR64~-=*&...............+#*,'b5YSR8f_3=#@..................++@@@+++.............................................",
"..@*3adeiippghgiijpii7ebda;9=*+....+&>3;aabe4gimppikgiijiigbd9&...@#=,adf7giiiffefgihig4edc3*&........@#>3cabe4iijpig7fffeba-*@...@#>9aeijqqqqqjjjjppigba9,*%+...%,cbegipied03-3cafgig7fba;=*@...+#,;dbgijppijgebdbeipppijigbc*..+#>cdegimiigebaa0adbegipiigbc*..+#=cbgimjpiigbbbfgpijmiiea9*@..+%3abgiipigebac9;0degiijigba;*....@%$=cabf7gijpjpjjjpig7fbd9>@........+#*-cafpqUqiea3=%@...............+&#$9cbijWWjgd9=*&................%=3cbiqUqjgdc-$@...............+@&#&%###&%&@&@@@++.....................................",
"..&,cb4ioqWZomXXoWWonVlkeeba9=%....%=3cde47hVXoqWZnmVXqWWomhe0*..+@*>c(7klmoqomkhhmqZnmVh7bc3#+......&*=3cd:4hmoZWWoXVVllkkea,&...&*3abioWWUTTUUWWWWWqmgba9>%@...#cb4ioqqqmebda0dfiqopVhkedc=%+...*9dfkmqqWWWqoi777iqqWWWWomhb,+.+*cdehpqWqomh7eb{b4hhpqWWjmhb,+.+*3agjqqWWWoi7f7ijqWWUWjib9,#...$_ehmpWWonh7ed_db4hmoqWnphea>+...@*=-aeklVoZqWWWqWWWqnVhkea>#........@*,9abgjWUUpfa9>$@................@*=90fiZWWogbc3$%+..............+#=9afjqUUqibac>#+...........+&&#*==>>===>=*==>=**#&....................................",
".+$!]zxHGDEEvCGDDEDvDBCAtsz/{;$...%,;{/rsxACCGDEEEvGGvELEDHts/-..+*-;]rtCCHvDvHCCCGDEGHBCyz]',&.....%$-!)/rstBHGvEDDHCBCCBtsF~$..+%-~FKtvEEEEEEEEEEEEEGyzF);-%..+>{zyADEEvGxzr/^^sAEDGHCAy/{;,@..+=)^yBGDEEEELDHxtAGDEEEEEvvAz'@.+-(rxBGDEEDCCAszzsyBCHvEEvHtz;@.@-)^JDEEEEEEHAxyBDLEEEEDwr:;=..+,FsAGvEEvvCAszrrstBHvEEDDAx/;@...%,;)/sACCGLEEEEEEEEDGHCtzF!$........#,;)/ztDEEvGKF~;=&................%,;~FItEEEvyr]~-$@..............@$3~:KwEEEvAs/{;-*@........+%#,-;;'))~)))~~'~~~!;;;-%+..................................",
".+*!]zyCGLLLvGGHLvDLHCCCCAyzF~$+.+*-)]rsxBCCCCGGDvGvCvLLLvHAs],+.+%-']rtACHDLvGCCCvvvGCCBAzF);*....+%-!)F/zyBCHvLGLGHCCCBCBs/)$+..#-~]IyvLEEEuEELLLvLvAxrF);$@...>(ryCHDLDHysrr^rKtHvHCCBxr]!-#..@,)/sBHLELLLDHAByAHGLLLLLvHAr;@.+-)^yBGLLLLBCByssstCCGLLLvHAz;@.@=)^sGvvLLLvHAABCvLLLDvGtr{;$+.@-FstHLLLDHCAyzzzyACBLLLLGBsF;&...%-')/sBBCGGLLLLLLLLLvBBAsF;*+......+#-!{/syGLLEAsF~;,%................%,;)FKyLLELyr]~-=&..............@$;~FztLEuLts/]~-=#+.......%=-;!~)]F///FFF]{]]]])~;;,&..................................",
"..&>;{}IJwwwwwwJJJJJPKJKJKI[|;*...%>;~2IKKPsPJPJJJJwwwwwwOP[]~$..+@*=;{F^QPwwwwwJJJJJPsKK^F~-=&....+&>-~{F[IKJwJJJJJKKKzKzI/)-%...@*-;([8JOwOOOOJ6PP85Q|~!-=%....$;{2IJwwwP[2{((1:QPJJKKr^{!-*@..+*;)}QPwwNwOJPI[/[IPOwwNNwK[1-...*;)}IJwNNwKIr/Q^^QIKJwNwwP[{=+.+*-_}<6JOwwwPI[QKOwwOJ65[(;,#..+$!:[PwwwwJKI/F:F[IKJwwwwPQF~=....@*-;(FIKKJJJJJJwwwwwJKQ/]'-&.......+&$-!|[5OwNw6}~->*@................&*=-~2<YwwO<(;-*&+..............&%>-_e5wNwwPQ:!->%@.......+&*=-!~)|}[[}}:]_))_]]1)!-$@..................................",
"..&$-!|28OwwwOO6<[[QQQIPOO8<|;*...#>c([8Ow65QQQ[[IP6OYRwO6<1_,#...&#>-!(12<OSYSSYYP<QQQQ[}(;-*@.....&*-'|[QQPOOP5<QQIKIKIQQ:'-&...&#=-a|[<Q5PPI<<<[[21d'->>#&+...&,_|[8RRM5[1(_a_(:[QQKIQ2(;,*@..+%=;(15OSwO8<Q2}:}[<P6YSMO<:;*+.+#-~1[6YNS8I[[QQQQ[[QPYSSO<}~>...%>c~:2Q56YO6[}[<OOO6<[2(;-$&...%-'|[6OOOP<<[1||eQ5POOO6<1~-%+...+#=-_:QIII<I5I5IKYSR8[}|_3=%.......@#*,'|[5ORMO51'-*%@................+%$3c(<ONR84(;,*@...............@$>3c|<OSSO6Q1~-*#@.......@#$-;_1145665[[}2||:}[[2~;>%..................................",
"..+#,cdfhmppppig7fbee7hpqWqigc>...%-abiqWWoi7fffef4mmpnmni4b0,#...@%*,;abfijWUWWqqmg44774ea3=#......&$3ae7hmnqZpikhhhhlhhk7ba,%...@#*,;df7kkhlhh4eebbba9,*$&@....#>cbfpqZqmg:bdaabb77hhlkfb;,*@...#,9abijqZomk7feef47inqWqjgbc*..+*,cbfpjWWji47hlmhhghpqWqpgfc$...%=9adefhponig4gijopi7fbac=*@..+#>cafgmmmjppgfbeginjXmihfdc,&.....%=-a17hhhhhhilmmoqqigbba-=&.......@**3ae7moWWqiec9*&+................@%*30biqqUjgd9-*&...............+%=30biqWWomhea->%@.......&*>9~bf7gpjopihg77f77kh7b0,&..................................",
"..+#,cdfhVVXXVVkeeeee4hnWUWj7b,@.+*9dgpqUWqm441eef4hVVVXVV7ba3%...@#$>9ab4ioWWWqopi4ffeeeda9>&+....+&=3deklloZWonpmmVlVlVh7:c3&...@#$,0dekhlVVVkkeeb_a09,>#&+....&30b7mXoomk4bddbb4klVVVVk1a9*@..+@=;abhXoonmVlk4e4kVmnoZophb0%..+%90d7mXZonVlmmoonmllpoZZnhfd$+..&*,cabeglnoommmmoXXh7bdc3>#@...@=90:7klXnZom744ioZZmVh7ba9=%....+#=9ae7klllVmnjoooqqi7edc3*@.......&$>9dellZWWqpfac>$@................@*>30fiqUWqgb03>&+..............@#>9ceiqWWZXl4dc=*&......+&=3afhmmmnZoononpmmlVVVl4d9#..................................",
"..+$;~FzACCCCCBxszrzzsADEEEvy^!@.@-(^svuEEDHsszzzsxACCCCCBs^{;*...@#=;'{/sADLvvHHAszr^//])~;-%....+%=-~FrxBHGvEEDvDvHCCCAts^{;*...@*,;)FzxBCCBCtxz//(~';-,$&@....#;)/sBGBCCtsz^/^rsxACCCAAz]~-%..+#-'{/sACBGCBBxssstCCHHHCtz2~*..@>!)/zAHGHHHBvDuEEGHBHHHGHyr],...+$-!)FrzxHHvDvDGGHBsz/{~;-=@...&$!{^sxtHGvDHtyttDDDHAts/(!,&....&=-!{/zxytBCHEEuDDHHxz/]~;>&.......@=-~FsAHGLEvAJF)3=@................&>;~:QAEEEvyI]'-=@.............+#=;~{rtDEEDGts/~->*+.....%-;{^xHuvvGGHGvDuEuDvHCAAs/)*..................................",
"..@$;)FztCBCBCCBszszsyAGLELGx^;&.+-{/JAvELvHxsszzsyCBCCCCBs/);*+..+#=-!)/ztvDDCAxsz^F]{))!;-$%....+*=;'FrsACvLLEuLLvCABAAyz^{!*...&*=-'FryABCCBAsrF{)!;-,=*%+....%-(/ztCCBBysr]FF^zyACCCCxzF)-%...&$;~FryBCCCCBAssyABBCBAysr];*..+#;)FzyBBCHCHGEEELGCCCBCCtsr)=+..+*-;)]/zstCGLLEvHAxs^]);-$%+...+#>~FrzyAGLLvCACHGGHByzr]~-#+....&$-;)FrzsyABHLELLGCtsrF]~;$@.......@#-!{ryAvLEDHzF~;=&................%>;)FKALEuDxr]';*@..............%=;)FKALLLGAyz]'-$&+.....%-']IyGLLLvBCvLLEEELvHBCBs/'$..................................",
"..+&=-):^KKJPJJIQ/}[/QKOwww82(-+..#;)25wwwOPQ/[[/QIJJJJKKr[);$&....+%$,-!1QJwJK^}]_~;-->>**#@+.....&#>-'{/^KJwNNNNwwPK^^//F(;-%...+&*>-~{F/rIzI/})!;->==$%&@+....@>;)2rKKKI/F(_')(]F^QKKz[F';=@...+&=-'(]/^IKKrQFF//IzKr^[F);=&..+&=-~]^KKJJKKJYSNNOPKKJsKIF(;%....@*=-;'{2QKJwNNwPI}F~;-->%+.....+@*-')|}I6OJOOJOJJ5[F(!;$&+.....+&*,;~{]FF[Q8wNNwJKQF1~;-*%.........+%=-~:QOwww6}_->#@................+#=-_:<ONwOQ_!->@...............@*>;~:5wNwOQ}(;-$&.......@=-!|<OwNwJPPwwwNNwNwPKI/F'-&..................................",
"...%*-'1[IIP6YO6Q[[[Q<POSRY5e'=..+#-'b<OSROPIQQ}[[5OYOPIIQ1~->&.....@**-;d46Y8<}1(';>=*$*$%@.......@#*,;(|}[KOwwSwOOP<Q[[}|_;=&....@%*-;(:2[QQQ2(_;-,>>$*$%&@....+%-'([QIIQ2|(~!!(|}}QQIQ}|~,*+....@%=-!(|}[QI<}}:1[<I<[}(_9-#+...%*-c(}QIIII<6YNNSO6<P6PK2:'-#....@%$=-;(:}<8YSSOI[:(_;-*%@+.......@*>-;_2Q88RRRY8<}(;->*&+.......@$*-;_(|}4<6YSSO5[}|_'->>&+.........@*>-_e6RSO5:;-=#@................+&*-;b<OSR84(;=*@...............+%*,0|<YNR8e(;-$&+.......+#=3_f5YO6<<Q68YOOYO6<Q[:(3#+..................................",
"...&=3017hlmjqqjikhhlmpoZqjibc=...%,;bgjqqomlhh4hijqqjmlhkea3=&.....@*=3cbgpqjifbd09,>*$##&@.......@#*,;abefgimVmXmpnjmih7ebc,&...+@%*-;dbe4khk4bd0;-,=>***%@....+%>cb7hhh77ebddadbe4khlh7ba3#.....+%*,;abb7ipmg4ffhppifbdc9=&....%*,;afhhllllpqWUUqqjpmmh7ea,%....@%$,;0de7ipWWWjmkfba;,>$&+.......+%$,;af7ijUTUqigea9,*%@........@**-cdbfgijjjjpmh7ebbdc9>*+.........@#=3afjqUqiec3**@................+%*,0bgqUWjgdc=$@................#*-0biqWqjfd3=#&+.......+&*,cbgggheeffgigihi77b1dc-#...................................",
"..+#=9aehVVXoWZZnpnmXnXooXpgb;%+..&=3afinnnXVlVVlmnZZoXXVh4b0,%....+#>,;afhoZoikeed!c3>**%%+.......&*,9abe4kkklVVVXXZZZnVlk4d9#....@#*3ab4[hlVlkeb(a~c09c3>=*&...+*9_ekVVVlk7ee1b:4khVXVVk4dc=@....+@*=3adfhnZomhkhmoom7ba;=$%....&*,017lVXmXnnZWUUWWZoXXVhea3&...@#$,30_e4hVoWWWZmlk4dac,=#@.......@#=99bekmqUTUqmkba9=$&........+&$,9'b:7ioZonXVlh444ee{ac=#........+&*>3afjWUqpfac,*%@...............+*,30fiqUUqgbc3*&...............+#,9aeiWUWogb03=&.........&#=90bbfbbbbbffefff4ebdac,%+..................................",
"..+$;)/zACCHHHGvvDvvGHCHtysQ{!*...@>c{^sxtGCHCCCCCHGGCCBCByr]'*...+#,;_]^stDLDAAssr/{);-,*$@.......#-')/zxtBCACBCHCGvLGvHHBy^{=....&=-!{^sxACHHAyszzrrr^F])!-$+..@='FztCCCCCAyssssytBGGGHAsr]-#.....&*-;{FrxHvvHHBHGDDtK/{'-$%....*-!{^xACBGvvLLLLLEELGHBCtzF;%...%>;'{/rxtCGLEELDGHByz/]);-*+......%=-'(/stCGEEEDys^{;-#@........@#-'{/zstCDLvHHCCCAxtyyzr{;*........@*,;)2JGEEEGK/{;,*@..............+%=;~]KtDEEvyQ);-%...............%-;_[VwEEEvJr]~-*+........@*,;_1///}//}/}//^//^F]);-%...................................",
"..&*-)/sABCCCCCGvLvvGCAtsz/F)-*+..@*,!]/zsyACCBBCBCCBCCCCAsr]!$+..&=-~]/zyALLGCBtxsz/]~;-,*&.......#-!]rxBBCCCCCCCCCBHGGGLGtr(>+...+%-;(^zyAHGGCBtyyAAyxzr/]!>%..+>'FzyCCCBCBByyxABCCGvLGHyrF~#.....+#=-!{[zABGvvLvGHHAzF);-$@...+%,;{/sABCBGLLvCHGLELLCCAAz{;@..+*-!{/zsACGGGHHHHGGCAAsr]~-$%.....@#--']rsACHGvGtsrF);$#+........&=-~FzyACvGLvCCCCACBBBAtz/~=+.......&*,;)/KALvuts/)'-=%...............%=-;]KyvvLvy/);-*+.............+%>!{/sALELGxrF~-*.........+%$-!~)){))){)]){]]]))~',*&...................................",
"..+#=-~FIKJJJKKKP6PPIQ/:{)!;-#&....@#>c'){F2^QrQIrKKKJJJzI}{!-&...&*=-)|}<POwwPK^Q/F|)'-,*#&+.....+&=-~FQzKsKJKKKIKKKPJwNNwP]!$....+@$>;){}IJwwJKIrQrKrI/[]_-=@..+*-!{/KzKzKzrQ^/rIKJwwwwJQ:)-&......+%*=-~:QIPwwwNwKI2(!-=%+.....+*=;~]/IKJwwwPIQIJwNOPI^/{;*+..+&=-']/QKJwwJQQIPJwwKI/2);,*@.....+#=--~{[IIKPKKQ}(;-$&+.........@*=;'FQKKwwwwKKrKrrzzKzr[{;*.........&*-;_}8Mww6}_;->*@...............@#$-;1<POJK[(;=*%...............&$,;)}5OwS8[_!-*&..........+@%#$=>>>>=->-,--,--==*#+....................................",
"..+&,-~|[QIQQQ[[}21:|(_~9--**%......&#$>-;!((|11:}2QQIPPI[}_;>&...+$>;~:2[5OYO6Q[[22:(!;>$#&+......%*-;|[QIIPPIIQQQQQI6YNNY<:;*+....@%$-;(|[5OYP<QQQIIIQQ}:_-*@...&*-!1[QIII<Q[[[[QIKJwwY5[(!-%.......+#$-;_}Q5OSNYO5[1~-,*&+.....+@#=;_:}[5YM65}2[5YY6<[}(!-#....%=-_|}QI6OO5[2[<6OOP<[}_;>$&.....&*>-;_1}[III<Q}(!-=*@..........&#>-~|[<IORS65QQQQIQIIIQ}_;%.........@$$,a:5MSY5e_;-*#@...............@%$=3_2<I5[:'->#@..............@&*-9_:5OSR8ea-=#@.............@@&%%&&&@&%*#$$#%%@@+.....................................",
"..+%,;ab4hhlhh7ffbbda0c99>$#&@......@%*$=3390addbee44ilmlke0c,%...@*,0bf7kpqWqmhk774ebac3=#&+.....+#*,0|45lllmlhhkhhhipqUUjibc*.....@&*,3adfiqoplkhkhhkk74e03*@...&$,0b4hhhVlih7hhhlmoWWqpgba-@.......+%*,9af4ijWZopl7b0->*&.......@#*30bf7ijqjgffgiqqphfeb;,*+...%=;dfghioqqigf7ioqomhh7bc,*&....&%=3adbe7hilllh4bc-**@..........@#=-ae7hmjqWomhhhh5hllkked9#.........@*$,0fiqWoiedc-*#&+..............@@#>3abkhh7bc3*%@.............+&#=3cdfiqWqpf0-*#@.................+..+.+@@&&&&+.+.......................................",
"..+#,a14lVXlllh7e:bdac9,=**#&........+@#$$>-cadb:e4khVVVVl7ba3#...%,9d7kmmoZWqoVlhlmh7ed03=#@.....@&$-c:kVVVVXlXmnmnnnnjqqjgb9%.....+%*=3cbfinonmnmXXVVlk71a9=@...@*,9de4kVmXnmmmlmVXZWWWoke03#........@*>9ae7lnoZZnh41c,*#@.......&%>3a1f4inomh7egmoomk4ed03*@..+*3afkXmooZomk74loWZonmi7bc,%...+#>cdeghimpnXonXhea9>#&..........&*>9deklXnWZqnnmXmnXmVVl4d9*.........@#>3a7pWWWphbac>$#@..............+%$=3aekllkb0,>#@.............@#*>9db7mZWWjgd9>*@........................++++...........................................",
"..#-)/zxAHHHCCCtssr^]);-,=#&@.........+&*=-;!{FrzsABCHHHHBAz/)=..+*;(/yvDDuLEvGGCHGGvAs/]~-=%.....&#-;)^xCCCCCHvvDvvDvvvGGxK2)$......%=-;~]/stGGDLGvHCCtxz^]!-@..+%>;~{FrstCHvLDDGGHHvLELDts/'*........&#-!{/zxHHHHAszF);-#+.......%$-'{/zsxAHAyzzzyHBAssr/);$@..+>)/sGDDvvvHAAxxHvvEvvvHy/(;*...&,~]KtDvDEEEDvDDAKF';=*+.........%>-~FstCCGLEvvLDvDDvHCCAs/!$.........@$-!{KAvDDGyz^{!-=%+.............+%=-;{rxtys/);>*&............+#=-!)/zxGDLLAK:)3=&.......................................................................",
".+*;)^sAGvLLLvGCBssr]~--*&+............+&*>-!{/zxxCGGvLLLvBtr(>+..*;)^JGGvDvLGHCCAHvGxz/]~-$&+....+#=;)/sAACBCBGGDLvLDGAxsz^];#......+#,-!~FzstGvGvGCBtyzr/);*+...+$-;'{FrstCCvGLvHCBGvLGGAzF!#.........#>-;{/zxBBAyz/]~-$%+.......+%--)]^rsttyzr^rsxAxsr/])-$+..@='1zwGLDHCAAssstGvLLDDvy^);*+..#-'/swvLvuuuEuvutz]~->&+.........&=-']ztACHvLLLvLLGLGHBAxz];*+........@*-;)[sAHBAAyrF~;,#@..............@*>;~]rzz/{!-=#+............+#-;'_rsABAGAyr{;-#+.......................................................................",
"..%-;|[PONNwwwwJK[}]~;$#@................@#$,;)F[IPwwNwNNwKQ]'*...@=-~1<56P6PIIQQQ<<<2(!--*&.......&#=-')]F/[[[Q565655<[1();-$@.......@%*=,-_(}Q<85IQ2F{)~!-=&.....@#$=-;)1/[I5P6I<QQI5P5[2(;=+.........@%$=-'(F2/2](!;>$&+.........+%*-;!){{]{)!'!({]1))~;-*&....%,!|[55KIQ[/]1:}<55655[:0-*&...@$-~2I8JOOOOOO8P<1'-=#+...........%*,;)]}^<I88888666I<[/]);,&..........+#$-!(:}2/^[])-,$#@...............@%*--;!!;-=*&@..............&*>-;|2Q[[}1(!-=*+........................................................................",
"..&$;_}[POSSSYO5Q}:~;>*&+.................&*=3~(}[IOwSNSY852(;*+..+%*-c_(1|||1((((|(a'9->*&.........@%*,-;;~_(((|111|1(_;--,*@.........@&#$=--ca||1_(!;;-->=&+......+&*=>-;_((|111((((|||_;-,#+..........&%$==-;!'!c->=#+............+#**,--;---->--;---,==#&+....&$>9'_|1((~~';;0_1111(_9-*#+....&=9a14[[2<<[<[}|';=*@............+%*>-;;_(111|||1111(_';->*&...........+%#-9!_((|(~;-**%+................@%#>$>>=$*&@...............@%=>;'||1(_~;-$*@.........................................................................",
"..&*3abfgimipi5g4b1a9=#@..................@#=3cdbfgiipipii4ba3%....&%$,,3c00000ccc;c9,>*%&+.........+%#*>,-39ccc;cc0;cc99>**%+..........@&#$>>,39;0cc,,>$*##@.........&#$=>39cc0c0c00;c;993>*&...........+@%$$=,-3,>=$#&..............+%#$*===*=$>>*,,=>$##&+.....@%*>,99cccc3-,,399ccc39=>*&.....&$,0abfbfffffbbd;3*%+.............+%*$>,99c0000c0c0cc9,,=*&+............&%$33c00a0c=>$&@..................@@#%%%%%@.................+&**,9'ac0c9,>#%+.........................................................................",
"..&=30d:47hhhkk4ebd03$%@..................@#$,0ab|47khhhh7fba3#....@%**,,-99c9c939,,,=*#&+...........@%***==,,,3>--3>-,,,*$#@............@%%$*=,,,,,,,****&+...........+&#$,,3-399933,33->=**@............+&#$$>$>==**%+...............@@&##$**%*##*#%*#%%@@......@%#*=,3,,,,,>>=>,,,9,,>$*#&....+&*39dbeeeeeeeeba9>*&+..............@%*$=,3,-3-399c99,,=*$#&............+@#*$=>--3-,>*%&+...................@@@&&&+..................+@#$=,3-93,,=*%+..........................................................................",
"..#,;)]^zssyyxsz^F])!-*#+.................@#=-~{F^zssysxssrF(;*....+&#$>3,9;;;;-,---->=#+............@%%#*>>--,333-3,---=*#&+............+&#*=>,>,3---=*##&+...........+&*=>--,--;;3;,-,-=$%#+............+@#**===$$#&&+.................+@&%%%%&&&@#%##%&++......@&##*>------>==-----3-,=##@.....%>;_F^rIrrKr^^/{~3$&...............@#%*$------->-;;---$###@............+&**=>------,$%+.....................+.++.....................@#=>--->--=#%&+..........................................................................",
"..@*,!)]/^zzrz^/{{~;>*&...................+&*>;~){F^zrzz^^/{'-&.....++@#*$$*#*#$$$**%%@+...............+++&***=$$==$$*#%#&@+...............+&%%%$$*$##@+................++&%%***$****$**&@@+...............+@&%%#%&@.+..........................++.+..++...........+.+&&%*%*%%##%%%#%%*%##&+......+%>;)({{]]]{{()~->#+.................++@&#**$#$=$****%%+................+&&&%*#$***%+.................................................+&**#$$**&@+............................................................................",
"...+@#*=---;;;-->$$%@++......................+&#=>--;--;---=$%+............+.+.+.+.+........................+.+..+.................................+.........................++...+...++.................................................................................+.++..+..++..++............+@#*$=$=$>=**#&+.......................++.+..+..+.+........................+.++........................................................+..+.+...............................................................................",
".....+++++++.+@+.................................+..+@@+@+++....................................................................................................................................................................................................................................................................................................................................................................................................................................................................",
"................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................",
"................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................",
"...+@&&&&&&&&&%&&&&&&&@+........................................................+...........................................................................................................................................................+&*%%%%*%%%@+.......................................................................................................................................................................................................................................................................",
"..+&*%#**#*$$>*=*$=>=**&+....................................................&%#%###%&+........................@&&&&%&@+................................................@&%%%@+.....@&%%@+.................+&#####&@+....................@&#$>>---->-,=*#@+.................................................+@&&&&&&@+........................+@@@@+.......................................................................................................................+@%&%%&@+............................................",
"...+&&&&&&%#*-,>=>,--==%@..................................................++@%#***%#%@......................+@#%%#%%%@@+.............................................+@#%%%#%%@@&@@&&%##&&@+..............@%**#%##&@+..................+&#*$>==,=,=,>=*$&&@..............................................+@@&%%##%%&@+.....................@@+@&%%&+.....................................................................................................................+@@%&%##&@++..........................................",
"...@&&&&%#*=3;;;-;!;c;-,*@.................................................+&#**>>=>**&@...................++&#*$$$$$*#%&@...........................................+&#*$$$$$*##%###$#$*$*%@.............@%#$$=>>*#%+.................+@**>,----;----->=$*&@............................................+&&%####$$#%%%&....................@%%%#%%%&+...................................................................................................................@&%%##$$*$#%@@+...................+@&@@@@@+............",
"..+&&&%#$,c0adbddaddaaa0;,#+..............................................+&%$>,3c93,>#&+................+@%**$=,,,->>*$%@+........................................+&&#$,-3,,,,=$*$>=>,,,=>$#+...........+&*=3-c33>*$@+...............@%#>=39aad~dddaaa;9,>$@................+++++++++@+...............+&%*$$>>,=,=>>**#@+................+@%$**===$$*&+...............................................................................................................++&#$*>==,====*#%@+...............@&#*$#$#**#&@+.........",
"..@%%*>30_b|447744eb:b:ebd9$..............................................@%>,ca1e1bac,$%+..............+%*=3ccaaadada03=$&+.......................................@%$,9!adddaa0ccccaaadaac9=#...........&$=3~be:bac=*@..............&%$>3'be7giiiiig74eba3=#+............+&%%#####*#*%%@+............+%$=>39;aadaaac;9,*#&@.............+#*-900a00c3=**&............................................................................................................+@%*$-90caaaaa00c3=*#&.............&#**>=3=3,,==*#%@.......",
".+#=>-)FrzyxBCCHABAxxxxxsz/~%...........................................+#=-!)FzyBByrF);>*@...........+&#,;'{F^rzzzzzr/{!;-*@..........@&%%%%%@+....+%#%%%@+......@#-;)Frzszszz/F]F/rzzzzr/])>@........+&#-'{rxBAxr]~-=@...........+&=-;']/sBGGDvNvGGABAsr);>&..........+&#=,,-,,,,-----$$%@........+%$>-!)]/^rrzzrr^/]{!;-=%+..........&*-;)]//rr//])!-=%+.........................................................................................................@#>-;')F/rrzzzrr/F{~;->%+.........@%>-;!)){)){))!;-=$&......",
"..%==;)rzyAGGvLGLGvGvGGCtyz{>...........................................@#-;)FrsACCtzF)!->#&+.........@*>-')FrzsxAtxxsrF)'-=#.........&#=$>>>=*#%&%##$=>>==#&.....%>-;{rsBAtAxszr^/zsxytAyz/{;#.........%=;'FsABCBzF~;>#............#,-!)/sAHGGDDvDDvHCBAr]!-#.........@&*>-;;;;;--;;'!!;-=#+......+&*>;')]/rssxxyxszr^F]);-$@.........&*,;)]/rzzszrr/{!-$&+.......................................................................................................@*=-!'{FrzssyyyxzzrF])!;,%........+#>-!){F//^^/^F{~;->*&.....",
"..%$=-~][IJwwwwNNwNwNwwwK[F~>@.........................................+&#=-;_2IJJJKQ|~;-=*&@.........@%*-;~2QIPIPJKPI[|!;-*%........&%#**=*$$**#**$***=$=$*#+....&*,-~}IJJJJPK[}]2[IPPPJKI}_-%.........%*,;)[KJJK})->*&...........+#=;!~:[PJJJJJJJJJJKKrF~-=%.......++&%*=,-;!;;->-;~~'-,*%+.....+&&$,;;~1}QIKPKPKPIQ}:)';,$@.........@#*-'(F2F/[/QQ[(!>*&+.......................................................................................................@*=-;~):[IPIKPPKI<[1(~;-=%.........%=,;)12Q<<<Q<[1!;-=*%.....",
".+&=-;'|[POwNNNwNNNNNNSY6<1(;#.........................................@%*>3~(}5OwY6[1_;-,*#%@.......@#$>-!176OYwOYYOO5}(!-=#+......@@#>,-,--->=>*>=>>,---,=%@....@*,;(78OYRRM6<}:}<8YSMRR8[(;*.........@$>3([OOO84~-=#@...........+*,;~(:<6O85<<<<<IIIQ[1~-=&........@&$$>-;~()!--;_{:(!,$%+.....@&#*,;(12<8OYOMwYYO8<}1(~3=%........+&*>-'|}[[}2Q565}'-$#@......................................................................................................@&$>;__1[58OYOYOMOO6[:(_;-#+........&$-~:[<8OOOYO5}('->*@+....",
"..&*,;abgpqWUUWUWUUTUTUWoifbc*.......................................+&#$=-cdbgmqUWoifba;3>*&+.......@#=,;afiqWWWUWWWqjgba9=*+.....+%**3900cc;c3939399;c0cc3*@....&*3cbgqTTTTTqigffiqTTTTUqgb3#........+&*,;bgqWqjgd9=%@..........+%=-;dbgpqojlhhhhhkhll7ec9*%........@&*=-;adbba!c;deee0-*%@.....@#$=;abf7iqWWWWUWWWqp74bdc>%.......+@%*-cde47777ipqjga9=#@...........................................+++....+++++..............................................+&#*30defkjqWWUWWWWqji7ebc-%........+#*9afimqWWWWWqgba;>*&.....",
".+&-,0d4moWUTTTUUUUTTUTUqnhfd,@...............+@&%&@+................@#=,c~be7ijUUUomh4|d0c>$&.......@*>3abfpZWUUWUUUWjhed;3*&.....@#*-;d(bb:bbd(ddd(dbb1ddc3#....&$9cepqUTTTTUjhgijWTTTTTqib9%........+#=3abiqUUoib03>&..........%#>cdbehpWWnmlllllVVVVkea-=&........@%$,c0dbee(0cab4ked3$#@....+&*3ca:7klnZWUUUWUUWWnVkked9*.......+%$,9_ekllQllVoZqib9,*%................+@+++++&&@@@@@@+........+@&%%&#%###**###%&&&+........................................@*=9cd4khmnWWUUUUUUWZXhk410,@.......&#,c|7lnZWUWUWqmed03=&.....",
".+%-!{^sGDEEEEEEEEEEEEEEEvts^'&.............&&**>-=$$#&@...........+&*-!{FrzyBHDEEEEHAAsz/]'-%......@#-'{FzyGLELLLLEELGsrF);-%.....&>-~]rsssxysxsxsysyyxssrF~;&...%-'1IwDEEEEEuvAttvuEEEEEEAI)=........&$-)FKAEEEDyr]~-$+........@=-!{^zxAvEEDCBCCCCBCCCAz]~;*........&*-;)]/rzr/{)]^sxzF~-=%....&>-~]rsBHHGvLLLEELLLLDHHAtrF-&.....&*=-~{^stACACBHGLvyI{'-=@............&#*$>=$*$=>,,,>==**&.....+@#=,---;;;;;;;;;;;--,>*%&+....................................%,;)FsyCCGLLEELELELLvGHAAs/($.......#-;)^yAGLLLLLLGtz}{!-=@....",
"..%,;{/sHLEEEEEEEEEEEEEEELBsF;&............@#>=---;--=*%@..........@#-;)FrsACGLLEEELELGtsrF);*+.....@>;)FrKxCLLGCCCAHAys/{';$&....+#-')/stBBHHGGGGGGGHCCBAs/);*...%>;)^sAGGvvLvHByAHLEEvvGts/)*.......+&=-']KtGLuLxr]!-$&........@$;~FrsyCvLLLCCCABABAAAxzF~-*+.......@%-;))]F^/])))Frr/]!-=&....#,!{/stGGGLCvGLLLLLGHGvGGts/~#.....&*-;){/sACCCCCBvLDAr]~-=%..........+%*=--;-;-;--;;;;---=#&...+%==-;;'!!))))))))~~~!'--=*@...................................+%-!{/sGvGLLLLEELLLGGGGLGHtz{,+.....+#>-)/zyBBCBHCHAsr]);,*&....",
"..+#>;_48wNNNuNuNuNuTuNSNw52)=+............@&$>=,---,$$%@+.........@%$-!{/[IJwwNwwNwNwwI[|);,%.....+@*>;)12QPwwPQ[2}}}|(!;=*%+....+&$-!{/rKKwwwwNwwwwwJJzI^]!-&...+#=-~|}QIPOwOPQ[QPOwOKIQ}|!-@........@#>-':<OwwO<(',$%+........+#,;)FQQKOwwOPKrr^/^//FF)!-*&........++#=,--;'!;---;~)!;,$%@....&*-!([PwwwwJJwwwNwwsJwwwwP[(;%.....@#>-;)]/IKzKKKJJwO<1~-=#@.........+&%**,,----;----;--,,>*@...@%$=,-;!!!~~)_)~~)~!;;;--*$@.................+.++..............+%=-~:IJwwwNuwNuNwwJJJwwwOK})=.......+%*-'(]}22[}}22(~;,>$&+....",
"...&>c_}5RwNNNNNNTuNTNNNSO<:~=+............@#*=---;;-,*%&+........+&%=-!(}[<POYMOOOOYR8<1(~;=%+.....&*,;(12QIO6<}|(((a~;-=$#@.....@#*-')[QIP6OOwOwOwOOOPII[|!-%....@#=-~|:}<6OO<}}[5Ow6<}:1~,#+........@%*=c(<YSS84(->*@.........+%-9_e[<P6OYOP5K<[222}:(~-=#@..........+%**=>,,=**=---,=*%@+....@=-!(}<OwwOJJJwSwOPPPPOOO64|;#.....+&$-;~(}[QIIIIPOY6<1;->%@.........@%$>--;'!!!!!'!_~~;;--*@...+*=-;_(1b:1::b:1:111{|1_c-*&..............++@@%&&%&&@@@+........%=;_|<6OwwwwNwOwwOJJJOOw8<:~>+.......+#=-;___((___~;-=$#@+.....",
"...@=9afpqWUUTTUTTTTTTTTUjibc$.............&$>3caa_ac9>#&@........+%$=;de4hhlmmiigiimmiged0;=@.....@%$,;dbf7imi7fbaa0;93,=#&+.....@#*3ab7hllVnmmmmmmnmmllk7ec3&....@%$3;dbfgpqqmh4gmjqpgfbdc,*.........@%$,9bgqWWjgd;=$&.........+#-0fipjojppjjojpih7e:bba3=%@...........@%**$$$$***>>>$#&@.....+&=9abgkmmXoqqppppmlmllmmmkge0*.....@%>c0bb4hhk77khpqjib09>$&........+%*=3cdbbeeebbdbeefbba0-%...&*-cbgiijijijpijpijpiiigbc,#........+@@&%&%###**#**#%%#%+.......#,0bfhimmnqWqopmmmooommmikfb>.........&*=-,cc;cc993,>**&++.....",
"...&=9d4oZUUTUTUTTTTTTTUWZif0#............&%=-ab1eee1a3$#@........@*=9abklVlVVlh744khVl74:d0,#.....+*=3a|4kklVlh4:ba!99,>$#@......@*>9aekVlVXVXVllVVVXlXVVhed3#....+%*>ca|ehnZZpllVXZZnhebac,#+........@#*-0biqUWqgb03=%.........&,0bgpZWZoXXoWWWZnllhk4|dc,$@............+@%%#%%%%##**#&+.......%,017lVmXXoWWZnVVVVlXXVVVlh4d=....+%>-~be4klVVlhhVoZqi7dc3*&.......&#*3;a:4khkhkk4ekklll7eb0*..+%,0biqqWWWWWWWWWWWWWUWWjgbc$@......@%**===,,,,333,,,,>==*%+....+#;_eklVVVnZWWoXVmnoWonmVVlhe9&........+%*=,=,,,>-,,***&+.......",
"...#-_/JGEEEEuEEEuEuEEEEELw/!#...........@#,;)Fzzsssr/'-*#+......+%=;)FztBCHCBBtsssxACBxsr/);*.....&>;)/zxACCCCBxsr/{);;-,*&......%>;)/sACCCCCCCCCCBCCCBCBBs^)=....+%*-!{/zxvDDGHCHvDEvxz^]~;$@........&=3c(kAEEEGxQ);-=&.......+*!FztDLELDHGvEEEELHCAtyz/{~-%..............+@@@&%&&%&%&@........*!]zxCBCCHDvEGHHCCCCCCCCCCCxr;....@$-~FrsxCBCCACBHGDDAs^{~-$@....+%>;;)]rxACCBCBAyyABCCCAxr{-..+$!{IxEEEEEEuEEEEEEEELEEDyKF!#....+&*,-;!))))(){]]{)))~';->*+...&,)/sABCCCGLELGHBCHDEEGHCCBAs{#.........&#*$>,----==**&@........",
"..+%-_/sHLLDEELEEuuEuEEEEvy^;%...........+#,;)/zssxszF);>*@.......&=;)FzACCCACByszzytBtsz^]);*+...@#-;)/sACCCCCAAssr/{~;-=*@.....+%-;)/sACCBCCBCBABCCCCCCCAs^)$+...+&>-;)/zsHLvvCHCvGvHyz/]~-*+.......+&$-;{rJvLuvy/{;-$@........$'FKAGLLLvCHvLEELGCBCBAxr]);*+...................++.++.........+='/zACCCCCGLLvBCACCCCCCCBCAA^-+...@*-)FrstABCCCACCGLLts/]~;=@....%=-;~]/zyCCCCCCAAABCACAAyr{=+.+$;{kyHGvLDvLDDDLDLvLLLLDAzF)$....@#-;'~{]F//^^^/^/^//F])~;-#...&!{ryBCCCCHGLLGCCCGvvvCBCCCAs{$...........+@@%***%##%&@.........",
"...&=;_[6wNNNuSNuuSuSuNNNw<1;&............&*-;~]FFFF|)-,*&........+#=-):rKKKKI^/2F:F}//]_~;=*%....@#>-':QKJJJwJJKII[1);,$%@.......@*--~FIKzKKIrI^rQrIKKKKKr});%.....+%*,;!1[<JJwwwOwOJ<[1)'-=&.........+%*,;([5P6<[_;,$&.........%>!1QOwNwwJPJJOOJJPKJKPI[_;,%...................................*;)F/KKzKJwwwOKQ/QrIKIIrIKr^|>+....&*-!(]/QzKzrKIKJOJ<2{';=&.....%=-;!):[IKJKIrIrrrKzKzK/F_;*...%=;_}<5P6P6J6666JOJwwNwO<})-#....&%=;')|}}<QQ<Q<Q<[<[[}1!-*&...+=']^IrIKKPwwwJJKKJJJJPIQrKr};@.................+...............",
"...&$-0}6wNSNNNNSNTNNSNNSO<19*............@#=-;_)(_()'-=#@.........&=-!|[IIIQ[21((((1((~'-==*@....@%=-~15OOSSYSYYY652(!-*&@.......&$=-~1[IIQQ[}}2:}2[[IIIKQ:'-&.....+@**-;_|[I6YMMYO65[:(;-=$&.........+&$>-~1}[[2(!-=%@.........@>9_48SwYOPII<<I5IIPOYO8<1;,#..................................+&,_:[QI<IIPYR8[}::}[[QQQQQQ[(=....+&$,;_(|}QQIIIII5K<[2(~;>%+...+&*-;(1}Q5OP<[[[QQIIIII[}('-%...@#>3_12}[[[[[[[[[Q<6YwS6<1!,%...+&$>!(|2<66OOOOOY8Y6YY6<(3=%...+#;(}QQQQQ5OSYOPIIIIPIIQQQQ[}-+.................................",
"...&=9afpqWUUUTTTTTTTTUUWqgb0*............&*=3cadbbbda-=#&+.......+%=3ab7klhk4fe1bbdbbdac9>$#&....@#$9agpqWUUTUWWqqpgba-$#@.......@$>-a:7hlhh74feeee7khhlhhe09%......+%*,3abfhpqTTTqmh4bdc3=%@..........&%>90bffffdc,>#@.........@*30fiqWqjmkhkhhhhlpqWWqiea3#...................................%>0b7hllmmooqpif4e4khkkhkhk4b>....+&*,;a(efhlllmlVlmh7eba;=%+...+#,;de7gpjqoi44775ilhlh7ba;=%...@%$3cadbbbbbebfff7gpqWWjgba3#...+#$-abf7ijqqqqqqWqWqqqjif0,%....*9de4hkhkijWWqpmmlllkhhhkhkf9+.................................",
"..+%,0d7jWUUUUTTTTTTTTUUWqmfc*............@*30de47744(0,$%+.......+*=9_}kVVVll<7444444e:dc9,*&....@*,3afpoqqUUUWZZom4eac,*%+......@*,ca4llVlVVhkk7kkllVVVlh4d3%.......&=3cdeklnqTTTqXVk4bac>$&..........@$>9dekhk7eac=*&.........@*,cbgpnnnXmnmpmmmXnWUUqp7b9*+..................................%301klmnnnZZWZpmilimmVVllll7b=+...@%$3adb4hXnXnXonXnXh4:ba9$@...%=3dfimmoooomlllmXnnVllk:d9,&...@#*,30aadddddbbbe4hmZWWqmfd3%...@%>9aeehlXoZoZZoZoZoZojibc>%...+*0bQkhhlVXqUUonnXXVVVVllllkec&.................................",
"..&>;(^JvEEEEEEEuEEuEEEELDyI)*...........@#-~FzyBCCAxz]~->#+......&=;~FzACBCCCCBAytABAAsrF{!-*....&$;_2zyHHGDEEEGBCAsrF);-=%+....+%>;)/sACCCCCCABBCABCCCCCAs^)$......@$;)]^stBGLEEEEvCAsrF)!-%.........+#-;)^stCAAzF);,*@........&=9~:^zxAHCHvDDGGGHDEEEDts^{,+.................................+*;{/sAGDvDEEEELvLEGvvvHCCCAsF-+...&*,!{^zxBDLEDvLEDDvAsz^]!>@..+*;{^xGvDvvGCCCCBHDDDCAysrF~;*...@#$,3!~_))_{]]]F^zsGDEEvAK^)=...&$-!]/zsxAACCCBCBBCHBByK2~9$...+=)/sACCBHGDEEDHHCBCCHCCCBBtz~%.................................",
"..&-!{/svLEEEuuuuuEuEEELELy^'*...........&>;)/sACCCCBs/);,#@......@=-'FzyACCCCACBBBBACAyz/{'-#+...+=-~]rstCCGLLvCCBxzrF{!--*&.....#-')/zACCBCBCCCCACCCCBCCAs/)=+.....&=;)FrsACvLEEELCCtsrF);-%.........&$-')/sBCCtz/);-*+........@*-;~]^zsxtABHGGGGLLGGGGAzF)=+..................................*;{^sAGLDEELLEEuLEuLLvBCCAAs/-+...&*,;)/ztAvLLLELLELvHxzr]!>@...*-{QyDLLLGCBCCBCHLLGCAxzr])-*+...@#=>--;;;;!'))]F/sALLLDAz/)>+..+#>!{/rzssyyxAAAAAtxysz^]'-%+..+=~/zyBCCBHLLvGCBCCCHCBCCCByr'&.................................",
"..@*,;([6NNSuuuuNuNuSNuwNO<|-&..........+%*-;1[KJJJJPQ|!->&+.......&$,!{^rKzKzKzQ/rrIKr/]_!-=&.....&=-'(F[IKJwwJIIQ[]|';-==*#+....+*,;)2rKKKKzKzrKrKzKsKKKr})-%......@*=;!(F[KPwNNNwPK^/('-,*&.........@&*-;_/IKzI}~->*&.........+%=,-;~(]F22[QQIPwwwwJKI[(!-#...................................%$;)}QJwNwNwNNNNNNNNNwJKzK/F!*....+&*=-~(25wwNNNNwNwOK}:)!-%....&=;(<ONwwJKKQrKKJwwJI^/1{!-=&.....+@&%***>$$=>>-'_}<OwwO<1_,%....@#=-'~({]}F}F/2//F:F]{~;,=&...+#-']/QzKJJwwwJKKKKKJJJJsKI/(-+.................................",
"..@#=-_}6NNNSTNNNSNNNNNNSO<_-#...........@=,!1<OYYRR6<b'-*%+.......@%*-':}[QIIIQ<<<QQQ[1('-=*&.....%*,c_(}[<8RR8<2211~';-->$%@....+&=-!1}QKIPPI<Q<I5P5PIII[1~-&......&#=-!(|}Q5MSNNO5Q}|('-=$@.........+%$=3_1Q5KQ1~-=#@..........@$>-9'(11:::1[[<ORR6I<[1_-=%+..................................@*-'(}<OwwNwwwNSwSSwOOPII[2(;*.....@%>>;_1[6OwwwwwMO6[1_!;=%....&=9~[8ORY8PIQQQ<6YY8<[}1~;-*&......+.++@&&&%%#$==9_26OO52(;-%.....@*>--;'______(_((_~!!;-=#+....#=;_|[QKPOwSwP<QQIIPPPP6I[1~=..................................",
"..@#>9agpqTTTTTTTTUTTTTUWjgb;%..........+&*-aepqWUTTqiec9=@........@#$,9d:f4hhmpjjjjmk7eda9>*&.....%*,;dbf7ioqqpgeebbba~0;3,*&+....&*,cb7khlmpojjjoojopmhk7b0,&......@$=-cdbf7ijUTUji7ebdc-=*@.........+&$-cdgmjjiea9=#@..........@*=;abbfeeeeef7gjqqpik4b03*@...................................+%=9abgmjnpnoXpnnooqomlhh7:a3%.....@&$=3cdfgiiiVimiihfda9,*&....&*-0fgmppjjpih7hippm5k74bc9=&............+@@&&%$=,0bfgggba9=&....+@%*=>--;99cc9;cc;cc9-,$#@.....&*-0de7hmXoWqplhhippnmmlkfb0*..................................",
"..&*,abgjUTTTTTUUUUTTTTUUqmfa$..........@*,0a7jZUTTTUjfa9>#+.......@&*>9ad:ekVXqUUUqoml4bc9,*&....+%=3db[klmoWZph44eee:b|bd03=+....&*9aeklVXoZZWZWWWUWZXVlkea,&......@*>cabekhpqUTTqmh[ebac>$@.........@#=3abioZWoib03=%..........&=caekkkk444e47loWZnhkf(c,>&...................................+%=90b7lXXXVXXXXmXnnXXXVV7e03&.....+%*,90abe44hhhhh7fbac9,*&....@=,9d44lXoZoXlhlVVXXVVVhedc=&...............+@%%$,9abfebd;,*+.....+&%#$*==>,-,-,,,3,,==$*@......&*=3dekVVnZZZnmlVXZZnXXVh4d9*..................................",
".+*-'FztvEEuEEELEuEEEEEELvtK]-+.........&,;{QsDEEEEuuuz});>@.......@%=-;)]/zyBHDEEEEDCxz/)!->%....@>;)FztCHHvEEvAAxyysxysyz^{;%...@*,']zxBBCGLLELLEELDGHCAyr{;%.....+#-;)FrsxBGDuuEEGAtsrF{;-%.........@*-']rtLEvvyr]~-=@........+$;{rsBCCCAxxsxxHvDDGByz/);,#...................................@#-;)FztBCCCCHCBHCGHCBCBBx^{-%.....+#*-;~)F^zzsssszr^:(';-*&....@$9~FrsAHGDvGBBBCCCBCCCBsr{!$................+&#=-'(F//F(!-*+......@#*>=,-----,-,>---,$#&+......#,;~FzxBCCDDvDHHBGvDvGCCAz/~>..................................",
"..*-']IyBLLELLLLELELLELLvHyzF-+.........#,!{[sHLEEEEEtzF~;,#........+@*,;)]^zyBGuEELHtsr]~;-$+....#-!]^sBvLLEEELvHGHGGHGvHAs/'$...@*,;{/sxtABCCCBCAAHHABtys^),%.....&#-!)/rxBGLEEEELLGBsz/]'-*.........&=-~]IyGLLvtr]~-=&........&>;]ryBAACBByxyAAvLvBtsrF);=&...................................+#=;']^sABCCCCCLvvCBCCByxzF),+.....+@*=-;!){F/F////F{)';-$%@....@$-'(/rsxBHCCCBCCACCCCCCyzF)=+.................@#>;')())!;=%.......++&&%####%*#%%#%**%%+........&$-!)/zxyBCCGGGvvvvGCBAysr{;#..................................",
"..&=-~1}IPwwNNNNNNNNuwwwP<}(;$..........@*=;_[6wNNSNN8}_;=*@.........+@#=,-!)1QPwNwO<2{);,*%@.....@=-!|<OwNNNNNNwNwwwNwNwwO<|;#....&*=-~{]F22}}}:::11:F:F]{'-$+.....@&$-!(]Q6wwNuSNNNwPQ1(~;=&.........+%=-':<ONNO<|'-*%+........@*-!]^rKzKKKKIIPJOwOK[F(!-=*@...................................+@&*=-~)F}/IKJwwwwJJrQ/]{~;-#........+@&$*=----;-;-,-==*&@+......&*>-;~1}[IKKKKzI^QrKKKK/}_;*...................+&*=,-==#%@................+...+....+...........+@*=-'){F[QKPJwwwwsKI[F{)!-*+..................................",
".+%*,;(1}Q<OOwwwwwwwOOO5Q2(!-%..........&#*-0:5SNNNNY51!->#@...........+&#=,;_1<YNR8[1'-=$%@......@#=9_78NNNNNNNNNNNNNNNNSO<(,%.....&*>-''___~~';;;;;;'__';;=&......@%*,;_|[8MNNNNNNwY52(~;-*@..........@*-'b<YNY84(;,$&+........+#=-_}QKI6OOOO8OOYw64|_!-=#@.....................................+@&#=-;!(1}[PONwwP<[}(_;-,#@.........+@@#***>*****$*#%@+.........@%*=-;(:}[[QQQ[21[QIIQ[:(;*....................+@&%%%&&+.......................................+@*=>-!~|1[IJwNwOPQ}:_!;-=%+..................................",
"..&*>;_b:f7g5iiiiii<iih7bbac=%..........@**,0fiqTTTTqgb0-*#@............@%$=90bgjqqpfd;3*%@.......@#=3agjWTTTTTUWZWWZWWWWqjgb9%.....+%$=9399ccc39-3-3-39c9-,*&......+%*,90_fiqWTTTTTWqieba3,*@.........+&*,;bgjUWjgd;=*@.........+#=9dfhhmpqWqWWqWqqjgbac,*&+.......................................@%$=-c_df4ioqqomhf|a03=$%+...........++@%%##*#%&&&@@+..........+&*$>30be47k774eef4hhkeba3#......................+@++............................................@#>,30defimqqqpi7e(a0->*&...................................",
"..@#=3abb}ef7474477777feba09=@..........@#>9afpqWUqUqifc3>%@.............@#$,cdgpqjifc3>*&........@*>cdfpqqWWWWqZoZoZZZZZopgb3%......@*>>-9-3-,,,>>>=-9;93-$*@......@#$>90bfmoqqUUWWqoi7dac>$@.........+%*,cbiqUWqgbc3*@..........&=cdeklVnZWWqZZZooifd;9>*@........................................+@#$>99abegmpopi4ed~33=#@..............++@&@&&@+................+&#=,9ade444eeb|e4774edc3%......................................................................+%*>330de4imjnmh4bda3,*#@...................................",
".+&=-;)/^rrzrQ^QrKrrKrr^])!;-@..........%=-!:rtGvvvDGyQ{!-=&.............@*,9!{rxtyP^|;3=&........&>3~:rxtGGHHGHGHHHHGHHHAtKF'*......+%$------->======-;--=##@......@#,-')FQstGGGvGGAAsK/{~-=@........+@=3c{IxDEEGx[);,%.........+*-~FrsyBHGGvHHHBAxK/{';>#@.........................................+%*,;!)]/rzsKzK/]_~;--#+...............+@@@++...................@%>;!){]/^///FF/^/^/F{~;#.......................................................................&*--;')F/zsszKr/{)~;-*#@...................................",
"..&$-;)_]]///FF///^^//F]);;-#+..........@*-;)^stCBCCtsr);-$&..............%$-;'F^zz/{';-%+........&*-!)/rssxsxxxyxxAttxxssr/(;#.......+@&*$$$*$####%&%%*#*%@........+#=-;~_FrssxsxsxssrF])!-#@.........@#,')QyGGLvs/);,#+.........#-!]/zsxtBBBAAyssrF{!;,#&...........................................+@#=;;!){]FFF]{~';->%+..........................................+%=-;;)){{)))))){)))!;$@........................................................................@#>--!~{]1FF]{)!;->%@.....................................",
"..+&$=--,;-;;;;;;;-!!;;,-=*%+............&*=-~][^QrQ^F_;,*@...............+@#>,;~~~!-,*&+..........+%=-;'(({{{{]]]]]]]1{()~'-*+............++.@+...+.+.+.............+%**,-;!(({1{1{({~;-,=*@...........&*,;([58P52_-=*@..........@#=-!)1]F////}/1(~;-=*&...............................................+@##=>-------=$$%@..............................................@%$*=>>-->>->,--=>=*&..........................................................................@%$*==>--,3--->$#&+......................................",
"...@%#%%%%#%#%%#**$***%%%&@+.............+%$=;_|:}12|~;>*&+.................+&*>>-->>#&+............+&#>,-;--3;;;;3;-;;;--->*&+........................................@%**=--;-3--;---=**%&+...........@#$,c(}[2:_;,*&............@#>-;!__(|(((_~';,=*@+..................................................&&##**=***#%@+................................................+@%%%#&&##%###%$#%&+............................................................................+@&#%#*$***%&&@+.......................................",
"......++++++..+++...+++..+................&*$,caa_da09,$&@...................@&*#**%%&&..............@%#*$=,,,,=,,,-,>=>=**%&...........................................@%##*$=,,,>===$$%@++.............&*>9adbbdc9>%@...........+@%#>,339;000cc3-=$%&......................................................++&@&@@&++........................................................+.+@&&@%@@@@+.................................................................................++@&&&&@@+.........................................",
"..........................................+&#=,,99399,=*&.....................@&%%%&@@...............+&%#***$=*>=*******#*&@+............................................+@&#****$***#*&@+...............@%=,00bdac=*%@............+@%*$>,,3>,,,,>**&@..........................................................+..................................................................++@+.........................................................................................+@+.............................................",
"..........................................++&%=>>-,=>>*%+......................+@@@+..................@@&##%#%%#%%%***#%#%&.................................................@%#%%####%%@.................+&#=-;~~';=*%+.............++%**$$>==>=**##%@..........................................................................................................................................................................................................................................................................",
"............................................+++++@@@+++..........................+......................+..+.++.++++++.+.......................................................++.+..+...................+++@&%##&&@+...................@@++@@+@++..............................................................................................................................................................................................................................................................................",
"................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................",
"................................................................................................................................................................................................................+...++...............................................................................................................................................................................+@&&&&@+.......................+@&&@+..........................+@%%%%%%&@+.................................................",
"............+@&&&&&@@+......................................................@&%&%%%%&@+...................+&&%&&&&@++....................................................................................+@&&%#####%*####%&@..................................................................................+@@@@+..............................................................................+%##==,,>$$%@+.................+%%$=,3>$*%@+....................&%$>3-3333=$##&@..............................................",
"..........+@#=>333,>*#@...................................................@#*=,3--33=*%@................+@*=>-3333==#@+.................................................................................+%*=,3,39;9c;9c9;33$%+.............................................................................+&%***$*#@+............................................................................#=,ccddddac3=#@................%>9cadddac3=#@+.................+*3caddb{b(a0c,=*&+............................................",
"........+%=,;~{]]]{';->#@...............................................@#=-;){]{F]]);->%+............+&=-;~{]FFF])!-$*@+.......................+&&&@+................................................+%$,;')]F/^^^^r^^//F{~-#...........................................................................@%$>-;'~!!;,*&+....................@%##**%%@+...........................................%>']/rsxysr/]'-$%+.............&,)Frzxxxz^F);$#@.......+@+.....+$~]/zxyxAxysrF]~;,##@@@@@+.....................................",
"........%=-;']F/r/F]~;-=#@.......................@@@+..................@#>-!)]Frr^//]);-=#@...........&=>;!{]//^//])!-=*%@..................+&%%##==*#@.............................................@#$>-;;)F^rrzzszzszzr//{;=+.........................................................................@&*,-!){{])!;-=@.................@%#*$=>,>,==##@........................................+%-)FrstBAAxrF);,*&+............&-]rzxBBBxzF]~-=*@..+@&%##$#&...@,{/zyBBCCBBxsr/]~-,*$#%%*#*&..................+@@&@+...........",
"......+&*=,-!)(]]{_);-,=*@...................+@&@&&&@+.................&*=,-!){]]F]_);-=$%@..........+&$=-;~{|F1]|)~;-$*@@..................+&%#$$$>*#&+...........................................++%$==-;!)]F]FF/FF/}FF]_'-%.........................................................................+&#*>-;!)))~;=*$@................+&#$$=>=,,-=>**%&.......................................+%=;)F/rrKr/F_'-=#@++....@@+....@$;{F/rKr^/|!;=*%&@+@%%%#***%+..+$;)]/rzzzzK^F]_~;,*#%%%#$$*%.................@@%&%&&@+.........",
"......@&#=-;!_(|||1(_;->*&+..................@%#*$$*#&+...............+%#>-!_(||::11('-,**&+.........@%*>;~((|::||((!-,$#@+................+&%***===>*#%+..........................................@%*=,;!~((:}}4}44[}4}}:1!-#+........................................................................@#*$,-!_|||('->%&................@%*=,--;;;;--,$*&&.......................................%=;_|2QI<<}|_;=$%&@.@+@&@%&@...+$!(}[QI<[:(!->$%%&%##$==>>=#@...*!(:[QQIIIQ[}|(~;,>*$$$*===#+...............+&##$#$#%&+........",
"......&*$-0dbeeefeeebd;,>*@.................+%*>333,>$&@..............+%*=cdbefeef4eeba;,=%@.........&*=9abeee4444ebbc9>*&+...............@&*>339cccc>*%@.........................................+%$>90abefgipjjjjijijipigb;#........................................................................+&#=-cabfgiigbc-*#+..............+&#$3;adbdbdaa;3>$#@......................................%=3ab7ipmphfd0,*#&@@&&&##$$*+...*cbfimpmi7ba;=$##%#*=,9cc09=@..+$0be47hhkhh77eedc->**=339cc-&..............+&**====$$%@........",
"....+&#>-0|7klhklkklk4d03=*@...............+#*3caadac,$#@.............@#$90ekkkkhklVk4edc3>%+.......+%*-c|khlkhkllhk2bac>*&..............+&=>;ad(bbedc3$&+........................................&*=3_e7hlmoqqqTTTUUUWWqqpgd,@.......................................................................&#>30degmqUqjgb9,*&+............@#*=3!be7kkkk4ebac,*%@.....................................#,0beinZZomke0;,$##%#*>>333,*..+>_bkmoZZXh4b0-==*=>3;adb4ebc#..+>dek<lllVVVllhked0-33;0d|eba=..............&*=-0'a0c=*&+.......",
"...+#=-;)FztACCCBCBCAxrF)!;$&............+%$-;)Frzzr]~;-$%............&=-)/sBCACCCCCCtz^]~;=@.......@=-;{rtABCCCABCAyz/]~-*@.............%=;~]rzzssszF~-=@.......................................+#-'{/sACHHvLEuuTuuuuEEEvvx[;#.......................................................................%>-~{/stHDuEuw^{'-#@..........+&=-;~{^stBCBCCAAsr]);,$@...................................+*;{/stDEEDHtz/);-,---;!){FF]-@.+-FzxHLELvAs^{';;;!~{FrzsAyz],..@;FsxACCCACCCCCByrF{))F/rsxsr;@............+*-~]zssrF)-=%.......",
"...@*-!)F/sACBBAABBCCAz/]);-#@...........&=,;!]zxHAxr{;->*%+..........&=;~FztABABABCAAs^])-=&.......&$-']ryBBACBCHGByz/])-=&............&*-!)/zyAAtsz]~-=&..........+&%%%##%&@@...+@%%##&+.......@$;']rAGGvLvDvEEEEEEvvGGvtsF;%.......................................................................&=-;)FzyCDEEDtr]~-=&..........@*>-~{FzxBBABBABBts/{~;=#+...................................#;)FzyBHHGHyz/);;--;')]F/rr/;@.@-]/stGGGHAsr]~;;')]/zsyAyyz{>+.@-FrytAACCCCBBBAsz/F]/rzsAAxr;@............&=;)/sAAx/);=*@......",
"...@%>;!(][rKrr//^rKzQ/()~->&+..........+&*=-;(Q6wwP[~;,*#&@..........@#>-~{/^^/^rIzK^F)!->*@........&*,;)F^^rIKJwwKQ]_;-*%@............&#=-~]/rrr^F(!-$%+..........@&%#%#*%%%%&@@&&%&%#%&@......&*,;)}6wNNw6IPwSNSwOPKIIQ4:~=+.......................................................................+%*=-'(}<OwNO51~->%@..........@#=-;){/rKr/^^rrKr/]);-=&............+++.....+..............+&=-'([IKPKI[F~;>>=>,-~(]F[^F-@.+$;_:QKPKKQF_~;--;~)F//^//F{;$..@=;)]F^QKJwwJK^/F](_({F//r^/(=+............@#>;_F^^/(;,#%+......",
"...@%*-'(12QQQ221}[Q[[}1(~-*&+.........+@#$>-c(7OSM64(;->*#%&.........@#*,;_11222}[QQ[(~--*&........+@*,;_|2[2QQIOO84_!-=$#@...........+@*$-!|[IQ[1(~->*&+.........@&##*$=$$*####*###$$>$$%%+....+&>3_b5MNNM5<5YSNSO6I<Q2:1!-*+........................................................................+%$,9~1<6SwO<1;-*%@.........+@#>-!~|}QQ[2222QQQ}|~!-=%+.......++@@@@@&@@@&@&@@+...........@*-;_|[IQI[}(_;->>=,;_|:}}[1-@.+*,'1}QII[[}(!;--;_(:[QQQ}1_-%...#-;(|}[QPOO8<2::(((|:}2[[[2~>.............&*,-_|221~-=*&+......",
"...@#>9adefkhh7e1f7hh74bda3$@.........@%*=,90dfiqWWjgba;9>*##+........+%*,9_be:e447hkfba9,*&........+&*-9abe477hpoqpgbac=$%@............@*=30b4h<7edc3$%&..........&**>-33->==**$*>>,-33,,=#&....+%,cafiqTTqigijUTWqolh77bbc3%.................+++++...................................................+&*,9abijUUjgb0-$%@..........&*,;ab:7kh7fee44hh4bba;=*+......+&&%#$#%*&%%%##%&%@+.........&*,cde4hhk74bd03>>>3adee477f9@.+$,0b4khhh4ebd00cadbf<kh7e:d9#..+#-c_ee4hpqqphffebbdbf477h4e0$............+&*,;ab1bba9>#%+......",
"...+*>9abeklVVh74kkVll7eba9=&.......+%*=-9cdbbgpWUWqm7ed~c93*%........@#$-0be47kkkllkk1a;3*&+.......+#*-cd:4kkllXoonhedc9=%&............&*>3_e4khk:ac,*#@.........&*,c!ad(da093,=,3cddbddac3$&...+#-cbfjUTTTjmmqUTTWZnVhk41a-#+...............@&##%&@+..................................................&>,cafiqWUWieac,*@..........@*9'be4kllIk[kklVlk4:ba9*&....+%*>,3333,=,,-3,-,,=*%@........&>9ab4lVVVlk7ed'c;0d|47kh<k49@..*9dekVVVlk74b(dd|e[kllVl7ed;#..+$ca:4klVoqWoVhkk[447k<llhkea$+...........@**9!de44eb'3$#@......",
"...&=-~{/rxtCBCBAACCCAyr/{!-%......&*-;~{F^zsstDuEEDHxssr^F{;>@......+&=-'{/zxBBBCCCAsrF~;-*@.......@$-;)/zsABCBHHvHtszF);=*+...........#>;~]^ssyz/{~;=#+........+=;{/zsxAxzr/])~)]zxAtxszr]!$+..+$!1QJwuuTEGHHvEEEEGHCAtyrF~,@.............@#>>---->$*%@..............................................+%-;{FzADEEEtKF);,*+........@$-~]rzyACCAtyxBACCByz^]~-#...&#-;){FF]]{){{]]]]{)';-=%@.....+*;)FzsCCCCAAyzz^//rzxtCCCAxz'&.+-~^zACCCCCyyzrrzstACCCCAsz/(>..@;FrsttBCHvGGHCACBAABCACBys^(=............%,;~]rzyyyrF)-=%......",
"...@$-;)]rsABCBBBBBCAAz/]);>#+....&*>-')/rzsxABvEEELHBAxyzr{);#.......#=-!]^stACCBBtxz/{~;,=%.......&$-;)/zxBACCBCBCBsr/);>*@...........&=-;{F^rr/]~;-*@.........&>'FryABBBAxr/F){/JGLHCBts/)-%..+$!]^svEEEuvBGLEEEvGCBBAxzF'>@............@#>-;;'~;;->=#+..............................................%-;)FKAvLEuAzF);,#+........@#-~]^syBBCByxtABBCBxsrF~,%...&=-!{/rrr/FFF/F//r/F{';->#&....+*;)FrxBCBCBAxszrrrsyABACAys/;@.@-]^stCCBCAAxszzstBCACAAAsrF)=+.@;/sAACBACCCCCCCACBBCBCAAxrF~$+..........+#-;)FryBBtzF);,#+.....",
"....@**,-'{/IrrQ^^rI^/1~;-=#+.....@%*=-~1/QQQIKONSNwJPIrQ[2(!>%.......&$=-!(/IrKKzr^/F(;-=*%@.......@%>-;|2[rIrKKKKI^F]);,$%+............%$=-;~)~;-,*#+..........@*-)F^IzsKK^F|)!!([PJJKKr/{!>&..+#=;_25MNNwJJJwNNwwJKzQ/F{~-#............+&*=,;!!!;;->#&+.............................................+@==;!:<Owww5}(;-*%.........@%*-!(]/QrKr^//IrKIr/](!-#+...+&=-~{]}F1{|{1]::}}|);-,=*%+...+%,;):QPJsKr^//}FFF//rKzKr/])=+.+$'{FIKzKKr^/}/2/QzKzKrKr/:~;*..+,)F/^^rIrKKKKzKzrKrrKzK^F_'-&..........+&#=-;)F/zKrF~-,*@......",
".....+#*,-!(|2}}}}22:(;-=*#+......+#$,c~[568688RNNNSYO8666<}_-%.......@*$-~|}QIIIQQQ}1(!->$&+.......@**-a:<5<Q[[QIQ[21(';=#@.............+@%==-,,>>#&+............#-9(2<8OJ8[:(_~~_1<5IKQQ[|;,%...@=-c(}56O68OYNNNSOPIQ[2|(;-%+...........+&*,;!(1:1~;=*$&..............................................@$,-a|<RSNY5f~;,*&+........@&$=;~(|[QQQ[22[QIQ[1(~;,%+....%=-_:2[[[}1::|}[<<41~!;,*#@....#>;(1[Q5IIIQ[[[}:[[[QQQQ[}(;>..+$;|}[<IPK<QQ[[[[QQIIIIQ[[:(;#..+$'(:}[QQIQQQQQQQQQQIQQQ2|~-*&..........+%$>-!(1QI<Q1~-*#@......",
"......&#>=3~a|:e2f1d_0->>#&.......+%$,0eiqqWWWWUTTTTTWqWWqjibc$.......@*=9_ek<hhh<hh7fba;,$#+.......@$=3agjjih7khhhhfbd0-*%@...............@##***#%@+............+#-cdeioqqoifbdaadb7hkhlh7ec-&...@*>9afh5lnoqWUTTUqmhk7ebb9-%...........@%#>9ad:777ea;=#%+............................................+@*,;dfiqTUqpgdc-*%+........@&$>30_b4hhh<77khhh4bdc-=&+...+%=;d7hhhhk74ff7ijji7bda9=$&....%>0bfhhllh5lkh777hh<hhhh7fb0>..+>dekhllmmlklkhlklllhlhlhk4b0$..+*cd:7khhlhlkkhkhh<hhhk74bac=@..........@%=90dfginpifa9=$@......",
"......+%*,-0ade4eeeba93=*%+.......@#,3agpZUWWUUTTTTTTUWUWWWif0*.......&*,0bklVVVlVlVVkebc3=%@.......&*>9dioonlhkllVk[edc9>%@................+@&&&@@+.............+#3ab7mZWWqmhfbdbbekhVVVll4d3#..+&*-9dehlVnZWUTTTUWnVlk441a3#+..........@#>9~beklVlkea3$%@............................................+&>3abgiqTTWp7ea9>#&........@%#=9!beklVVllllVVlkeda9=*+...&=,0|kllVVVVhkkhXqZjl741ac>#+...%-aekVVVVXlVVVVVlVVVVVlllked,+.+,bklVVXlXXXVVXVXXVVXV6Vlll7b>+..=0b4kVVXVVVVllllVVXVlllk4bc3%.........&#>-ab4kmoZZohbc>*%+.....",
"......+&$-;_{F^zzr^]{~;>=%@.......&$-~FKGLEEuEEEEEuEEEEEEvvAk(>......+*-!]rxBCACBCCCByz^{'->&+......&=-!2JDvGBBCCCCAsz/);-*%................+@@@&@+..............%,!]rsHvELvHxsz^rrsACCCCCAs^'$...%,;)/ztACHvEEEEEEEDHCBxsr]~,@..........&=-)FrsABCCtzF~->&............................................%$-~FrxGDEEEGxzF);,*@.......@#=-~]^stBCCCCCBCBBxs^{~-=@...%-!]ryCCCCCCCACHvDEGHAAsr])-%..+$;FzxBCCCCCCBCCBCBCCCCCCByzF;@.@;/xBCBCCBCCCCGHHHHBCBCCBCBy^;@.@,(^zxCBCCCCCBBCBCHHHBCCAsrF'*.......&%>-')/zACHLLEDxQ{;-#@.....",
"........@#,;;){F/F])';-$%&........@$-!{IxtBHGGLuEuEEEvGHGGGs^)=+......#-;)rsABBABBABAsrF)!-#&.......&=-!FztBABBABBAyz/{);=%......................................@$!{/stHvGGAyzrr^rsAACBCCBs/)$+..+$-!]rsytCHGDuEEELvCCAAsr]!>@..........&$-)FzyBCHHBzF~;=#+................+@&&@+....................+%>;']rsyGDGGAszF~;-*&.......+#=;~{/zyBCACACBCCByz/]~-$&...%-!)^yACBCGHCCBCHGvvvHHBs/{!*+.+>;]/syABACBCBCCCCCCBCCCGCAz/;@.@-FzxBBBCBCCCBCBHCHCCCCCCCCAz!@.+-)FrstBACBCCCvCGHBBGGHCCyrF!*.......%,;;)]/sACHLvLDy/{;,*+.....",
".........+%*=,-;---=>#&+...........%*=-~1:}}[2<ORNNRPQ2[}::_;-&.......@*=-~]F/^^r^^/F]~;->$@+.......+#*>;d:2[////FF]_!-=*&+......................................+%>;_:QKPJKI[2{(((]/QKKKKI/~-%....@#=-;){][[IJwNwNwJKK^/F|!-%...........+&*-~][PwwwK['-=%@................+@@&&&@+...................+%*>-'1}[4[[<[2]'-=$%@........+%=-;){FQrKzKzKKrQF]_;-=%+...@#=;'{F[IJwwJKKKIPPOwwwJQ:'-%...#=-;){FF/2/Q^QKKKKKKPwwwOK}(=+.+*;~]FF//QrKKKKKKKKII/QIIJOP}-...%-;')]F/2^QPJwwwJJPwwwwJQ1~-%......+&=-;!)1/IKJOSO8Q(;>$&......",
"...........&&%*****%&@+.............&*=,3c!_(12<MNS6<:1(a;c-,#+.......+%$=-!((1:1:|1(~-=$&@+.........+%*>-c_((||:((!;==$#+........................................%$-;(}QIIQ[}|(__(_:}[III[:_-&.....@%$>,;!_12<6SNYOPIQ[}|(;>#+...........&*>;_1Q6O65|;>%&................+&######&+..................+&**-;~((||||1(_'->*#+.........@*=;!_:[QQ<IIIQQ[:_~;,$&....+#>,;_(:QKOOPIQQI<I8YSS8<|_;#...@#*--;!((11}[QIPPIII<OYwY5:~>..+%,-!__|:}[QIQQQ[Q[Q[22[<885|>+..@%*--'_(|:[<OwwOPKI6SSO8[(!-%......@*>-'(::[Q<<555[1~->*%+.....",
"............+@%%&&&++...............+&$>=,90abfgpqjpgbd093-=*&........+@#$,3c_____0_cc,*#@+...........+#$>99aa_0dac3-$*&&.........................................&$,cdfhhlh7f1bdddde47hlhhed,%......@%*=-30dfgjUUUqplk4fbd0>%............&$=30dfgigfd9>&+................+&$*$*>$*&+..................@#*=9;aaaaaaaac3=$#&.........+%=,;ab7gmmmmpmmii7bac3*%+...+&=39abbginXmlhhhkimWUWqifd9#...+%*=,;0adbe47hhmlikhijWWqpf0>...&=9adb:f47hh77774477777hmigb$...@#$>,30d:f7imjnpmiljWUqjgbc,&.....@%*-cb47hhhhh7efbbc9=**+.....",
"..............+@+.+..................@%*>99adbehmnnmkfda93=*#@.........&#**>999c9cc99,$*%@.............@*==--c9c3-9,$*%@..........................................%*3c|7lVVllk742ee47hVVmXlkb0*.......@#$,90bfioWUUWnVlk7e|a9#+...........@%$,c0abbbac,*&................@*>,9c0c93>*%+................+&%$=33393!93-9>$#@@.........@*=0d:7inqZWZZWqZXi7ed03#+...@#>30d|4klmXVXVllllnWUUqp7bc$...@&#*3cad|ekhlVVVVVlVnZWUZpgb,+.+%-9_b4kklVhlk7e4f4kklVVllkgd=+..&#*>3c!b4klVmXXVllXoWUWjhea9#....+&*>cb4hVlVVVl[4eedac3>*#+....",
".....................................%>-3;!)FrstCCCAyz/]~;-,$%.........+%#=>--;;;;;;--$#&@.............+%$---;;;;-->=#&...........................................*-'{rxBCCCCCBtyyxABBHHGGGtz{-.......&==;!)/zxvEEEEDHCAysr]~>@...........@#=,c!a_a09c3=#...............@=-;)Frzr/{';>*@................@&*>--;;;;;;-->=*&+........@%-;]/zxGvEEuEEEEELHszr]'-@...%=-~]^zsyCCHBCCCCBHvEEEEGyr{-...@#=-;(FrzstBCBCBCCCHHLEEEGs^;@.+=;~FzxACCCCAxszzzsxACCBCAxz],+..&=,-!)FrxBCCCBCHCHBvEEEDAs2)*....@$-'{ryBCCBCCAysszr/{~!;-*@...",
"....................................+%=-;;!)]^sABBCBxz/]~;;,=&+.........+&&#$---->>$$%%++...............+%%#*$$=>-=*&+...........................................+*-;{^yCCCBCCABBABBCCBLLLGAzF,+......&*,-!)FIyGLEELvCCBAsrF',@............+%=,-;!;;--$#@+.............+#>;)Frytyz/)!-=#.................@%#*,>,-,->>$##&+.........+%>!(/zstvLEEuEEELLtxz/]!>&...&>;~]/zsyACBCCCBCCBGLEELtsr{=+...@$-!{FrzyBCCCCCCCCBHLLuLGyr;@.+$;)FryBACBAAszzrzzyBBCCBByz]-+.+%$-;~]^zyACCCCCCCCCvLELGts/)$+...+=-~]ryBCCCCCBtszzr//])~;-*...",
".....................................&#*>--!_(FQIKKI/}_~;->*%@............++@@&@%%&+++....................++.+++@&&@..............................................%=,;)/IJJsKzKrrrrrKJJwwwOP}~=.......&#*>-;):Q6NNwOJJKr^/1);*...............+&%**##%&@+...............@#=-;(/KKK/|';,*%...................++&&@&&&@++.............+&%=-!(2<6OwwOwOwOJ<:(~;-&+...+#=-~(F[QKKzKKKKKKKJwwwO<2(!*.....&=,;)]F/IrKKrIrIIKPwwNw6[|-+.+*,;)F[rrIrI/F|{(]:[IPPKIr}];*...@%=,;'|F^IKKrIIKrKKwwNwO<}_;%.....%=-'{/IKKKrI^/}]:F}F|)!;,#...",
"....................................+@#>-;!!(1}}Q[Q221(~!;-,*@.................+..................................................................................&*=;_}QPPKIKIQ[[[[IKJwwSO<|!*+.....@&#$,-!_|46RNNYJP<Q[}:~;*+................+@&&+++.................&*>-~14P66<:~;-=%+......................+....................+%*=-c~12<[<<<[<421~;-,*&.....&,;_:}[[QIIIQ[[<866665<}(!,%.....@*,;~1}[QQQQQQQQQIKOSNR84_,+..%-!_:[QQQ[21__~(|}[QIIQQ}:_;#...@#>-!(}}[Q[QQ[QQQ<IJSNR8<:(;#.....&$,;(2QIIIQ[21|(|:}}1(~;-*+..",
"....................................@&*-cadbbee4k774febbda09=&....................................................................................................&*=3aehkVmmmmmimiilmjZWWqifd$......+%*=3cabfgjUTTqomkhk7eb9*........................................+&=3cbfiqWqpgba9=*@............................................@%*>,93caddd0daaa;9,=*%@....+#>cb4khllhhk777iqqomh7eb03=&....+&*-0b44hkkhhhhkhhhmoWUqpgb,+.+%9abf<hh7e|da0ade4khhh77f:a9#...&*>;df7kkk4k7k7khhmjWTUjgfd9%.....@*,;dekhlhk7f:ebef7kebd03*...",
"...................................+&$,cd:44[kkhkllkkk4ee:da3#+..................................................................................................+%*,cb4lXVXoZZqZoonXXZZWWZphb,+....+%$,cabe7hmqUTUZoXXmVlhea,@.......................................&$>9dehpWUWoi4dc3*&.............................................&#%>=99990c0c399,>*$%@+....&$9d4hVlVVVVlkhhXoWomhk4ba3$&....+#=9_ekVVlklhllhlVlnZWUWol49@..*cd:kllVh4:bddbe4hlllllkkeb0*..+&*3ceklllIlhkklkhVXZWTUqm7e0*.....&*3!b[lVl6VVhk47kIllk4eda>@..",
"..................................+%>-~]rsytBACCCACBBBAyysr/)-%..................................................................................................@=-'{^sBHHGLLEELDvvHBvLEEDHtr;@...+%=-~]/zxAGvLEEEELGvGGGHs/!#......................................+#-;)/stvEEEDBsr{!-=@............................................+%#=3-cc00~0'0;;3-=*@.....+*-)FstCCCCBCBBABGvLGAysz/);>&....%>;~/sABBCABACBCBCHGEEELvAs)@.@-(^zxBCBxzr//F/zxACCCBCAtyr(-...#-']ztBCAABAAtACACHGEEEDHxz{=....+#,!]rxCCCCBCCBAAACCCBxs/];%..",
"..................................+*>;)/stCCCCBCBCCCCCCCBCxz]!$..................................................................................................@$-!)rxCBHGGGvGvGHHABBHHGHxsF;+...+%=;)/rsAHLLEEEELLLLLLLGx^~*......................................@#>!{/sBvvELGHsr]'-=&.............................................++%$,>----;->--$*%@+......*;~FzABBCBBBAtyAAHGtysr/]~-$+...+%,;~FstAAAyyAtBABBABLLLLvAz)&.+,{/zyAAAsr/]]F^zyCCBCBCCCtsF,+.+%>;]ryAAAyysssyxAABvLLLvCyr(=+...+#=;)^stCCCCCCBBBBCBCAysrF;#..",
"...................................%*,!|5JwwwwwwwwwwwwwwwOK[(-%..................................................................................................+&*-;)}rPJKP5<Q[[[[22:}}}:(_-#....+@*>;)|}QJwNNNuNwNNNNwwO<|;&.......................................%*-~1[IOwNwOK}(!-*#+.................................................&@@&#&#%&@@++.........@$-;(F^^^//FFFF2[[[2|)~;-=%@.....@#=-')FFF]]]]]]]]/2IJwNwJQ1-@..*;')]]]]{!;;;;_:QJJJKIKKJPQ($...@*=;)FFFF]]))){]FFQPwNwJI[]!*....+&#=;)F/rIKsKKIrIKKzKI/F(~,+..",
"...................................@$=9|IOOYYwYwYwSwOwYOOM84_-#...................................................................................................&$=-_:QQI<Q[2||(_~'!!0c0c9>#+.....+&*=;_|[5OwwSNNNwwwSwR84~,&.......................................&$,;(}<8RSR6[:~-=$%+......................................................+................+&=-!(::(__~___(||(~;-,=*#%+.....+&#=-!!(_';;-;;!!_145OYO52(-+.+&=-;;;!;--==,-c([6OPQQQ<865_$+..+&*-;~__!;;;;-;;~(}<6wY8<:~-&.....+&#=-_11[<PJ666668O6[:(~-*+..",
"...................................@*=9agijpppjjjppjpjpjppgfa>%...................................................................................................@#=3a:7hlh7fbd0c033->>===#%+.......&*>3cafgijjjjjjjjpjppgfc=+.......................................@$>;af7ijqjigb0-*%&+.......................................................................+&*,;00_a9,390000a0;3=>$#&&.......&%$,99cc9-,=,,-3cabgimigea$...&*>,3,-,,>**>-3afgii7f47iiga#....&#>390099>>-=,-90bgiipgfa03&.....+@%>,;adbgjqZqqWqZqjgba9,%...",
"...................................+%$,3dbffg777g7gg7g7gfgba3=&...................................................................................................@*>-aehlVh4eb09,>*%&%&&&&&.........@#$,-0affg7g7g7g7ggffb09*........................................@%>3db4hmpihedc->#&.........................................................................&#>>999999,9,3,;99,>>*&@+.........&*=--9,->>>*$>-90cdfffba3*+..+**=>>$=**$$=*33abfbebbfbbd3#....+%*,93>-=>**>=,330abffba03=@......@#$=30aehoZWWZWWWZoibc9>#+..",
"...................................&*=39ad12F4///F///[F::1dac>%..................................................................................................+%=-!]rytBxr/]_9,#%+................@#=-9'_1]}/[//F2FF1:(d!9$+.......................................%=-!]/zsxtys^]~;=*&........................................................................+&#=>-;;;;------;--,==*&++.........@#$--->===>===--;~a(b{(!3%....%*==-=,==**=,9ca_|{]]{|1da,%....+%*=>--==>=*=,-;;'ad(1{_';-&......@#=-;_(FIyGHHHHHGCxKF~;,#...",
"...................................+&#=-;!~){())))))({))~~;--#+...................................................................................................&*,;)FrszzF{~;-*%...................+&$-;;!~~'~)))))~)~~;;-#+......................................+&#>;)F/zsysr/);-$&+..........................................................................+%$>,>->,=,=>$$$*%%%+.............+%*#*#$**=$**=,--;;';;;>&....+&%*%$##%&%#*=,-;;''''!!!->@.....+&%#**%%@&&#%$->-;;!;;;-,#+.......+%>,;')F/rrrzzrrr^])'-*+...",
".....................................+@%*>==-->===,-->>,===*&+....................................................................................................@%#=-'){{)'->=*++.....................+@%#==,>=>>=,,>,>=#%&+........................................+@#=-;'({]1)'-=*&+.............................................................................+@@@&&&@&@&&+.++.+...................+@@@@&&@@#*&%*$*%%@........+.++.+....@%#*$*#***#$#@...........+++...+.+&%&%*$*%%&&+.........+&%#$>3;;!;!!c!;;-==#@....",
".......................................+@@&&#%**#*%%%##%#%&@@.....................................................................................................+@&#=-';!!;=$%@+........................++@%##$*%$##%%%%@.............................................+%*$--;;;-==%@......................................................................................+.....................................+++++...+......................+&@+@++.+++......................+.++..+................+@%#*=>=======**&@.....",
".........................................+++@@@@@&@@@@@@++...........................................................................................................@%*,,,=*%&++............................+@@@@+@@+...+...............................................+&&%%#%*%&%@..............................................................................................................................................................+.......................................................+@&&%%##%%%%@@+......",
"...............................................+..++...................................................................................................................++@@@++.+...........................................................................................+++++.++..........................................................................................................................................................................................................................+.+.......+........",
"..........+++@++++.............................@@@+@@@+@+....................++++@@++.........................+++++++..................................................++@@&&&@@&@@++...........................+.......................................................+@+@@@@@@++............................+++@@@++....................+++&&&@++.....................................................+++++++................................+++++++++..................++&#$$$#&++..........................................",
".......+&*>=-,-->$*&+........................@#*$=>----=*#+...............+%*$------>*%+................@&%%#*$$>>>>$*#%@..............................................+@#=,-;!;;-,>$#%+.....................@+@@&@@@@@@&&@...........................................+##>>,--,==$*&.........................+%*>>,-,>>$#@................&*>--!;--=*#@................@&&&%%%##%%%%%@+...............+%*==----=*#%@.........................+&#*$---->>*#&@.............+%$>-)~))~;>$*#&+.............................+........",
".......+#*-;!~';-=$%@+......................+@%=,-;;~'~;**@...............+*=-;!)));-=*@...............+&%#*$=,>>>>>,=$##@..............+++++++++@@++++...............+&%=-;'))({)!->$&@...................+@%%&&%%%%&%&&&&++..............++@@@@&&@@+@&@+............+%*,;'~!;-,=*#+........................&#*--!~;--=$#+..............+%=-;')~!--=*%+...............@&%&#$%%#*#$##*&+..............+#*,-!~';-***&+........................+%*=>;!';;-=$%@.............@#,-!)]1|)';=*#%+................++++@++.++@@@+........",
".......&*=-;~(1_;-=$#@......................@%$>-;;((1~;=#@..............@#*>;!((||_;-*#&..............+&$$=-;;;;;;;-,=*%&..............+@&&%%%%%&&%&&&@..............+&#>-!(|221|';>*#+..................+&##*#*#**##$####%@.............+@%##**##*##%%%&+...........@#*-!(1(~;-->*&......................+&%$=-;((_!-,*%&.............@%*>;_(||(!-,>*&+.............&&%#$$*>>$*$*>$*#%@+............&*>-;~|(~-=*$#%+.....................@&%#*=-;(1(;-,=#@............@#>-;~|}[[:_!-=*%@..............+@&%%&&&&&&%&&&&&.......",
"......@%$=90deeba;,*#%+...................+@#*=3ca_bbedc,*%+............+&$=30abeeebc9=*%+............@%#*>3;aaaaaaaa;3>*#@............+&&##***######%%&+.............@%*,;abe474edc3*#@.................@%*=>>>=>>,,=>>==>>#+..........+@%#**>>==>=>==*$$&+..........@#*-abeb_a0;,>*@+...................+%#*>,;abeba;3>#&+...........@&*>3abeeebda3>$%+............+%#$=3-3-3>3-33,,=>#&+..........@%*=3ade:dc9=$*#@+...................+&%#$>3cdbeb_c3=#@...........+%*,;ade77kfbd03=*@.............@%%%#$*#%%#%####&%@+.....",
"......@$=,;de4k4bdcc,*%+.................+&*=,ca1ee444:a3>%+...........+&$=9~b}7khk[b~c,$#@..........+%=,99dbe44eeee:bac,=#&..........+#*=>,-3-,,==,,-=$*@...........+&*>3_b2khlhk4(c3*#@..............+%*,30caaaaaaadaaaacc>#........++&#=>3ccaaaaaaac93,,=#+.......@%$,c(4444e|dc3=*&+................+&**,9ca(ekk4|a9=>#@..........&#>-9a{4khkke|d93=*&..........@%*>-ca1bd~aa_dbdaa93=#+........+&#>3;de[7eb~ac,>*&+..................&%$>3;a(e4k4ea;3=&..........+&*,9a14khllk41d03=#+...........&*=>,,,,=*>>,,3-==>*#@....",
".....+&>;;)FsxBAxsr/{;-*@...............+#=-')FrsAAtysr]!->&..........@$>;~]rsABBCCAsr]~-=*+........+%>;)]/zxACBHHtAAyr/);,*+........@#-;~){]FF{~~){]F{;-=&.........+&=-;{^sxCACBtyrF);=#+...........+&*>;){/^rrrrzrrrzrr^/F)-@....+&%$$--!~{F^^rrrr^/F]]{)!,%.......%=-'{/syAtAxz/{);-$%+.............@#=-;~]rzxyBByr]);-=*+.......+%=-;)]rsyCACAAyrF);-*@........@#=-!)/zyyzzrrzsxsr^F{!,#@.......&$,-~)/stBAssrF);->#&+..............+%=,;!{/zsxAAyz/{'-#+.......+@#=;~FrsACCCCCBxzF)!-#@........@#,;~){{]])!!~)]]]{)~;-=&...",
"......#--!)/zAABBAsrF)-=&...............%=-;)F^stBAByz/{'-=%+........&*>-!{/sBACCCBBAz/);-*&.......@%*-)]rzyHvLLLLLHCAsr]~-=%........&=-'{F^rzr/]{]/zz/);,*&........@*=-~]rxBABBBBys/{;-#&...........@%=-!]/rzzzzssssszszzz/];#....@#=,-;~)]/rzzzzzzzzr/FFF)!>+.....@#-;'{/zyABCByz/]~;-=#@.........@&##$-;!]^stBBABxrF);-,*&......@#=,;'{rstBACCCAByr]~;>*&@.....+&=-!)FryttyszsxyAxsr/F)-=%......+&*=;'{/zACBBAxzF);-,#&@...........+@#*--!)/sytBBByrF);-=&.......@*=-')^sBAACACBCByr]~;-#@......+&>;']F/rr/F{)]//r//F]~;>#...",
"......&*,-;)]^rrIr/F_;=*&..............@%*,-!)]/rKzr/]~;-*&+........+&#=,-~{/rKzKzKr/}{!-*%+.......@#*=;~]}QPwwwNwwOJI/|!-=&@.......+&*,;!)]}/}])')]}F(;-*%+.......+&$=-;)]^rrr/^^FF(;,$%@...........@%$>-']}/[Q[/^Q/[[^[/}:_;&....@#*,--'~(]}/[/[/[/22F:|();*......@#>,;'(]F^KzK/F|~;-==*%+.......+&#*$>--;)]/rrrI^/|);->$%@......@&*=-;~]/rIzKzKKr/]_;-=$&@.....@#>,;~(]^r^^/}//rr^/F|)',*&.......@#$=-')F/rrIr/})!-=>$#&+..........@%**,-;)]/rrrr//(~;=*%+.......@#*=-~{/IzKrKzIzI/F~;>=*@......@&*,;'_{]2]|)~){F2F{_~;>*&...",
".....+%>>;!_|2}[[[[1_-,*&+............+&$>-;~(|}[[Q}|_;-$#&+........+@#>-!~|}QQQQQ[[2:~;=$&+.......+&$,;_(:[<P6JOOOPQ[|~-=$%+........&*>;!(|22}|((((||);=$%+.......@&*>-;_12[Q[Q[21(~;$%@+...........@%*>c(}<<55555<555<555<bc*...@%*,-;~~14<<<<<5<<<<<<4}:_!>@....+%$>;;__:}}QQQQ}|(!;-->*&.......@#*$-;;!~(1}[Q[[21(~!;,*%@.....+&$>-;'(1}[Q[QQQQQ2|(~;-*#@.....&*=-'(|1[[[[}2}[[[[}1|_;,$%+......+#*,;;_|}}QQQ[21~;;,=*#@.........+&#$>-;!(1[[QQ[2:(!-->#@.......&*>-;~(}[QQ[[[QQQ[|~;->*@......@#$>;_(|:}}1(((|:}::(_;-=&...",
"....+&#>3cddb:f7k77fb0-$*+............@%>9cabbe4777fda-=$%@.........@%*3;dbef4k47444f1dc,$%+.......@&$,;dee47hhihihh4ed0-*#%+.......@*=3cadee77fbbbbbba;=*%+.......&#=3cad1f4<7<47bdc9=%&+...........@#*9agiqqqUqUqWqqqqqqUqgb*..+&#>9adbfijjqqqqqqqqqqqjpgfd,&...@&*-;aab:f477hk774ebdac9=#+.....@&$,3;adbbe74h<474fbbda9>*&.....@#,9!db:7477447k7h7febac,*&....+%=3;0bee4h4h44e7777eeedc-=%+.....+@$$-cdbbe44k774fbda;3=*#+.......+&#=-30abb74<k77ebbdc->*@.....+@#=-0_b:477[7444h77ebba3=&.....+&$>-0dbef77feeee474ebba;=#...",
"....@%=3adee44k<lVlkedc,*%+..........%*=-0db2kkkIlk4eac3*#&@........&*>cd1e7Illlhk4k7eb03=#@......+@$=3ae4khhklVVVVh7edc3>#&+......+%*,cd:e4klkk[444e1dc,$%@......@%=30d144khlVVVh71a;>*%@...........@*,3agoWUTTTTTTUUWWUTTTjb>..@#>3~b47hpZWWWWUUUUUUWWZnXhea*..+#>3abe47kkhhhllVlhh774eda,#+...@*>-adee47kklllllhhkk74edc3$@...+#3cde47khlllhhkllllkk74ba3$+...&#,cde4khllllllh5lllhh471a9=%....+&*=30d|e44k<lVVkk4ebdac3*&......+&%=3cdbe2kkllVlk44e|dc3=#+....+%=30d:47kklkkkhklllk4eda3#+.....&*3a(e4[hkkk7[4kklkk4eba3#+..",
"...+#,;)FrzsxAABCCCts/]~-$&........+%=-'{FrzyBBCBBBxs/]~-,*@.......+#-']rsxtBCABCCABxsr]'-=&......+%,;)FsxACCCBCCCBBxs^{!-=#+......&=-!{/zstBCCBBtyyyz/{;-=@.....+#,;)FrzyABBCBBBBxz/);-*&..........+#-;)[sGvEDEEEEEEvLvDDuuw7;+.#-!{ryAHHGGvvvvvDDDDLLLvGBBsF-+.&,!{rxBHHGGHGvGHGGGGGGAGs^];$+..%-!{rxBHHHHGHHGHHHHGGHttK/'-#...#-)/ztHHHGGGGHHGGGGvvGHAs^];#...$;~FzyHtvvGGHHGHHHGGGGHts/);#....&*,;)/rssxABCCBCBBxysr/]);$+....+#=-'{FrzsytBCCCCCtysz^F);,&...+&=-~]rsxAACCCACCCCBBByszF),&....@$-~FrxxACCCCABACACABysrF'-&..",
"...+%-;)FrsyBCCCCCCCsrF);-#+.......+%>;)]rzxACCCCCBByrF);-$&.......&=-!]rsyBCCCCCCCCBsr]~-=&.......#,-)/sABCCBCCCCCCAzr]~->%@......%=-~]rsxBCBCBCCCByz/{!-*&......%-;)FzsABCBCCGCByz^{',$%+..........&-;(/stGLEEEEvHBCCBAHBAx/-@+#-~FPtvLGGCHBAyyxAtCCCCCCCAs/,++*-'FsGGLLLLELLLLLLLLEELutzF),&.+*;'/sGGLLuLLLLLLLLLEuEEExr]!=+.+*;)/JGGLLLLELLLLLLLLEEEvwzF)=+.+$;{/JGLLLDELLLGLLLLEEuEDwr{;*+...&=-']/zsABBCCCHCCBBAxsz^]!,%....@#,;)FrzyxBCCCCCCCCBysz/{!-#....#=;~FzsABCCCCCBCCCCCAAxzF)-%...+#>;)FzyBBCCCCCCCCCCCBtyzF),&..",
"....@*-!{}/IKJJwwwwOI}_'-=&.........&$=;(F[IKJwwwwOPQ}(',=#+.......@%=-'][rKJJwwwwOPI[{;->*@.......@*=-)/QrKJwwwwwOPI2{~;=$&.......@*>-)]/QKJwwwwOJKIF{~->#@......@*-!(}/IKJwwwwwJI}{!-*&@...........@*,;~2QPONNNwJKI/[[[rIK/(=++&=-)[8wwwJKI/}]1|1:[QrKKIIr})*.+&>;_[6wwNwNNNwwwNwwNNNNS6}(;=@..&,;_[8wwwwNNNwwwwwNNNNNS52~-%...&=;(QOwNwNNNNwwwwwwNNNNw5}_;%...%-':QJwwNNwNNwwwwwwNNNNw5{~-%....+%*,'{/[IKJJwwwwwwJKK^[]~-$@....+%*,!{F[QKJwwOwwwwJJI/[]~-$@....@#=-']/IKJJwwwwwwwJJKr/F_-$+....&#=-)]^rKJJwwOwwwwJJzI/F(;$+..",
"...+@$>;(}QI6YMNRNRY52(;,*&+........@%-;(2[<6YMNNMN65:(;,$%@.......+%$,'|}[I6OSSNNS8<1('-*#@.......@*=-!:[QKJMMNRNN6<1(~->&@.......@%*-'1}QIPOSYMNM8<:(!-=#@......@$>;(2[IPOMNNNMY5}(;,$#@...........+$>-a1[<8SNNS8<Q[::}4Q[2;*..&=9_f8RwR8[}|_~';'~(}[Q[QQ[|;%..&*-0|<688OOYO8886888NNNY5:~;*@..&*-a2<68OOOOO866886YNNNY5|~,*...&=-~1566OOOYO868688OSNSY51!-%...%=;_2588OOOOO88866OMSNNO<1!-#.....@*=;(}[<6YSRNNNNSYO5Q}1~-#+.....&$,;(}[<POYRNNNNYOJ5Q[|'-#+....@%$-'|2[IKOYSSYYNSOOPQ[:~-#.....+%$-!1[QIPwYNYNYSSYJIQ[:_-#+..",
"....+*=;d:7ipqWUTTTqifbc9>&+........@#=;de4hjqWTTTTqjeba-=#&.......+&*,0b47hpoWUTTTqieba;>$@.......+%*3a|44ipqUTTTTjifba3>&@.......@%*3a:fhhjqWTTTTjifba9=#@......@*>cde4hmoWUTTTqigbc3$%@...........@*=9afgmjWUWqpi77fe47k7bc%..&>cdgpqWqmgeba99-90def7774fb3#..@*,cdfgg5i5mgggffggijUWqieac*@..&*-cdf7hhi5mi77fgggiqWWjiea9#...&$-9dfg5ilmmi77777giqWWqgfc9#...&=3abekhi5mmh77777gjqUWjiba-&....+&*>cdeehpjqUTTTTTqjikfb_3#......@*,;de4hmoqWUTTTqqji4fba,#.....@%*,0be7hpoqUTTTUWjmi7fba,#.....@%*3a|f7lpoqTTTTTqqph74b0,#...",
"....+&>3cbe7mooWUTTWjl71c3>#+......+@#>3!be7mjqWUTTUoi71c3=&+.......@*=;db4hmnoUTTTWmh71a3*#+......+@*,9db4kmoqUTTUqmk4103>&+......+%$,cde4hXnqTTTTqmk4(c3*&+.....@#*30df7lpoTTTTUjh4(03>%+.........@&$-0b4mooqZoonVVllkkkk4b;#..#3aehoWWZmhedc93339cbe4444ed9&..@%-;ab4khVVVI74ef}4ioWWqifd9=@..&*,cae7khlVlhkf44k<moWWqiba,*+..@*,cae7khPmml74fe7hmoWWqib0-%...@*-cbf4kllmmh44e47hnZWWoifc3#.....@#=3cbffipjqTTTUqjlg4edc=&......&*=90befkipqUTTUopk74:d;,&.....+&#=cabe7hmjqUTTWoph74bdc,#+....@%$,cabe7kmjqTTUWomh7fbac,%+..",
"....+&-;~{^zxHGLEEuEGBAz/);>#+.....+&*,;~]rztAvDEEuuGHxzF~;>%.......+$-;)FrstCvvEEuEGBtzF);>%+......&=-;(F^stHvLEEELHBxz]';$@......@*>-!{FrsAHvEEuuEGAyr]~->%+....@*>-~]rstHvDEuEuvHyzF);=%+.......+#=-~]rxDDDvGGHCCCCCCCtsz/'$+.*~FKADEEEtxrF)';;;'~]/rrrr/]!%..&$3_FrsBACCBAysssxBAGvLGxKF_-&..&=;_FzsACBCCAyssytAHvLLGyI{;$...&=9_FzyACBHHAxssxxBGvvvGyQ{;$...%-;)/zxtCCHGAxssxtBGvLvGsQ{;*.....&=-;~{/rzswvEEEEAxsK^F{!3*......+*,;~{F^zstGEEEvGysr^])!-*.....@%$-;){F^zstDEuEvAysI/])'-=@....@&$,;~)F^KxtuEEEEHyKr^]);-*+..",
".....@$-')]zyCCvLEELGHAs/)'-=&......%=>;'{/zyCGvLEDvvCBs/);-*&.......#=;~]/sACHDvELLvHAzF);-$&......@*-;!{/zABGvuELGGCAzF);,#......@#=-!)/zsBCvLEEEvGCtzF);,*@....&$*-;{/zyBGLEuEvvHAs/)!-=%+......@*-;)/KAvLvCCBCCBCCCCCBsrF'*.+>'/ztvLEuHsr]);;--;;)]F/^^F)-%..+$-!FrxABCCCAyssxACCCBCts^{!,@..@$-'FryAACCCAxssyBCCBCCAs/);*+..&=-)FryAACCBByssyBCCCBBszF);*+.+#>;)FzyABBCCAyssyBABCCtxzF);*+....+%=-;'{F^zstEEEuAsr/F)!;,%+......@#-;!){/zsHLEuDAsz^])!-,%+....+%#=-;')F/KyHLEuDAzr^])';,%+.....@#>-;;)]^zyGEEuHAsz/]);;,%...",
".....+#>-;_1QJJJP6P6JOPQ|~-=*&......+%*>-!_2<JOOP6PJOJPQ{~-,*@.......&*=-'(2IJJJ6P8OOJP[|'->*@......@#*,-!)2KJJJP68JJJI[('-=%+.....+%$=-!):[KJJJ866JOJK}('-=$@....@%#=-;(2QJJJJ888JOKQ1';=*%@......&*>-;(:5JwwJsKsKKKKsKKr2{~-%..%-_:<ONww52('->$*$$=-;;!!'!-$+...&=-'1F/QIKK^/2F[rKKIQ^[{~-=%...+#=-'{F^rIKrQF2F[IKrIQ^}{!-=%...@$=;~{F^IKKKI/}/^QKIQ^[1(;-$&...@*>;_1/[rIKKQ/}2^IKIQ^2:);-#@......+&#==-;_(45wwNO<}(!;->$#+.........%$=-;;1[5MNNO<}(';-=*%+......+@%*>,-;~1[8wNw6<:_';-*#&........+&*>=-;_|[6wNw6[1)!;-=*&+...",
".....+&=;!_:<6O5<[4<8Y6<1~!3=#+.....@&$=;'_:58Y5<Q[<6Y6[|_;-=%......+&$>-'(}<6O5<[Q56Y6[1~;-*&.....+&%$,;~(156O5<[Q<6O841~;-=@.....+&#>;!(1[6OO5<[[56Y5[(!;-*&....+&*>-!(1<8O6<[Q<6Y8<:('->#@......@#>3!_:Q6JPPIII6666665<:_;=@..#,!b[6MSO<:~;=*##%#$*=,>,=>>&+...%*,;__}[QQQ[}::}[QQQ221~-=&+....&*,;_:22QIQ[}11}[<Q[}}1~;=#+...@%*-;(|}}QQQ[}1:}[QQ2}|(!-**&...+&=,!(:2[QQQ}21}2QQQ}}1(9-*#+........+&*=-9~1<YSS67(!;,$#&@...........&**,c_15YNM64(!;,*$%@........++%#*=,c_15MNR8}('->*#+...........@%$=-9_e5YRY5}_;-=*%+.....",
"....+%=-cdbfiqqmgffgpqjifbd03*@....+&#>3cdbgiqqpgffgjqjieba0,#+.....@%=-adbgpjqigffijqjifba0,#.....+&*=3adbgmqoige7ijqpiebd;,%......@*,;abegpqoig7fijqjgfba;,#+...@#=30dbfiqqpgffgpqoiebbc3=#+.....@*,;abb7imlliVmoqUWWqqifd9>@..%3cbgjWWqifa;,=$###*$>=>>=**@....%*-cdbe4hmhh4}f7hhh7feda3>&.....%*-cde44hmi74e44hlhhfed03$&....+%*-9db44lih4ff475ihfedac3*&+....&=,cde4hhli7fee4hlhfeda9-*&..........@#$>90biqUUjgb03=*#@............@**>30biqWqpfbc3>*%@...........@%#$>-0fiqUqjfa0-*%&............+&#=9;0fiqUqifdc,*%@......",
"...+&#>0de7hnoZph[7koZZnh7edc,&....+%*30be7hpZophkkinWZph4ed9>&....+#>3a(e7hnZZnh4hloWomh4edc$@....@#>9abekkpZqXhhhloZomk7ed9$+....+#=3_b47koWqmh7hmqZom74bd9$@...&*9c(e7hnoqnhkkhoZqnl72dc,*&....@*>9d:44lVlXVXXoZUUUUUqjgb0,&..#3aeioWWqp7bd03-,>,,3-3-3-,*%....&*,~b4klmonmlllhnnXh7:dc3=#+....&=-a|ehlmoomllhVnnmh4eda3=#+...@#>3_b4klXoomllhmonmkebac,>&....+%=9a1ekhnonmlllmnpl71bac-$%+.........@%*,cafiqUUjiba;,$%+............@%$,9dfiqWWjgba9=#%+............@#*390fpqUUjgb9,>#+.............@%$>0bfjWUWjgd;,>#.......",
"..+#,;~FzxAHGELvHABHDEDGCtxz]~=...+#=;~FzxCCGELvGBAHDEvGCtyr];$...+#,;)/zAAHGEvvCAAGvLvGAAsr];#...+#,;)/syCHvELvHAHHDLDHCtsr{;%...+#-;{^stBGvEEvHtAvLLvHAAsr{;%..&=-)FzyBHGDEDHBBHvEvGBAyzF)3$+..+*-']rstBBHGGGGHGDEEEvDvts/{;%..*_FztGELDHssr/{)~~){{{]]{{);>+...*-!{^stHvLLvGCCGvvvtszF{~;>&...@$-~FzstGvuEvHCGHvDvtsr/]~;=&...&=-~FrstHvLLvHBHvvvGxz^]);-=@...@=-~FzsAHGLLGACCGDDGyz^]);,=@.........@*,;(/KtEEEDyI]~-=*@...........+&=,;)}ztEEEGJr{~-=*@............&>,;(FKtuEEvJ/(;-*+.............&$3;(}JtuEvvs});-$+......",
"..@#-;)^sBCBGLLLHCCHLLLHCCAs/)>+..&$-;]^yBCCGLEvHCCHLLLHCBts/)>+..+*-~]rxBCHvLLvCCHGLELHCCtsF!*...&$-!]rxBCCLLLvHHGGLLGCCBtzF'=...&=-~]zyBCHLLEvBCHGLEGCCBtzF'$++%>!)/sACBvLLLHCBCLLLGCBAs^)!>&..&$;)FztBCHLLLLLLvGHCHHHAyr]),%..*;FIyGLLLHAszrF]]]FF/rrrr/F),&..+*-!]^syAGLLvBCCGvLvAsr/]~;-*+..+*;~FrxAAGLLvCCBGvLGysr/]);>%...&=-~]zsAAGLLGCCBGLDGyzrF)~;,%...%=;~FryxHvvLvCCBGLLtxz/F)~;-#.........@$-;)/KAuEEDxr]!;=#+............&*-;)FPALEEvy^{'->$@............&*,!)/JALEvGs^);-$+.............@$-;)/VALuuGs/);-$&......",
"..+&=-!{/IKPwwNwwJKJwNwJJKr/|;*...@#=-!]/IKJwwNwJJKJwNwJJzQF(;*...+%=-!]/IKJwwNwJJJJwwwJJKr});%...&*>-~FQrPJwwNwJJJJwNwJKKrF_;#...&*,;'FQKKJwwNwJJJwwNwJsK/F)-%..@*-'{/IzJwwwwwJJJwwwJJzr}{!-*@..&*=;(/rIKwwNwNuNwJPKQIQ[2(~;$+..@$;([6wwwJIQ}]|)~)1]}}}/2F_'>+...&=-!)F[IJwwJKKKJwwO<}]_~;->&...+&=-'1/[KJwwJPKPJwwOQ}:_~;-=&...@*>-~12QIJwwJPKKJwO8Q}|)~;-=&...@#>-~]2QIOwwJKKPJwwPQ:{(!;,*&..........@*-;_e5wNwOQ|'->#@.............@&*,;~}5wNwJ<|!-=*%@............@%*,;~26wwwJ[|;-=%@..............&=--)26wNw6[(;,>#@......",
"...&$,;(}QI5OSSOJPIPYSSOK<Q2~;*+..@#$,;(}QIIJRSO6PK8YMw6KIQ}_;*+...&*-'1}QI5OYSwJIP8RSSPII[}~-#...@#*-!|2QIPOSYOPPPOYSOPK<[1_-%...@*=-~|[QIPOwSYJPPORSOPIQ[:'-%..&$-;(}QQPJSwYJPP8OSROI<Q2(;,*@..@*-;(:QQPJSNNNNNS6QQ[[2:1(!-*+..+#,_:<88O6P<Q}1::::}[<<<}:(!*+...%$,;_:2QPOY85QI5OY6<}((_';>#+...&*-;(:2<8OO6III6YY6[1(__;3=%...+%=-~_:[<8YO6I<<8OY6}1((~;-=#...@%>-!(:}<8YO8III6OY54:(_~;-=%..........&*=-c|5YSR84(;-=#&.............@%$=9_|<YSR82('->#&+...........+@#$=-a:5YSY84(;-$$@+............+&*>-a15YSR5e_;,*%&......",
"..+&=3cb7hmmjZqommlmjqqoplh7d9*...@*=9ab4hmmoqqqpmmpoqoXmlhfbc*....#=-cbkhmmoWqomlmmqWqommhfd3%...@$=9af7immoqoopnmjqqZXmlhfdc$...@*=9aekimmoqWjmmpoqWopmlgfd9#..@$3cdfilpoqWopmmnqWWomlh7bc3*@..@*3cb7himjqWWUUqqjih77febba0$+...%>0d7hilpopmhk77khimjjjifbc$+...@*-cdefgpoomlkhmpqjgfbbdaa9*+..+&*3cdffhpoomihhmjqpgfbbdda3*...+%*-0de4hpoomihhmjqpgbbbbac3#...@%=3cde4ipoomhhimjqigfbbbaa-&........+@%*,9abiqWWjgb;3=$#+...........+&%>-cafiqUqjgd0->*%@...........+&#>-cafpqUqjg_c9=$&+...........@&*$3;dfiqTqjeb03=#%+.....",
"..@=-'b7inXoYZoXXVVVnZZoZomifd=+..@*-!b7mXoonZZnnXXXnoZooonlfd,+..@$3ab7mnnooZnnXVVXnoZoooXie0$...%=9~b4mXonZZoXXXXnoZoooonhfa=+..#>c_bhmnXoZZonXXXnnZXZnomkea*+.%-0d4iXooZZoXXVXnooqZooXi4dc,&..%30d7inXoooqoqqZoXVlk7k444e_9%..+%>9de4lmnZZoXVVVVVXZZWZph:a,@..+#,cdb4klXnXmlhklnopmhkk44ed,&..+*=9~b4klXnXVlhhmmnmVkk444e_=+..&*>9ae4hlXonVllhmnjmik7444e0$+..&$,0de4klXXXmhklmnomlk4444:a$........@*=33adgiWUUoiea03,=*@.........+@*>,30bfpqUUogedc3>=&+.........@#*>,0abgjUUWjged;3,$#@.........@&$=39abgjWUWjhbdc93*#@....",
".+*;)FzxHEEDDCCBCBCCHHGDLEDHs/'@.+$;)FzyvLLLLvHGCBCCBHvLvLDGs/;@..*-)/zyDEELvvvCBCCCCGvvLDDts/;@.+=!{/sADvEEvGCCBHCBCGGLvLDAsF;+.+=!{/stvEEvGGHHCBCHBvvLLLDtKF-@+$'FzxGvDEDvHCBCCCBGGDLEDGyrF!$++$'FzxGDDDvGHHGGGHBCCAxyyAAAz{=..+#-!]rstAGDLDHHCHHHHLEEvGyzF;%..%,'{^zxABHvBHtAttBHCCBBBABxr{*.+*-;(/zytBHGHBABtCCCCCBCCABxr;@.+*-!)/zxABCHHBttAtCHBCCBCBBy^;+.+*-~FrsyBCHGCCAxtACHHACCBAty/;+....+&#=;'){FrsHuEELtsrF{)'-$@.......&#>;!)]/rxGuEEvtK^]{~'-#+......+&$,;'{F/zsvuEEDAz^]{'!-=@......+%=-;~)]/zyGEEEvxzr/]);-$&...",
".+#;)/zyvLELLGCCCCCCCBGGLEuGxr;&.+$!(/KtLEEEGCCBCCCCCCBLEEDHxr~&.@$!{^KtLLELLCCCCCCCCBvLLuLGyr;@.+>;{/stLLLLLCCCCBCCCBCLEEuGs^;@.+>;]/KGLEELLCCBCCCCCCGLEELHs/;@+*)^zyvLELLCCCCCCCCCCGELuvxzF)$++=)/zAGLELGBBCBCBGCCABAtABCCsF-+.+%-!{rzyAHGGGGCGvBBCGGvvtsr]-&..#-']rsACCBGGCAtyABCCBCCCCCAs{>++%;~]rsACCBCCCBtytBBCCCBCCAAr~&..*;)]rsACCBHHCBAxBCCCCCCCCBAr;&.+#;)FzxCCCBHCAtyABCBCCCCCCCxr;@....&*=;!{F/rzxHLEuEBxzr/])!-#......&#>-~{F/rKyGEEuLByz^/]);,#......+*>;!)]^KsxGLEEGtsr/F]);>#......@=>;~]F/zzxvLELuAszr/]);=#...",
".+%>;(2<ONNNwJKKrIrIKKJwwNNOI}-@.+%-!(25ONNNwJKKIrIrKKJwNNw8I1-+..#-!1[6YwNNwJKI/QrIKKJwNNw8I1-@.+#-'1[8wNNNwJKIrIrIKJJwNwwJQ(-+.+$-~:Q6wNNNJJKIrIrKKJJNwNw8Q(,@+%;|[5ONNNwJKIrIrIzKJwwNNOQ})-%..%;_[5ONwNOKKKJwwwwwJzKrKKJJ<_>....%$-')]}QIPJwwwwJJKPI5<21_-$+..&>;)}IPJwwwwJIrIrIKKJJJJKzQF'*.+&,-~}<PJwwwJJKKIIrKKJJJJsKQF-@..&=;~}IPJwwwwPKrrIKKKJJJJsI/],+.+&=;([IJJwwwJJIrIrKKKJJJJKz^{=+...+&#*-;)1F[Q<JNNNw8I[}F|~;=#......@*=-!)12[[IONNNMPI/:](~;=#.....+@*=-!)(F}[KOSNNwPI^}](~;=#.....+&$=;!(]}[Q5ONNNOPQ}}]_~;=%...",
"..%=;(}5YNNNOPI[2}}2QIPMNNMO<1-@..%=;([5YNNSOII[22}[QK8YSNN8<:-@.+%-'125MNNS6PQ[2}}[QK8RNNS6<:-+..#>'1[5MNNYOPQQ2}2[QIPRNNR6<|,+..%-~|[5MNNSOKQQ2}}[QIORNNR8[|-+.%-(}<ONNNOPIQ}}}2QI6ONNS8<}_;#..#9(2<ONNRO5IPOSYSSYYP5IP8R85($+....&#>-9~|:[QPJJJPQ[}:(_0,$#+...%,9_25OYwSYw8PKIIIIPOwwO6<[|!*..%=;_26OYYSSY8PPPIKPKOwYOPI[(-@..&=3_48OSYYwYJ5KIIIPKOYwO6<[)>+..#=9(48OSMSNY8PKIIIPJOwwOP<[(=....+%$>-_(}}[Q58SNNR8IQ[}1(;-#+.....&#>;_|2}[<58SNNR6<QQ}](;,&.....+%*>;_|:[Q<5MNNNM6<Q[21(;,&......@*>;_|}[[Q6MSNNY6QQ}}1(;=&...",
"..%>cbfiqUTUqmlkfee4kimqUTUqif9@..%,cb7iqUTUjmkkfee4hhmqTTUjie3+.+%3ae7mqUTUomh74ef7hlpqTTUjhf-+..#-0bgjUTUUjpk7eee4hloqTTUjgb3+..*9afhpWTTqomh4eee4hloqTTUjgb,@+%cd7iqUUUqmkkfef4hhpqUTUqigd3%+.#;bgiqTTWjmmjWUUUUWWopnpjWqid>.....+&#$,cabfhmmVmikfbac3>*&.....@>;dgjWWUUUWopmmmpmnqWWZni71c*..%,0bgjWWUUUWqmmmmmppqWWZjl7b3+..&=cbgqWWUUUWqnlmmmnoZWWZni4b>+..#,0bgqWWUUUqopnpmppoqWWZph4d>....+&*,;defkh5mqTTTTjmkh74ba-*@.....@*=9de4khlpqTTTqjlhh4fba-#.....+%*,;de47klpqTTTqjlhk74ba-#......&*,cde47klpqTTTqplh77eba3#...",
"..%,abhmqUUUqXll7444lVXZUTUqm7c@.+#,a:hXqUTUZnVh444kllnWTTUoVec@..#3_ehpZTTUnXVk74kklVnWUTWoie9+.+%3d4ipWUTUZXVk447klXnWTUUom49@.+*;b4ljWTTWoXVk447hVXoUUUWome9+.*;e4moUUUZnVl7447lVXqUTUqmkbc#..*cehjqUUWZmmoWTUUUUWZnnXoUqjb,......@#$,cdeklVXXXlhed03=*&+.....%=9bgoWWUUUWZnnnXnnoZUWWoVhec#..%3abiZWUWUUWoXVXXnnZZUWWnmke9@.+&,;bioWWUUUWZnXXXnnoZWWZnVkb,+..%9cbioWUUUUZonnXnnnZWUUZoVkb,+...+#*3ab4khVlnqTTTUoXVlhk4dc=&....+%*3a:7kllVnqTTTWoXVlkke(9$+....@#>3ae7klVVXqTTTUoXVVkked3$+....+#=9_e7hlVmnqTTTZXVVVkkea,*+..",
".+*!]rstvEELDHCtysyxACHLEEEDHs)%.+=']zyHvEELDHBBsssxCHGDEEEGAs)&.+=!FzyHvEEEDHCAxsxtCCGDEELGAs~&.@=~FzAHDDEEvGCAssxtACGDEEEGtz!@.+='/ztvLEEEGBCtssxAAHvEEELvtz'%+=_rxAvvEEvGCtysxxBCGDEEEGHxr{=++>(rxGDEEEDGHvDEEDLEDGGGCGDDwe,+.....@#,c)/sxBHGvGHxzF~;,=@......%-_/xHvLEEEvGHCGCHCvvLLvGByr)*.+*;]IsGDLLLLLGCBCBCHvLELLGCxz'&.+*;_/xGvLDLvvvBCCCCCGvLLvvAy/-@.+*!1IyDLLLEELHBCCCCHvLELGGAs/-+..+&=-!{rxtACCHvEEEEvGBCBxs/)3%....&=-'{rstCCBGDEEEEGBCCBxs/)-%....&$-~FzxAACCGvEEELvCCCAyzF~-&....@$-~FztACCBGDEEEEvBCCAyzF~,@..",
"..$;)/zyAGHHBBAyszssABAAHBHtxz)&.+*;{/sxBACHACBxsssytAAAHHHtyr~&.+=;{/stAHGGCCtyszsttABBGHHBs^~@.+$!]rsxAHHHBBtxsssyAACAHAHts^'@.@>;]rstHHHHCBAysssyBACAGGAty^;@+$)^zyAHAHBCAysszyAABCAHHAxs^)$++>)^sxtHHBCBACCBCCHBCCBCBCHtsF-......@$-;)/sBHGLvvtsr{'->%+......&>!1ztCCCHGCCBCCCBCCCHHCAyz/'*+.#;)/sABCCCCHCCCCCCCCCCCCBxsF;@.+%;']zACCCHHCCCBCBCCCCBHCByzF-+.+*;)/stCBHCHBCCCCBCCCBHCBAyz]-+...@*-;)rzyABBACAHHHCABtyyzF),%....@%>;]/zyABCCBGGGHBCABxsrF)-&....+*-;]/syBAACHHGGHACAAxsrF',&....+*-~]rsttBBCAGGGACBBtysr]~>&..",
"..@=-_(:}[[[Q^/F]{]]F2[[[Q2}:_,+..&>;~(}2[[Q[^/F]|{]F/[[2[[2{_-...%>;~1:[[[[[^F]{(]{F[/[[[}2]~=+.+%>;_1:}[2[^^/F{{{]/[^[[[[2{~>..+#,;_11}[2[[^FF{{]]2[[[[[[}{~=+.%-~(:}[[Q[//F{){]F2[^[[[2]{',&..%-~1:}[[[[//[^QQQQIIrIrQ^[}_-%.......@*,;(2IJwwwJQ:_;-=%+.......+%-;(:}[Q[III^rrQ^Q/QQ[[/:(~>@..+*,;(2[/QIQQrQQ^Q/QQQQ[/2](!$...@=,;_:[[QQIIQ^Q^I/Q^QQ^[2F(;$...&*,!(2[/IIIIQrQrQ^QQQQQ[F:)!*.....@*,;~]]F/^[Q[[[[Q^/FF]_!-$+.....@#=;))]F/[^QQ[Q[Q^//F{(!-*+.....+#,;){]F/[^2Q[[Q^[/F]])!-#+.....@*-;)]]F/[Q[Q2QQQ//FF])!,&...",
"..+#,-!_(_(||(__!!!!~(((|((_!,*+..@%=3'~((((|(__!!!'__(|1((_!-%+..&*-;!___|||((';;!__((((|(~';*...@*-;!_((1(((_'!!!'_((((((_';*+..#*-;'_((1(((_'!!!__(|_||(_!-%.+@=-!~_(|(1__!;;!!~(_((((_';;$+..&>3;~_(||(__((({|||:::::|(_;=@.......@%*-'(}<668<:~;,$%@.........@*>;~)(|::::1111:|:||((_~;-#+..+%*-;~_(1|1:|:1]|1{|||__~';-%+...&#-;~(((::1::1:|1|1(|(__!;-#+..+#*-;~((11::11|1:||||||(_~;>%.....+&#=;;__(((||1|||1((~~'-=@.......@*>;''_((_||1||(((_~';-$&.......&#,;;__((|1|1|||(((_!;-#&......+&*--!__((|||1(|((((~~;-*&...",
"...&*>33cc0;0cc9-9939c90cccc9=&...+%$>,9900c0c99-333c9c909cc3=&...+&*,39cc;c0;9-3--9cc009ccc9,#....&*,33c90090c933333000c9c9-=&...@%=,39;9c09cc93339ccc0c0;c-#+..+*>339c090099--3999cc09093,=#+...#,-39cc0cccca00a0c~a_aac0c3%........+@#*9;abbffba3,>#&+..........%$,39c!a_aaaa0c'0a0!0cc93=&....@%$>;c9_aaaa~aa~c00000cc9-=&....@&=3-c0cc'a'a~a~0cc000c99,*@....&#>>;cc0aaaa~cc0'0000c099,=&......+%$=,330900~a0;0cccc-3=*&.......&*$=333c0c0~a000;9c;3,=#+.......@%$,339cc0c000aa0cc33,>&+.......&%>,3939c0a0000!;c993,>%@...",
"...+&#=,,3,3,3>->,=,3,9,3-3,,=&....@%*$>-,>-3,-,>,,,,3,-39,,>=&....@#$=,-,33>3-,>>==>>-3-3-,=*@....@#*=,,9>>-,,,,>,=,>>>--,3>*&...+&#*=,,9-,-3-=,==>,,-,3,3==%+...%*=,-,,-,>-,$>>,,9,,3-,,>**@....@#>>-,-,99399999999933-9,>=#+.......+%%*=3-00a003,**%+...........+%*>-933339;939333;93-,=**&....+%#$,>3-33;993999-3-3-,=>*#@....+&%*>--939-39c9-3--3>-,-=*#+....+&#>,,-3-3;999993--3,9>-=$%+.......+%*=>,,-33399939-,=>$*&........+&#$$=,-,-33993339,=>*#@.........&***,>-333-3333-9,,>$*&.........&#*=>-9--939,-33,-,>$%&....",
"...+@%$->---------,-------->-$&....@%=>=---,-----,>>-------->*@....+&**-,----,-,>,=>->-----,>#@....+&%$>----,---,----3----->>#+....+&#$>--------,-->------->=%....&**>------>,==>----------#%+....@#$>--->----;;;;;;;;;;;--,#@.........@&#=-;;!cc;;-*%&............+%$>--;;;;-;;;-;;,----,$#&@.....@#$,--;-;;;;;;;;-;-----==#@.....+%*>---;;;;;;;;-;-;---->#&......@#$>---;;;;;;;>-;-;>--->*#+.......+#$>-----;-;;-;----=#&+.........@#*=,------;;;---->=*%@.........+%#$>---;,;;;;--,-->##@.........+#*>-,--;;-;-;---->=*%@....",
".....+&%**%*%*%#%**#%#***#*#&@.....+&&%***$**#%#%%##%*$###%*%&+.....++&%##*#**%%#%##%****%**%@.......++&**$**%*%**%**$$**%%*#@......+.@&##$*%*%%%&%#**#**#**#&.....+%##$$***%%%%##%*#$*##%%%+.......@%%%*=*$*$#$*=$$>>====*%@...........+@#$==>>>>##&+..............+&%**$$===$=$*#$>*#*%%@++.......+&*%#$$***$==*#=$=$**%%@+........@%#*=====$*$$>$=#**%%&+........+&#**$*$=$##$=*#=$$*%%##@..........+@%%*#*$=***$$**%%@+...........@%#**$==$**$*#**%#@+++.........+.++%%##*$$$$$=$*%%%&+............&%%*$==$=$===$#%#%&+.....",
"...........+..++..+.+.+++.++............+.+.+.+++....++++...............+.+.++........+.+..................++.+..+.......++.............+....+..+....++++.+.............+..+.++.+..+.++++..................+.+.++.+..++++..................+++++++........................+++...++..++.++..............+...++.+.++.......+..............+++++......++..+++.................+.++...+...++.................+.++.++.+....++....................+..+.++..+....................++........++...................+..+++++.+.++.+........",
"................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................",
"................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................",
"..........................................+@&%%%**%%&++++..................@&%&@+...............................+@%%%@+.....................+@#****&+.......................+@&%%%%%%&++................................................................................................................+@%%#*%%@+.............................+@%%%%@+....................@%%****%@+............................................................+@%%&++........................................................................",
"...................++...................+&=-;!))~{)'!--,-=$&+..........+%*=-~);;--=*&+.......................%*=>;''!-,$%&+.............+%**=-~({~);->*&+..............+%*>>-;!))))'~!-->>*&+..................................................................................+++.+@&&@+.............+&*-;!')!;-,$%@+......................@%$,;;;~!-,%&+...............@#,!))())'-,*%@+...................+++..............................+%*>>;;';-=*%@................................................+%*****%&+...........",
"......@&%%&%##%%&%#%%%&@+.............+%#>-;))F/^//F])))'!--#@.........%>-;)]]]~)';--%+....................+%=>;!)]]])~-,*&+............&$-;!]/^//])~;-*%+............+%*-;!))(F/FFF]]))';-=%+...........+&%&#%%%#%&%%@+....................................................+@%#*###**==###@..........@$-;~]]]{)~'-,*@.....................+#>-;!)]]]~;-*%.............+#$-!)F/r/F])!-,*%@..............+&%##*%%%##%%%@.....................+&$-;!))))';-=*&...........@&%&&@+...........................+@#$>--;--*##&@........",
"......@&%$#%**#$*#*$#%%&@.............+#*=-;)_]}/}F]_()))!-=*@.........&*-;~{{1{)~;-=#+....................@%>=;;'{]]~'->$&............+@*=-;)F//}]{';-*&+............@%*=;!)(]1F}]({_()~;>*%+..........+@%#%###%*$#%%@+..................................................+@&&#%#*#*$$=>**%%+........+&*=-!){({()!-=*@+..................+&&*,-;!){{)!->*%+...........+@%*,;)]}/}F();->*@+.............+@%##%#%%%%*%&&@+....................@*=-;!)({{';,*%@..........+&###$%%&@@........................&%*>,--;-,$##%@+.......",
".....&%#$*>$**>**=$*$*##%&+..........+&%$>;~(:}[2[}}:1}1(~;>*@........+&$=;(1}}1}('->#@...................+%#=-;~(1}}1!-=*&............+#$,-~|}Q[Q}|(!->*&+..........+&#$-;(|}[[[[}21::1(!->#@..........@#$$$*#*$**$$$#%@................................................@%&#$*$=>,>---->**%@.........@#>;_|}2}21~;>$#@..................@&#*-;~(|}[1_;,$#@...........+%$,-;_}[QQ[:(~;=$#@............+&%#**$*$$$$$$$#%&+..................&#$>;'_(}}1(;-$#&.......+&&%*$$$*$*#%%&......................+&*>,--!;;-,=$#%@.......",
"...+&*$*>=333333,-3,,>=*$$#&+........&%*=-0de44hhh74f44fedc-*&........+&$,cbe7774e~9-*#+..................@*$-;adbe74ea9=*%...........+&%>-0df75kh7eba;,$%@..........+%*>9abe4hhhk7eeeeeba-=#@........+@%*=,,,>=>,-=,>**%+.............................................+@%$*=>,,-3cc90c0c>=*&........+@#=;de4774e_c,*#%@................+&#$=;0dbe47edc3**@+..........@#*-cab4khkkeedc3$$%@..........+&#*$,-,==*=,-==>**%@+...............@%*>3a~be47eb0-=#&+.....+&$$>,,3>,>=**##@....................+%*=,;0ad_dc93=$#&+......",
"...&=,3cc_a_d~dd_dddaa0c3,==*&......&%>,30_e7klVVlllhhhk4|a3=%........@#=9'e[lllhkea93*&+................+%$30d|e4klhedc3*#+..........+&>3ad:klVVVlk4:dc,$%+........+%*,3a14kkllVVlhkkk4edc>*@........+*$,;!aac;cc0aa993>*%..........................................@%#=>39ccadd(bbbee1da9=#+.......&$=99b4klllk7d09=*#&+.............+&**3c_be[kll4e_;3=#+.........+%$-0d:4klVVVk4ed03=>#&........+&*>>;0~aac;c!aa0933==#+...........++&#$>ca(e4kkVked03=*@.....%*,3ca0_daac9-,=*%+.................+&#-0dd1ef4ee(a03=*#+.....",
"..+*!{F^zssssssxsssssz/F]{)!-$+....+$-')]/zxBCBCCCBHCCBysrF~-=+......+%>-']rxBACCAyr]);>#&+.............@%,;)/zyyBACts/{'-=@.........+#$;)/zyACCBCCCxs^F';>#+......@#,;~]/sACCCCCCCHHCAyz^);,%.......+#>-~Frzr^/F/rzz/F{)!-#+.........@@@&&@+.........+@@@@+........@*-;!){F^rssssyyAABBxrF!-&.....+%$-;)]rstBCCAyz/{~;-=#%@+.......@%#=-;;)FrsxAACBxr/{';,*@......+&*,;)FzyACCCCCBAyz/])!-=@......+%*-;)]rzzrFFF^zzrF]{);-#+........+&$=,;;~]rsytBCBts/]);-#....&>-)]rzssssz^FF{~;,$%+..............@#,;)/zstBBHAAxsrF);-*&+...",
"..%-~FrsxBACCBBBBAABAAyz//]{;-%...+#=;)]/rsBCCCCCCGvGHBxs^{~;>%......@#=-!{/zxBCBAyz/]~->*&+............#>-~FryABCBtyz/);-=#+........@#,;]ryABBACCCABxz/]~-$#+.....+*-!{/ztACCCBCBHGGBtsrF)-,#.......%*-;)/ytyzzzzxAysr/F);>%........&%$>==*%%@+..+@%%#*$***&......@$>;!)]/zsABBBBACCGLDGy/{;$+....@*>;~)FrzyAACCBxr/)!--=**&......&*=--;;){/yBCCBBxsrF)!--=%......%>-;~{rsABBAAAACBAsr/]);>#+....@&*,;']rsyysr/zsyyyzr/]);=%......@%#*=-;;~{/stCBBBAsr/{~;-*+..+%-!]ryBABAAAxzr/]~->*%+............@#=-!]rxBCGGLLHCAs/{';,*@...",
"..@$;)F^IzKsKsKzKzKzzKr^F1(~;>&...+&*,;)1F[rKKJJJJwwwJQ2F)~-=*@......@&$>-;){/rzKzQF|';>>#&@..........+@#>,-)FrKzzr^F|);-*#@.........@#=-~F^rKrrrrKzr[]_~;,$%@.....+#,;!)]/IKzPJJJwwwI[]_!-=%@......+&#=-']^r//1FF/rQ/]()!-*#+.....+@&#*$$>$*#&@@@@&%#*****#%+....+&*=-;~{F/QrzKzKsJJwwwO<|!>%....+@%$=-!~{]F^KzrI/F{~;-,>*%&......@%$==--!)]/Izzrr/F|)!;-=*&.....+%*>-;~]/rKrrrIrKzr[F]);->#+....@&$=-;)]/Ir/F|F/rr//F|);-=&.....+&#*$=>-;;']/rzKzr/F])!;-$*+...&=-)F^zKzKzKr/F|);-=*#&@...........@#=,;']^IJwwwwwKK^]~;-*#@...",
"..&$-!(2<PPPPIIIIIIQQQ<<[7}1c-*...@%$-;~(1}QIKIPKPOOO6[:(('-,$&......+&#*=-'(1[QIQ[}|~;-**#&@.........@&$*,;~|[II<[}1)~;,>%&+.......+&#$,!|}Q[[[}[QQQ}:(~;>*%+......&=;'(|}[IKIPPPOOO<}(_;-$%@......@%$$-;|[Q[}:|2[QQ}:(~;,$%@......+%#>----=*#%%&%##*>--->>*@....+%*-;((:}<<IIIIKPPOYNSO<1;,#....+%$=-;'~((12QQQ[}|(~!;-,>$&+....@%$=>--;'_|[QIQQ22|1~_;->*%+....@%*,-!_|2QQ[[22QQQ[}:(('-=$&...+&#*,;!_:[Q[:|1|}[[[}1|(!-=#+....&#*>=---;!_|}QIQQ[[1|(_;-=*&..+%*-!1[QIPPP5Q[}1(~-,$$#%@.........+&*>-;(1<P666O86J5<}(!->*@...",
"..&=9abgmqoqnmlhkhh<khlpjqjgbc=+..@*=9abb47kklliVmoqopgfebd0-=&......&%$>-;abe4h<k7eedcc,>*%@........+#*>,90be45h<h4fbdc9,*%@.......+&*>-0:4hk7747hkh7ebdc-*#@.....+#=;adb44hllmVmoojifbac-$%+.....+&#=>;ab7h744f77<77ebdc3$#@......&*=9caa09=$*$#**$39aaac,=@...+&=,cbefgmjjphkhmoqWWWWqifa3#....@#>9!adb:ee44kk44eebdda;33*@....&*>-caadbbe7kk<774ebbbdcc,$@...+%$=90dbe7<h74444h<7ffebd0-=@...@#>,;adbe7hkf:bb44h774eed0-*@...@%$,9;aa_dbb:77<hk47febbd09,%...#*3c17hhnnoph77ebda;>=**&+........+%=3cdbgioopigimjoigbda3$&...",
"..#=;_ehnZWZoXVVllllVlXoWUWpgb,+.+%=-a:4kklVVVlllmXnXVVkk74|dc#.....&%=,39d:4klVVVlhk4eda93$#+......@*=,-c_e4kVVVVllk4e(d03>%+.....@#*>3abekllVlllVVVk4:ba93*&....+&*,c~b}7lVVXXXXXXXl7:ba9,*&.....+*=,ca14<llhlllVllk4eba;,*@.....&%=9'bb1ba09,=>>33;abebd0,#...%*30b4klVoZZnmllXZZUUTUqp7b0$+..+#>9de4k7kkkkk7k7kkkkk74e(a9*...@#>9a|44kkkk<kkhhkkhkk742ba9%...+*-c~e[khlVVk744klllQlkk7:d9#...&*30de4k<Vlh74e4kllVllhk7:a9%...&>9ad|e47k7kkkllllIVlkkk4410>+.+&=3aeklmnZWoXVkk44bd0c3=$%+.......&*,0de4hmZomlhlmoZni4ed0>%...",
"..*;{^stDEELDCCCCBCCCCHLEEEGs^!@+&=;{/sBCCCCCBAtxABCHBHCCAAsr{=+..+%=-;~]FzsABBCCBCCAysz^F);-%.....&=-!){/ryABCCCCCCCxsz/F)!,&....+#-;~{/zxtCCCCBCCBCBysr^{~-*+...%>;!{/rsxBCCCGBGCGHAxsrF{!-$+...@*-;~]/zxACBCBBCCCCtysz^]~;#.....#-;)^zsszrF{)~~))]FrzssrF'>+..*-)FzACCHGLEGHCHHDEEEEEDGsrF-#..%-!]rxBCBCCAAysyyBBBACAAAsr],+.+$-!]zyBABCCAAyxxABBCCBCBAyr],+.+%-~FzxBBCCCCAyssxCCCCBCAtsr];+++$;'FztBCBCCAxsssxACCACCAtsr{=+.+$;{/zxBBBBBCCABABCCCCCCBAAs^;@.+*;']ztCHGLEvHCCBtysr/F{)!;=&......*-']^zxBvLDHBACHDLDBxzr]!>+..",
".+$-)/zAGGLGGCCABBABBABGGLDGA^'%+%,')^yBCBCCBCByttBCCCCCCCBxr{-+..@*,-~]/rsACCCCCCCCCCAysr]);$+...@*-!)F/rsACCBHHCCCBCyysrF~;=+...%,-!)FrzyCBCCHHBCCCCAysz/{!>%..@#-;)]rzsACCBCCCCCCBBAysr]~;>&..+#=;~{FrsABACCCCCCBCCAyszF);$+...+$-~]ryBBxzr/F]{]//zsABAs/)=+..*;)FstBGCvGvHCCBCGLLELELtxrF~#..#;~FsBCCBCCCAsssytCCCCCCByz{-@.&$;)FsACCCCCBAyssyACCCCCBBxz{-+.+*;)/sCCCCCBBysssyABBCHCCBxr{;%.+>;{/sCCCCCCByszsyBCCCBCCByr{-..+=']rsBCBCCCCBBAAtBCCBCCCCByz~@.+*-~]ztBCvLLLGCBCCAxszr/F)!-$@.....%-!]rstAGGvCBBBCLLGAysrF'=+..",
"..#,;~:[IJJJJIrI^^^^[QQPJJ6KQF-@.@*-'(QJwwwwJJrQ//QrPJwwwJK[{;*...+&=-!(F[IKJJKKKzKKzKJKIQ|~-=+...@#>;~]}[QKJJJKJKKKKKPPK[:!-*@...&=,;~|F^QrKKKKPKKKKJJPKQ|~;=@..@#*-!(F[/rKKKKKKKKKKJJKI[|!-=@..@**,;)]}^rKzKKKKKKKKJJPI[('-#.....%=-~2IJPKQ2F|))(]}QIJPJQ1;*...&=;)[PJwwJPPIIIIKPJwJOOJPQ})-%+.&,-)[KwwwJKr[FFFF[IKJwwJK^]~=+.@%,;([JwwJJKr/FFFF^IKJwwJK/1!=...%,;(QKwwJJKr^F]F2^IJOwwJK[]!=@..%-;1QJwwJKKr[F1F2/IJwwwJI[{;*..+#-']/IJwwwJJzQ//F^IKJwwwJKQ(-+..&=-;{/QKJwNNwwwJJJJIQ/}]);-*+....+&=-!)}[QPJPIQQQPwwOK/}{~-#...",
".+%*-'_:QKPPQQ[}:1||11}Q5PIQ[1;@+@#=-(<6OwSSY8<[}}[[<6OSYO<}(c#...&$>;_1}Q5JOPPQQQQ<I6OOY54~;=&...@$,;(:[Q5OO8IQQQQIIPOYO5}~3=&..+%*-'|}Q[QIQQQQQQQQIPOR85}_;=&..@%>-'|[QQIIIIIQQQIIK8MMO<:'-*@..@#>-~|}QQIIQQQ[Q[QQP8OYO<1!-$+...+&=3(78OOOI<}:_((2[QKOOO5:c*+..&=c([6wSOP<[[[}[[IIIPPP<Q[2_-%..&=3_[8OJOP<Q}(_(|}[5JYSO5}(!*+.+%>3_46OwOP5[:(_(11[KOYYO52(;*+.+%>,d[OYwOP<[1(((|}[8JSYO<}(;=@..%=;(<6OwOP<2|(_(|2Q5YYYO<}(;*+..&>;_1<8YNYO<Q[:1|}[IPOYSY5}(,+..@*=-~(}<5RNNSwSwSYO8Q<[}|~-=&.....&*=;(11[QIIQ[[[5YR8<2:(;>%+..",
"..&=90bfimpXik77eb:bbbfgillhhfc@++#>cbgqWWUUUji7ff44hpWUUqieb;%...&=-cbf4hmoqomk7khhljqWWjgbc3&..+&*-ab4khmoZomh4khhmpZWWjgbc>%..+*>3ae4<hllhhhk7khhmoWUqjgdc3&..@*>;ae7hlhllkhk7khhmjWWqpfdc>@..@*,;df7<hllkhkkkkkhpqWUqifa9=@....#=9dgpqjommh7bee4hipoqjib3%...%>0bgjWUqpg477774hhlmmlik74b9%+.&=3dgqWWZp57ebadd1fiqWWqm7bc*+.+&>9dgjWWqnk7ebad1b7iqUUqi7bc*...%>cbgqWZqmh7ed0ddbgmqWWqieb;=@.+%>cbiqWWomk4bd_abegpqWUqiedc%...&=9abgjqUqqik4:bb47hpqqWqiea>...&*>-abfgiqqUWqqqqqqmllh7fbc3&.....@*,;def4hihhghijqUjifed0-#...",
"..#,cdehmoZoopnlk7444e4hmVVVhk0%.@*,ceiZWUUTUZmhkkkhlnWUUqpkba*+..#,0(4hVVnZZomlhkllXoWWUoifd9*..@*3cb4hlXXZZnmhkklVVoWUWoiedc#..&*3017lVlVVVlhkhhlVVoWUWjhea3#..@=3a:7VVVVVVVhkhklVmqWWWjhba3#++&=3a:klXVVVVVlhkhlVXoUUWjgba3%...+&*9cegmnmnnmlhhhmXonmmigbc#+..%9afioWUWpikkllVlllVmmVVVVkea*..&,cbioWWZnVke1bdbf7pqUUZj4ea>+.@$>cbiZZWZnVk4|bdbfkmZWUqmhba$+..%3cbioWWZnV<eb(beekpZUUZpkba=@..#,0eioWZZnVkeddbbehmZUUWpgbc*...%=9abhmqqqnVlk7447hVmooZjif0$+.+&$3cde4hmoqqjjpmjjmXXVVVk41c*....+&$3!b4kllXnnpojqWWolk4e_3*+..",
"..*!]rxADEEEELLGHAAysssyBCBCCx]*@%-c]KtDvLEELvGCABBtBvEEEDHsr]=+.+=']zxHHGGGvGAtyxAACCLELGAsr{=+.#-~]rxHHvvDDGAAyxyACGvEvvAs/(>+.%;)FzAHGGCCCCtyttBBCGvLvvAs^)=++#;)/ztHHGBCCAAxxxtACGDLvGts/)*..#;)/stHHHCCCAAAxytBHvDEDGAz/'*...+#>;_2rsyGDEvGBAHvDLGAys[{'=+.+=)/stLLELGAtACCCCBCBCCBCBCBs/,++*!{rtvLLDGCts^/^^zsHEEEEvxz]-@.@>'{zyvLLvvCtz^//rzxHvEEDGyr{-+..*!{KtGvLGHCtzr/FrsyGDEEEGyz];%.+=!{rtvDvGHBxs^/^rsyHvEEDHxr]-...%>;(^sACHGCHCAysstACCHHHHxr(>...%,;)/zytCBHHAyyyyAAACBCCCBsF-....+*-~]rytBBGvvDLEEEELHtxz/);&..",
".+$;]ryHLLEEEELGCBtxszsxABCCBy]#+&>']ryCCCCHGCBCCCABAHLLELAsr{=+.+>)/zAHLvvHCtszzzssAABHGHCAz{-+.%;)/sAGLvGHCxyzzzssxACHHHBxz]>++%;{/sAGDLGCBtsszssxxCCHHCAyr{=+.&;{/sHvLLGCAAszzzsyABBHHCAyr(>++*;]rsHGLLCCAAsszzsxAAHHHCtyr)=...+#=;~]^zsAGLLGHCHDLLvAsr/{;$..+>_/KAvLLvHyABACACBABCCCCCCAs]-@+=!FryCCCCCAyz/]F^rstGELLHyr]-@.@=;{rxCBCCCAsz/{{FrstGLLLtsr],+.+$;]ryCCCCBAyzF]]FrstLLEGHyr];%+@$!]zACHCCCByr/FF/KsALLLLtsr{=+..&=;)FzyCBCBCCBtyxyCCBCCCAs^)=+.+#,')/zsABCBAyssszsyBACCCCAy^-@...+#-)]zsACCCHLLLEuEEGHByz/{;*..",
"..%,!1[IONNNNNwJKQ/FF{]/^QrIr[~%+@*-!]QKKJsPKKKKKKr[QPwNwOP}(;*...*-(}PwNwwI[/:()(]{2QKKKKIr}_=+.@,;(}PwwwJI[F]()({]2QKKKKKQF_=..@>'1[6wNwJK^F]{){)F}QKKKKIQF~*++&-!|Q6wwwJI^F]()({]2QKKKKI^]'*..%-!:QJwNwJI^F])))(][IKKKKI/1'*....@%=,;~1}<OwwwJJJwSYP[}(';=#...#;_2<OwwwPQ/rKzKzrr/rrIrKIIF~#++#-!|[KKJKI^2]);;~(:<OwwO52|!>+++*=;([KKJKI^}|~;;'(2<wwNw5}(;#...%>;1^IKJrI/:{';;'(25wNwOP}|!>@..%-;|[KKKKQ/}('!!~{25wwwOK2(;*....&$-;(F/^IPJJKI/^IJJJKI^2]~-#...@*,;)F2^IKKr[2]:F:/QrIKKzI^{=+...+%*-!]F/rKKJwwwwNwNOPI/2{~-&..",
".+%=;(1<6SSNNYJ5[221__(|}[[[Q[!&+@#=c_}QQIIIIKIPP5Q[[5OSS8<|_-%..+%-0:5YSS6[:('!';;_(2[QIIQ[2(>+.@=9_15OwY6[1(!;;;'~(}[QIQQ[}~>+.&=;_ePRNS6[1(_!;;;~(}[QIIQ[1~=+.&=;(}6RNR8[:__'';!_12QQIIQ[1~$+.&,c(46SNY5[1(~;;;;_(}QQIQQ[:;*.....@#=,3!125OwYOO6OY8<1(~;-*&...%-01<YwSO5[:[QI<Q[2[[QQQQQ[:;*..@=;_}[IQQQ2__;--;;1[6SSO<:_;%..+&=9_2[IIQ[21_;--;c1<8SwO<:~3*+..%>c_}QIIQ[}(~---;_1QOSSO<1_3*@..&,9(}QIQQ[1(~---;~{<OSS8<|~-%....@&*-;_(:}<OOP<[[<PO8<}1('-=@...@#=-'(}[[QQ[}||(_||2[QQQQ[}~=.....&*,;_|}}QIIK66O8OO65<<[:'-%..",
"..&=;aegjWWWqX5hfebbdadbe47khec&+@#=;afkhlhhhmppopi47iqWWjiba3#..+*9afiqWWjgba;---3;ae77hhhkfd>+.@$cdfiqWqpgba9-9-90ae7hkhh7fd=+.&=cdfpqWqpfb_c-3-30de7khkhkfa=..&,cbfjqWqifba;3-33cde7khhhkf0$+.@,cbgpqWqifd0;9--3cde47hkk7ea*.....@#*,9cbfhioqWUqjpigba0->*&..+%3abgjWWqi7f7hlh74ff74hkhh4e0*.+&=3afkhlk7edac,--9dgjWWqieac#...%=9afkhhh7eda3-,9;bgjWWqgea3%...%=cdfhhhh4:b03,>9abgqqWjgbac*@.+&,0d4hhhh4edc3,,-0bijWWjiba3#....@%#=3aab7ioqmi4hioqpgeda9,#+...@#*9abe4hhhkfbbbdbb47khhhkfd>.....%*3cdb47hhlhhg7gimpjjjpgd3%..",
"..#,cbflnWWWoXlh4ee1bbb4kklllka&.@*30|7lXVVVVVnZonmhhXZUWZifdc%...$0d4pZWWjhbac33,39deklllllkb,+.&,cbgpWWWphba99>,-c(ekkllllkb,+.&,ab7pWWZj7ba99>-99beklllVl7b>+.%30egnWWWp7b~93-,3cb4kkllVh7d>+.#9aegoWUZpfdc9,3,9adekklVll4d>+....&*>30d14hmnWTUUoXVk4bac3*&...$9demoUUZphkklVll[4kklllllh40*+.&=cd4lVVVh4e0;339abhoZWqm7dc*+.+%,;b4lVVVk41ac39cabioWWqmfdc*...%3cb4VVllk71ac3-caeiZUWZm7d9=+..#3cb7VVllh4|dc-39abiZWWoifd3%....+@*>-0db4poZnVllmoZohedc9=#....@*=;a14klVVlk42ee44klllVll7b,+...+&=-ab4kkVVVl744<hVnZWWqif0*..",
"..*;)/stGLLvvHCtxzrr^rrxtBCCBy]*+%,!]rtBBCCCCHGHHHBHHvLEELts/)>..@-{rsHLELvyr]);;;~)/ztAABBCtr'@.%;]/yHDEEGyKF)!;;'{^stCCCBBx^;&+*!FIxvEEEGyrF_';;~{^stCCCCBy/;@+*_FKxDEEvtJ^]_!;;~]^sACBBCAy/;@+*~FzAvELLHK^(~;;;~]rstCCCCAs/-@...+*-;)FrsxBHGEEEEGGHAsr/{~-*...>)/zAEEEEGCCBCCCAyxxACCCCCts]-++*;{FsBBCCAyz/(~)(/rxDEEvtJ^(-+.@$;{^sBCBCCyzF{'){/zyvEEvHs^{=+..*;{rxBCCCAtz/(~~)FzADEEDts^)-&.+$!]rxBCCBByz/(~~)2zAEEEvtK^)=....+@#=-']^ztDvGGGGGDDHxIF);>#....#-;)/zxACHHHBtyyyxAAHHBCCAsF-+...+*3~FrytACCCAxssxAHHLELvtKF-+.",
".+%-~{rsACCCCBtyzrr^^^zsBCACBx]#@&>!]ryCCCCCBCBCBHCBCHLLLLAs^(=+.+-F^JtLLLvxz/)~;'~]^sACCCBBA^;&+*!]rsGLELvxz/)~;'~{/sAACBBCyr;@.*;FrsGLLuGyrF)!;')]rsBACCABx/;@.*;FryvLELHsrF)!;'){rsBBBCBBx/-+.='FKxGLLLAsrF)!;!)]ryBBACCBx/;&..+%=-~]/zxBGvvGvHvGvvCxsr/);*+.+=)}stLuELGCACCBABxyABBBCCCBsF,++*;)^sBCCCBxz^])){/KAGLLLBs/{=+.@=;{/xBCCCByz/])){/KtvLLLts/(>+.+$!{ryBCCCBxz/])){/KtLLLuAs^{-&++>!]ryCCCCtxrF{)){/KAvLLLAzF)>+.....@*-')]KyBGGLELLGHts/{'->%+..+&,;)/zyBHGLGCBCBBCCGGLvGCyzF-+...+*;~]zsBBBCCAysssxxCGLEDHsF-@.",
"..@=-;(2IKJKKr^FF()))(]}rIrKr['%+@*-!]/KKJKKIrIKKPKPJwwNww52(;#..+=;([8SNwO<11~;--;!)/rzzKzI^],++&,'([6wNw8Q})';-;;'{/rKzzKr/(>+.&>!1[6wNw6Q1(';--;']/rKzKzr/)=+.&,!1<6wNY8Q|);;--;~]/IzKzKr/(>++%-_:<JwwwP[|)';--;']/QzKzI^/_$....&*,-~{2[IOwwJPKJwwwJQ/1)'-%...%9_:<ONwwwKKKrr^^/F^rKzKKrQ}'*+.%=;)/IKKKr/F|)';!):<ONNw52);*+.+%=;)/IKKKr[F_~;;~(:KOwwO5}(;#...%>;)/IKzK^/](~;;!(2<wwwOK}(;#+..%>!{/KKKK^/|)';;!(}PONwOI2_,%......+@*=-'(}IPOwNNSJ<[]_;=*%@...+@*,;):/QJwwwJJzzKsJwwwwJI[{-*.....&>-~]FQrIKr^F:F:F[KOwww<2_=..",
"..@*=-~|[IIIQ[2:__~;!_1}[QQ[Q};@.@#=c(2QIP5Q[[[[[QIIJOwNS6<:_-%...*;_:5RSR8[:(~;;-;~(}[QIIQ[2~>+.@=c_15YSM821~!;;;;~(}QQIQQ[1'$+.&>cd}8RSY6[1(!;-;;_(}QQIQQ[:!*+.&=c_28YSR6[|(';-;;_1}QIIQQ[:'$+.&-;(48RRY5}1~!;-;!_|}QIIIQ[|!*+...@#>-'(|[<ORO6QIP6RY6[}1(;>#...#-~1<OSNSJPIQ[[[}::}[IIQQQ}1;#..&=3':[IIQ[}|(~!'c_|[PSSO5:_-#..+#>-~:[IQQ[}(('!;'_:[OSSO<{~-%+..&>;_}QI<Q[}1~';!~~1<OSSY<|!-#..+%=;_}[IIQ[11~~!;'(b<OwSO71!-%.......+%$=-'(}<6SNSY5[:_;,$#&+....@*=-!(|[5OSYPPKIIQPOSNS8Q:_;#....+%*-;(:}[QQQ}1|(1|:<OSSO5:'$+.",
"..@*,;dbglmih44ebd0_adb7hh5k7b9&+@*=cb4hmmlh7f4777hiXoWWWqgea3#..+%9aeijWqjgfbda~aadb7h5llk7ec*..@*9afiqWqjgfba~aaadb7hlm5k7e0*+.@=cafiqqqmgeb_a0aabb7hlli<fec*..&=3afiqqqpgebaa!aade4hll574bc#.+&>0bgpqWqigbbaaa0ad:7hilk77d9%...+&*,;ab7gijqoihhimqjpi7fba>#...%-cbgjqWqomlh774eee4hillkhfd3&..&=3abkhhh74bbdaaabbijWUqiba3%...&>9a:7hhh7ebbaaaadfgjWWqiba3%...@=3abkhhk7eeddaaabfgoWWjiba-%...%=3aekhhk7f:daaaabeiqWWjgba-&........@*=-caegpUUUjieba9,$%&+....@#=;abfgpqWWomllhlmpqqopfba,%....@*=3cdee7hh<7ebbbefgjZWqgfc$..",
".+%>30d4mnonmlk74ee:e47hmnXmhe9@.+$3abhnnnplhk774klVXoUTUqifdc*...$9abinoZnVk74e:1e47lpXoml7ea*+.@=9afioZonlk44e1e24khnnnmh7ba$..&=3dfioZoXVk7e:e1e47lpnnmh7ba*+.@=9afmnooXlk4ee:eeekinonmh4bc*..%,3dfmoqonlk4e:1eef7lXnnmh4dc#...+*=3afimXnonnlkkhmnonmmmgbc*+..&,0bgpZZZoooml<k7Q7hmnonVked3%..&$9'ekVVVVhk4eb1eehioWWqpfd9*+..&=9dekVVhlhk4eeeef7mZWUqifd;#...%>9_ehIVlll74eee:f7mqWWqifc3#...&=c_ekVVllhkeee1efhmqWWoifa3%........@$>9a(e7pWUUqi7:d03**%@....%=9ab4klpWWZonXVVVVXmpigfac,&...&#=30(4[lllVl<kkk77hmZWWqmfd>+.",
".+*;~]^svvELGHBtyysxxABvDEDHxz~%@&,!]zxDvvDHCAxyxxBCGDEEEEts[)=..+=!:rxHCHHCCAtyyxxAAHDDLvts/_>+.&-~]rxHvHHCCAAyxyxAAGvDvvAs/_>+.#-~|IxHCHBHCBAxyxyAAvDLvvtz/)=+.%-'FzyBGCHBCAyxxxttBGvvDGtz^)*..&9~FztHHHBCCAyyxxAtHGDLDHxKF'*..+%-;{ryvvvvGHtysssxCHGvvGGK],+.+*c)/sAHGGGLvvHAAAAAHGvDDtyrF;$..%,~]rxACCCCAAyssxyAGDEEGtK/~=+..%-'FzyACCBCAyxsxxtAGEEEEtIF~>...%-)FzyCCCBCAtysyyAAHDEEvyI{;$+.+#-)/zyCCCCBAxsssytBGDEEvyI{'$.......@*-!)FrsAGuEELAxz^]~;,*%...+>!{/syAHGEELGBCCBCCByssQF)!,%...%>;~FzxtCCCBCCBBBCCAvDEEvGKF-+.",
"..*;)FzxvLELLCCCBBABBCHvLvvGs^~&+%-']IADLLGvCByyyABCHvEEEuAsF)>+..$;(/stCBCCCCCABBCCCGvLGGyz/)=+.@>!{rsABCBCCCABBACCHGvLvGxzF~$++@>;)/ztCCCCCCABBBBCHvvLvHyzF'*..@>'{ryBCBCCCCABBCCCCHvDvHsz];*+.&,;]rtACCCCCCCBBCCCCGLvGtsr]!*...+$!{/JGDvHAxszrrzsytHGvDAK{=+..*;)^sBCBCvDLGCCCCCCGLLLLAs/{;%+.@>;]^sAABBCCCABABCCHGGLDyr]'>+.+&>;{rsBBBCCCBAxACCCGvLLDyr{!$+..%,!]ryAAACCCBBABACCHvLLvxr);*+..%-']rxAACBCCCABABCBGvLLGxr{;*.......%>;~]/stHLLEELHAsrF);-,#@..+=;]/sBCCvLLLHCCCBBAxsrF{)!-$+...#-;)FzyCCBCCCCCCBBCCvLELDts/-@.",
".+&>;(:<OwNNwwJJJPJPJJO6O6P<2~>+.@=-~15wNNNwJKIFF/^IPwwNNY52(;%...&$-~1F[^QKKKJPJPJJJJP6P<}(!-#...@$-~]2^QrKKKJJPJPJJOP6P<2(!>&..+&*-'(F[^QrKKKJJJPJJ868P<:(;>&...#>;)]2^QrKKJJJKJPJJPP65Q:_;>@..+#=;~F}^QrKKKJPJKJJJJJ6PQ:_;,&...+&=;_}[5<<[2{_'~~)]}[<5<4(;*...&>;)2rKKJJJJJJJJJJJJO685[:);=+...&=-)]F^QKJJJJPJ6JJJJJJP[_;-&...@*=-)]/^IKJJJJPPJJJOOJ6P[(;>&...+%=-)]/^IKJJJJPJJJJJJJJK[_;=%...+*=;)]/^KJJJJJPJJJOJJJ8K}_->&.......#>-;~:QIJwNwNNOPQ}(~;,*@....*-~]QPJJwNwwJKKrQ/2{~~;-==*@....&*-!([IJJwwwJJKrKKJJwNNwO5:_$..",
"..%=;(2<OSNNSSwYwYYMMMO8<Q[:_-*..@*-a1QOSSNNY8<}1|}[<6MNSO<1!-#...+#=-;_(|2[IPOOYYYOO85[}|(c-$+...@#>-!(|:}QKPOOYYYYY65Q[2(;-*@...@*=-;(_:2QKPOOOYYOO6<[}|_;-#+..+@$=-!((1}QKPOYYYYYO5Q[}(~9-#+...@*>-'((12QIKOwOMYY86<[2(_;>#+....@#>3a(1:((';;->--c'(111_c-#+..&*,'([QIIPK6OYSYSYYO8<[2|~-=%+...&*=-'(([5OwYYYRSRYO6<<[|~-=&....&*,-'_|}POYYRMRYYY8P<<41'-#+...+%*,-'(:[6OwYYYRRYYO6<<4|;,>@...+&*=;~(|[6wYSRRRRRROP<<}('-#+......+&,;~(158MRNNNNMY5}|_;-*@...+%-_:<OYSSNSO5<[[1(!c-,=**#@+....@$,c|[8YSSNMY6<QQ5ORwNNSO7|;*+.",
"..%>0b7ioWUUUUUUWWWUTUqpg7ed0,%..+*-cbiqWUUUWjgeb1e4hmqWWjgba-%....&$,90_(e7hmqWUUUWqmhfbd09*%+....&*,90_be4hmZUUUWWWph4fd09=%+....%*,-0a1e7lpZWUUUWqigbbdc3=%....+%*,9a_bekhpWWUUUUqigfba0-$&....+%>=9cdbehinqUUUUWqmgffdc3*%.....@%*,;00aa;3,>>$==,30caa03=%...&*,cbf7hhmmnoWUUWWqoi47bd9-#@....@#>>9adfioWWWUUUUWjmh4fd0,$&....@#>,;abfpqWWUUUWWWjihffac=#.....&*=-9abepqUUUUUUWWjih4fac=$&....&*$-9abgpqWUUUUUUqjik7fa3=%.......+#,cabfiqWTTUUTTWjgeda-=@...@#,0fiqWUUUWjmk4eba;3==$#&@......@*-;bijWUUUWqph7hpqWUWWWjgb3%..",
"..%,0ekmoWWUUTUUTUUUUTWph4edc>%..@#30fiZWWUUWoifebf7hnZWWqibc>%....+%=-0adekVpZUUUUWZph4edc->&....+&$=-0adehVnZWUUUWZjh7eb09>#.....@*=39abfhVnZUUUUWZmh4bdc,=&....+&*,90ab4kXnZUUUUUZm7f1d9,=%.....@*,-0d14kVoZWUUUWZmh4edc,=&....+@#$,9c00c9>=*$$$$,,900093*&...&>>017llVXnXZWUUUWWomh4edc,$@....+%*--cdfpZWWUWUUUWZmhkebc,*&....@&*,30d7pZWUUUUUUWomkked9=%+....@%$=9cdgmWWUUUWUUUomh4ed9>#+....@#*39cb7oZUUUUUUUWoVh7ed9=&.......@*3cde7pZWUUUUUUUoiebac=&...@>9aepZWUUUWZVlk4ba3>$$%@........@*,cbiZWUWUWZphhlpWUWUUWqgd3#..",
".+*;{rsAGLLvLLEELELELEvtxKrF)3*.+&>;(/yDvELEvvyz^^rsxHvLDGs[);*....+%=-!)]rsAHDDELEDDtsI/F_;-#.....@=-;!)FrstHGLELLLvHxzr/);>#.....+*-;!)FrxAHGLDEELGtJr/]_;>%....+&$-;~)FzsBHDLEDLvvtsr/{~;$&.....@$-!)F/zyAGGLLELDDAsz^F~->&....+&#=-;''';-->=***>,3;!!~;;>%...%>;)^sBCCCCHHLLLLLLHtsz/]'-=@....@%$-'_]rxDLLvLLLELHAtszF~-$&....@%$3;(FKALLLEELLLLGBxsrF~;*+....@#>-')FzADLELLLLDDGBAsz]~-$+....@#>;')FKADLLvLLEELGAysr]',$.......&=;~F^sAvLLELLELvHxz/]);%...@,;{rxDELLLDGtAszF);-$#@+.......+%>;_/sGvLLLDGHttAADDLLLDHK:-#..",
".+*;~FrsxBABBBBAHABBBtwsrF])',&..+*;):rsAttAtsz/]]F/rsytxs^{',&.....+%=;!)FrzsyAAAAtxsr/{)!-=&+....+&$-;!)]/zsABABtAysr/])',$@......+#>;;)F^zsAABBAAsz^F{';,%+......+#=;')FrzsABAAtAyz/F{~;,%+.....+@$-'){FrzsABBAtAysrF{)',%+......+&#--;;--$%%&&##=>--;;->#+...@=;'/zytAtytBCBBBAtyz/F{~;,#+.....+#=;!(FKyABBBBBtAysr/]);,#+.....+#>;;(/zyABAHBBBAxsr/F)!,%+.....+%-;!{2zxAABBBBBxyzr/])-*&......@%>;'{^zAABBBBABxyzr/]);,&+......@#,;)]/KytBAABAtysr/{);>%...@$;)1ryAABAtssr/])!->#+..........@$-'{rsAABBAyszzzsxAAAyxz/)-&..",
"..@#=-;~)({|{|11:1|((()a!;-,*&+...@*,-!_(((((_!;---;;~_(_~;-=#+.......@*=-;'~)((1(((_~;;->=&@........@&*=--;'~)((((((_!;-,=%+........+@*=,-;'_((((((_!;--=*&+.........+%=,-;~)(({(((__!-->*%.........+%*,--'~_((((((_~!--=*&.........++&&&%&@@++..+.@&#$***%@....+&>-']FFFF{){{{{{(((~;;->$&+........@#$,-!_({({({((__';--$&+.......+@#=,;!_(((11{_()_!--=#%+........@*=-;'()(({{{1))~!;-,*@........+&*=,;~(((1111((_~;;-=%@........+&#*=--!)({|{(1(((!;-,*%+...+@#,;!_((((((~!;--=#&+...........+&*=-;_()(|(((_~__)((((~0-=%...",
"...@#*=--------;;;-99---,**%&+....+%*=>,--,3--,==***=,,-,>**&+.........+%#*=>--;;3---,=**%@++.........+@%*>>>------,,,,**#&............+#*=>,-,-----,>**#%++...........@%#$>>,---9,-->>**&+............@%*>>,------>-,>=*#&+.........................++++++.......@%=-!___!;--->---,--=**#&@..........+&#>>,,--------,>>*%&@..........@@*$>>--------,,>=*%+..........+@%**,-----;----=>$$#&..........+@&%>,>----;9---==**%&...........+&#*==-3-----3-,,=*#%......+&*$>=-----,->**#&&..............+%**>>---------,3----,==*#@...",
"....+%#*$*>*>,>>,,==>$$***#%@.......&%*$$=$**$$######***$$%&@...........+&%***>=>>=$>$*&&@+.............@&#**$>>$>==$$$*&@+.............@&%##$*>>>$>*$*&@+..............@&#**$$**>*$=**&@+.............+&&%**$>$>$>$***%&@.........................................@*=39333,>=,=*$==$$*&&&+............+@&#$*>*=$$$$*=**#&+.............&*$$$>**$>>>**$*%@..............&%*$$====,>*>***%&+............@@%*$$=>>=-=*>**#%@.............@%#$***,*,$$*$$*#&@+........@%*$$>$$>*=$*&@.................@%%#***$>$=$>>**=$*$=*$%@....",
"......@&*$*$***********%%@++.........@@%*#****%&@&&@&%&%%#&+..............+@#*##$***%*&+.................+++&##%**##**%++..................+%#$****%*#@+.................+@&%$$$$*$*##+..................+@@%%#*****$*%%@..........................................+@**>>,=$>$$***##**%&+................@&#***$=****#&@++..............+&##*****###$*%&@@..............+@%**##*$#**##&@@...............+&%#*#***%$$%$#@@+.............++@%#$$**$=*$*%&@@+..........+&%*%**%*#%@+...................+@&#*$*****#*$*****##&@.....",
".......+@%&%%%%**##%%&@................+&&%%%&@+..+..+.+@&@.................&%%&%%%%&@+...................+.+@%%&%%&&%&.....................+@#####%%@+...................+@@%######%%+.....................&&%%&%&&%%&&+...........................................+%*$$*%%%%**#%%%%&@+..................+&%#%%*%%#&@+...................@%&#**%%%&%%&+.................@&&%&%&%%%%&&+...................+&%%%##&&#&&&+................++&&&&%&#%*##@...............+@#%%#%&#&+......................+&&&%&%&%&&%%&%&#%%&+.....",
"..............+.+........................+...................................+.+................................++++++......................................................+@&&&&&&@...........................+.+...................................................++++++.++++++..+......................++++.++.........................+.++++..........................++..............................++.......+.......................+.+.+.......................+..+............................+.+.++++..+.+..........",
".............................................................................................................................................................................++++++++........................................................................................................................................................................................................................+..................................................................................................................",
"...........................................................................................................................................................................+@@@@&&@&+.......................................................................................................................................................................................................................+++.................................................................................................................",
".........+@@@@@++.................................+@+@+........................+@++........................................................................................+@%####%%&+...................................................................................+++@+@+..................................+@@@@++....................+@@@++++....................................................++@@+++.................................+@++@++.........................+@+............................................",
"........+&%##**#&@+...........................+@&%%**%%@...................+@%%*#*#&+.....................................................................................+%$*,,>,=>$%@.................................................................................@%##**#*%+..............................+&####%##&+.................+@***$*#&@+.................................................@&*#*$#%@+..............................@&#****%%+.................+@&%#%**%@...........................................",
"........&=--;;;;-$#&+.......................+@#=--;;;;,$&+...............+%=--;!;;;>$%@...................+&#******%%&@..................................................+#-;'~{){)!;=#+..............................................................................+%=--;;;;--*&+..........................@%*=-;;';--$#@..............+&==-';';;>##@..............................................+&=>-;;;;-$#@...........................@&*>-;;;;--*@..............+@#=-;;;;;-=%+.........................................",
".......%$-;!)]])!-,=#@....................+&#*-;;~)]]);>*@..............+%>>;')]]]~;,*&................+&&#$$-------->*%+.................+@@&&&@+..++...................%=;'{F/^//]~-$#+.............................................................................@*,-!~{])!;-=&.........................+&*=-;)]])~;-=#@.............@*,;~)]]]~;-*#&................+@&@@@@@+@@@.................&$>;!)]{);-=$+.........................&*$--~)]{~!->$&............+%==-;){]{)'-$%+.................+@@@@@@@&&@+...........",
"......+&#=-;!)(~;,=$%@+...................+&#*=--;~)~;-*%@..............@%$=-!){_)'->*&................@%%#>=->>,,,,->=#&+..............@@@&&&&&@@@@@@+.................+%*-;)(F[F});,*%+............................................................................+&*>-;!)();,=$%+........................@&#*,-'))';-=$#@............+&*$-;')_)'-=$%@..............@@&@&&&&@@@@@&++..............+%$=-;~_)!-=**@.........................@%$>-;)))';-**&+...........+&*=,-~)))!;>*%@................++&&&&&&&&&&@+..........",
".....++%*$-;_((_;->*#&+..................+%#*$>;!~~((',$#+.............+&$=-;~~(1(!-=*%+..............+@#*>,-;;;-;;-;-,=*#@............+@&%#%%%&&&%&&&@@................@%*,;_1}}[1(;->*&............................................................................+&#$>;'((_;-,=#&+......................+&#$>-;_((_;->*&+............@%*=-;((1(~;-**&+............++&%%#&%&&&&&%&%@@+............+%*>-!(11~;->*#+.......................+&#*=-'~|(~-,>#%+..........+@%$>-;_(|(~;,$#%+..............+@&&##%&%%%%%%&@+........",
"......@%*>-cdbbda;9,$#@+................+@%$>-cadbbb_a-*#@............@%#$,;adbeebdc9=*@.............+&%$=,9cdddadaaa0;3=$%+..........+@%$$$=**$$#$$##%@+...............@#>3cdb4774ba3>$#+...........................................................................@%*>,;0beba!93=%&+.....................@#*=-;abbbd!3>*&.............&#>,;abeebd0;>*#&...........+%%#$***$###$#*###%@+...........@%*>-cbbeda;9,*%.......................@*>>-cabbb_c-*#%+..........+%*=-;0bbebbc9>*#&.............+&%#$$$$*####*$$#&+.......",
"......@#>=cae[k4ee(ac=$&................+%=,3'be4444ea9>*&............@%*-ade47kkke(a9=*&............&*,30~bf7ggkgg74ebac=$#+.......+@%=,3ccc93=,33cc3=#@...............@*,cd47kkk74bac=*@...........................................................................@%$>90b4444e{ac3*%@...................&*=30db14k4ea93$&............&*>3ab47kkk4eda3=*&.........+%*>-cc093,,,3cc-3=*$&+..........+#$,ca:474eeda9$%....................+%*>9aa|e4k4ba9>*&@.........+%*>9d:27kkk41d93$%@...........+%*,39c'c3-,,-c99=#@+......",
"......@*-;)FzxCAAAsz]~-=%+............+%*>;~]rsACBAsrF'-,#+..........@$-;)/sACBABAAsr]!-=@..........&=-~]/zstGvvvvGHAAsr]~;=%......@#=-;){/^rF{)){F//{;-$@............+&$-']ryBCCAyszr]!>#+............+&&&&&&%@@@&&&&&%@+.................+@&%%%%&%&&&%@+...........@#-;~{^xABAxyz/);-#%+...............+&=-~{/zyyAAAs/);-#..........+%=-']rstBBCCAAs^);-$@......+@#-;~{F/r/])))]/^F)~;-$%+.........@=-;)]zxCAAxsr]!-#.................+&*,;~]rzyABByr{~->*@........+%>;!]rxBCCBBAsr]~-,#+.........&*-;)]F/^^{)))]//F~-$&+.....",
"......&*,;~FzyACBBts/);-*@............&#=-!]/zACBBtsr]~;=#+.........@#>-']rxBBCCCCAxrF~;=#+........+%=;)/zsAHvDLDLDvCCyz/);,%+.....@*,;)]/rzzrF]]FrzrF~-=%+...........@#>-)/zxBABAyyzrF~-$&.........+&##$$>>>$*$$$*>$$$**%+............+@###*====>,=>>$**&@@.........+#>-!)rsBACBAyr]~-,*#@..............&*-;)FzxyBABtz/);-%+.........+#=;)]zyBCBCBCCxz]~;,%+.....+*>-'{F/zzr/F]F/zz^])!;-$&.........&#-;~FzyBCAByzF)-$%................@*>-!)/zytBBAsr{'-$&+........&=-;)/sBCCCBCAyz/);,#@........+#,-~)F^zsz^F]F/rz/);>*+.....",
"......&%$=-!{/^rrr//(;,=*@...........+&#=,-~{F/rKr^F(~->$@.........+&#=,;~]/rKKrIrr/1);>#&+.........&*-!):[QP8JOOOJJKI/])!,*@......+%*-;'(]F}F{_){{F]);>*@+...........@#=,;)F/r^r/^FF|~->%@........++&#*****=$*##$***=$***%@+..........&&%**>>>>=>>=*=$*$#@@.........+&*>-;)F^rrrr[]);-=#%&+............@#*,-!)F/rrrQ/]';=*&..........@#*,;)F/rIKzIrr/F);-$%+.....+#*,-!){F}F|_({{FF{)';,>#%+........+&$>-~]F^rrr/F~;>*&................&$=,;~{F/rr^/F~->#&.........@%*=-!(/QrKrIrI/F);-$#+.........@*=-;')]FF]_((]F1);=*&+.....",
"......@%#>,;_(2}[Q[}(;->#&+.........+@%#$,;~_:2[[21_~-,*%&.........+&$>-;_(2[[[[[[[}:_-=$&+.........&$=;(:1[[<<<PKP<Q[1(;->*@.......&*=;'(_:1:|(|(:1_!-*#%+...........+%$=;~1}2[[Q[}(~;-*#@........@%#*$,>,,>,,===>,,>,,>=**%+.......+@&#*$>=,,--,-,->,>=*$&+.........@#=-;_(:2[Q[[1~!;>*#&+...........&**=-;~(}[[[2}|~;,>*&.........+&#>,;_}[[[[[[[[2|~!-,*&.....+%$,-;~_|}::(((|111(~;-=*%+........+@#=-'~112[[}|_-,$&...............+&*>-;~|}[[[:|~;,*#+.........+&$,;'(1[[[[[[21|~->*@..........@*>-;_(|::|1((_|(_->#&......",
"......&#*=-cdb:e7hk4ba;,*%@..........@$*,-0d:f4474eda9,$#@.........+&*-;0dbe474f4e74eb0,>#@........+&$,;def4747khhhk4fbd;>$#@......@#=-cabbeeeeee1eeba;>$%+..........+&*>-cab44<kh4ebdc-$#+.......+%*$,399c9c;c9999c9c;c93>*#+.....+&##$>,3cccc;c00;09cc3=*%@........&%$$-;ad1f4kk7fbac9=>*&+........+&%*>,;abb47<ke:ba;,>=%+.......+&$*,90bf74444477f:bac9=&.....@%$,90abbeebbbb:febbaa9>*%@........+&$=-0d1ee774edc,*%...............@%*-cabe4<74bd0->%&+.........@%$,;0be4744ff4eba3>*&.........+@#=-cabeefeeeebeda;=*@......",
"....+&%=>c'dbe4<lVlk4|a93$*@........@*=-ca1e4k<lkk4ed!9=*%.........&$,c_be4kkkkkkkkkked;,*&+.......@#=cd:4kkkkkhVVVlh4eda9=#&.....@#=3ad:e4kkk7k77774:a3=*&.........+%#=3cae[khllVlk4dac,*%.......&*>3cadb(bbddddd(b(bbd(ac9=#.....&**,39c_dbb:b1b:b(bbda03>#+......&*$=3cd1eekhlVhk4:dac3>$%.......@#*,3;a_b}kklllh4e1dac3=%.......@*=,3a(4hIlhkkk<hk4e1d03#+...+&$=3a(:ek4kk[474k74ee(ac>*@........@%*,ca|e4<llh7ba3>#+.............&*>3;db2klllkedc3=$&..........@%=3~be7klhkkkk4e(03*&.........+%*>9abe4kkk77744ed9,$&......",
"....&=,;)]^zsxtBCCHAAsr]);-$&......@*-~{/rsxACACCBtxr/{;--%+......+*-!{rzyACCCABCCCAts/{!-$&......@#,;{^sACCBCCCCHGBCAsrF~;,*+....%,;)FrssAACHBBCCCAxz/);-#+.......+%-;!{/rstCCCHCBAxz/{~->%+....+$-!{/zsssssszszssssssssz^]'>@...%>-')]F/zzssyyxsxyssssz/{!,&.....&$-;~]/rsyyCCHBCBAyzr/]);-%.....@*-;~{F^zsAACHCCAAxsz^]);-%.....@*-;)]/zyACACABHCBBAszrF);%...+*;']/zsyBBBABABBCBxyzz/]'-*+......@*,;~{^zytACBCxzF);=&............&$;'{FrsxtCBAAz/);-$@..........#,;)FrstBCABBBBys/{;-%.........&*-!)FrstCCCCBByxz^);-%......",
"...@%=-)]rsyBGvGLGLHCAs/{!-,#+....+%-;]/zsAHvGLvGHCByrF);-$%+.....&=-)FzyBBGGLLGvHCCBy^{'->*&.....@=-;{/xtCCCGLLvLGHCCxz]);,*&....&-;)/zyBCCvvGLGCCCAz/);-$&.......@$-;]/zyACvvLvLvCByzF)!-=#@...&=;)/sAHGGHHAAAAABHGGGGHAxr];#..+%-;)FrzstCHGHGGGGGHGGGts/);*....+#=;~]/zytBGGvGvvGHCtxzr/);$+...@#=;']rzstCGvGLLvGGHAyszF);*....@#,;)FrsACGvGLvLGvvGCBys/{;*+..%>;)FrxyBCGvvLGLGHHCAAsrF~-=%......&*-~)/rxGGLvvGHs/);>#...........@*,;)FzyHGvLLGHs^{!-#@..........%-'{/zxBGGLLLGHxz/);=#+........&=-']/zxBGGvGvHAyz/);>#+.....",
"..+@%*,;{}QKJwNwNNNwJKr:);-$%+....+&=-)][QKwwNNNNwJKI/_;->*&+.....&*>;(/QIJwwNNNwwwKr[{'-=*&@......&*=;)/IrKwwNwNNNwJK/}~;,$#&...+@*-'{/IKJwwNNNwwJJr[('->*&......+@*=-'][IKJwNwNNwwKI/('-=$%+...@=-_}POwwNNwJJzKJJwwNNwwJI[{;%..@%>-~|F^IPwwwwwNNwNwwNNY5}~-#....+#*-;(F[IPwwNNwNwNwwPI/}]~-%....@#*-!)}/IPwwwNwNNNwwJKQ/1'-#....@%=-;1/QIJwwwNwNNNwwJKI^]'-%...%*>;(FQIPwwwNNNNNwwJKI^});-*@......@#>;!(25wwNNNw6[_-=*@...........@#=-!(2IOwNNNwJ[|'-=&..........+@*-!)1QPwNNwNwJQ1~-=#&.........@%>-'(:[6wNNNNwP[|~->$&......",
"...@&$=;(}[<8OSSwSSOOPQ}(;-=$&.....%=3~1}Q5OYSwwSwOP<[(!-=$#+.....@*=;_}[Q5OSwSNSOOPQ[|~;-$#@.....+@*>-_:[QI6YSNNwYO6KQ:(;-=*@....@$>;(}[<8OSSNSSYOP<}(~-=$&.......@%=-_1}Q5OOSwSSYO6<[1';-*%@...@*-015OwRNSYO8KPPOOwYMRY65[:;*..@*,9_1[Q<6YSSRRMRSSSNNNY51~-%+...@*>-'1}[<6OYNNNwSwYOP5<Qe(;*+...@*>3!:}[<6OwSSNwwSSOP<<[:~;$+...@$>-~1}<K8MNwwSNNSSY65<[:~;%...&=-!|}Q<KORwNwSNNSRPP<Q[|!-=&......+&*-c~1<8RNNNN64_3>#&...........+&>-;_|<8YNNNM64~-=$&...........@*=-;(15OSNNNR52(;-$@+.........+%*-'_(}5OSNNNR5}_;-*&++.....",
"...@#*,;de47iipppmpmppmgbd0-*&....+%=;a:7hhipppppmpppied0;=*@....+&$>cae4hiipppjjpppmgfda3>*@......@%>30|f7h5ppppjpmppi7bd;3*&....@*>cde4hipppppppjppheda3=#+......@%=-ae44hippppppjnmifba;,*@...@*3cbgippjjjoqqqjXppppppppmga$+.@*-afgppppjjjppippjqUTTqjed9*....@*=9dgijjjopjppijjpompppgfc=+...&*-0dgijppjjpjipijjjXppigbc=+..+@*,!bgipjojjjjpijjojopppgb0=...%>9afippjojppippjjojjjpied9,&......+&#>9cdfipqqTWjgd9>#&...........+&*-30dfimqWTWjgac,*&...........@#$-90deijqUUqjea9,$@...........&%=-0abgijqUUqpba;,*&.......",
"...&%>3a14klll5hilhmooomked03*@...+#-0bekkllhh5ihmXZomhe|ac>&.....%*,cb4k<h5hih5kmnZoXkeba9=%+....+&$>cd:47khhhhhilXoZXi7edc,&...+@>3a17kh5h5hihimoZom7eda9*&+.....&*>c(4kll5hhh5hmnooph4bdc=&..+&=3ab7lVVVXmqWUWWnmlhhhmmoqib>+.%,0bgpqZZomlggf4ghVjUTTTjgb0$+..+%*90bioZWqnmmhihhVVXZZWZngb3%..+%,9dfpoWZoXm5hhghhVnoZWZpgd3#..+%=3afmqZWonm5hghhlmnoZWqngb,@.+%3afioZWZnm6ihghlmnoWWWoiea3#.......@*=-9abfgjWUWqgb03=&............@*$,cabegpWUUjgbc3*&...........+&*,,0abfijWUWjgb;=*&...........@%$=3;abfipWUWjgb9,$&.......",
"..+#,;~]zyAACCCBBABBDDvHxsr/~-%..+#-'FryBACCBBtBBBGvDGAyz/{;-@....*-'{rsACCCABABAHHLDvtyz/{;>&....&#-;{/zxtBCABBtABGDLDAxzr]!-@..+%-)/zyABCBAABBBAvEvGtszF);$&...+&=-!]rsACCCBBABBAGLDGAyz^]'>@..#-~FrxBCCCCCDEEEEGABBBBCvEEwQ-&+*!]zADEELGCAsI^rzsAHuuEuuV/{,+..@=3~FKtEEELvCAAyxABBGDEEEvAr(=++#-!{/sGEEELHCtyyyyBAGDEEEvyr($+.&=3)FsHvEELGCBtyxAACCLEEEGyr'@.+=)/stEuELvHCAyxAAHGvEEEvxK]'=.......@#>3'(}rsGLEuvyI{!-$+...........@#>-'(FKsGuEuDy[{'-*@..........+%=-;!|2ryGuEEvs^{;-#...........@&=,;~|/zyvuEuGK^);-#.......",
"..+*>;)/ztBCABCCABBBGLvGAxz/);*+..%-)]ryABBCCBBBACHLLGBss^]!-#...+*;!]ryBBBBBABBBCGLLGBys/{!-#+...&$,;(/zyBABCBABBCHGLGBAsrF~-#..+*;)FzyBBCCBCBABHvLLHAxz^);-#....%>-~]rxAABCCBBBACGLLvBxsr]!-%..%;)FryBACCCCvEEELvCBtAABGvEA^;++$)FztHLLLGAsr/FF^rsxtuvGtz/)>@..@$;)FKALELLCCBAxyyACCLLELvtz]>++*-~]rsGLEEGHCBAxxyACHLLELGtr{=..&>;_/KGLELGHCCAxyACCCGLLuGx^;&.@-)/JALEELHCCBxyxBCBvELEDAzF'$+.......@$-;~]^JtLEEvxr]'-$&...........@#*-;)F^stLLuvyr{!-=&..........+&*=-;)]QsGLEuGs^{!>#+...........+%>-;)FIsGLEDHs/{!>%.......",
"...%=-;(F^QrKIKKPKPJwwwPQ}]);$&...&=-~]FrIKKKKIPIPwwwOI[F(!-*&....&=-!(//rIKKKIPI8OwwPI2F)!-=@....@&=-;)F/QrIKPKPIPOwwOP[/]_-#&..+%=;~]/QrKKKIKIPPwwMJQ[F);,*%....@*=-!(/^IrIKKIPKPOwwOI}F|'-=&..@=;_]/QrIKPJMNSNwJIIQrIIJMY81>+.%-_:<JwwwP[}(!;;'_(:[[4[2(!-%...+#=;~26SwNwJKI^^Q^IKPwwwNO<1;*..%=-'1[8wNNwKKIrQ^QIKPOwNwJQ|!#+.@*,;([6wNNwJKrI^[/IKJJNww8Q|-+..*;(}6wNNwJKKrQ^QrKPwwNNO51_;%.........&*>-!)25wNwOQ|!->&@............@&$>-!([8www8[|!-$#@...........+%#*=-'(}6www6[(;-*%+............+%$>-!|[6wSSP}(;,$@.......",
"..+&*=;_:2[Q5688Y6YRMNM5[:)!-$&..+%=-;(}[QI66OM8MMMNM6[}|(;=*&....%>-'(}[QI686M6YMRNM8[21_;=*&....@#*-;(1}[Q868R6RMRNRO52|_;-$@...#,-_|}[Q58OY8OORRNR5[:__-=#@....@%$-;(}[Q<8O6Y6YYMNM6<2|(;=*@..%,;_1}QQI66MRNNNR8KQQQ<<8MM5b=..&-!(<8SSO<}(_;;-c!_d|:21(~;-%+...#=3a15RNNOPIQQ[QQQI5ONNS8[(c*..&*-c_e5RNNOPI<QQQQQQPOSNR84(;%..+*=9_f8YNSOKIQQQQQQQ6OSSY84~,+.+%;_b5MNNR65QQQQQQIIOMNNO<1'-%.........@%=,-'1<YNR84_;-*#+............+&%$=9_15OSR64_;,*%+............+&$>,-_|5MNR8e_;>$&+............+@**--a15YNR5e~->%@.......",
"...&>,cdekhimqUUUTUUTTqjgfba3=&...%=;0b44iioqUUUUUTTqjgfbd0,*&...+#=3ab77imqWUUTUUTTUjgfbac>*&....+#*-0bekhipWUUUUUTTTqifbbc3$@...%>;de4himqqUUUqTTTUjgeba9=*@....@*=9ab4ghijqUUUUUTTTjgfe_0,%@..&-0be4hhmoqTTTTTUjmhkhlmjWqib>++&,0bgjWWqigbbdacaadbbefbbac-*...+#-cdfjqTTqpl5lkhhllmjUTUjgb9#..&*-0dgpqTUqpVlmlhllhmjWTUjgd;%+.@$-0dgjUTWqmll5hhlhlpqUUqpg0,+.+%3afiqTTWjVh5hhhllloqTUjiba3#.........@%*>3cfijUWjgd9-*#@.............@%$=-abiqUqjgdc-*#@.............@#*,3afiqUqpf09,$#@.............@$$,9afiqUqpea;,$%+......",
"..+#=caehlmnoqWqUqUqUUqjh7ed9=&...#,0b7hmmnoqUUqUqUUUqik4b!9>%...@$9a|7lVmnqWqUqUWWUqji7e1c3>&....&*3cdehmmXoqWqUqWWWUqph7:a9=&..+*3ae7lVmXqWqWWWWWUqjh7ed;3*&...+&*-0b7kVmoqWUqWqqUUWolkf1a9>@.+*0(4<VVXmoWUTTTTWoXVXVVXqUqpf,+.&-abhpWUqnlh742eeee477h77eba$+..@=30bgjUTTWoXlVXVVVlXoqUWjiba*+.&=3cbgjUTTWoXnXXXlVVXoWWWjgb0#.+%=30bgjUTUZnXVlVlVVVnqUUWp7b,@.+$cdgjqTTWoXVVlVlVlXnZWUqifd;%.........@#>3cdfpqUUjiba9,*%@............&#=,caeiWUUogbc9,*&@............@*>30dgpqUWjgba9=*&+...........+&*=-abgpWUWjgb09=#@......",
"..&>!{/stGGLvDDDDDDDDvDGAys^{;*..+>)/ztvLvDDDGDDDvDvvHBxsrF'-=@..%-)/sxDDDvvDDDvvvvDDGCtsr]!-#...+#-~FzyGGvLvGvDvvvvDvvHByz/)-%..@-)/stvDDLGvDDvGvvDGGCtsr{'-%...+*-)FzAvvvvDDvvDDvvDDGBtsrF~-#.@,/sABBCBCGvDEEuEELHCBCBHHvGx[;++%9)/sAGDvDvGHABBABABHGHGtAzF;+..%-~]QJvuuEEGHCBCBCCCHGGDDHyz],+.#-_FQsuuEuEvHHGHCCCCCGvDvHxr{=++*;_FKxuuEEEGBCCCCCCCHGDvvHsr!@.@-(/JGuEEEvHBCCCCHBHGGvvHAz/_>.......+%*,-~{^sGLEEvAK/)'-,*&..........+#,;~{/JtEEEvAK])'-=*@.........+@#-;~]rsGEEEvyrF);-=%+.........+&*-;~]rsGEEEGsrF);-=%+....",
"..%-!FrxGLLLvCAAAxAACCBCBts^);*+.+,)^JALuEGHBtyytBACBCABszF);=&..&;{/sHGLLvHCtAyytCHCBAAsr]~-*+...*;)FKtvLLLvCBtAxAACCCCAxz/);*..+,{rsHLLLvCBAtxAACCCCAAs^{!-*+...*;)/stvLELGBAAxtBBBCCCAxzF)-%.@-FsBCCCCBCtALEEEEvBCCCCCCCAy^-@.#-~:rxBCHvvLGCCCCCCHvvDLGAs^-@..&-~]^sGEEEEvCCCCCCCBBCCBCAsr{=++&-~FrsGEEELGCCBCCCCCCCCBCtsr(>++#;)FryvuEELGCCBCCCCBCCCCCBs^'&.+,{^KvuEELvCCCCCCCCBCCCCAxz/)=+......&#=-;)]^JtLEEvAz/{~;,=*&........@#>-')F/JALELvAzF{!;-*%+.......+%*=-;)FrJtLEuvxzF{'->*@........@%*>-;)FrsGLuuGy/F)'-,*#@...",
"..@>-~1[8wwwJ<^[/[/QIKKI^/F|!-%..+*;(2PwNNOKQ/[/[^IKKKrQFF(;-*@..@=;(28wNwOII[/[[[KJKK^^/1~-=%....&=;_2<ONNwPI[[/[^QIKIrQ/1_;=%..+$!|[8wNwJIQ/[/[/IKKI^/F{!-*&...+%,;_25OwwwPQ[/[/QIIKKr^}]~;>&.+=)}rIKKKIrQQ6SNSNOJKKKKKKKI[)$+.@#>;_F[II8OwJJJsJzKJJOwJPQF)=+..+*-!([6SNSNJJKzKKKzKKKKKKI[|!*..@*-'|46SNSwJJzKKKKIKKKKKKQ}{!%.+@*-!|7ONSNwJKKzKKzKKKKKKIQF_-+.+*;(}5NSNNwJKKzKKKzKKKKKI[]);*......+&**,-;'(2PYwwO<}(!--=*%@.......+@#=-;!)1[8YNwOQ:)!-,=*&+.......@%*=--;'|[6Mww8Q1_!-,=$%+.......@&#>--;~1[6www6[|_;--=#%@...",
"..@*,0(48SSR8[}}:}2}<KIQ[[1(!-#...#;_1<YNSO5[2:2}[[<I<Q}}|~;,*@..@*c_15YNS8<[}}:}[<5P<Q}21~;=&....%=-!1<OwSY6[}}}:}[<I<Q[}:(;,&..+$9_}5YSR8<}2}:22QII<[2}(!-=&....&=-_1<OSRY5[2:2}2Q<I<Q[2|_;>&..*;:[QIII<Q4<8RNNROPIIQQQQ<[}~$..+#*>3!(|}Q56OJOO6PI<II5<[|_,*...+%=ca:5MNNYOPIIIQQQQI<II<[1(;*..+*=c_}5MNSOPPIIIQQQQQ<K<<[:_-#..@*,c_f5RNSOJPKQQIQQQ<I<I<[:_=+..%-~b<RNNYJPI<IQQQQQ<I<<[}(c-%......+%$,-;!(|}5MNS8<:(_;-,$*@.......@%$>,9~((f5MNR6[:(~;-,$*@.......@%*>-;~_1}5RNR841(!;-,*#@......+@#$,;;_(|45MNM84|(~;->>*@...",
"..@*,0dgpqWqji74777hppplk74ea3#..+%3afiqWWqig77ggiijjpih7eb;3*&..&>cafiqUWqih7777gmpjph47ed0,#....&=9cbgjUUqph7777gipjjih74ba-%..+$cdgiWUqji47777gjjjmh77edc=%....&=3afiqWUqig7777hijopik74b0,&++$0ekimpppmipjTTTUqjmmhhhmmiga$...@*$>3cabf4imqWZomlhhh74ba0,#...@*=30bijjqjopmlkhhlhlmpjpied3#..+#=9abijqjoopmlklhhhlpjppied9#..+%=30bijqqojjpikhlmppojopgf0,+..%>0bgjqqqjoXmklhhlhmjjjigbc3%.....+&*>;abbbfgjqTTqigeeb~c3*%......+%*=;0abffgjqTTqigebdac9$&......+%$-cabbefijqTUji7fbba0-=@......+#*,;abbffijUTqqifeb_a;,$&...",
".+&=901gnWUWZmVVVVmnoWZoXVl7bc*+..$cbemqUUWoXVVXnnqUUoXVlked9>%+.@>0bgpZUWZnVVVVVmoUWqnVlkea,*+...#=cdfiqWWWnmVVVVXXWUWXmVk7d9#..+=0bgjWUWZXVlVVVnoUWqXllkba3#+..+#30dfmqWUWnXVVVlmoWUqnVVhed3#..=d4kXnZZWqWWUTTTUWZZnXVXnooib$+..+&*=,30(ekVnZWWZnVlhk771ac=%...@#>30b7mnXoZZoXXVVVVXnWWWjgbc%..+%$30bhVnnoZZoXXVlVVnoWUqjgb;#..@#$90bgmmXoZWZnXlXXZZWWUqp7d,+.+#,3dfinnXZZonXVXlVmoWUUqiba-#.....@#>9_e4khlmoUTTUoVlkk7:a9#+.....&*=0d:7kkVmqUTTWpVhkk4ba3#+.....@#,9de7khlmqUTTWnVlk72ba3#+.....%*9cb27khlmqUTUqnVlk74ba,%...",
"..#-']rxvEEEGHCCHHHvEELGHCCxr]=+.+=(^stDEEvvHHCGGvDEEDHHCtz/),*..#;{^stEELvvHCCHGvDEEDvCCtz/'=@...#3~/ztDEELDCCBCGGDEEEGCCAy^)=..@-]rsGLEEGHCCHGHGvEELvCAAz]'=+..+*;_/zAEEELvHCHHGvDEEEvHBAs/'$+@-FsAGDLELELEEEEEEEEvGCHCGDDxe,....&=-;!)/zyBvLEEvGCBCAxz^{~-#...@$-;(^sACHLLEvGBCBCHHvEEEDJ/)*..@*-!|^sACHGvLvCCCCCCvDEEEDP^(=++&=-9_}ztCHGvLvHCHGvDEEEEEwse-+..*9_FzxCGvDLLGCCCCHHDEEEuwr{9$....+#-'{^sACBCHvEEEEGHCCAAs/);&....+$-!]rsACACGDEEEEGHCCAAs/)-&....+$-~]rxABCBGDEEEEGCCCBAs/),&....+*-']rxABCBHDEEELHCCCAAz/~>+..",
"..%>'{^KAGvvHCCCCBHHGGGHBCAyr(=+.+=)FKAAHGHCCCCBCBGGGGCBBAzF~;%+.@>)FKyBGvvBCCCCBHHGGGCCCyzF'>+..+%-']QyAGvHCBCCCBHGGvGCBBAs/)$+.+-_/sxGvGHCCBCBHHGvGGCCBxr]'>@...%-~FKxHGvGBCBCBHBHGGGCCCAz/'*++>]zyBHGGvGvGvDvDvvGHHBCCCGtz{$+...+&*>;)]rstHCvGGCCBysr/]';>%...+%$;)FryAAAHGHCCCCBCCGvHvAzF;%...&$-)FzyAABHHHCBCCCCHHGGtxzF;#..@#=;']^syACHHHCCCCHGGvvGGxz{-+.+#-!)^sxABHGvHCBCCCCHvGvtJ/);*+....*-!)rsyABCBHvDvGCCABBtsr);*....+$-']rsyBCCBHvLvGCBCBBxs/);*....@$-~]rsxBACCGvLvGCBCBBts/);%....+#;~FrsyBBCCGvLvHBCCBBtsF)=+..",
"..+%=-'1}QQQIKIKIKKKIIKKIrQF);*..+%>;):[[IIKKKKKKKKIIIIrQ/|!-=@+.+%>;(}[QIIIQIKKKII<IIIrQF{'-%....+*=-~1[QQIKKIKKIIIIIIKIr/]_-%...*-!(2[<IIKIKKKKII<IIII^/_'-%....&$,-~:[[IKIKKKKKIQIIIIrQ^]~-@..%;)1[IIKIIII<Q[[QQIKKIIQ[2:_>@......+%*>;)]2IKJJKKI/F{~;-$#@+....+&*>;~(]22QIIKKIKKKIQ[4e1d;$+...+%*,;~)]2^QKIKKKKKrQQ[72b';$+..+&#$,-'){:[QQIIIKKIIIQ4}e|_,*....%=;!)]F}[QIIKKKKIIQ442e(!-*@.....@*-;)]F^QrIIIIIIKIrr^/F_;*@.....%=,;)FF^QrIIIIIKKIzr^/])-*@.....#=-!{FFQ^KIKIIIIKIr^^/])>$+....+&=-!{F/QrIKIIIIKIrrr//]'-*...",
"...@%*-9(1}[}Q[[Q[[QQQ[[Q[}(',&...@*,9_|2}[[2[Q[Q[[}[[[Q}:~->#@...+*-c_|:2[[[[[Q[Q[[}[[[}|!-=%+...+&*>3~(:}[[[QQ[QQ[[[[[[2:_;=&...&*-0(12}[[Q[Q[Q[[[[[[}}(!-*%+...+*$,9_|22[[[[[Q[Q[}}[[[}|~3*&..%,;_(}[[Q<Q[}:|::2Q[[Q[2:(!3*........@#>-;(1[IP6IQ[2('-=*%+........@#=--;'(:}2[[Q[[[[::(__c-#+....+&**-;;~|2[Q[[[Q[Q[}1__!->@.....+&*==-;~(:2[Q[[[QQ4:|_~;3>&....&**--;!(:}[[[[/[Q[}:(_!c-*#+.....@#=-'_|}}[QQQQQQ[Q[221_!-$@.....@%=;'_|}}QQQQQQ[Q[[}}|_;-#+.....@$=;~(:2}[QQQQQQ[Q[}}|_;-%......@#=;'((:[[QQ<QQQQ[[221('>&+..",
"...+%$-;abeef777k7777744f4ea;=%....%$30dbe477777774fff44eb'-=%+....&=30bbf47777774ffefffebc,*@.....+#$,00bff4777777fffef4eb03*@...@#>9abee44777774feee4eed;,$&....+&*$30deef47k77774ffffeeba-*&..&>9cdb74477ffbdbbf47774fb0c=#........@#$9abfipoomhfba;=*&+.........+@#>>39abef7477774bba09,*@......@%#$,9;db47777477feda0c=$&......@%$*=39abef77k774fbdc03,*&.....&#>>,30dbf4777774ebdac->#@......@%=-0d(b47777777747f:bdc,%......@%*-0ab:f7777777744f:bdc,#......@#>3addee7777777744eebd;>#......+%>30db:f477777h47fe:bdc>%...",
"...+&*=9adbee4477744eeeeeeba9=&....&=3cdbee447744febeeeebdc,*&.....%*90dbee4474744ee:eef|dc3=%......@=,cdbbee4444744ebeeee|09=@...@*=3adbeef477744eeeeeeba9,*&....+%#$30abeee47777eee:eeeed09*@..@*,c'befeeeebdddbbeeeee:d03=%+......+@*,;b7lnZWWXie1c3>#@...........@&%=>90dbee4444febda;9,*@......+@#*>,9abee4444efebda;3,*@.......@&#$>9adee444eefebac9,*%+.....+&#=,9cdbee4774eebda03>*%+......+%$30adbe47k77k774eebbac,%+.....@#>30adbe47k7k7k44ef1bd0,#+.....+%*-00dbe47k7kk774eebbd0>&......+#=30adbf4k7k7k7k44bbbac=&...",
"....@$-;){]F]^rrzrr/^FFFFFF)',%...+&=;~{{]/^rzrrr^^/]FFFF)'3=%.....#=;~{{F/rrrrrrr^F///FF{';>#.....+&=-')]FF^rrrrr^///]FFF{);=@...@#-;~{]]/F^r^rr/^F/F/FF)'-$@.....&#$-'){{//^rrrr^^FFFFFF{';=%..&=-;~{FF/FFFF(({{]/F/FF](!;>&.......+#=;{rxBGDvDvtz/);-#+...........+&%$,-~)]FF^^F/FF{_);3>#@......+@%#>-;~{F/rr^//FF]()!3$#@.......+@#>-;~)]]///F/FF{)!;-=%.......@#$-;!){{F/F//]F]{)';-*&.......+&$-')){F/^rrrzrr///]])!-%......+#>;~){]]^rr^rrrr//FF{)~,*......+*=;~){{F/rrrrrrrr//]])'-#.......%,;~)]]F^rzr^rrr^/F]])'-%...",
"....+&*-;!')))(FF{{{{{)))'';>*@....&#=;;~~)]F]F]]{){))'~!'-,$&.....@$--;')){{{{{{]{){))~~;;-=&......&#>-;!~){{]{({{{{))'~~;;>%+....@%=;;!~~){{{]{]{){))~''-$%+......+#,-!~~')){{]{]{)())~'!->#+...%=-;!'_)~)'~'~!''~~~~'~;->*@.......+%=-)FzxBtHGyz/]~;=#+.............+@#,;!'))){{))'~;--,%&.........+@#=;;!)){{{)))~~;;->%+..........@#$-;!~)))))))'';-,$%+.........@#=-;!)'))))))~;;->*&+........&#=--'!_){{(]{]{))~)!'-=%......+@#$,;!!)){{]{]{{{))~'!->&+......+#$-;!~){{{{{F{{){)~!;->%+......@#$;;!~_{{{{(){{))~!!;;$&...",
"......+@#==>-,,-----,->==$*&@.......+@%%==>>------,,=>>==**&++......+&%#$=,--------=>=>==*%&@........@@##$==,-,---->-=>>==#%@.......+@%===,=>----,->,===***@+.........&%*===>,,>,,---=====*%@......@##=>=,=,=====>=>=,>=>*%@..........+%*>;~(::|:b_;-=#&@.................@*$=>>>,>=,=>$%&@.............+@%$==---->=>==$%@++............@@@&*===,=>==$*%&&+............+@#*=>====>==>$%%@+...........+@%**>=>-----,-,-==*=*+.........+@%*=>=>->--,,,,===*$%@.........++%*===,,------>>,=*$&&+........++%$>=>----->-->===$#%@+...",
".........+&&&%&&%&%&%&&&%&+............@+&&%&&&%%%%%&%%%&&+...........++@&%%*#%%%&##%&&&&@+...........+.+@&&&&%&&&%&&#%&&@+...........++&#%%%&&%&%&%%%%&%&+............@&&##$#%##%%#%*%%&@+..........&&@&&%&%%&%%&%&%&&&&&+.............@#$=--3;,-$*%%&+..................++@&@%%&%%%&@@+.................+@@&@&%&#%&&@+...................++@&&&#%%%@+++.................@&&%#%#%&%@@+................+@%&%%&%%%%##%%%%%@@+............+@&&%&%&&#%%%#%&@+.............+&&&&%%*#%#&&&&@&&.............+++@&&%%#%&&##%#%&&+......",
"................+.+.++..........................+..+.....................++.+..++++.+.......................+.+...++..+.+.................++.+.+.++.......................++@@++@@@@+@++..............+..++.......+......+...............++@%%%#%&+++........................+..+.+..+.......................+..+.++.+............................+...........................+.++.+......................+++++.+.++@@....................+..+++..+......................++++.+++@@+++.........................++.++............",
"................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................",
".........+..+++.+............................................................................................................................+.+..................................+.............................................................................................................................................................................................................................................................................................................................................",
".....+@&#%##***#%*#*#*####&@+................+@@@@@@@@+........................................................+@@&@@++....................@%%#%###%@......................+@@&&%%&&+++++......................................................................................................................................................+&&%%%&@+..................@@&&%&@+..............................................................................................................................................",
"....+@&&****==,===*=>=**%%%@+..............+@@&&&&&&&%&@+................++&@@++..............................+@&&%&&@@@..................@&#**=***#&+....................+@&&%&&&&&&&&@+................................................................................................................+@@@@@@..............................+@@&&&&&@@+................+&&%&%%&@@+...............................................................+@@++...........@%######&&+..................................................",
"...+&%#$$>,,--;--------=$$##@.............+&&####*#*#%#%&@..............@&#&%%#&@+............................+@&%##%%#@&................@&#*$>>,>=*#&+...................&%#$#$*$####%%&@...............................................................................................................@&%%##%&............................+@%##*#$*#&+................@&%%*#*##&%@...........................................................+@%%%&#&@.........@**=>---=>*%@.................................................",
"...@#$*,39;ccaaa000c0cc;,=**&............+&##*==>>>>=***%&+...........+&%#$$$*$*&&+.........................+@@%#**=>*$%&+..............+&#$=33999->$*&+................+&#$*==>,,==*=*$#%+............................................................................................................+@%#*=*=$*&+..........................&%$*$>=>>*#&+.............+@&*$>>>>=>*%@+........................................................+@#*=$>*$*&+.......&%*=3;acc93>$*@................................................",
"..+#=3cad:beee4e:e1eeeebdac3$@..........@&*>3ccaac09cc9,>**@..........@%=>3cc03,>*#@........................+%$=,-0aac3=*%@.............%$,90~be:bdcc,>#@...............&*>3c'adaaaccc33,**@..........................................................................................................+&*$-9c;c3,=*%+.......................@*>3c9cc0c3>*&.............@#=,99aaac93>*@.......................................................@&*=,caaa9,>%+.....+%=-0dbfee|acc=*&...............................................",
"..&,!]/zxAGAGAGAAAAtABttsr^{;$+.......@%=-;']/rrzrr^rr/{~;-=%.......+%=-!)FrrrF{~;->%+.....................@$-;!)FzsyrF'-,*@..........+%>;)]rsyAHysrF);,*&............+%$-'{/rssszz^//FF]~-=%+.............+....+@&&%&@+......................+@&&&@+................................................+#>;!{FrrrF)~;>$%@...................@#>;)]F/rrr^{!-=%+.........+%$-')F/zssz/)!;=%....................+++..+@@@@@@+...................&#>-;~{/sys^{!-*&+...&,'{/stGAAAsrF)-=%+......................+&%%%&%&@&&&%&@@+......",
".+#;)/zAGLLLELLGCCCCGGLCByz/)-%......@#=--!]/sttyxysssz/)';-#&......@*-')FrstxrF)~;-$%+...................@#>;~)FIyvGy/);-=%..........&$-!{/sAGLLLAs/]!-=*&...........&$-!)FzstABAxzzrrr/]',#@........@%###%#####**$***#&...................@##**$**#@............................+@@+...............&$-!)FzytsrF)!;-=*&................+&#$-!]/zsytxs/);,*@........+%=-;)FrsAABxzF~;-$#..............+&####*####=$$$$*#@+................&*=-;'{/KAGAsF~;-*&...@>']KwuEEvCAs/{!-=#@..................@&%##$$$>*=$*$>**$*#&+....",
"..&,;(}IJwNwNNNwJKJJwwwJI/F_;>&......@%==-;~]/^r^^/^Q/F{!-,$%+......@&*-!)F/r^/_~;->*&+..................+%*=-'~(}5OO<1'-*%@.........@%*>-~12PwwwwP[]~;=*&@...........&*>-~{F^rKrr//}F{]_~-$%+.......+@%*********>*$$**##+................+@&**>*>***&+........................+@@@&&@++............+%*,;~)F^rQF_~;->**@...............+@@**>-~]F/^rr/]'-=#@.......+&%*=-;)F/rKzIF(!->*%+............+@%*******$****=**#&@+.............+@&$$=-;!1[8O6[_;>=*@...+*;~}6wNwwJK/{!-=*%&+.................@@%#****$$*$**$>****&@....",
"..%=;_:[8ONNNNYOPIKPJwO6Q2:_;>%.....+&$$--;(1[Q[[Q[QQ[:(!-=*&+......+%$,3~|}[[:1('-,>*&..................@%*>;!((2<66<(;,$%+.........@#*=;'(}<ORRO5[|~;,$#@..........@%$,;'(}[QQIQ[}21:((;-*&+......+%#*$>>,,,>>==,,=>$*#%@...............@%$$>,--->$$%+.....................+&%%%%%%%%&@+..........&#$,-!_:[[}1(_'-=$*%&+............@%%#$>-;_(2}[[[[(;-$#@.......@&#>,-!(:}QQIQ}|';,$$&+.........+&#*$$>>,,,>=>>,,,,>*##@+..........+@%%#*=--9_|46O54_;->*&....%-~b5RSYOPQ[('->$#%&+...............@###$>,-,,=,=,>,=,>>**&+...",
"..&=cafgmjoqqWqoojpooomi7f|a3=&....+&#=,;ad:fk<iiiiikheba->*@.......@&#>-0be77efeba;>>#@................@#$=-0dee7ipigd0-$#+........+&$>30bbgipjqpigeba3>*&..........&*=-0dee75hl5iggfebdc,*&......+@#$=,9c;0c9939c0cc3,=*@+.............+%*=3c0aac9=*#@...................@&%%###******##%&@......+&*$-90db7774ebba;,>=#&@.........@@%$$*=,9abf7<774ebc-=*%+.....@#$=,30dee4khkh7eba;=>#&+........@#$=3399;ccc339caaa03*$#@.......+&&%%$$$>,;abbfgipifdc9>*&....%,0bgjqjplh7bac3=$*&&+............+@%$*==c0aa0999900c999,=#@...",
"..%,cb4hlXXnnooqWWWZqnXlk4bac=%....@*=-0be7klVVXooZnmVke_9,*&.......+%*,9abeQkllkkedc3=#&+.............&%*,3ab4khhlihfdc3=#&........@#=3;d4khVlmmmllk4(a9=%+........+&=3cdekVVVXVXnXni4:b03$&......+#>-0a(b4ee(ddd|e2bdac,$&+...........@**,0d|e444d0,*&+................+#*$=>-33-333333,==#+.....&*$-9ad|e[kkhlk7ed093>=*%+.....@%**>,39;ad:4klVlk7e1dc3>#&....+#=3;adbekIlVlVVlk7edc3,**@......@*=,;!dd:e4:b(ddfgigfac3=#+.....+&*==>,3330dekhlllih4ed03,#+..+#,cb7imXXVlk4b_cc3,,**%+.........&%*>,99abgii7bdd1e4ee{da03*+..",
".+*;]rsBBCBCCBGvEEEEEGHAxsr/);*...@$;'{/sABACCHGvLELGCAz/);-=@.....+%$,;~FrsxAABCByzF)!-$#@..........+&*-;)]rstCBCCBxz/)'-*#@......+#,;)FryACBBAtBBCByz/{;=#@......+#-;)FrsACBCCHGDLvAsr^{!>%.....&#>;)F/zxtAyzzzsxAAxz^])-#@..........+*,;~FrstBBtz/~;=#@.............@%=-;;~){]]]]]]]]])~!;$+..+#=;;){/rzsxACBCCAsr/]{)!;,%+...+#>-!~{]]F^rstCBCAAyzz/F)';=&...&-!)F^zsxACCCCACCBBxr/{~;,$@....@$-!)//zsxyBAszzzyGDGsI]);-%....+*>-'~)){]F/ryACBCCAAsz//]{;#...*c_FQtAAHCCtyzrFF]{)!;-=%&.....+&$-;~)]F/sHvGysrrsxBBxysr/{;#..",
"..*!)^syBCCCCCCGDvuvvGBCAyz/];*+..%,!)/zAACCCBBGvLvHHCts/{';>&......&=-;)]rxBCCCCBAsrF);-=#+.........&*,-!]/zyCCCCCAyzF{!->%@......&$-!{/zyBCCCBBACCAyz/{;-*@......&$-!)FzxBCCBCHGvvGtsrF{;,%.....%$-~]/rsyBAByyxyBBAyzrF);=&..........&*,;)FzxCCCCs/);-*@...........+&#=-;'{]F^rrrrrzrrr/F{)-%..&$-!)]/zssxyyABBBBAxzr/]]~;,&...&>-')]/rrzzssyABABBxxsz/]);-#..+=;)FrzsyABAABACBACCAsrF]~-=%....&=;)FrssxBBAByzzzxtGGAz/]);$@...&>;~)F///rrrzyABBBABtxszrrF),+.+*-!{^sACBCCCxyszrr/F])';-*%.....%-;){//zsytGGtzzzsACABtAsz/)=..",
"..&,;)]/QKKKKII<<I5POwwPIr2]_;%...%=;~]FrKzKIrIKPKJJKKQF)!->$@......@*=,;~]}rKzKzKrQ/|~-,*%@........+&*=-;)F/IrKzKKr[});-=$%@......@*=-!)]/QKzKKzKzKr2])!-*#@......@*>-;'{/IKzKKJKJPKQ1(';>$@.....@%*-'){F/rrKrrrrzr^F]_~-,*@..........@%$-!)2IJwwJI1!-=%@...........+%*=-;~{{}//[/[/[/[/}F_);%..&*-!)1F[/Q//F/////^/^[F:{~-=&...@=-;){1/[/}FFFF//^QrQ/[F|~;=%...$;)|FQrrIr^/^//^rrKrQ/1)',*&...+%=;~{2^rrrr/FF1::[<IPQ^}]~-$+...@$-~)]:/}/[F}////[^^rIrQ/}]~=+..&>,;)F/QKKzKrI/Q^^}](~';,*&....+%>-~_F2[QII5<[1]F//rKrrrQF{~>..",
"..@*-;_1[QIQQQ[[[24<8YY6<Q[:_-#...&=;_1}[QIQ[[2Q<I<QQQ[:(;-=*&.....+@*>-;~12[QIIII[[}1~;->*&+......+&#$>-'(}[QIIIIQQ[:~'->*%@.....+&*,-!_(}[QQIQQIQQ[}(!;,>*&+.....@#*=-'(1[QKIIIII<Q}1~'-=*&+....@#>,;~(1}QQQQQIIQI[1(';-$#&..........@#=-;(:QPYS8<(;=$#@..........+&#$>-;(1[[QQQQQ[QQQQ[}:(;*..&*-'(2}QQQ[}||((|1[[QQ[}:~;>%...&*-'_:[2Q[21_|(1|:2QQQ[21~;=&..+%;(::[QQ[[2::|:12QIQ[[2|!-=%+...&=-_|2[QQQ[}1(1(1:[QQQ[}:_;=%...@$;__}[[QQ[}21|||:2[[QQ[Q}|_>+.+&*=3~(}2QI5KIQQQQQ2}((~;->#+....#=;_12QQQQQQ[2(((1[[QQI[[[:_=+.",
"..@*-cde4hlhh77ff47gjqWjmh7ed3#..+%=9d:4hhlhk447hhhhhk4edc-=*&.....+&*,;0de4khhlllhh4ebcc,=*&......+#*,9;a:77hhlllhh4fbac9>$#+....@#>-cabbehkhllhlhh7fbac3>$%+....+&*>-;abekhllllllh7fbda;=$%+....@%=30db:7kkhl5kl5k7eba;3>*&.........+%*=9abfijWUqib0,**&+.........&#*-90abekkh5hhlhhkhhhkfba*+.%*3abf7<kh4ebbbdb147hkk44b0-&...%=;abe7hkk7ebbddb:4khhk7eb0,%..+*cde7<khk4e|:b1efkhhk77ea9=#+...&,9ab77khh4ebbbbbf4hhhh4edc=&...+*9defkhhh74e:bb|b}77h5hh7ea>+..@*>-abe44lmmhhhhkhk4bbba;>*@....#>cde47klhhh4fbdbe4khhlhh4ed>+.",
"..@*30d4kVVllhhhhhhmqWWomVl7ba$+.+*-0b4klVVVlhhlVVVlVlh4ed0c,#+....@$9cd1e7klVVVVVVVhke:d0c>$&....+#=9cd|e7lVVVVVVlVVk4e(a;3*&....@*,cd1e[hlVVVVVVXVVk4e1ac3$%....@#>9a|e4klVVVVVVVVVk4ebdc3$&....&>-cd147hlVVVVVVVVlk4eba3=#+.......+&*>3c_ehmoWWqied;3>$#@.......@%=30d1e[hlVVVVVVVVVXVVlked$..&,cd}klVXVlk41b|bekhlVllk4b9$+.+&,9(eklVVVh741b|beklVVllk4b9*...=a1khVVVlh7eeee}klVVlVk7e'3=%...#-014kVVVVh72e:be4hVVVllked9#...@=ab4<lVVVllk4ebe4kklVmVVh7|3+..&$,9_e7hVmXmXVVVVVVkk74eda3=@..+*3ae4hVXmVllk4e1e4klVXVlVh4b3@.",
"..%=;{/zACCCHHGGGGvDEEEEvvGtz{,@+&,']zsAHGGvvGHHBCCHHGHAtsrF),&...@*-{^sxABHGGHCCHHGGHBxsrF);$+...#-;{^sxAAHGGHBCHHGGBAtsr]~;$+..@$;'FrxAACHGGHBCCHHHCBAsr]';*+..&=;)FryAABGGHCCHBGGHCAAxrF)-#...&$;)/zyABHGGHCCCHHGHCAAsr{!-&......@*>;'{]^zxtHvGGxK^])!;,=&+....@$-;{/sxBAHGHCCBCGGvHBCCCyzF,++*;{/stAGGGHAssrrrsyCCCCCCyz]-%.+*;{/sAHGGGCAxzrrrsxACCCCByr(-+.@-FztAvvvHAAsszzsxCCCBCBAz/~;#..+$!]rsAGGGGAAszrzzxtBBCCCAx^)=...&-{^sAHvGGHCtyszzytBCHGvvAy^'@..%,;{/sxBHGvHHCCCCBCHHHGtsr]'$..+>!]rsAHGvHHCByszsyACHGvvHAxr'#.",
"..&,;)FzyCCBGvLLLLuEuEEEELGGsF-@.%,!]rxBGLLLLLvGCCCCGLvCCAxr{!*..@*-~]zyCCCGLGBCCBGGvGBCByr]!-%..&$;~FztCCGGvGCCCCGLvGCCAs/);>%..@=;{/sACCGGLGCCCBHLvHCBBs/);=+..&>;{/yACCvGLvHBCCGLGCCCAy/{;$@..%-;]rxBCBGGLvBCCBGLGCCAAzF)-*....@#$=;!)]/rzsytBAAsz^F)~!;,$@....%>;~]zyCCGvvvHCCCCLLvCBCBxz{-@+*;)/sAGvLvHByzrrrsyABCCCBtz]!%.+*!{rsAGvLLGBysr^/zyCCCBCByz]-+.@-]zyHGLLGCyxzrzzyACCCCCtsF);*+.+>;]ryBvLLLHAyzrrzsACCCCBByr(>+..@-(/sAHGGGBCCyszsyACCGvDGAs/;@..#,;)/zyAHLLLHCCCABBHvDuvAsr{=+.+$!{/stHGGGCCCyszsyBCHvvGGBsF;@.",
"..&*=-~{/IKKwwNNNNuNSuNNNNwP[_>+.@*,;{}IOwNNwNwwJKKJwwwJKI/]_-#..@*>;)/IKJJwwwJKKKJwwwJzK/:~-=&..@*,;)/IKJJwwwJKKJJwwwsKK/|;-*@..&=-'{^KzJJwwwJKJJJwwwJzI/{!-%...&=-']/IKJJwwwKKKJJwwJJzI/{!-%...@=-!{/KKJwwwwJKKJwwwwsKz/_;>#....&%$=-;~)_{]2F[/[/}F(()';->$&....@*,;)2rKJJwwwJKKJJwwwJKKr}{;#+.&>;)2IJwwwJI[F(((]^IzKzKK^]',&.+&=;(}IJwwwJI[F|{(F[rKzKzK^{;*..+>_:[PwwwwKQ/|{]][rKKzKKr});=&...#-!([KONNwPI/}{){F/IKzKzI/(;*....#-'(}IPPPKKK^/}F/QIKPPPI[1'$...@$=;)F[IPwwOI[^[^[QIPPJPIQF'=...&=-~1}IPPJKKrQF2/[QKPPPPI[1;$..",
"..@#>-'(}[QI6MNSNSNNNNNSNSY6}_=@.@#,;_:<8wNNNww6KIIIOwOPIQ[:'-%..+*,3~}QKIJwYOPIQI8OOOPII[:!-*@..@*=;_2QKIJOw6IQQIPwJOPKQ[1;-$@..@*-;(}QIKJwOOIQQIJYw6PII2(;>#+..+$,;(2IIPOwY6IQQ<JYOJPIQ[(;>#+..@=-'12QIKJJw6IQIKJwOP5KQ}_;>%....@$=>-!_((|::::e::||{(_(';-=%....%=-;~}QIIOOYJPI<IOwSOPII[:'-%..&>-!|25MwY6[1((___:QQIIIQ[|;=@..%=;~:[6RwO6[}(_~_(}QQKIKQ}(;*+.+*;(}5Oww8<}|(___:[QIQKIQ:!-$&...#=9~:<OwSY6[}(~__(2QIIKIQ}_;%...+%=,;(}[I<IIQ[111:QIIQ<<2:_-%...@%=-'_:}5OO6Q2||||1[<I<IQ[}~$+..@#>-'1}QQIQIQ[2|}}QIII<Q21~-@..",
"..@*,9abgimpnqWqqqqqqqUUTUqpga=@.+%=3abgpoZqZqomikhkpppmhh7ed3#..+*-cdfimpjqopi77hijqjpmmkea9>&..@$,cd7immpojmh47hmpoppmm7ec3>@+.&=cabgijppommhh7gmjqjpmm4ba-*...@$3cb7lmpjqoph47hppoppmi7b0-%...&>9degmppnommk77ipooXpmi7bc,#...+@*39cbffggggggggggggfgeebc,#....&=9ab7impoqqpmkhljoqoommkfa,%..@>30beiooomgebdad(e7hhllk4b;=@..&$3cbgmoooi7fb_ddbe7hhllk4b3*..+*cdfijqophfbb0ad:4hhllk7ea3=&...%>9abgmoqoigebdadbekhlllhe_3#....@#=-cbe7hhlih7ff7iilh74bdc,%...@#=3abf7ipji7bb(bbefhhhhh4fd=....@%$9abe47ili44ee7ilih7fbd9$@..",
"..&*9ab7ioqooojjjiipipjWUUUpgb,+.@%>3a1kmnnZnnXlh47hlXXXVVl4b9*++&>9deiXoZojmik477hmnoZoomgba,&..&,cdfiXZZnXmik777kmpoZZop7b0,&..@,cb7moqZommh4474kmpoZoom7b0$@.+&-0b7mooZopmh7777hmnoZZom4d0=+.+%-ab7moqZnpmh777khmpooZnifdc$+...#-!bfijjjojqqqqqqojjjjjjif0=+..+#,cdeioqZoppmVVVXnZZZZqomhb0%..&*9cb7lnnnVh7e|bdbeklVVVVkea3&..&=9~b7lnXnlh4ebdbb}klVVVlk:0*+..*cdehXnnXlke1bbbe7lVVVVl4dc>%...%=90:4mnnXlk4ebdb14klVVVVkb0*....+&$>c_bekmnXm5hkipoph4bdc9=&...@*>9a:4kmnnmh4eeee4khVVVll7d>+....@*,0abekmXnmhhhlnnmh4bdc3#...",
"..#-~FrxGvEEvGCAxJsJxAGvEEEvxr!&+&*-!]^sAHHGHHBtysssABCBCCCyr(>+.*!]/sHDELDHxsszzzsyAGDEEvtzF)$+.%;]rsGDEEvHtsszzzstHvEELDAzF~$++*!]rsHvEvvAyszzzssyCvvEEHyz]-@..*'FrxGEEvvAyszzzssACDLEGGxr]-@..*~FzADEEEvtyszzzzstHvEEvHsr]-@..+>'/syvuuEEuEuEuEuEEEEuuuNs4-@..%-!]rsHDEEvHBCCCBCGHDLEEEvAK]-.+#,')^stHBHCAysrr/rsxBCCCCtzF;%.+#>;{/stGHHCtxzr^rrsxACCCBAz],+.+=~/ztHHHHAysz^rrzxtCCCCAs^{;*..+#-'{^sABHBCyyzr^rrstACBCCyz(>+...+@*,;~]/stvGGHvGGDGGyz/{;-*@..+#>;)/zxAGvLGAAyxyxyAGvHHAtsF-+.....%>;)FrsAvGvGHvHGvAsrF);-#...",
"..%-~]zyGLLGvCxxsszzsstvLLLGy^;%.+*-~]rsCCBHCCBysszsxAACCCCyr),++%!]rJtLELGAssrrrrzsAGLELLAz/)>++#!{rJtLELGtyzr/rrzstHLELutzF)$+.*!FrxGLELvAszrrrzzstHLLuvxzF;@.+*!FryGLEDDyszrr/rzstHLLDGyr{-+..*'/KxHLLuGAszr/rrzsxvLLLGsr{-+..+=~FzxAGHuDvuDuEuuuvuDDvDAz]-+..&-~]rsHLELvCCBBCCCCBCLEELGtz{=@.&=;)FzACCBCBxsrr^rzytCCCCAzF;#+.&-~_/zACBCAAszr/^rzyBCCCBAz]-@.+>~]zyBCBCBxsr/^/zsyBCCCBs/);*+..%-']^sBCCCAAxzrr/rsyBCCCCxr{-.....+%=-;)FzyCGvLLLLGHts/]~-*@....%,')/zyBGLLLBBABBBAGLLEvByr]>+.....@*;!{/zyCCGLLLvGCAzF);-$&...",
"..@=;'1Q8wNwPI2F||]1:2Q6wNw8[(,@.+%$-;{2rKJKKQ^/]]]:F^IKKKK^{!*.+&-'1[6wNwO<2]((((1:[PwwNO<1_-%..@-!{[8Yww8Q}{1((({:[PwwwO<:_,%.+#-~1[8www6Q2:((({1:[PwNw8Q|;=+..&-~1Q6wNwP[}](((({2[6Sww6[1~>..+%-):QOwNw642{()({:2Q6wNw6[(!=+...%>;_|e472<<<<<h<<k<<7777e(;*...@*-'|[6wNwOKIrIzKKIIKJwNwJ<1~*..@*>-']QKKKrr/2{()|]/^QKKKr}~-@..@*-;):QKzKI^/]1(({]F^QKKKQF_=+..&>;1[KzKIr2F1){)]F/IzKKIF{!-%...&*-;)}IKKKr^}]((({F2/KKKz/];#.......&*=-;1[IKwwNNwJKQ](;-$+.....@*-;)2[QPYwwJKKKrIKJYNwOI}(;*......+@*,;_|[IJJNwNwKI[|!-,*&+...",
"..&*-c(46YSY5}1(____(|}5YSM52_>+.+&#=-'1[IIIQ[}|(~_(:}[QIQQ2_;%+.@=;~:5ORY8[|((~___11<OSY8<1!-%..&=9_25YSR8[((_~___1:<OSR84|!-%+.@=!d}8RSM5}|____~_1}5YSM64(;>+..%,c(}6YYY54((_____|}8YSY54_;*+..%-c146YMO52___!~~(128YSY5}(;$@...@*>3c!a_|b|||1::1|||d__!;-$&+..@$-c_15YSSO<QQQIIQQ[Q5OSR8[(9*+.@%*-;_}QI<Q[:____((}[QIIQ[1'-%..@#$-!|[QIIQ[:_____(}}[IIQ[1;>+.+%=;_}QIIQ2}(____(|}QQIQQ}_;=%...@$=-~:[III[21____((}2[I<Q2_;#.......+%$>;~|[<6RNSO5[:(;-$%+.....@%*-!(1[5ORYO8865868OOO5[|_-&.......@#*>;_:2<OSNSOI2:~;,*#@....",
"..%*9;dgpqWqpfbbdaa0dbgiqTWjfd>@.+&#=3ab7hlhh4fbdaad:e4khlk4bc*..&=cafiqWqpgbbd0aaabfiqWWjgba-%..%>cdeiqWqpgbdaaadabfiqWWjgbc,%..&,cdfjqWqpfbdaaaadbfiqWqpgbc$+..&,0bgpqWqigbdaaaadbfpqWqpfbc*+..&3cbgpqWqifbaaccadbgpqWqigdc*....+%*>,,30aadbbbbbbbda033,-=*@...@*>cdfiqWWjihhhllh77gpqWWjgbc*+.+#*-cd4hlh<74ed_ad:f4khlk7e03%..@#*3cb7<lhk7f|daddbe4khlk7bc$...#=;aekhl<7e:da0ddbf7hhl7e0c=&...+#=3ab7hhh44bbda0dbe4khlh7bc*.......@&*,3abfijUTUjieba3=*@......@*$3abf4iqWUUUqUqUqpmil7edc3&......+@#$,9ab4ijUTUjgfda3,$%+....",
"..&=3abhjWUWph4e|bb1eehjWUWjgb,@.+%$3;d4llVVlk44:bbeekkVVVlke0=++@,0b7mZWWoi7ebbb1bf7mqWWoifa3%+.&-abgnZWWph4e|b1bee7pZWWoiba3%..&30b7jZWZpheebbbbefhXZWWjhba=+..#9abgoUWZpkeebbbbefhpZWWjgb0>+..#9abhoWWZp7f:dd(befhpWWZp4b0$+....@%#=,390dbeef77febdc9,,=*#@...@*30bgmWWWZXmlmXXVhhhpWUWoifa*..@%>9a:kVVVlhk4e1eeekklVVVkebc*+.+*>-a:kVVVIlk4eb|e}khVVVVked>@..%,914llVVh74e:b1e[kVVVVl4ba3#...&*>9a}kVVVlk72b::e4klVVVVk:a>+.....+&#>-0d1kijUTUoi4da9>#&......&$=c_e7hmqUUUTUUUUWoVlh7eac=&......@%$=3'be7ljWUUjieb0->%@.....",
"..*-_FryvEELvAxyzzzzsyBGLEEGx^c%.@=-~]^sBCCCCBAszrrzsBACCCCyzF;@+#;{/sGDELGAAyszzzsxBGLEELxK{~$+.%;]rsGLELvAtssrzzstAGLELGyI];*+.*!:rxGEEEvAxyzzzzsxBvEEEvyQ(-@..*;FKxDEEEGAxszzrzsxHvEEEGy^(-+..*)FztDEEEvAyszrrzsxHGEELGsI{,+....@&**39~(/rsttHGAJrF(!;,=*#@..+#-~]^sGLEEvvGGHBGCCBHvEEELyr_>.+@=-~]zyCBCBCtysszsxBCBCCCAsr(=+.&=-~]zyCCCCBAxszzsyACCCCCAs/;@.+*!{^yCCBCBAtsszsytBCCBCCyr])=+..&=;)FzBCBCCCtyszssyACBCCBxzF;+.....&=,;)F^stCCvEvHtz/{!-#@.....+#-;{/sxCHGDEDDDvDvvHAxsrF)!,@.....+#=-!)FrsAHvEvDGsrF);>*&.....",
"..#-'FrxHLLLvCCtxsssACCvLLLGsr;@+@*;)FryACBCCBtxzzzsytCCCCCAs^;@+#;]^stLLLGCCAysssACCvLEEDyr{;*+.%;{/sGvLLDCBAxssxABCGLLLvy^{;#.+*;FrJBLELDCCAxsssABCvLEEvs/),@.+*!]ryGLLLGCBAsssxACHvLLuHs/)=+..*!FIyGLLLGHAyszsstCCHLDuts/(-@.....+@*=-;)FzACGuLLAr]~;-$#&+....&>']rsGLEEELLvGCCACCBvLLLGy^)*+.&$-']rxBCCCCCAyssxACCCBCCBsr{>++&$;~]rxBBCCCAAyxsytBBCCCCAsr;&.+$;)^sACCCCCBxsssxCCBCCCAxr]'>+..%=;~FzxCCCBCBAsssAACCCCBCAs/;@....@*=;!{/ryACCCHHtyzF);>%@.....@=-!{/sAABCHCHtAyxysszrF])!,#+.....@*,;~]/zyBCCCHHtsr]~-=%+.....",
"..@*,;(}6OwwJJKI^[[QQKJJwwOP[_>+.+#,;)][rKJKKIr[F1]F2^KJJJKQF_-+.&=;_25ONwwJKKr[^QQKPwwwYJ[(;>&+.@$;_}5OwwwJKKQ[[^IKJJwwwP[_-$@..&=;(2PwwwOJKrI[[[IKPJwwO8[(;*+..&=;(}6OwwwJKrQ[[[IKJOwwO5}~-*...@$!([6wwwOJKI[[2[IKJwwwO5}~;#.......+&%*=-'1[PJwwO<|!-=#@.......+#-!([5wwNNNwwPQIIKKJwwww6[_-&..+&*=;)/IKzKKKrQ/[QrKJJJJKK[{;*..+&$-!{^IKKKzKr[/^QrKJJJJKI/{-+.+%=-~F^KKzKKKI/[QIKKJwJJK/:';%...@#=-~]QKzKKzKrQQ^QrKJJJJKr}_-.....@#*--'{F[QKPJKKI2(!-=%+......+#=-'{F^IKKJII[22::{(~!;-==%+......@#>-;)(FQKKPJKKQ1);,$&@......",
"..@#=-c|[P8OJ8P85555888OO654|;*..@#=;_1<5O6O8554:1|}[586OO8<}(,@++*=;([58888P855556666668<1!-$&..+*,!([P8PJP8K655566PO6O5<|;-#+..@#-0|[586O88P555586O8888[1;,%...@*,;|[PPJ6P8K5555668O886[1c>#+..@#-~1<588J885555556P6JP54(;=%+.......+&&$=;(:[88854(-=*@.........%=;_1<6OOwSSY655568PP6P5<:!$@...+&$=;(}[QIPPP5<556PPOYO8<[|!#...@#*-~|}[Q<P655<<5PP6OOO8<[_,@..@*=;_1[[<KPP55<5PPOJOY88<1(;*....@#=-~|}[QIPP65555PPPOOO8<2(=+...+@*>-!(|}<88J6J6<}_;>#&........%,;_(}[QP6P5Q}}:|_!;->=**@........&*=-~(:}<66OJ68Q:!-=%@.......",
"...&*,caf7hipoWWUUqTUqqjih7bd9#+.+$,cb7pqUTTUqqigbfgpqUUUUqjge-+++$=9abghimjqWUqoUqUqjmh7fd9,#@..+%=cab7ilpoqWqUqUUqqpli4fd9,#...+&=cae7hipoqWqUqUUqqjih4bd3=#...&*,3cbghinoWWWWqWWWqji77bac=%...+%,;df7hipqWqTTqTqWqpih7ba9=&.........+&*>3abe7i5fba9>#@........+#=9ab75mmoUUUWqWUqWqpmh7fd9$+...+&*>-adefipqqWqqqqWqWUUUjied*....&*>cabe7ijqqqqWqWqWWUUUjie9@..+#*,cdbegpqqWqqqqWqWUUTqjgbc*....+%$,;ab:gijqZqqqqWWWWUUqjge3+...+%*3abfgijUUUqWqifa3=#@.......+#=;de7hijqqoih7f|a93=*$%%@.......+%>3ae47ijqUqWqoie03$#@.......",
"...&*,9ab4klnZUTTTTTTTWolk4b09#..+*3dfljqTTTTTqjk77ijUTTTTTZm4c@.+&>-a1ekhXWUTTTTTTUUomh7fac>*@...&$-ab4hkXZWUTTTTTUWolk7eac=#+..+%>3ab4hloWTTTTTTTTWolh7ea9>&...@#=9a|4kVpZWUTTTTUUWolh7ba9=%...+%>9ae7hlnWUTTTTTTUWXVh4ba3*&..........@$=3~be77<7ba3**@........+#=!aekVVXoWTTTTTTTUWolh7:a9*.....@#=3ade7mZWUTTTTUUWUTTTWphb,+..+&$=9~be4mZWUTTUUUUUTTTTqm7a&..@%>,c!b4koWUUTTTUUUUTTTUjl7d>+...+%*=9adb7mZWUTTTTUUUTTTUqm4c@...&*-017lVmoUTTTUWogdc>*&+......@*,a|kVXXZUUZXVlkeac,>$&&+........%$,a|7lVnZUTUUUqpfa9=*@.......",
"...&=3!|^stBGDELEEEEEEEGAys/{;$+.&>'FsBvEEEuEEuDtxxBDuEEEuEEGx(#+@%>;(/stAGvEEEEEEEEEvAAszF~-#@...%>;(/zxtGvEEEEEEEEEGBxsr{'-$+...%-;{^zxAGEEEEEEEEEDvtysr]!-#...&=,~{^sxCGLEEEEEEEELvAxs^{!,%...+*3']rstBHDEETEEEEEEDAxs/{;-#.........+%=-!{/zxyxs^('-*@........@>;)FzxCCHGEEEEEEEEEEvHtsr1!$+....&=,;{FrstDEEEEEEEEEEEEEEDtr;@...&=-'{FrsHvEEEEEEEEEEEEEEGx{%..@#,;')FzxDEEEEEEEEEEEEEEEHs/-+...+%$,!{FrsGvEEEEEEEEEEEuEEAx)&..+%-!]zxCCHDEEEEEEGs2)3,*+......&-!]zxACCvEEvHCBtzF);-*&+........+*-~FztCHGEEEEEEvGKF~;>&.......",
"...+#-!{/zsAtGDuuuuuDvGHyxz/)-#..@-~FzxBDEuuuuuttssxGuuuEuuHAz)&.+#>-~]rsytGDEuuEuuvGBysz^{!-$+...%>;)FrzttGDvEuuuDvHHtyz/);-%@..+%=;)FrzytGvEuuuEuDvtysr/{;,%+..+#-;)/zsAAGuEuuEuvvGHyyz/);#@...+%-;)/zyAtGLEuuuuvuvAyszF);=&..........@$-;)]/zssrF);-#+........&,;)/zABCBGvEEuEuuEuvtxsz/];*.....+%>-;]/zyGGLvEELLDDEuuuvty/;@...+%$-']^zxGGEuEuEEvEEuuuGAx)&...+#>;~{^stGDvEEEELvEEuuDAts]-+.....&>;)]/KxGvvuEEuEDEEuuDGAs)&...#-!]zyACHDvEDDDvts/~;=#+......@>']ryCCCHvvGHCByr{!-=#+..........#-!FzAABHvEEELDDxz]~-*@.......",
"....+%*-;~(:}4[k<h<<4[4}:)_;-#+...%-;{:}4<hhi<4}::11e7hh<k[42(-+..+&$,;~(124[7<k<<<7[[1(~!-$%@....+@#-;~~{2[[[<k<<<[[2:{_!-$%+....+%$-;~)1}4[<<h<<[[[2|(~;-=&+....@*=-;~(:}[2<<<Q<[7[}:(~;>$+.....+#=-!~):24<<5kh<7[42:)~;-=%@...........+%*-;')))~;>*#@.........+#,;(F[KKKP<<<<<<<<[[2:(~;-$+.......%$=-;~1}[<<Q<<Q<<<<<7[2|;#.....+&*=-!_:2[<<<<<<<Q<k<7[}(-@....@#*=-;d2[<Q<<[<<<<<<<42:);*.......@#=-;_:4[<<<<<<<<<k<7[:(,....@*=;{/rIKP6J6PP5Q|'-=%@........#-!)/QKKKPJKKI^/|;,$*@..........+&=,!{^rIKKJJPJPK[|;-=%........",
".....+&*$--c0_a__0_(___';-==$&....@#=-9;a__~__a~';''_~_a_a_~;-%+...@&*$>-;00_~__d___a';-,>*%+......+%%*--99aa~__a__a~!;--=*&+.......+#=,-;0aaa~_da_d_~;-,=*%@.....+@%#=--;0aa_0~__~_~!;-,=*@......+@%*$-3c~a~ad_d____';->=*&@.............+&%$>>,->$$%@...........&>;~12QQQ[}:|(_d(d_a~;-->$&+........&#*=-90_a________d__a!-$+......@&**=-90a_a_a__(_d~__~;;#+.....+&**>9c0a__d(a____d__';-$@.......+&#=,-90_a__d__d__d~_'!-#+...@%>-!:}[[QQ<QQQ21~-,#+........+&=-'_:[Q[QQ[[[}|~-*#&+...........@#=-_:2[Q<Q<<[[f|~->#+........",
"......+%**==->,3999033,-,>$*%@....+%$>,3,9c99993-3,3333333333=@.....@%#*$=-393399933,9-=**#@........+&%$>,,3339033333,,=$*%@........+&#*$,,3,939c09333==$$*@.......+@%#*$,-9-cc999333,==$$%+.......+&##*=,,-339c9333,,>>$#%@...............@&****#*%&+............%,;_bbf4fbbaaa0909933,=**&@.........+&#*$,,33,3333399c3933=&........+&%*$,,3333333909993,,=&......+@%$*=,,339cc99333cc93,*#+........+@%*>,>339999c9c3c093,#@....@&*-9def44fffffba0,$&..........@#>cdbe4777febbda-*%&............@#=-abef44f4ffeba;,*&+........",
".......@&##==->,,>-33>,=$*%%@......@&*>=>,3--,>=>=,=>>,,=>==**@......+%%**=,=,3-9,>,>==$*#@+.........+%#%$=,>9,3,,>,>,=$#%%+.........@%%**==,=9-9>-3,=>**%&+........+@%#**==,9-9,,,=,=>*%&@.........+@%$$*=>,=-39,,>>,$$&%@.................++&&%%&@+............+&*99addbddc0c933-9,>,*$#%&...........+&#***>,>,,,,,,-3,,>=$&.........+@&*=>=,,,,,3,39>>,>>*@........@&#$*>>3-3,-,,,39,,=$*@...........&%*=,=,--9-39,,3,3,=#+....+&*>9aadbbe|bbda03=*&..........&*=99dbbbbebddaa9>>#@+............&#=3!dbbbebddaac9**@.........",
".......+@&##$>---,,-,,,>=#&&+......+&#=,>,33>>==$==>3-,-3,,-$%........@&#%*>,,-,3--,,==*%&+...........@%%#*>>3,-3--,,>=#%@&...........&&##=>-,--3->,,==#&@@..........+&&%#=>>-,-3,,,,==#@+..........+&&#*>=>,3,,3--,,,=*%&+...................++@@@+..............&$,;!''_~~'!!;---,,>,=$#&+............+%#**$,,,-3--3-,,>,=*&..........+@##$>-33333-3-333>=#@........@&@#*=,-,-,3-3--,-,,=#+...........+&#>=>3,3-,9-3-,,>==%......+%>;;)~]{{(){);';,*&..........&$>;;))(]{{{();!;-$%+.............&=-;;'){({({~~!;-=%+.........",
".........++@%#**#$$*%#%#@@+..........@%%#$#*###%%&##%%$$**%%%+........+..+&%%#*$***%##%%+.................&&###%#**%%%&&++...............@&#%##*%%#%#%&+++.............+++@%%%#%%%%%%%&@+............@&@@@%$$*$$$**##%%&+........................+.................&*==-,-,->=>=>***%#%%&+...............+.+@%%##%%****#%##%&..............+@%%%%%*##*****%%@...........++&%%*$*****#*$%%%&@..............@&*#*$#$===**#%#%&+.......@#$>=-,,---,=-=$#@............&*$>,,->-;---->#%&@+..............@*=>-,---->-->$*%@..........",
".....................+.+.................+......+........+..................+.....+............................+..+........................+++....+.............................++++...........................+.....................................................+.+.+.++++.+.++.+................................++..........................++.....+.....................+...+...+.+.....................+..+++++..+............+++++@@+@+.+.+...............+++++@@++++..+++..................+..+++@@@+.+...............",
"................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................",
"................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................",
"......................................................+@%%%%@.......................................................................................................................................................................................................................................................................+&%%%%%%#%%%%#%%#%@+........................................................................................................................................................................",
"................................................+&%**=>-;;;--$%...........................................................................................................................................................................+@*****#%+...................@%***$$**$**$*#%@.................+@@+.....................+#>,;;;!;;;;;;!!;!;;->=*#&.......................................................................................................................+@&%%%%+.....................................",
"........................................+@@&%%%##*=--;!)))~~;-*+.........+@@&&@+@@&%%@+..................................................................................................................................................+%=>----=##@.................&#*=,---;;-;--->=*%@..........+&%%%#**#@....................%,;~))))))))))))))))'!;,=#@...........................................++@@@@++..+@@@+..........................................................@%#*=$>=$##@...................................",
"......................................++@&&&%#***$>,-;~)(()';-*+.......@@%&%%&&&&&%%%&@+++...........................++...............................................................................+++@@&&+...........................@#$,---,=**@+................@#$>,----------,>$%@..........@%%&#*$$#&@+..................%-;)(((()~~~_~)_~)((~!-=>%@.......................................+@@@&@&&%&@&@@@@&%@@@@+.....................................................+%#*$>>,==**@...................................",
".....................................+&%###$>*$$>=--!(17<7}:(;$+......&&##*#####***$$$#%&+........................++&@@@@+...................................................++&&@@+.................@&%#&%#&#&+........................@#$,-;~!;->#&................+&#=-;!!!!!!!!!;;-=#@..........@&#$*>,=*#&@+................+$;b}4<4}::::|:::2}4[7:_9=$@...................+@+................@%%#%###*#$#*#######%##%&+...................................................@%*>--3;;;-*%+..................................",
".....+++@@+......+@@@@+.............@%**$$=,333333;abeijqjpgfd-+.....+#*>>,>=*==,>>,==*$%&+..................+@@@@%&##$#$%&@+..............................................@&%%##%%&+..............+&***$*>$*$&@+......................+&$=3cbebdc,*#&+..............+%*,0dbbbbbbbbbddc-$&+.........&%$=3c99,>$%&+...............@-agjjqjihh777774hijqjjec-*&+.................+@&&&&++...........+*$***>=>,>,=>>==>>===$**%&+.................................................+#*=9;a0ddac>*@..................................",
"....@&#*%%#%@@@&%%%####&...........&=>,339caada_addb4hjWWWoPl49&....+#=,9cc0999c90c00c9,**&..........++@@&&&&#*$=>=,33,3,>**&+......+@@&&&&&@+.++@@@@@@@@+...............+&*==,,>==$#%++..........+%$,39399393>*&+....................+%$=3014k7edc-=#&@............+#=3cd4444444744eedc=#&........+#>3cadd~a-=>*&+..............#9biqWWZoVVVVVVVVVoZWWqgb9,*@...............+%*$=****&@.........+#=3-ccc0c0c0cc9c0c00;c93,>*&................................................&*=30dbbeeeed;,#@.............+@#%&&+.............",
"..+#=---;--,=$*==---;;->%@........&>!){]]F/rzzrrrrrsxBGLELGHAs)#...&*-;~]/^^F]F]///^//]);-=%+......+#*$>-,,--;;!~~)){{]{{)!;-*+....&*$>,--,-,>=>>---->->,$%@............+%>;!){{{{)'-,$$@+........#-!){]FF/FF{~;,*&+................+&$-;!)/zABBxrF)';-=%@..........%>;~FzAABAABBCBBys/{'-*@......+#-;'{/rzz^{~;->#&@+...........-]KALEELvCBCCBCCCHGLEELxQ(;-#+............+&$>;;!''!;-=%+.......&,~{]F/^/^^^^/^/^^^^///]{)!;*+........+@%**$*$$*$$**#%@+....................%>-!{FrssyAtsr])-*+.........@%*>>;---=%+...........",
"..%>-;')~~';--,,-;~))~!--*&+......#;{F/rrzzyytyzzssyBCvLLLvHBz)%..&=-;~]rsysrr/rrrzzzzrF);>*&.....+#=-;-;;;!'~)){]F//rrr/F{);=%...&=--;!!!;;;;!!;;;!;!;;---$#&........+##-;~]/rr//F{!;-=*#@......+=!{F/zsxxssQ]~->*@...............&$--;!)]/xACCAsrF)!--=##+.......&$-;)/yACCBABCBCBAsr]!-=#+.....@>;!)]rsyyz/])!-,$*#%%@@+.....+,FztDLLLHCCCCCCBCCGLLLGyI]~-%.............&*-;!){{))~;-*&+......$~FrsssxyxyxyyAyyxxyyxJsrF{'=+.......+&*,---;-;;;;--=$*@+.........+@@@.....%$-!)FrxtCCCCAs/{!>+........&*=-;'~)~;-=#&..........",
"..%==;!~~);-=>*=-;~)();-=*%@......$;(]}/[/IPJJII[//QKKOwNwwKQF;&..@*=-;([PPI[FF2/[/Q^QF(;,*$&.....+#=---;;;;'~))){1F:/[F}F(~-=#...@*=-;;;;;;;;;;;;!!!!;;-->*%&+.......@#*=-':<P65[:~;-=$$#&@+.....*!{}IPJOOO65:;,>#@..............+#*==--;~:IJwwKQ|);;-,=**&+......+%$,;1IJJKKrKzzr//F]'-**&+.....@$=-!)}<66<:(!;,>$*#&&&&@+.....>~}PwwNwJJKKIIrKKKwwNNw<2~->&............+&*>-~({{{)~;,*%+......#_[K6OJOJOJOOwOOOJOOJOO6<}|!$+......+@%$>>>-----;--,=*#&&+........@&&&+...+%*>-'([PJwJwwPQ:)-*........+&#$>-'~~!;,*#&+.........",
"..#=-;_(1(';>=>,-;)1:(~;-*%@.....+>_12[[QQ<6YY8<[[[QQPOwwYP<2(=+..@$,-~|5665[:::}Q[QQQ}|!->*%+....%=-3;'~~~_~((1::}[QQQQQ[1_;-&...&$>3'_(_~~~~~~~~_____!;;-=>#@......+%*=-;(48OY6<}(~;,=**#%&....+=!|[5OYMSSR5:c-**@..............&*=,-;!~(}<YRY8[|_!;;--,**&+.....@#*,;|<8OP<QQIQQ[2}_;,$#%+.....&*-;'(e5Y851|_;-=*$*####%%@...+*!:<YSNSJIIIQIQIIIJOwSO<|~9*&............@%#=;_:}}1|_;=$&@......*d<8MOYYYYSSNMSSSSSRRRRO5[1'$+.....+@%**,-;;;!~~~!;-->**&@.......+&%%%&@+@&%$=;~|[6YRSSO6Q|'-%+.......+%$=-!~(((;->*&@.........",
"..*30df4gebc99-9!df7gedc-=$&.....+>b47hhimpjqjmi74hhiXpjopm7e0=+..@=3cdeijqp7ff47hhhkh4ea;,=*@....%3abefeegffgggggiiipipiigb0;%..+&>0affgefffegeeffegefebbc3,*&....+@%**,9abgpjopi7bdc;9-,>*%@+..@,0b7ioqqUqqjfa9>*&..............#,90ad_begiqUUji7bbbdaa;3>*&.....@#*9ceiqqphkhk<h44:d0-=*%+.....&*9cdbejqqigbdc;,,,,>,>==$&@...$cfiqTTUjmilimmmmpooWqjgba9=#+...........@&$-0be47fedc-$&@......*agipjjojqqqqqWWqqqjqjjjigbc*+....+@%$>3;adbbeefebbac9,>#&+......@$,==#%%&%#*,0dfgjWUUWjpgd0>%+.......@#*,;dbfeed;-=#&.........",
".&,a17ipjmged~adbfipnhedc3*%+....&c:klXnZoooojmhhhlmoonXmm7fba>+..#,0de7pZZnhhQhlVlVVlI7edc9=%+...>bgpjjjqjjqjooooooZZWWqqmhfd=+.+=cbgppjjjjjjqjjjqjqjjjig4bc,%+..+%*=3;cade7mXnmlkk4eb(daac,*@..@>ab7lmnooopi7ba3>*&............@,a:e47kkkloUTTWphhkkk4e|a9>%+...&*=3cd7mqZXlllVVVlk4edc3>*&.....#,cdb4ijWqpheeba'aaaaaaa09>*@.+=afjqTTTqXXXoooooZooXomhed03*@...........@$=cdekllk2ba9=$@......%3dfggghiiiipoooopimiiiggba0$.....@%>3cd:ekhijjqjjg7e|d9-*&.....+>adac-****$,3~e7mZUTUjpgfd9-%........&*,cbe7imigba9=&.........",
".$~rsBGvDvAsrrrrzsHDDys/{~3$&....%(rtBGvLELvGHCBAACDLvGHtxsr/)-+..=)/zsxGLEDBttAACCCCCCtxrF);,#..+;VwEuuETuuuEDDLLvLEDuuEEDAxr;@+&;{IxvDEEEEEuuEuuuuEUuuuGAz]~$+..%>;~)]/rrsxBCCBCCAyyzzzrr]);*+.%;{^stCBCBHCBxKF(!-=&...........=]rsABBBBHHvEuEEGHBCBBABsr]~>@..+*;!)F^sHDDGBBABCBBtys/])'-$&...+,!]/zytGLLHtszr^//^rrrrr/]'-%++;2suuuuEDHGDvEEELEGGHGCyz^{'-%..........+#-;{/sBBAtyzF~;,%+.....#9_b}^rKsssyHCHHHAAsssKzQ2]~,+...@$-;)FzstAHDEuuuDvBtyr]~;,#@...&!rz/]);;-3;!)^stGEEEEGys^]~3%+......@*-']/yAHDDtz/);$@........",
"+={rxHDLLLtJrrzzsyHGvAJ/{';=@....%!zABHLLLLGCCCBBBCGLLHAAsz^]'=@.+>(^zsAGLLGtyABCABCCAACyz/{!-*+.@~zGDEEEEEEEEEEEEEELEEEuLvHy^;@.#-]zAuEEuEuuEEEEEEEEEEEEGtz/'$+.&=;~)F/rzzsyBCCCCCCByssszr/);*+.&-)/zyACCCCCByr/]'-=#@.........+-]zyABCBCCCLEEEEGCCCBCCBxz/)>%..%,!))FrsGDLGBABCCCABAsr/)~;;*%..%,!]rzyBvLLCAyszzrzzzsszzrF~-#+&-^svEEEEvGCvLLLEELLCBBCts/F);%..........@*=;)/stBCBxrF);$%......&-;))F/^rzsytCBCCAyszKr/F])!>+...#,-')/sABCHvLEEEuDHByz/{';=#+..&~^sr/{!;;;;']ryBHvvELHsKF);,%......&*,;~]rxBvLvAs/{;>&........",
".*;1IPJwwOP[:F1F2QPwOK1);-=%+....+-(/IJwNwNJKrQ^/QIOwwPI^2F(;-*+..>~F}[KOwYOIQIrKKKKKKKK/}]~;,%..+-15OYRNSNNNNwNNwNNNSNSNS6I})>+.&=':8wNNNNSNNSSRNNNNNuSMPQ2)-%..@=;'(|:}}2[IKKPKKKKI^QQQ/}{!-%..@=;_]^IKKJKKI[]{~;-*%+..........=):/rKzKzKJONNNwJPKKKJzI/F);=%..&,;!_{}QPOwPIQIKKKr^^/F{~;--=&..@=-~]2[IOww8I[[[222[Q[[/[1)-=&.+,{[6SNNNwJJwwNwNwwwwwJJI[:(;-&..........+%#,;_//Kr^F{)->#+......+$>-;;!)_|F2QKJJKQ2}]]())';-#....%=-;_]/^IzJwwNSNROKIQ}{);-*#+..+-]F}]~;-->--!|/IPwNwO5[(!-=#+......+&*=;_FQPJwO5}_-=%@........",
"+*_25PJOJ8<42:::2[6O6<(0-=#@......$~:[5OSNY6<}}:}}<6RY6Q[}1_;=&..+>(4<56YMSY855586JO86885<}_;-*+..*_:<<5558RRNSOOOwwNSO855[:(9*++@,015MNNMO88556558pMSNNM<}(~-#+.&>;(:4<<<5558OO8886656555<1_-&..+$-'|[58O8J65Q}1(!-$$+.........+$'1[QQQIIIPJMNNR6II6JJPK[:_;=%+.*;_(1:}[6YY6<Q<PPIQQ[[}:|~';-%..@=;_}}Q<8RMO855555555I55<[|;=&.+>(45MNNROPIPOOOOOOJOOYJ5<4:~-%+.........+&*>;_1[Q[2:(;-*%+......+#*=-,;!_(|}[IKIQ}11((((__!-*+..+%=-!(}[QI<IP6OO886655Q}(!;>#+..@-(24[2d;->,-!(1[<6OO8<|!3=*@.......@%$,;(}5P8654_9-$%+........",
".=dijjXmmlh774474ijqjgd9=$%@......$0begoqWqmfeb|bfgjqqpi74ea;=%...3fpjqqUTTUqWqqZqWqWUWqojgfac*+..%,cadbffgpqqon6mnqqjigffba9,#+.@3afiqWqjig7ffffffgjqUqjgba;,&..%3agijqqqqqqTUTUUUqUqUqWqjib9%..+$3abijqUWWqomh7fb;=*@+.........*d47hklllhmjWUUqpmmoWqqpifb;=%.+>0ee77hiqqWpimpoqjmmk5h74bbd;*+.@>0b4hhmoqUUqUqUqUqUqqqWjje0=&.+3egpqUUWjmmlhilllmoqUUWqqjgb0*+..........@*>;de77771d03*&.......+#,9c0aaabef7kl5h4e1bbbbbbb0,@..@$-abf4hhkhlmmmmiipoqopgf_0,*@..+,bgijiga;--9ade7glli5fd;,*#@.......@#$,;bijjmigba9>*%+........",
"+$biqZnVVVVlkkhhhVoZoibc,*%+......*014loZWZm7eeeefioWWnmVh7ba3*+.@9gpWWUUTTTUWWWWUWUTTUWWomfb0>+..%=990dbfgmoZXXVXnZZXifbdac-=%..%cbgjWUWohk4eeebffgpqTWjied0>#..%cbhpZWWUUTTTTTTTUUTTTTUWZpe0$+.@=cb7pqUUUUZZXlV<ea9=*@........+>bkVVVVVlVXoWUUWoXnZWUWoVh:a,&.+,:7kllVXoUUonXoWWZnnXVVVhke1d=++#3d4hVXXZZWUUUTTTTTTTUUWWjgc,&+@9elnWUUWZnXVVVVVXXoWUUWWWoif0$..........+%*30b4hVlkeb_9=%+......%90_db1be47klVXmVhk4444k[74(9#..&3a:7klVVVVVXXXVlhmoWZomkfbc=@+.@3ekpWoibd00~de4kllVVl7b0,>#@......+&*=3cfpqZnl7109,*&@........",
"+=eJtHCCCCCCCHHGGvvGHx^(;-*@......>{ryAGGvGtszrrrsxvuEDvGHtz/)-@.@;KtGvLEEEEDLvDDGGDDEDDDHyrF{;@..#>c'_1/IsAvGvGCHGHvAsr/](!3,&.+$)/sHEEEvHyszr^^rzsvLELvtz/{;*++$_^sAHvLvEEEEEEEEDEEDEvLvDtz:,+.&;(/sAHLDELvDHCCBzF);=%........+;^AACCCCCCHvEEELGHGDEEEDHtsF'=@&;ztBCCCGvEEvGHGEEvGGHHCBAAys^;@+>(rsBCCHBGLGDvEEEEEEDDvDGAIbc%+&~sBHDLDLDvGHHBCCBHGDvvvDDHtr{-+.........@$-!{rxBCBtsrF)-=@.....+-]rzsxsyABCBHvvvGHAtBBBBBAxr)$.+=)/ytHCCACCBHCBCBAHGDvvGGAzF;#+.@'^xGLvHsr/F/zsACHCCCAs^(;-*@......@#>-'FVADDGts/(!;,=%@.......",
".=)FrsxtBCCCBHvLLGGCxz/';=#+.....+-{zxCCCCByzrrrrzyvuEELLGAsr{-+.+-]zABHvEELHCCCBCCCCCCCxsr:);=+..&=,-!)]/rsACCCCCCByzrF(~!--#@..#~/sHuLLvAysr^]FFrsGLLLvys/(;$+.%;]rsyBCCCHvEEEEEHAACCCHCBtr(-@+&-{/zxBCCCCCCBCCtz/~->%+.......@;rtCCBCCABAGLLLLBAAvLELvBAs/)*+@'rtCACBCvLLGBHvLLvCCCCBCCBAs^;%@,]rxBCBCCCCCCCCGLELGtxysz/F~-#+&~rACBCCvvLvHBCCCCCBCCCCCCBs/~*..........%=-~]ryABCAsrF';=&.....@;/sBBBAABACCGLEELGCCCACCCByr)$++>{rxDGHABCCCCCBAyyACBCHGvHJF;#+.@;/sGvLtxzr^rztGLGHCCAs/);-%+......+#=-!FstLLAyzF{~;->*+.......",
".&>-'(]2^rKJJwwNwwJQ[:~->#&.......$'2^rIKII/1((((1<8wNNwNw6[1'=@..*;]2[IJwwPI//IrKzKKKI/F{~;,=%+...+&*=,;!|}QKKsKKr[](~--==*%+...+>~:5wNwJI[](';;'([6wwwJQ:~->&..+*-~(2[^IKKJNNNRPQ[QIIIKKI[{'$+.@,;(][QIKKKKJsKKQF)-,*@.........-1/IrIrI/^QJwNNOPQKONNwJKQ2);%.+-|^rrrKPOwwJJJwwwwJJsKKKrQ/F)-@+$']/KKKzIQ^Q^^IPOwO<[::|_';>*+.+-1^IKKJJwwwJKKzKKKKKKKKKQ[F~,&..........+%>-!{/^Kr/F{~->&+.....+-]^rrIrrKKzJwwNNwJKKzKrKrr^];*+.*;:5OwPIQrKKI^Q/[/^QIKPwwJ[_-%...>!26OOPQ21||}<JwJPIQ/]!-=#+........@%*-_}PwOP[:_'->*$%@+......",
".+&=-;~1:2<IPJwwwO6[|_;=*%@......+*!|2[Q[Q}:_'!!_(26RNNNwO6[('>...#c_|}46MM522}}QQIQQ[[:(!3=*&+.....+&**-;~|}[QQII[1_;->*#%&.....+*0:5MSR6[:(!---'_:<OMY84('-*&...%=-_(:}}[Q6SNNM<}}}[Q[QQ[2(9#..@=;~(:[[QQQPPI<Q[|;-*#@........+=)2[QQQ[[225OSNO<4<8MSwO<[:'-&++=~2[[QQ5ORRPIIJwwJKIIQIQ[2:(~>@+*!(2QIIQQ}}}}}[<OO64|1_'9=$%&+.+=_2[QIIPOww6I<Q<QQQQQIQ[[1(;*...........@&*,;~:QQQ2:(!-*#+.....+=_2[[QQQQQIP8SNNY8IQQQQ[[[1(;%.+*;|<OO5[[[QQQ[}}|11[}QIOO6f_>&..+%-(<8O52:(((1<8YOIQ21_-=*@+........@*>-~:5MO<e(_;-,>**#&+.....",
"..@$>9abbf4hmoWUWqmgba3=$#@.......*cb477kk7edaaadbgpqWWWqjmgba>+..#3abbgpqqjgff7hhhhhk7ed9,=*&+......+%$,3ab4khlhh4:a-,**%@.......=aepqTqjgfd99-9c0fiqWqpgbc3=&...&*3cab:f7hmqqWji7f7khhhhkfac#+.&>cde47khkmppmhked;,*#@.........=b7khkkk74gpqTUqiggjWWWpi7ba3&..*cbe777kpqqnimponmmhhh77eeb_c$++*0bf7hk74eeef47ijpigbac;>$$%@...=ae4kllmoWWopmmmimmmmihh7ba9#+..........@&$,cd7kih7:dc,*#+......=dbef44777k5pqWWjmh774444e|a-%++>cfijpi47kllh7ebbb:e4hijqpga>@...&,0gipgfebbbeijqji7f10-=*@........+#$,9dfiqjieb_ac;3->>*%@....",
"..@*=3ad:4kVnoWUUWphedc3=#@.......=d4klllhke1dddbehjZWZXonXh4b,+..%9a|fhjqUjhh7kllVlllk4dc9$$&.......+#*30(e7kVVVlkba3=$%+.......@,dgpWTWohfb_c99abfpqWZog:ac,%...@*,cade4klmXZoni4khlVlVlh4b9$.+%cb4khVlVXnZomh7edc,$#@........+,1kllVllllVoWTUqpmmqUUWomk4d9#.+%cdb44kioWZXVVXnnXVlkk4ebdac3#++,b47[77k447khlhVnXm4ba0,=#&@...+>deklVXnWUUWWqqqZqooooXi7b~,=@..........@$=3afinoni7ba3>*@.....+*cad|beee[7hmXoonlh74eebbdac=@.@,b7lnnVlhmnom44e:ee7khXZWjgd9#...%>cbggefee4kkmoZol7eac,*&+.......+%*=9dekmopiffe4e|d_a9,>#@...",
"..&>-'{F^stCHvEEEuvyz/{~;,$@.....+;rxBCBBCAszrrrzsyHLLvvCCCAy^;&..$~FrzyDuEvAtBBCCCCCCtz/);-=&.......@=-'{/stCCCCAx^{!-=&........&'QsvEEuvAsz^{)(]^JtLLEvtz/(;*+..&,-')]rstCCCGGGAttBBCBCCAs/)>++=]zABCBCCGDDGCyzrF);-=%&@......+;zAACCCCCCGDuEEEGHHEEEELCAs/)=.+%!{/rzsyvEDDHACCCCCBAxz^]{~!-*+@'ryyssssssxtCBCCHAtz/{~3=*&+....-(rsACCGEELEuEEEEDEEEvDtz/{'-%+.........%>-~FKtvuvHsr]~-=%+.....*-~({1F//zsxBCGGBtsr^/F]{)!;=&.@!rACHCCACvDDAxzzrrsABHvvEvxr(>+..%,0(2^^zzsABBHLDGxzF)!;=#+......+&=-;{^stCHAAssyBtysr/F)~->%+.",
"..%=,;)FrzACGvLEEEGxzrF);->#@....+;^yACBBAAxzrrzsstGvGHBCBBAsr;@.+*'F^zxvuDGBAAABACACAAz]';,$&.......&>-!{/sAACAAAs/_;-$+........&!/xGuELGAyz/]))F^zALELHAK/);*...@*-;~]/sBACCCCGCAACCCHBCyzF;*++={sABCCHHGGGGtsz/]);--=*%&&+...@;ryCCCCCCAHGEEEEvBHvLLGvByz/!*+.#-']/zsxvGLHACBCBCCAysrF)';;,&.@;^zzrrrzzssBCCCCBByr]~;,$&+....+=)^sBCCHGDDuEvuDuEuELvvAK]~;,&..........%>;)/sGLLvtJr]~-#@......@,!'~~){F/rsxCCCCyz^F))'!;>=#+.&~zxACBCCBHGHttzrrrytCCCvvGy[~*...+$;')F/rzxACCGHGAJ/]';,$@.......+*>-'{rsBCBByxstBBByyzr/)!-$@.",
"..@#*-;'{}IJwwNNNw6I[2(!;-=*%+....-(/IrrIr^/]|F2/[IPPKI[/F]])!$+..%-~(148OwPIQ/IrzKrKr^])-=$&+.......@*=-!)}rrK^^F]'->#@.........+>_[8wNwOI[:)';!_([PwwwOQ:)-=&...+&$,-!{/rKKsKJKQQIJJwwPIF{!>%+.#!FIKJwwwwwJPQ2F(~;,=>$#%&&++..+>(/^IrQrQQIJNNNYPIIIJJJKI2{!-#..@=-'(F}QPwOPIQrKIzQ^F]);-,=#&+.+*;~)~'){]F[PJwJJI[]_;,*%@+......&,)FQKKKKPP555I5666OJJP[{!-=#+..........%*-;([6wwwP[(;-*&+.......#=>==--!_(F^KKKr[])!--==#&@...@-:^KKKKIKKPP<2|||]FQrKKJPI2(,%+...%*=-')(2IPJwJP5[1~;-=%+........@#$=;)]QrIrQ[F2/^KKPPIQ1~;,*@.",
"..@*$,;_(2<8SNNNSSO<Q2(_;->>&+...+*~:[Q[[[2:|(|1}[[QQ[:|_!;--=%+..&>;~125YY522}}[QQQQ[}(;->*@.......+%$>-;(2[Q[}11'-=#%@.........+>~:5MSM6[}|_!!~_(}5ORY6}|0->&...+%=>-;(:[III<QQQ[Q6YSY64|!->%..%;_[IJOwwJPIQ}:__'3->=*$$##%&+..*!(12[[[2}[5YNSO<}2Q<IIQ}|_;*@..@*-!(12[6OO<}2[QIQ[}|(;,**%@....+$,---;')|}5YYO6[(_-,*%@........@=!|[[QQ[4}}:224[Q<II5Q}_3=*@..........+%=,;_}5YSY5|~3=#@........@%#$$$=-;_|2QII[}_;->**&+.....&31}QIIQQQQIQ}((~~(}[QQQII[:0,@....@#>,;;(:<OYO6<}(~;>*&+.........@*=-;(}[QQ[}}(|12[6OYO5:_c,*+.",
"..@$=-cabeiqWTTTUqolh4bbac9>#&...+$~b747hk7f:bef774747bdc-,,=*&+..&=9abeiqqjg7fe7khhh7fb93*#+.......@%*>;ab4k<7:b_c-=#&+.........+$0fpqUWjg7bdaaadbfiqWqpgba3=@...@#=,;abeklhhkhh77gpqWqpgba9=@..#cbhmnWWWqnmh4ebda09--,-=*$#%+..#9dbeeeeebfiqWUjiff7hlh4eb03*@..@*3cbf4gpqjiff7hh74ebd9-$*&......%$>=-;adbgjqWqjfda3=*%+........+*cb7khk74ffeeff77hhlhkfa3=*@..........@*=9c_gpqWqif03=*@........+&%##*>-cab4hhl7:a3,*$%@......%9b4khhkkhhh7fbdadbf7hkhhh7b0=&....@%*3;abeiqWqpgba;,$*&..........@$3;dbekk44eebb:fhpqWqigdc-=&+",
"..#=30(e4hpqUUTUUWoXVhk4e1d'-*...+=aeklVllhk747klklll7e_9,,$$#@...&,0de7pWqoikkk<llVIlk:a9>*&......+%=3ca|4kllk4bd03>*&+.........@3dgjWTWoVh44eee}4hpqWWohbac=&..+%>9ad|eklVVVVVllhVoZWZnkb'3=&..*a4hXnZWWZZXlh74feebb_aa'0c-=&..#9ab:ee4e47pWUUqih7hlVlked!3*&..&3014khlnqomh4hllVkkeb03=#@+.....&*=>90d:7hjWWWpgba3$*&+........+*cd4khhk774447khkVVVVl4dc,$&.........%*=,;aehpWUqpbc3$$@........+@@%*>,ca14kVVVledc,>#&+......%ceklVXVVVVVl4ebb1e7lVVVVV7b0>&....&$3;abe7pZWZnhe_9,=#+..........*,0_b4hVllhk7[47hmoWWWohfd0-%.",
".@>!)/sAAHGvLELDvLDvvGGGAts^{-@..@-{rytCHGHCAACCCCCAAsr]!c->=*@...*;{/zxGEEvHBBACCCCCBtz/);-%......#>;)/rsyBCCxz/F)!-#@..........&'/JHuEEvHAAAtxAtAAGEEEDxK/)-#+.@=)]rzsxBBCCCCCCHHvGvLvGs^{!-%.+>{zACHLDvvvGHHHHHBBtysszzr/]'$+.%;{F//rzzzxGEEEuGxxtAAxs^F);>#++>)/sAHHGGvGtxxBCCCBys^{;-=%......#>-;'{/sxCHDLLts^{;,=%.........@,~FrsyyxxyAttBACHCHCCts/);-&.......@%>-;)FrsAGDDvAK]~3=&+........&%=,;']rsyBCCBts/);-*@.......#~rsAHGGGGCAtxszzzytHHGHBAs/)-#...@$;~]^zytGGDDHs/{~c=&..........+-{FzsABHHHCCBABAGDDuEEvHtz/)=+",
".#;)FzyDDGGHCBBtBHGLLLEuDGAs/;&.+&-)/zAGvGvGCCCACACByzF);->=*@+...*;{/zsHuDvHCCCCCCCBBys/);=&.....+*-)FzyAACAByr/]'-*+...........%!/sHDELLHCCCBCACCCvLELHAKF);#.+%;{/stBCCCCCCACCGLLDHCCxzF);$&++=]rsxCCCCCCCHGDLLLLLCCABAxsr{>++&>;'){]//zstuLEvtsszzzr/]'!-=@.+={zxHLGvGHAysstCBBBxzr)'-*&+.....%,-;~]rsBBCCBAsr]';>#@.........@>!)]/rzzsAABBCCvvvBCBAz/)-=@......@#>-;~{/sBCCHHHyr]'->&.........@%>-')/ztBCCCCAs/);=%+.......@;/sALLGLGHByszzzsAHvLGGAsr]'-&...%,;)FzxACCCCAyzF);-#+..........@;FzxtCGGvGBCBCCGLEEEEuLvByr),+",
".%-~_[6OwwPKQ[2F2QIwwNNNwOKQ{-@..+*-~1QPOwwJJzKKzKr/])!-=$#&+.....&=;~|[8MwOKIrKKzKKrI/F~->%+......#-'(/QrzIr^F)!-=$@.............-([PMwwJPKKKKzKzKPJwwwJ[|~-*@..&-'|/rzKzIrr^/QIJwYwPKI[1!-=#+..&;~F[rKKJzJKJwwNwwwwJKKIrI/]'*...&*=,--!_126wwwO<21_)~;;-=>#@...$'2<JwwOPQ2F:FQrKr^F]);,*&&......&$,-;)][rI^[}1(~-,*&@+..........#=,-;!~(]/^zzKJwwwPKI^]!-=%.......@#*=-!)FQIKKKKI}(;,=#@.........+&$=-!(}rKzKzKIF~;=*&+........*!1<OwwwwKQ[/2F2/KJwww6Q1);,*@...%>;'{}^KKKIIQ:(;,=#+...........+-(2^KJJwwJJKzKJJwNNNSNwJKQ1;$+",
"+*;b4<5665<}:((_(|4558O685<:~=@...%=;~|<586KIIQQQ[2:('-*#%@+......&*-!(}5YY6IQQQIIQQ[2}(;-*&+.....@*;~|}[Q[[21(;->#@+............+$;1<6OOPIQ[2[22[[Q5J88<}_0-*@.+#;(:2QQQ[}}::::[5885Q22(~-=*@+..&>~|}[[Q[Q[Q<5688OOPPIQQ[[}|;*+..@%#$$=,-!1<ORR8<(~;->>>*#&++..+>~1[566P[}((_(2Q[2}|(!-*#@.......%*,;_(1}2[}|(~;->*&+............+&#==-;!(|}QQIORS6Q[}1_3=%@.......&#>-;_(}<II<[}:(!-*%+..........@&#>-;):[QIIIQ[|'-*#@.........%-~:<5665Q2:}[4[<<<5P<[|~3,*&....#3'14[<Q[[}1(_;>$#&............@-_2Q5POJJKIIIIIPP6OMMMO6P[|;*.",
"+>bgppig74bbdaaccadfegiiig7ba>@...&*390be777hk444e:(93=#%&+.......@*3cbeiqZpmhhhlhhk74:a;=*&......&,abe7hh44e(03=$&@+.............*9bglmlh7eb|b|b1be4hih7ba;=%@.+*0e77k74eb(dd_bf7gg7fbda9>$#+...@3ae747f4eeeffhghillllhh44ed;*...++&%#*>3cbijUWqgb09>$$*%@+.....,b7ghhg7fd000de474:ba;,*%@+......&=;abbee4e|ac-->$%+..............+&*$>-9_bf<hmoqWjhfbd;,*%@......+%*,;aefkpjpgebda3>%&...........+&#=9cdeklllhh4bc,*$@.........&=3abbffefbfgjjqpi7febdc3-=%.....>0bgppm44ebd~;=$*&@............+,d7ioonmmlhhhkh77ghi5ipojifc*.",
".,fpqoik4ebac9999ccabf4Q4[f:a,...+&#>30d:f4h<hhk4ebac=$%&@........&=9ab7pqZoXVVVVVVlk7ed9-*&+.....#9beklllh4bd0,>#%+..............*0bklVVh7e|bddadbb4khk4ba9,$+..=bkhlllk4|ddaadbe774eb(09=*&+...%317kk44eebbee477klVVlVll7edc%....+@@%>=90fiWWUjgb03,$*%+......@3ellhk74ed0c00b774ebd03*&+.......%,0|447k4ed03,=*%++...............+&#*-9abklVXoWWjheba9,$%@+.....@*>3de4lmoZoied09>*#@...........+&$,9'b4llVVVVkbc3>%+.........@*,90abeebe7pZWWom7ebac9,*#@+...@,b7pqoml7:d09,>*%%+............@,bgjWWoXVVVlllk747[hhlnoZpf0*+",
"@;IwDDAsz/F)';;;;'~1/zsyxszr]-+...@$,;~F^zsyBAtysz/]'-=#&+........&;~F^sGLLGCCCCCCBCtxzF)3$@......={rstBBBts/F~;-*&+..............>)^sACCtsr/F]{){]^zyyys^F~9=@.+-ryBAAAsz/F]({{Fzssz^F]);-=%....%~/xAyszrr^/F/zssxAACCCBAxz/_=+....++#>-'{IyDEEux[_93=#+.......@'sBCBxys^]'!~{rsxsz/]~;=#+.......*;{rsyyxsz/)!-,*&+.................@#$;!{/sBBHGEDHxz^]~;>*&......%>;)/stCHDDDyrF)!-=#@...........+%=-~{^sBCCCCBs^)'-#+.........@=-;'_//r/rJtDLEvts^](!93=%@....@'rxHDLGtsr])!-,=*&.............@!^xHEvGHCCBBCCtysssxtAGvEtI|=+",
"+;rtHAxKr/{!;;---;'~{/rzzrr/{-@...@%=-~{//rssyszz/F);-$+..........@>']^sAGGHBBCBACBAyzr]'-$+.....+=)/zyAAAyzF{!-$#@..............+$;FzAAttr^{{'!!~)]^zssr/{!,#@.+-Fsxyyyzr{'~'~~]FrzrF(~;-$&+....@;/zxszr/F](]F^rzyABAAAttzrF~=+......+$-;)/yGGGxzF)-,#++.......@'ryAxszrF)!;!)/zsz/])!-$+.......+*;{Fzsssz/{';,*%@...................@$-;~FzABCCGGts/F)'-#%+.....+#=;)FzyACHGtJ/{!,>#+............+&=-')/stBBABAs/);=%+.........+&*>;!{FFFFryHDGttI])!;,#@+.....&'^sAGGAyzF);--=*@..............&;/stvvHAABBBtxyzr^zzyytGtw^)=+",
"+$ae2e1_!;-=*#%#***=-;!~~~!;-%.....+&*,-;;')))))~';,#%+............#,;~1[<KQQ2//2/F])~';,*@.......&>;))){])~;-*#@+................&=;)]]])~!--=>>,--!)()';-*&+...#-)){{)~;-,,=,,-;'!;;->*#+.......$;~))~!;;---;!')){{F]]]{)~;>@........@#=-~:[<<410-*#@..........$!]])))!;>=>,-;))~;--=*&+........+$-!~)))~;-=*&+......................@%*,;)]F[[[[e1';-=#@+.......@%=-']F^[Q[e(;-=#&................&*>-!(]]F]]{);-$%@............+&*=-;;;;_:}[7}:~;-=*&+.......+-)2[Q4}(~;-=**&+................=~(e4[[}2FF]]])~~!~))1224:~,%.",
".&>;;c3,,$$#%+.++@&&**>,=>=*#@......+@&*==------,>>#@..............&*=-'(:::(__'_~!;--,*%@........+*==-----,>*%+..................+#>--;--,==**%*#**=,>>>=%&+....+*,-----,=*###**=>==*##&+........&=,---,===*$>>,,--;;;;--,,=%+........+&*=-0_((a9=*#&+..........+$-----,*$#%#$=>>>=*%%@+.........+@#,-->>->**@+........................@#$=-;!!_~ac3,$#%@.........@%$-;~(||(c99,*#+..................@*=,-;;;;;--=*%&...............&%**>>,-9cc009,$#&@+........+=_(__ac3,=**&+.................+#=9'__a!'!;;;-;--,-,--;0;3>>%+",
".+#*==**$#%&+......+@&**$**%&.........+&&*$*******%@...............@&*>9cdba9333333,==$#%@.........@%$$$>=*$$%@....................&*==,=>>*#@@@&&%#*$*##&&@+.....@#$=$*$$%%&&&&&####&@+..........@&**$**##%##*#*$**==,>>$$**@..........@&$>9c009=*$%@............#**=*$*%%@@&&%****%%&+............&**$*$$%%@..........................+&%*>,,3933=>$#%@..........+@#=-0adac3->*%@+..................+&%$==,-,,=**#@+...............++&%%#**=,-3,=**%&+..........=0a033,==*%&....................@#=,9,333-,,,=>$$*$*=>,===$*@.",
"..&*#$**%&&+........+@&&@&@+............+@%#****#%@+...............+&#*,99c993,>,===*#&&&@.........@%%*#*$*%@@+....................+&%##$##&@+..++@@&@&&@@+.......+&##*#&&&+@++..+++.++............&%%%&&&@&@@@@&&#*******%&&...........+%#=>33,>=$%&+............&**#*&@@....+@@&&@&@+.............+&###&@@++............................&#**====>**%%%@..........+@&*,90cc3==*%@+....................+@&#*******#&@...................+&&%##$*==**&@...........+%33,,==$#&@.....................+%*=====$=$=*$**#$%##**>*$*&+.",
"..+&%%%#&@+............+.+...............+@&%#%&&@+.................+&**=>>>=$*****##&&&&...........+&&&%#%%+......................+@&%&&&&+..........++@@+.........@&&&&&++.......................@@&@++.......+@%&#**%&&&@+...........+&&&%***$%#&@+............&&&&+........+++..+.................@@@+++..............................@&%#****%%#&@@+............+%*>>=>$**@+......................+@&&%###*%##@+....................+@&&%#%**%%+.............&$$$$**%@+.......................&#***#%%*#*%&%&&@@%&%**%#&@..",
"....+++................................................................++@@++++.+.++......................+.............................+..........................................................................+.+++....................++++.+..........................................................................................+.++++++...................+.+@+++++................................++.............................++++................++....+...........................+++.++.+.++++.+..++++++...."};

View file

@ -1,533 +0,0 @@
if get_option('resize-pool')
config_h.set('USE_RESIZE_POOL', '1')
endif
srcs_toytoolkit = [
'window.c',
color_management_v1_client_protocol_h,
color_management_v1_protocol_c,
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
text_cursor_position_client_protocol_h,
text_cursor_position_protocol_c,
relative_pointer_unstable_v1_client_protocol_h,
relative_pointer_unstable_v1_protocol_c,
pointer_constraints_unstable_v1_client_protocol_h,
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_protocol_c,
viewporter_client_protocol_h,
viewporter_protocol_c,
]
deps_toytoolkit = [
dep_wayland_client,
dep_lib_cairo_shared,
dep_matrix_c,
dep_xkbcommon,
dependency('wayland-cursor'),
cc.find_library('util'),
]
lib_toytoolkit = static_library(
'toytoolkit',
srcs_toytoolkit,
include_directories: common_inc,
dependencies: deps_toytoolkit,
install: false,
)
dep_toytoolkit = declare_dependency(
link_with: lib_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 = [
{
'name': 'damage',
'sources': [
'simple-damage.c',
viewporter_client_protocol_h,
viewporter_protocol_c,
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
],
'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',
'sources': [
'simple-dmabuf-egl.c',
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_wayland_client,
dep_libdrm,
dep_libm,
dep_matrix_c,
],
'deps': [ 'egl', 'glesv2', 'gbm' ],
'options': [ 'renderer-gl' ]
},
{
'name': 'dmabuf-v4l',
'sources': [
'simple-dmabuf-v4l.c',
linux_dmabuf_unstable_v1_client_protocol_h,
linux_dmabuf_unstable_v1_protocol_c,
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
weston_direct_display_client_protocol_h,
weston_direct_display_protocol_c,
viewporter_client_protocol_h,
viewporter_protocol_c,
],
'dep_objs': [ dep_wayland_client, dep_libdrm_headers ],
'deps': [ 'wayland-cursor' ]
},
{
'name': 'egl',
'sources': [
'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_protocol_c,
ivi_application_client_protocol_h,
ivi_application_protocol_c,
],
'dep_objs': [
dep_libm,
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
{
'name': 'shm',
'sources': [
'simple-shm.c',
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
ivi_application_client_protocol_h,
ivi_application_protocol_c,
],
'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',
'sources': [
'simple-touch.c',
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
],
'dep_objs': [ dep_wayland_client, dep_libshared ]
},
]
if dep_vulkan.found() and prog_glslang.found()
srcs_simple_vulkan_shaders = [
'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
if simple_build_all or simple_clients_enabled.contains(t.get('name'))
t_name = 'weston-simple-' + t.get('name')
t_deps = t.get('dep_objs', [])
foreach depname : t.get('deps', [])
dep = dependency(depname, required: false)
if not dep.found()
error('@0@ requires @1@ which was not found. If you rather not build this, drop "@2@" from simple-clients option.'.format(t_name, depname, t.get('name')))
endif
t_deps += dep
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(
t_name, t.get('sources'),
include_directories: common_inc,
dependencies: t_deps,
install: true
)
endif
endforeach
if simple_build_all or simple_clients_enabled.contains('im')
executable(
'weston-simple-im', [
'simple-im.c',
input_method_unstable_v1_client_protocol_h,
input_method_unstable_v1_protocol_c,
],
include_directories: common_inc,
dependencies: [
dep_libshared,
dep_wayland_client,
dep_xkbcommon,
dependency('wayland-cursor'),
dependency('cairo')
],
install: true,
install_dir: dir_libexec
)
endif
tools_enabled = get_option('tools')
tools_list = [
{
'name': 'calibrator',
'sources': [ 'calibrator.c' ],
'deps': [ dep_toytoolkit, dep_matrix_c ],
},
{
'name': 'debug',
'sources': [
'weston-debug.c',
weston_debug_client_protocol_h,
weston_debug_protocol_c,
],
'deps': [ dep_wayland_client ]
},
{
'name': 'terminal',
'sources': [ 'terminal.c' ],
'deps': [ dep_toytoolkit ],
},
{
'name': 'touch-calibrator',
'sources': [
'touch-calibrator.c',
weston_touch_calibration_client_protocol_h,
weston_touch_calibration_protocol_c,
],
'deps': [ dep_toytoolkit, dep_matrix_c ],
},
]
foreach t : tools_list
if tools_enabled.contains(t.get('name'))
executable(
'weston-@0@'.format(t.get('name')),
t.get('sources'),
include_directories: common_inc,
dependencies: t.get('deps', []),
install: true
)
endif
endforeach
demo_clients = [
{ 'basename': 'clickdot' },
{
'basename': 'cliptest',
'dep_objs': [ dep_vertex_clipping, dep_matrix_c ]
},
{
'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': 'editor',
'add_sources': [
text_input_unstable_v1_client_protocol_h,
text_input_unstable_v1_protocol_c,
],
'deps': [ 'pangocairo', 'gobject-2.0' ]
},
{ 'basename': 'eventdemo' },
{ 'basename': 'flower' },
{
'basename': 'fullscreen',
},
{ 'basename': 'image' },
{
'basename': 'multi-resource',
'add_sources': [
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
]
},
{
'basename': 'presentation-shm',
'add_sources': [
presentation_time_client_protocol_h,
presentation_time_protocol_c,
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
]
},
{ 'basename': 'resizor' },
{
'basename': 'scaler',
'add_sources': [
viewporter_client_protocol_h,
viewporter_protocol_c,
]
},
{ 'basename': 'smoke' },
{ 'basename': 'stacking' },
{
'basename': 'subsurfaces',
'deps': [ 'egl', 'glesv2', 'wayland-egl' ]
},
{
'basename': 'tablet',
'add_sources': [
tablet_unstable_v2_client_protocol_h,
tablet_unstable_v2_protocol_c,
],
},
{ 'basename': 'transformed' },
]
if get_option('demo-clients')
foreach t : demo_clients
t_name = 'weston-' + t.get('basename')
t_srcs = [ t.get('basename') + '.c' ] + t.get('add_sources', [])
t_deps = [ dep_toytoolkit, t.get('dep_objs', []) ]
foreach depname : t.get('deps', [])
dep = dependency(depname, required: false)
if not dep.found()
error('@0@ requires \'@1@\' which was not found. If you rather not build this, set \'-Ddemo-clients=false\'.'.format(t_name, depname))
endif
t_deps += dep
endforeach
executable(
t_name, t_srcs,
include_directories: common_inc,
dependencies: t_deps,
install: true
)
endforeach
endif
if get_option('shell-desktop')
exe_keyboard = executable(
'weston-keyboard',
'keyboard.c',
text_input_unstable_v1_client_protocol_h,
text_input_unstable_v1_protocol_c,
input_method_unstable_v1_client_protocol_h,
input_method_unstable_v1_protocol_c,
include_directories: common_inc,
dependencies: dep_toytoolkit,
install_dir: get_option('libexecdir'),
install: true
)
env_modmap += 'weston-keyboard=@0@;'.format(exe_keyboard.full_path())
exe_shell_desktop = executable(
'weston-desktop-shell',
'desktop-shell.c',
weston_desktop_shell_client_protocol_h,
weston_desktop_shell_protocol_c,
tablet_unstable_v2_client_protocol_h,
tablet_unstable_v2_protocol_c,
include_directories: common_inc,
dependencies: dep_toytoolkit,
install_dir: get_option('libexecdir'),
install: true
)
env_modmap += 'weston-desktop-shell=@0@;'.format(exe_shell_desktop.full_path())
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')
exe_shell_ivi_ui = executable(
'weston-ivi-shell-user-interface',
'ivi-shell-user-interface.c',
ivi_hmi_controller_client_protocol_h,
ivi_hmi_controller_protocol_c,
ivi_application_client_protocol_h,
ivi_application_protocol_c,
include_directories: common_inc,
dependencies: dep_toytoolkit,
install: true,
install_dir: get_option('libexecdir')
)
env_modmap += 'weston-ivi-shell-user-interface=@0@;'.format(exe_shell_ivi_ui.full_path())
endif

View file

@ -1,31 +1,28 @@
/* /*
* 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 to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 <config.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
@ -36,18 +33,12 @@
#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 <libweston/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 +57,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 +68,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
@ -92,6 +81,20 @@ static const struct wl_buffer_listener buffer_listener = {
buffer_release buffer_release
}; };
static inline void *
xzalloc(size_t s)
{
void *p;
p = calloc(1, s);
if (p == NULL) {
fprintf(stderr, "%s: out of memory\n", program_invocation_short_name);
exit(EXIT_FAILURE);
}
return p;
}
static int static int
attach_buffer(struct window *window, int width, int height) attach_buffer(struct window *window, int width, int height)
{ {
@ -104,8 +107,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 +126,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 +159,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 +180,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 +207,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 +258,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 +306,6 @@ static void
keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
uint32_t format, int fd, uint32_t size) uint32_t format, int fd, uint32_t size)
{ {
/* Just so we dont leak the keymap fd */
close(fd);
} }
static void static void
@ -443,8 +407,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 +422,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)
@ -480,13 +445,12 @@ create_device(struct display *display, const char *time_desc, int type)
errno = 0; errno = 0;
start_time = strtoul(time_desc, &tail, 10); start_time = strtoul(time_desc, &tail, 10);
if (errno || tail == time_desc) if (errno)
goto error; goto error;
if (*tail == ':') { if (*tail == ':') {
time_desc = tail + 1; end_time = strtoul(tail + 1, &tail, 10);
end_time = strtoul(time_desc, &tail, 10); if (errno || *tail != '\0')
if (errno || tail == time_desc || *tail != '\0')
goto error; goto error;
} else if (*tail != '\0') { } else if (*tail != '\0') {
goto error; goto error;

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

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

1140
clients/nested.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -3,29 +3,27 @@
* Copyright © 2010 Intel Corporation * Copyright © 2010 Intel Corporation
* Copyright © 2014 Collabora, Ltd. * Copyright © 2014 Collabora, Ltd.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 <config.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -35,15 +33,12 @@
#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/os-compatibility.h"
#include <libweston/zalloc.h> #include "presentation_timing-client-protocol.h"
#include "shared/timespec-util.h"
#include "shared/os-compatibility.h" #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
#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,12 +62,12 @@ 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;
struct wp_presentation *presentation; struct presentation *presentation;
clockid_t clk_id; clockid_t clk_id;
struct wl_list output_list; /* struct output::link */ struct wl_list output_list; /* struct output::link */
@ -81,7 +76,7 @@ struct display {
struct feedback { struct feedback {
struct window *window; struct window *window;
unsigned frame_no; unsigned frame_no;
struct wp_presentation_feedback *feedback; struct presentation_feedback *feedback;
struct timespec commit; struct timespec commit;
struct timespec target; struct timespec target;
uint32_t frame_stamp; uint32_t frame_stamp;
@ -100,15 +95,12 @@ 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;
int next; int next;
int refresh_nsec; int refresh_nsec;
int commit_delay_msecs;
struct wl_callback *callback; struct wl_callback *callback;
struct wl_list feedback_list; struct wl_list feedback_list;
@ -145,14 +137,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,67 +176,44 @@ 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 *
create_window(struct display *display, int width, int height, create_window(struct display *display, int width, int height,
enum run_mode mode, int commit_delay_msecs) enum run_mode mode)
{ {
struct window *window; struct window *window;
char title[128]; char title[128];
int ret; int ret;
snprintf(title, sizeof(title), snprintf(title, sizeof(title),
"presentation-shm: %s [Delay %i msecs]", run_mode_name[mode], "presentation-shm: %s", run_mode_name[mode]);
commit_delay_msecs);
window = zalloc(sizeof *window); window = calloc(1, sizeof *window);
if (!window) if (!window)
return NULL; return NULL;
window->commit_delay_msecs = commit_delay_msecs;
window->mode = mode; window->mode = mode;
window->callback = NULL; window->callback = NULL;
wl_list_init(&window->feedback_list); wl_list_init(&window->feedback_list);
@ -252,30 +221,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 */
@ -293,7 +248,7 @@ static void
destroy_feedback(struct feedback *feedback) destroy_feedback(struct feedback *feedback)
{ {
if (feedback->feedback) if (feedback->feedback)
wp_presentation_feedback_destroy(feedback->feedback); presentation_feedback_destroy(feedback->feedback);
wl_list_remove(&feedback->link); wl_list_remove(&feedback->link);
free(feedback); free(feedback);
@ -315,7 +270,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++)
@ -386,7 +341,7 @@ paint_pixels(void *image, int width, int height, uint32_t phase)
static void static void
feedback_sync_output(void *data, feedback_sync_output(void *data,
struct wp_presentation_feedback *presentation_feedback, struct presentation_feedback *presentation_feedback,
struct wl_output *output) struct wl_output *output)
{ {
/* not interested */ /* not interested */
@ -399,10 +354,10 @@ pflags_to_str(uint32_t flags, char *str, unsigned len)
uint32_t flag; uint32_t flag;
char sym; char sym;
} desc[] = { } desc[] = {
{ WP_PRESENTATION_FEEDBACK_KIND_VSYNC, 's' }, { PRESENTATION_FEEDBACK_KIND_VSYNC, 's' },
{ WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK, 'c' }, { PRESENTATION_FEEDBACK_KIND_HW_CLOCK, 'c' },
{ WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION, 'e' }, { PRESENTATION_FEEDBACK_KIND_HW_COMPLETION, 'e' },
{ WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY, 'z' }, { PRESENTATION_FEEDBACK_KIND_ZERO_COPY, 'z' },
}; };
unsigned i; unsigned i;
@ -423,6 +378,14 @@ timespec_to_ms(const struct timespec *ts)
return (uint32_t)ts->tv_sec * 1000 + ts->tv_nsec / 1000000; return (uint32_t)ts->tv_sec * 1000 + ts->tv_nsec / 1000000;
} }
static void
timespec_from_proto(struct timespec *tm, uint32_t tv_sec_hi,
uint32_t tv_sec_lo, uint32_t tv_nsec)
{
tm->tv_sec = ((uint64_t)tv_sec_hi << 32) + tv_sec_lo;
tm->tv_nsec = tv_nsec;
}
static int static int
timespec_diff_to_usec(const struct timespec *a, const struct timespec *b) timespec_diff_to_usec(const struct timespec *a, const struct timespec *b)
{ {
@ -434,7 +397,7 @@ timespec_diff_to_usec(const struct timespec *a, const struct timespec *b)
static void static void
feedback_presented(void *data, feedback_presented(void *data,
struct wp_presentation_feedback *presentation_feedback, struct presentation_feedback *presentation_feedback,
uint32_t tv_sec_hi, uint32_t tv_sec_hi,
uint32_t tv_sec_lo, uint32_t tv_sec_lo,
uint32_t tv_nsec, uint32_t tv_nsec,
@ -446,7 +409,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;
@ -490,7 +453,7 @@ feedback_presented(void *data,
static void static void
feedback_discarded(void *data, feedback_discarded(void *data,
struct wp_presentation_feedback *presentation_feedback) struct presentation_feedback *presentation_feedback)
{ {
struct feedback *feedback = data; struct feedback *feedback = data;
@ -499,34 +462,17 @@ feedback_discarded(void *data,
destroy_feedback(feedback); destroy_feedback(feedback);
} }
static const struct wp_presentation_feedback_listener feedback_listener = { static const struct presentation_feedback_listener feedback_listener = {
feedback_sync_output, feedback_sync_output,
feedback_presented, feedback_presented,
feedback_discarded feedback_discarded
}; };
static void
window_emulate_rendering(struct window *window)
{
struct timespec delay;
int ret;
if (window->commit_delay_msecs <= 0)
return;
delay.tv_sec = window->commit_delay_msecs / 1000;
delay.tv_nsec = (window->commit_delay_msecs % 1000) * 1000000;
ret = nanosleep(&delay, NULL);
if (ret)
printf("nanosleep failed: %s\n", strerror(errno));
}
static void static void
window_create_feedback(struct window *window, uint32_t frame_stamp) window_create_feedback(struct window *window, uint32_t frame_stamp)
{ {
static unsigned seq; static unsigned seq;
struct wp_presentation *pres = window->display->presentation; struct presentation *pres = window->display->presentation;
struct feedback *feedback; struct feedback *feedback;
seq++; seq++;
@ -534,17 +480,16 @@ window_create_feedback(struct window *window, uint32_t frame_stamp)
if (!pres) if (!pres)
return; return;
feedback = zalloc(sizeof *feedback); feedback = calloc(1, sizeof *feedback);
if (!feedback) if (!feedback)
return; return;
feedback->window = window; feedback->window = window;
feedback->feedback = wp_presentation_feedback(pres, window->surface); feedback->feedback = presentation_feedback(pres, window->surface);
wp_presentation_feedback_add_listener(feedback->feedback, presentation_feedback_add_listener(feedback->feedback,
&feedback_listener, feedback); &feedback_listener, feedback);
feedback->frame_no = seq; feedback->frame_no = seq;
clock_gettime(window->display->clk_id, &feedback->commit); clock_gettime(window->display->clk_id, &feedback->commit);
feedback->frame_stamp = frame_stamp; feedback->frame_stamp = frame_stamp;
feedback->target = feedback->commit; feedback->target = feedback->commit;
@ -560,12 +505,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);
@ -585,8 +524,6 @@ redraw_mode_feedback(void *data, struct wl_callback *callback, uint32_t time)
if (callback) if (callback)
wl_callback_destroy(callback); wl_callback_destroy(callback);
window_emulate_rendering(window);
window->callback = wl_surface_frame(window->surface); window->callback = wl_surface_frame(window->surface);
wl_callback_add_listener(window->callback, wl_callback_add_listener(window->callback,
&frame_listener_mode_feedback, window); &frame_listener_mode_feedback, window);
@ -599,22 +536,21 @@ static const struct wl_callback_listener frame_listener_mode_feedback = {
redraw_mode_feedback redraw_mode_feedback
}; };
static const struct wp_presentation_feedback_listener feedkick_listener; static const struct presentation_feedback_listener feedkick_listener;
static void static void
window_feedkick(struct window *window) window_feedkick(struct window *window)
{ {
struct wp_presentation *pres = window->display->presentation; struct presentation *pres = window->display->presentation;
struct wp_presentation_feedback *fback; struct presentation_feedback *fback;
fback = wp_presentation_feedback(pres, window->surface); fback = presentation_feedback(pres, window->surface);
wp_presentation_feedback_add_listener(fback, &feedkick_listener, presentation_feedback_add_listener(fback, &feedkick_listener, window);
window);
} }
static void static void
feedkick_presented(void *data, feedkick_presented(void *data,
struct wp_presentation_feedback *presentation_feedback, struct presentation_feedback *presentation_feedback,
uint32_t tv_sec_hi, uint32_t tv_sec_hi,
uint32_t tv_sec_lo, uint32_t tv_sec_lo,
uint32_t tv_nsec, uint32_t tv_nsec,
@ -625,12 +561,11 @@ feedkick_presented(void *data,
{ {
struct window *window = data; struct window *window = data;
wp_presentation_feedback_destroy(presentation_feedback); presentation_feedback_destroy(presentation_feedback);
window->refresh_nsec = refresh_nsec; window->refresh_nsec = refresh_nsec;
switch (window->mode) { switch (window->mode) {
case RUN_MODE_PRESENT: case RUN_MODE_PRESENT:
window_emulate_rendering(window);
window_create_feedback(window, 0); window_create_feedback(window, 0);
window_feedkick(window); window_feedkick(window);
window_commit_next(window); window_commit_next(window);
@ -643,15 +578,14 @@ feedkick_presented(void *data,
static void static void
feedkick_discarded(void *data, feedkick_discarded(void *data,
struct wp_presentation_feedback *presentation_feedback) struct presentation_feedback *presentation_feedback)
{ {
struct window *window = data; struct window *window = data;
wp_presentation_feedback_destroy(presentation_feedback); presentation_feedback_destroy(presentation_feedback);
switch (window->mode) { switch (window->mode) {
case RUN_MODE_PRESENT: case RUN_MODE_PRESENT:
window_emulate_rendering(window);
window_create_feedback(window, 0); window_create_feedback(window, 0);
window_feedkick(window); window_feedkick(window);
window_commit_next(window); window_commit_next(window);
@ -662,7 +596,7 @@ feedkick_discarded(void *data,
} }
} }
static const struct wp_presentation_feedback_listener feedkick_listener = { static const struct presentation_feedback_listener feedkick_listener = {
feedback_sync_output, feedback_sync_output,
feedkick_presented, feedkick_presented,
feedkick_discarded feedkick_discarded
@ -671,8 +605,6 @@ static const struct wp_presentation_feedback_listener feedkick_listener = {
static void static void
firstdraw_mode_burst(struct window *window) firstdraw_mode_burst(struct window *window)
{ {
window_emulate_rendering(window);
switch (window->mode) { switch (window->mode) {
case RUN_MODE_PRESENT: case RUN_MODE_PRESENT:
window_create_feedback(window, 0); window_create_feedback(window, 0);
@ -718,7 +650,7 @@ display_add_output(struct display *d, uint32_t name, uint32_t version)
{ {
struct output *o; struct output *o;
o = zalloc(sizeof(*o)); o = calloc(1, sizeof(*o));
assert(o); assert(o);
o->output = wl_registry_bind(d->registry, name, o->output = wl_registry_bind(d->registry, name,
@ -728,7 +660,7 @@ display_add_output(struct display *d, uint32_t name, uint32_t version)
} }
static void static void
presentation_clock_id(void *data, struct wp_presentation *presentation, presentation_clock_id(void *data, struct presentation *presentation,
uint32_t clk_id) uint32_t clk_id)
{ {
struct display *d = data; struct display *d = data;
@ -736,7 +668,7 @@ presentation_clock_id(void *data, struct wp_presentation *presentation,
d->clk_id = clk_id; d->clk_id = clk_id;
} }
static const struct wp_presentation_listener presentation_listener = { static const struct presentation_listener presentation_listener = {
presentation_clock_id presentation_clock_id
}; };
@ -762,22 +694,21 @@ 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);
wl_shm_add_listener(d->shm, &shm_listener, d); wl_shm_add_listener(d->shm, &shm_listener, d);
} else if (strcmp(interface, "wl_output") == 0) { } else if (strcmp(interface, "wl_output") == 0) {
display_add_output(d, name, version); display_add_output(d, name, version);
} else if (strcmp(interface, wp_presentation_interface.name) == 0) { } else if (strcmp(interface, "presentation") == 0) {
d->presentation = d->presentation =
wl_registry_bind(registry, wl_registry_bind(registry,
name, &wp_presentation_interface, 2); name, &presentation_interface, 1);
wp_presentation_add_listener(d->presentation, presentation_add_listener(d->presentation,
&presentation_listener, d); &presentation_listener, d);
} }
} }
@ -851,8 +782,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);
@ -876,12 +807,10 @@ usage(const char *prog, int exit_code)
{ {
fprintf(stderr, "Usage: %s [mode] [options]\n" fprintf(stderr, "Usage: %s [mode] [options]\n"
"where 'mode' is one of\n" "where 'mode' is one of\n"
" -f\t\trun in feedback mode (default)\n" " -f\trun in feedback mode (default)\n"
" -i\t\trun in feedback-idle mode; sleep 1s between frames\n" " -i\trun in feedback-idle mode; sleep 1s between frames\n"
" -p\t\trun in low-latency presentation mode\n" " -p\trun in low-latency presentation mode\n"
"and 'options' may include\n" "and 'options' may include\n",
" -d msecs\temulate the time used for rendering by a delay \n"
"\t\tof the given milliseconds before commit\n\n",
prog); prog);
fprintf(stderr, "Printed timing statistics, depending on mode:\n" fprintf(stderr, "Printed timing statistics, depending on mode:\n"
@ -906,7 +835,6 @@ main(int argc, char **argv)
int ret = 0; int ret = 0;
enum run_mode mode = RUN_MODE_FEEDBACK; enum run_mode mode = RUN_MODE_FEEDBACK;
int i; int i;
int commit_delay_msecs = 0;
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
if (strcmp("-f", argv[i]) == 0) if (strcmp("-f", argv[i]) == 0)
@ -915,16 +843,12 @@ main(int argc, char **argv)
mode = RUN_MODE_FEEDBACK_IDLE; mode = RUN_MODE_FEEDBACK_IDLE;
else if (strcmp("-p", argv[i]) == 0) else if (strcmp("-p", argv[i]) == 0)
mode = RUN_MODE_PRESENT; mode = RUN_MODE_PRESENT;
else if ((strcmp("-d", argv[i]) == 0) && (i + 1 < argc)) {
i++;
commit_delay_msecs = atoi(argv[i]);
}
else else
usage(argv[0], EXIT_FAILURE); usage(argv[0], EXIT_FAILURE);
} }
display = create_display(); display = create_display();
window = create_window(display, 250, 250, mode, commit_delay_msecs); window = create_window(display, 250, 250, mode);
if (!window) if (!window)
return 1; return 1;

View file

@ -1,29 +1,27 @@
/* /*
* Copyright © 2010 Intel Corporation * Copyright © 2010 Intel Corporation
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 "config.h"
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -31,13 +29,11 @@
#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>
#include "window.h" #include "window.h"
#include "shared/xalloc.h"
struct spring { struct spring {
double current; double current;
@ -53,11 +49,6 @@ struct resizor {
struct spring width; struct spring width;
struct spring height; struct spring height;
struct wl_callback *frame_callback; struct wl_callback *frame_callback;
bool pointer_locked;
bool locked_frame_callback_registered;
struct input *locked_input;
float pointer_x;
float pointer_y;
}; };
static void static void
@ -227,162 +218,21 @@ show_menu(struct resizor *resizor, struct input *input, uint32_t time)
x - 10, y - 10, menu_func, entries, 4); x - 10, y - 10, menu_func, entries, 4);
} }
static void
locked_pointer_handle_motion(struct window *window,
struct input *input,
uint32_t time,
float dx,
float dy,
void *data)
{
struct resizor *resizor = data;
resizor->width.current += dx;
resizor->width.previous = resizor->width.current;
resizor->width.target = resizor->width.current;
resizor->height.current += dy;
resizor->height.previous = resizor->height.current;
resizor->height.target = resizor->height.current;
widget_schedule_resize(resizor->widget,
resizor->width.current,
resizor->height.current);
}
static void
handle_pointer_locked(struct window *window, struct input *input, void *data)
{
struct resizor *resizor = data;
resizor->pointer_locked = true;
input_set_pointer_image(input, CURSOR_BLANK);
}
static void
handle_pointer_unlocked(struct window *window, struct input *input, void *data)
{
struct resizor *resizor = data;
resizor->pointer_locked = false;
input_set_pointer_image(input, CURSOR_LEFT_PTR);
}
static const struct wl_callback_listener locked_pointer_frame_listener;
static void
locked_pointer_frame_callback(void *data,
struct wl_callback *callback,
uint32_t time)
{
struct resizor *resizor = data;
struct wl_surface *surface;
struct rectangle allocation;
float x, y;
if (resizor->pointer_locked) {
widget_get_allocation(resizor->widget, &allocation);
x = resizor->pointer_x + (allocation.width - allocation.x);
y = resizor->pointer_y + (allocation.height - allocation.y);
widget_set_locked_pointer_cursor_hint(resizor->widget, x, y);
}
wl_callback_destroy(callback);
surface = window_get_wl_surface(resizor->window);
callback = wl_surface_frame(surface);
wl_callback_add_listener(callback,
&locked_pointer_frame_listener,
resizor);
}
static const struct wl_callback_listener locked_pointer_frame_listener = {
locked_pointer_frame_callback
};
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, enum wl_pointer_button_state state, void *data) uint32_t button, enum wl_pointer_button_state state, void *data)
{ {
struct resizor *resizor = data; struct resizor *resizor = data;
struct rectangle allocation;
struct wl_surface *surface;
struct wl_callback *callback;
if (button == BTN_RIGHT && state == WL_POINTER_BUTTON_STATE_PRESSED) { switch (button) {
show_menu(resizor, input, time); case BTN_RIGHT:
} else if (button == BTN_LEFT && if (state == WL_POINTER_BUTTON_STATE_PRESSED)
state == WL_POINTER_BUTTON_STATE_PRESSED) { show_menu(resizor, input, time);
window_get_allocation(resizor->window, &allocation); break;
resizor->width.current = allocation.width;
resizor->width.previous = allocation.width;
resizor->width.target = allocation.width;
resizor->height.current = allocation.height;
resizor->height.previous = allocation.height;
resizor->height.target = allocation.height;
window_lock_pointer(resizor->window, input);
window_set_pointer_locked_handler(resizor->window,
handle_pointer_locked,
handle_pointer_unlocked);
resizor->locked_input = input;
if (resizor->locked_frame_callback_registered)
return;
surface = window_get_wl_surface(resizor->window);
callback = wl_surface_frame(surface);
wl_callback_add_listener(callback,
&locked_pointer_frame_listener,
resizor);
resizor->locked_frame_callback_registered = true;
} else if (button == BTN_LEFT &&
state == WL_POINTER_BUTTON_STATE_RELEASED) {
input_set_pointer_image(input, CURSOR_LEFT_PTR);
window_unlock_pointer(resizor->window);
} }
} }
static void
set_cursor_inv_offset(struct resizor *resizor, float x, float y)
{
struct rectangle allocation;
widget_get_allocation(resizor->widget, &allocation);
resizor->pointer_x = x - (allocation.width - allocation.x);
resizor->pointer_y = y - (allocation.height - allocation.y);
}
static int
enter_handler(struct widget *widget,
struct input *input,
float x, float y, void *data)
{
struct resizor *resizor = data;
set_cursor_inv_offset(resizor, x , y);
return CURSOR_LEFT_PTR;
}
static int
motion_handler(struct widget *widget,
struct input *input, uint32_t time,
float x, float y, void *data)
{
struct resizor *resizor = data;
set_cursor_inv_offset(resizor, x , y);
return CURSOR_LEFT_PTR;
}
static struct resizor * static struct resizor *
resizor_create(struct display *display) resizor_create(struct display *display)
{ {
@ -392,8 +242,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);
@ -402,12 +250,6 @@ resizor_create(struct display *display)
window_set_keyboard_focus_handler(resizor->window, window_set_keyboard_focus_handler(resizor->window,
keyboard_focus_handler); keyboard_focus_handler);
widget_set_enter_handler(resizor->widget, enter_handler);
widget_set_motion_handler(resizor->widget, motion_handler);
window_set_locked_pointer_motion_handler(
resizor->window, locked_pointer_handle_motion);
widget_set_button_handler(resizor->widget, button_handler); widget_set_button_handler(resizor->widget, button_handler);
resizor->height.previous = 400; resizor->height.previous = 400;
@ -442,8 +284,7 @@ main(int argc, char *argv[])
display = display_create(&argc, argv); display = display_create(&argc, argv);
if (display == NULL) { if (display == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }

View file

@ -2,39 +2,36 @@
* Copyright © 2008 Kristian Høgsberg * Copyright © 2008 Kristian Høgsberg
* Copyright © 2013 Collabora, Ltd. * Copyright © 2013 Collabora, Ltd.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 "config.h"
#include <stdint.h>
#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>
#include "window.h" #include "window.h"
#include "viewporter-client-protocol.h" #include "scaler-client-protocol.h"
#define BUFFER_SCALE 2 #define BUFFER_SCALE 2
static const int BUFFER_WIDTH = 421 * BUFFER_SCALE; static const int BUFFER_WIDTH = 421 * BUFFER_SCALE;
@ -52,8 +49,9 @@ struct box {
struct widget *widget; struct widget *widget;
int width, height; int width, height;
struct wp_viewporter *viewporter; struct wl_scaler *scaler;
struct wp_viewport *viewport; int scaler_version;
struct wl_viewport *viewport;
enum { enum {
MODE_NO_VIEWPORT, MODE_NO_VIEWPORT,
@ -85,30 +83,33 @@ set_my_viewport(struct box *box)
src_width = wl_fixed_from_double((RECT_W - 0.5) / BUFFER_SCALE); src_width = wl_fixed_from_double((RECT_W - 0.5) / BUFFER_SCALE);
src_height = wl_fixed_from_double((RECT_H - 0.5) / BUFFER_SCALE); src_height = wl_fixed_from_double((RECT_H - 0.5) / BUFFER_SCALE);
if (box->scaler_version < 2 && box->mode != MODE_SRC_DST) {
fprintf(stderr, "Error: server's wl_scaler interface version "
"%d does not support this mode.\n",
box->scaler_version);
exit(1);
}
switch (box->mode){ switch (box->mode){
case MODE_SRC_ONLY: case MODE_SRC_ONLY:
/* In SRC_ONLY mode we're just cropping - in order wl_viewport_set_source(box->viewport, src_x, src_y,
* for the surface size to remain an integer, the
* compositor will generate an error if we use a
* fractional width or height.
*
* We use fractional width/height for the other cases
* to ensure fractional values are still tested.
*/
src_width = wl_fixed_from_int(RECT_W / BUFFER_SCALE);
src_height = wl_fixed_from_int(RECT_H / BUFFER_SCALE);
wp_viewport_set_source(box->viewport, src_x, src_y,
src_width, src_height); src_width, src_height);
break; break;
case MODE_DST_ONLY: case MODE_DST_ONLY:
wp_viewport_set_destination(box->viewport, wl_viewport_set_destination(box->viewport,
dst_width, dst_height); dst_width, dst_height);
break; break;
case MODE_SRC_DST: case MODE_SRC_DST:
wp_viewport_set_source(box->viewport, src_x, src_y, if (box->scaler_version < 2) {
src_width, src_height); wl_viewport_set(box->viewport,
wp_viewport_set_destination(box->viewport, src_x, src_y, src_width, src_height,
dst_width, dst_height); dst_width, dst_height);
} else {
wl_viewport_set_source(box->viewport, src_x, src_y,
src_width, src_height);
wl_viewport_set_destination(box->viewport,
dst_width, dst_height);
}
break; break;
default: default:
assert(!"not reached"); assert(!"not reached");
@ -121,7 +122,7 @@ resize_handler(struct widget *widget,
{ {
struct box *box = data; struct box *box = data;
/* Don't resize me */ /* Dont resize me */
widget_set_size(box->widget, box->width, box->height); widget_set_size(box->widget, box->width, box->height);
} }
@ -186,11 +187,14 @@ global_handler(struct display *display, uint32_t name,
{ {
struct box *box = data; struct box *box = data;
if (strcmp(interface, "wp_viewporter") == 0) { if (strcmp(interface, "wl_scaler") == 0) {
box->viewporter = display_bind(display, name, box->scaler_version = version < 2 ? version : 2;
&wp_viewporter_interface, 1);
box->viewport = wp_viewporter_get_viewport(box->viewporter, box->scaler = display_bind(display, name,
&wl_scaler_interface,
box->scaler_version);
box->viewport = wl_scaler_get_viewport(box->scaler,
widget_get_wl_surface(box->widget)); widget_get_wl_surface(box->widget));
set_my_viewport(box); set_my_viewport(box);
@ -289,8 +293,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 +306,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 +319,6 @@ main(int argc, char *argv[])
display_set_user_data(box.display, &box); display_set_user_data(box.display, &box);
display_set_global_handler(box.display, global_handler); display_set_global_handler(box.display, global_handler);
if (box.mode != MODE_NO_VIEWPORT && !box.viewport) {
fprintf(stderr, "compositor doesn't support viewporter\n");
return -1;
}
display_run(d); display_run(d);
widget_destroy(box.widget); widget_destroy(box.widget);

View file

@ -1,348 +1,155 @@
/* /*
* 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 to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 "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 "screenshooter-client-protocol.h"
#include "../shared/os-compatibility.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h" /* The screenshooter is a good example of a custom object exposed by
#include "pixel-formats.h" * the compositor and serves as a test bed for implementing client
#include "shared/client-buffer-util.h" * side marshalling outside libwayland.so */
#include "shared/file-util.h"
#include "shared/os-compatibility.h"
#include "shared/string-helpers.h"
#include "shared/xalloc.h"
#include "weston-output-capture-client-protocol.h"
struct screenshooter_app { static struct wl_shm *shm;
struct wl_display *display; static struct screenshooter *screenshooter;
struct wl_registry *registry; static struct wl_list output_list;
struct wl_shm *shm; int min_x, min_y, max_x, max_y;
struct zwp_linux_dmabuf_v1 *dmabuf; int buffer_copy_done;
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 {
int width, height;
int min_x, min_y;
int max_x, max_y;
};
static struct screenshooter_buffer *
screenshot_create_shm_buffer(struct screenshooter_app *app,
size_t width, size_t height,
const struct pixel_format_info *fmt)
{
struct screenshooter_buffer *buffer;
assert(width > 0);
assert(height > 0);
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); static void *
xmalloc(size_t size)
{
void *p;
wl_list_insert(&app->output_list, &output->link); p = malloc(size);
if (p == NULL) {
fprintf(stderr, "%s: out of memory\n",
program_invocation_short_name);
exit(EXIT_FAILURE);
}
return p;
} }
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 screenshooter *screenshooter)
{
buffer_copy_done = 1;
}
static const struct 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;
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(&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) {
*/ shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
} else if (strcmp(interface, weston_capture_v1_interface.name) == 0) { } else if (strcmp(interface, "screenshooter") == 0) {
app->capture_factory = wl_registry_bind(registry, name, screenshooter = wl_registry_bind(registry, name,
&weston_capture_v1_interface, &screenshooter_interface, 1);
2);
} 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,390 +157,153 @@ 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) create_shm_buffer(int width, int height, void **data_out)
{ {
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, write_png(int width, int height)
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;
FILE *fp; struct screenshooter_output *output, *next;
char filepath[PATH_MAX];
shot = pixman_image_create_bits(PIXMAN_a8r8g8b8, buffer_stride = 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 * 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 - min_y) * buffer_stride +
0, 0, /* src x,y */ (output->offset_x - 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), width, height, buffer_stride);
pixman_image_get_height(shot), cairo_surface_write_to_png(surface, "wayland-screenshot.png");
pixman_image_get_stride(shot));
fp = file_create_dated(getenv("XDG_PICTURES_DIR"), "wayland-screenshot-",
".png", filepath, sizeof(filepath));
if (fp) {
fclose (fp);
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, set_buffer_size(int *width, int *height)
struct wl_list *output_list)
{ {
struct screenshooter_output *output; struct screenshooter_output *output;
buff_size->min_x = buff_size->min_y = INT_MAX; min_x = min_y = INT_MAX;
buff_size->max_x = buff_size->max_y = INT_MIN; max_x = max_y = INT_MIN;
int position = 0; int position = 0;
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); min_x = MIN(min_x, output->offset_x);
buff_size->min_y = MIN(buff_size->min_y, output->offset_y); min_y = MIN(min_y, output->offset_y);
buff_size->max_x = max_x = MAX(max_x, output->offset_x + output->width);
MAX(buff_size->max_x, output->offset_x + output->buffer_width); max_y = MAX(max_y, output->offset_y + output->height);
buff_size->max_y =
MAX(buff_size->max_y, output->offset_y + output->buffer_height);
} }
if (buff_size->max_x <= buff_size->min_x || if (max_x <= min_x || max_y <= min_y)
buff_size->max_y <= buff_size->min_y)
return -1; return -1;
buff_size->width = buff_size->max_x - buff_size->min_x; *width = max_x - min_x;
buff_size->height = buff_size->max_y - buff_size->min_y; *height = max_y - min_y;
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;
int width, height;
wl_list_for_each(output, &app->output_list, link) { if (getenv("WAYLAND_SOCKET") == NULL) {
if (!output->formats_done) fprintf(stderr, "%s must be launched by weston.\n"
return false; "Use the MOD+S shortcut to take a screenshot.\n",
} program_invocation_short_name);
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 screenshooter_app app = {};
int c, option_index;
app.src_type = WESTON_CAPTURE_V1_SOURCE_FRAMEBUFFER;
app.buffer_type = CLIENT_BUFFER_TYPE_SHM;
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); display = wl_display_connect(NULL);
wl_registry_add_listener(app.registry, &registry_listener, &app); if (display == NULL) {
fprintf(stderr, "failed to create display: %m\n");
/* Process wl_registry advertisements */
wl_display_roundtrip(app.display);
if (!app.capture_factory) {
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) { wl_list_init(&output_list);
fprintf(stderr, "Error: display does not support wl_shm\n"); registry = wl_display_get_registry(display);
return -1; wl_registry_add_listener(registry, &registry_listener, NULL);
} wl_display_dispatch(display);
if (app.buffer_type == CLIENT_BUFFER_TYPE_DMABUF && !app.dmabuf) { wl_display_roundtrip(display);
fprintf(stderr, "Error: Compositor does not support zwp_linux_dmabuf_v1\n"); if (screenshooter == NULL) {
fprintf(stderr, "display doesn't support screenshooter\n");
return -1; return -1;
} }
if (app.verbose) { screenshooter_add_listener(screenshooter, &screenshooter_listener, screenshooter);
printf("Taking screenshot with %s source %s buffer\n",
(app.src_type == WESTON_CAPTURE_V1_SOURCE_FRAMEBUFFER) ? "framebuffer" : "writeback", if (set_buffer_size(&width, &height))
(app.buffer_type == CLIENT_BUFFER_TYPE_SHM) ? "shm" : "dma"); return -1;
wl_list_for_each(output, &output_list, link) {
output->buffer = create_shm_buffer(output->width, output->height, &output->data);
screenshooter_shoot(screenshooter, output->output, output->buffer);
buffer_copy_done = 0;
while (!buffer_copy_done)
wl_display_roundtrip(display);
} }
/* Process initial events for wl_output and weston_capture_source_v1 */ write_png(width, height);
wl_display_roundtrip(app.display);
while (!received_formats_for_all_outputs(&app)) {
if (app.verbose)
printf("Waiting for compositor to send capture source data\n");
if (wl_display_dispatch(app.display) < 0) {
fprintf(stderr, "Error: connection terminated\n");
return -1;
}
}
do {
app.retry = false;
wl_list_for_each(output, &app.output_list, link)
screenshooter_output_capture(output);
while (app.waitcount > 0 && !app.failed) {
if (wl_display_dispatch(app.display) < 0)
app.failed = true;
assert(app.waitcount >= 0);
}
} while (app.retry && !app.failed);
if (!app.failed) {
if (screenshot_set_buffer_size(&buff_size, &app.output_list) < 0)
return -1;
if (all_output_formats_are_yuv(&app.output_list))
screenshot_write_yuv(&buff_size, &app.output_list);
else
screenshot_write_png(&buff_size, &app.output_list);
} else {
fprintf(stderr, "Error: screenshot or protocol failure\n");
}
wl_list_for_each_safe(output, tmp_output, &app.output_list, link)
destroy_output(output);
weston_capture_v1_destroy(app.capture_factory);
wl_shm_destroy(app.shm);
if (app.dmabuf)
zwp_linux_dmabuf_v1_destroy(app.dmabuf);
wl_registry_destroy(app.registry);
wl_display_disconnect(app.display);
return 0; return 0;
} }

View file

@ -3,29 +3,27 @@
* Copyright © 2011 Benjamin Franzke * Copyright © 2011 Benjamin Franzke
* Copyright © 2010 Intel Corporation * Copyright © 2010 Intel Corporation
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 <config.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -35,13 +33,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 "xdg-shell-client-protocol.h" #include "xdg-shell-client-protocol.h"
#include "viewporter-client-protocol.h" #include "fullscreen-shell-client-protocol.h"
#include "scaler-client-protocol.h"
int print_debug = 0; int print_debug = 0;
@ -50,8 +47,9 @@ struct display {
struct wl_registry *registry; struct wl_registry *registry;
int compositor_version; int compositor_version;
struct wl_compositor *compositor; struct wl_compositor *compositor;
struct wp_viewporter *viewporter; struct wl_scaler *scaler;
struct xdg_wm_base *wm_base; struct xdg_shell *shell;
struct _wl_fullscreen_shell *fshell;
struct wl_shm *shm; struct wl_shm *shm;
uint32_t formats; uint32_t formats;
}; };
@ -65,20 +63,17 @@ struct buffer {
enum window_flags { enum window_flags {
WINDOW_FLAG_USE_VIEWPORT = 0x1, WINDOW_FLAG_USE_VIEWPORT = 0x1,
WINDOW_FLAG_ROTATING_TRANSFORM = 0x2, WINDOW_FLAG_ROTATING_TRANSFORM = 0x2,
WINDOW_FLAG_USE_DAMAGE_BUFFER = 0x4,
}; };
struct window { struct window {
struct display *display; struct display *display;
int width, height, border; int width, height, border;
struct wl_surface *surface; struct wl_surface *surface;
struct wp_viewport *viewport; struct wl_viewport *viewport;
struct xdg_surface *xdg_surface; struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
struct wl_callback *callback; struct wl_callback *callback;
struct buffer buffers[2]; struct buffer buffers[2];
struct buffer *prev_buffer; struct buffer *prev_buffer;
bool wait_for_configure;
enum window_flags flags; enum window_flags flags;
int scale; int scale;
@ -94,9 +89,6 @@ struct window {
static int running = 1; static int running = 1;
static void
redraw(void *data, struct wl_callback *callback, uint32_t time);
static void static void
buffer_release(void *data, struct wl_buffer *buffer) buffer_release(void *data, struct wl_buffer *buffer)
{ {
@ -122,14 +114,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;
} }
@ -148,39 +140,21 @@ create_shm_buffer(struct display *display, struct buffer *buffer,
} }
static void static void
xdg_surface_handle_configure(void *data, struct xdg_surface *surface, handle_configure(void *data, struct xdg_surface *surface,
uint32_t serial) int32_t width, int32_t height, struct wl_array *states,
{ uint32_t serial)
struct window *window = data;
xdg_surface_ack_configure(surface, serial);
if (window->wait_for_configure) {
redraw(window, NULL, 0);
window->wait_for_configure = false;
}
}
static const struct xdg_surface_listener xdg_surface_listener = {
xdg_surface_handle_configure,
};
static void
xdg_toplevel_handle_configure(void *data, struct xdg_toplevel *toplevel,
int32_t width, int32_t height,
struct wl_array *states)
{ {
} }
static void static void
xdg_toplevel_handle_close(void *data, struct xdg_toplevel *xdg_toplevel) handle_close(void *data, struct xdg_surface *xdg_surface)
{ {
running = 0; running = 0;
} }
static const struct xdg_toplevel_listener xdg_toplevel_listener = { static const struct xdg_surface_listener xdg_surface_listener = {
xdg_toplevel_handle_configure, handle_configure,
xdg_toplevel_handle_close, handle_close,
}; };
static float static float
@ -281,21 +255,12 @@ create_window(struct display *display, int width, int height,
exit(1); exit(1);
} }
if (display->viewporter == NULL && (flags & WINDOW_FLAG_USE_VIEWPORT)) { if (display->scaler == NULL && (flags & WINDOW_FLAG_USE_VIEWPORT)) {
fprintf(stderr, "Compositor does not support wp_viewport"); fprintf(stderr, "Compositor does not support wl_viewport");
exit(1); exit(1);
} }
if (display->compositor_version < window = calloc(1, sizeof *window);
WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION &&
(flags & WINDOW_FLAG_USE_DAMAGE_BUFFER)) {
fprintf(stderr, "wl_surface.damage_buffer unsupported in "
"wl_surface version %d\n",
display->compositor_version);
exit(1);
}
window = zalloc(sizeof *window);
if (!window) if (!window)
return NULL; return NULL;
@ -313,44 +278,32 @@ create_window(struct display *display, int width, int height,
window->surface = wl_compositor_create_surface(display->compositor); window->surface = wl_compositor_create_surface(display->compositor);
if (window->flags & WINDOW_FLAG_USE_VIEWPORT) if (window->flags & WINDOW_FLAG_USE_VIEWPORT)
window->viewport = wp_viewporter_get_viewport(display->viewporter, window->viewport = wl_scaler_get_viewport(display->scaler,
window->surface); window->surface);
if (display->wm_base) { if (display->shell) {
window->xdg_surface = window->xdg_surface =
xdg_wm_base_get_xdg_surface(display->wm_base, xdg_shell_get_xdg_surface(display->shell,
window->surface); window->surface);
assert(window->xdg_surface); assert(window->xdg_surface);
xdg_surface_add_listener(window->xdg_surface, xdg_surface_add_listener(window->xdg_surface,
&xdg_surface_listener, window); &xdg_surface_listener, window);
window->xdg_toplevel = xdg_surface_set_title(window->xdg_surface, "simple-damage");
xdg_surface_get_toplevel(window->xdg_surface); } else if (display->fshell) {
_wl_fullscreen_shell_present_surface(display->fshell,
assert(window->xdg_toplevel); window->surface,
_WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT,
xdg_toplevel_add_listener(window->xdg_toplevel, NULL);
&xdg_toplevel_listener, window);
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;
wl_surface_commit(window->surface);
} else { } else {
assert(0); assert(0);
} }
/* Initialise damage to full surface, so the padding gets painted */ /* Initialise damage to full surface, so the padding gets painted */
if (window->flags & WINDOW_FLAG_USE_DAMAGE_BUFFER) { wl_surface_damage(window->surface, 0, 0, INT32_MAX, INT32_MAX);
wl_surface_damage_buffer(window->surface, 0, 0,
INT32_MAX, INT32_MAX);
} else {
wl_surface_damage(window->surface, 0, 0, INT32_MAX, INT32_MAX);
}
return window; return window;
} }
@ -365,12 +318,10 @@ destroy_window(struct window *window)
if (window->buffers[1].buffer) if (window->buffers[1].buffer)
wl_buffer_destroy(window->buffers[1].buffer); wl_buffer_destroy(window->buffers[1].buffer);
if (window->xdg_toplevel)
xdg_toplevel_destroy(window->xdg_toplevel);
if (window->xdg_surface) if (window->xdg_surface)
xdg_surface_destroy(window->xdg_surface); xdg_surface_destroy(window->xdg_surface);
if (window->viewport) if (window->viewport)
wp_viewport_destroy(window->viewport); wl_viewport_destroy(window->viewport);
wl_surface_destroy(window->surface); wl_surface_destroy(window->surface);
free(window); free(window);
} }
@ -456,32 +407,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,27 +448,13 @@ 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)
{ {
struct window *window = data; struct window *window = data;
struct buffer *buffer; struct buffer *buffer;
int off_x = 0, off_y = 0; int off_x, off_y, bwidth, bheight, bborder, bpitch, bradius;
int bwidth, bheight, bborder, bpitch, bradius; uint32_t *buffer_data;
float bx, by; float bx, by;
buffer = window_next_buffer(window); buffer = window_next_buffer(window);
@ -556,8 +493,8 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
bborder = window->border * window->scale; bborder = window->border * window->scale;
bradius = window->ball.radius * window->scale; bradius = window->ball.radius * window->scale;
buffer_data = buffer->shm_data;
if (window->viewport) { if (window->viewport) {
int tx, ty;
/* Fill the whole thing with red to detect viewport errors */ /* Fill the whole thing with red to detect viewport errors */
paint_box(buffer->shm_data, bpitch, 0, 0, bwidth, bheight, paint_box(buffer->shm_data, bpitch, 0, 0, bwidth, bheight,
0xffff0000); 0xffff0000);
@ -570,44 +507,38 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
bheight /= 2; bheight /= 2;
/* Offset the drawing region */ /* Offset the drawing region */
tx = (window->width / 3) * window->scale; off_x = (window->width / 3) * window->scale;
ty = (window->height / 5) * window->scale; off_y = (window->height / 5) * window->scale;
switch (window->transform) { switch (window->transform) {
default: default:
case WL_OUTPUT_TRANSFORM_NORMAL: case WL_OUTPUT_TRANSFORM_NORMAL:
off_y = ty; buffer_data += off_y * bpitch + off_x;
off_x = tx;
break; break;
case WL_OUTPUT_TRANSFORM_90: case WL_OUTPUT_TRANSFORM_90:
off_y = bheight - tx; buffer_data += off_x * bpitch + (bwidth - off_y);
off_x = ty;
break; break;
case WL_OUTPUT_TRANSFORM_180: case WL_OUTPUT_TRANSFORM_180:
off_y = bheight - ty; buffer_data += (bheight - off_y) * bpitch +
off_x = bwidth - tx; (bwidth - off_x);
break; break;
case WL_OUTPUT_TRANSFORM_270: case WL_OUTPUT_TRANSFORM_270:
off_y = tx; buffer_data += (bheight - off_x) * bpitch + off_y;
off_x = bwidth - ty;
break; break;
case WL_OUTPUT_TRANSFORM_FLIPPED: case WL_OUTPUT_TRANSFORM_FLIPPED:
off_y = ty; buffer_data += off_y * bpitch + (bwidth - off_x);
off_x = bwidth - tx;
break; break;
case WL_OUTPUT_TRANSFORM_FLIPPED_90: case WL_OUTPUT_TRANSFORM_FLIPPED_90:
off_y = tx; buffer_data += (bheight - off_x) * bpitch +
off_x = ty; (bwidth - off_y);
break; break;
case WL_OUTPUT_TRANSFORM_FLIPPED_180: case WL_OUTPUT_TRANSFORM_FLIPPED_180:
off_y = bheight - ty; buffer_data += (bheight - off_y) * bpitch + off_x;
off_x = tx;
break; break;
case WL_OUTPUT_TRANSFORM_FLIPPED_270: case WL_OUTPUT_TRANSFORM_FLIPPED_270:
off_y = bheight - tx; buffer_data += off_x * bpitch + off_y;
off_x = bwidth - ty;
break; break;
} }
wp_viewport_set_source(window->viewport, wl_viewport_set_source(window->viewport,
wl_fixed_from_int(window->width / 3), wl_fixed_from_int(window->width / 3),
wl_fixed_from_int(window->height / 5), wl_fixed_from_int(window->height / 5),
wl_fixed_from_int(window->width / 2), wl_fixed_from_int(window->width / 2),
@ -615,41 +546,30 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
} }
/* Paint the border */ /* Paint the border */
paint_box(buffer->shm_data, bpitch, off_x, off_y, paint_box(buffer_data, bpitch, 0, 0, bwidth, bborder, 0xffffffff);
bwidth, bborder, 0xffffffff); paint_box(buffer_data, bpitch, 0, 0, bborder, bheight, 0xffffffff);
paint_box(buffer->shm_data, bpitch, off_x, off_y, paint_box(buffer_data, bpitch,
bborder, bheight, 0xffffffff); bwidth - bborder, 0, bborder, bheight, 0xffffffff);
paint_box(buffer->shm_data, bpitch, off_x + bwidth - bborder, off_y, paint_box(buffer_data, bpitch,
bborder, bheight, 0xffffffff); 0, bheight - bborder, bwidth, bborder, 0xffffffff);
paint_box(buffer->shm_data, bpitch, off_x, off_y + bheight - bborder,
bwidth, bborder, 0xffffffff);
/* fill with translucent */ /* fill with translucent */
paint_box(buffer->shm_data, bpitch, off_x + bborder, off_y + bborder, paint_box(buffer_data, bpitch, bborder, bborder,
bwidth - 2 * bborder, bheight - 2 * bborder, 0x80000000); bwidth - 2 * bborder, bheight - 2 * bborder, 0x80000000);
/* Damage where the ball was */ /* Damage where the ball was */
if (window->flags & WINDOW_FLAG_USE_DAMAGE_BUFFER) { wl_surface_damage(window->surface,
window_get_transformed_ball(window, &bx, &by); window->ball.x - window->ball.radius,
wl_surface_damage_buffer(window->surface, window->ball.y - window->ball.radius,
bx - bradius + off_x, window->ball.radius * 2 + 1,
by - bradius + off_y, window->ball.radius * 2 + 1);
bradius * 2 + 1,
bradius * 2 + 1);
} else {
wl_surface_damage(window->surface,
window->ball.x - window->ball.radius,
window->ball.y - window->ball.radius,
window->ball.radius * 2 + 1,
window->ball.radius * 2 + 1);
}
window_advance_game(window, time); window_advance_game(window, time);
window_get_transformed_ball(window, &bx, &by); window_get_transformed_ball(window, &bx, &by);
/* Paint the ball */ /* Paint the ball */
paint_circle(buffer->shm_data, bpitch, off_x + bx, off_y + by, paint_circle(buffer_data, bpitch, bx, by, bradius, 0xff00ff00);
bradius, 0xff00ff00);
if (print_debug) { if (print_debug) {
printf("Ball now located at (%f, %f)\n", printf("Ball now located at (%f, %f)\n",
@ -659,25 +579,17 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
bradius); bradius);
printf("Buffer damage rectangle: (%d, %d) @ %dx%d\n", printf("Buffer damage rectangle: (%d, %d) @ %dx%d\n",
(int)(bx - bradius) + off_x, (int)(bx - bradius), (int)(by - bradius),
(int)(by - bradius) + off_y,
bradius * 2 + 1, bradius * 2 + 1); bradius * 2 + 1, bradius * 2 + 1);
} }
/* Damage where the ball is now */ /* Damage where the ball is now */
if (window->flags & WINDOW_FLAG_USE_DAMAGE_BUFFER) { wl_surface_damage(window->surface,
wl_surface_damage_buffer(window->surface, window->ball.x - window->ball.radius,
bx - bradius + off_x, window->ball.y - window->ball.radius,
by - bradius + off_y, window->ball.radius * 2 + 1,
bradius * 2 + 1, window->ball.radius * 2 + 1);
bradius * 2 + 1);
} else {
wl_surface_damage(window->surface,
window->ball.x - window->ball.radius,
window->ball.y - window->ball.radius,
window->ball.radius * 2 + 1,
window->ball.radius * 2 + 1);
}
wl_surface_attach(window->surface, buffer->buffer, 0, 0); wl_surface_attach(window->surface, buffer->buffer, 0, 0);
if (window->display->compositor_version >= 2 && if (window->display->compositor_version >= 2 &&
@ -687,7 +599,7 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
window->transform); window->transform);
if (window->viewport) if (window->viewport)
wp_viewport_set_destination(window->viewport, wl_viewport_set_destination(window->viewport,
window->width, window->width,
window->height); window->height);
@ -698,8 +610,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);
@ -723,15 +633,21 @@ struct wl_shm_listener shm_listener = {
}; };
static void static void
xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial) xdg_shell_ping(void *data, struct xdg_shell *shell, uint32_t serial)
{ {
xdg_wm_base_pong(shell, serial); xdg_shell_pong(shell, serial);
} }
static const struct xdg_wm_base_listener wm_base_listener = { static const struct xdg_shell_listener xdg_shell_listener = {
xdg_wm_base_ping, xdg_shell_ping,
}; };
#define XDG_VERSION 5 /* The version of xdg-shell that we implement */
#ifdef static_assert
static_assert(XDG_VERSION == XDG_SHELL_VERSION_CURRENT,
"Interface version doesn't match implementation version");
#endif
static void static void
registry_handle_global(void *data, struct wl_registry *registry, registry_handle_global(void *data, struct wl_registry *registry,
uint32_t id, const char *interface, uint32_t version) uint32_t id, const char *interface, uint32_t version)
@ -752,13 +668,17 @@ registry_handle_global(void *data, struct wl_registry *registry,
wl_registry_bind(registry, wl_registry_bind(registry,
id, &wl_compositor_interface, id, &wl_compositor_interface,
d->compositor_version); d->compositor_version);
} else if (strcmp(interface, "wp_viewporter") == 0) { } else if (strcmp(interface, "wl_scaler") == 0 && version >= 2) {
d->viewporter = wl_registry_bind(registry, id, d->scaler = wl_registry_bind(registry,
&wp_viewporter_interface, 1); id, &wl_scaler_interface, 2);
} else if (strcmp(interface, "xdg_wm_base") == 0) { } else if (strcmp(interface, "xdg_shell") == 0) {
d->wm_base = wl_registry_bind(registry, d->shell = wl_registry_bind(registry,
id, &xdg_wm_base_interface, 1); id, &xdg_shell_interface, 1);
xdg_wm_base_add_listener(d->wm_base, &wm_base_listener, d); xdg_shell_use_unstable_version(d->shell, XDG_VERSION);
xdg_shell_add_listener(d->shell, &xdg_shell_listener, d);
} else if (strcmp(interface, "_wl_fullscreen_shell") == 0) {
d->fshell = wl_registry_bind(registry,
id, &_wl_fullscreen_shell_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 +702,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);
@ -817,11 +737,14 @@ 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); xdg_shell_destroy(display->shell);
if (display->viewporter) if (display->fshell)
wp_viewporter_destroy(display->viewporter); _wl_fullscreen_shell_release(display->fshell);
if (display->scaler)
wl_scaler_destroy(display->scaler);
if (display->compositor) if (display->compositor)
wl_compositor_destroy(display->compositor); wl_compositor_destroy(display->compositor);
@ -852,8 +775,7 @@ print_usage(int retval)
" --scale=SCALE\t\tScale factor for the surface\n" " --scale=SCALE\t\tScale factor for the surface\n"
" --transform=TRANSFORM\tTransform for the surface\n" " --transform=TRANSFORM\tTransform for the surface\n"
" --rotating-transform\tUse a different buffer_transform for each frame\n" " --rotating-transform\tUse a different buffer_transform for each frame\n"
" --use-viewport\tUse wp_viewport\n" " --use-viewport\tUse wl_viewport\n"
" --use-damage-buffer\tUse damage_buffer to post damage\n"
); );
exit(retval); exit(retval);
@ -904,7 +826,7 @@ main(int argc, char **argv)
strcmp(argv[i], "-h") == 0) { strcmp(argv[i], "-h") == 0) {
print_usage(0); print_usage(0);
} else if (sscanf(argv[i], "--version=%d", &version) > 0) { } else if (sscanf(argv[i], "--version=%d", &version) > 0) {
if (version < 1 || version > 4) { if (version < 1 || version > 3) {
fprintf(stderr, "Unsupported wl_surface version: %d\n", fprintf(stderr, "Unsupported wl_surface version: %d\n",
version); version);
return 1; return 1;
@ -928,9 +850,6 @@ main(int argc, char **argv)
} else if (strcmp(argv[i], "--use-viewport") == 0) { } else if (strcmp(argv[i], "--use-viewport") == 0) {
flags |= WINDOW_FLAG_USE_VIEWPORT; flags |= WINDOW_FLAG_USE_VIEWPORT;
continue; continue;
} else if (strcmp(argv[i], "--use-damage-buffer") == 0) {
flags |= WINDOW_FLAG_USE_DAMAGE_BUFFER;
continue;
} else { } else {
printf("Invalid option: %s\n", argv[i]); printf("Invalid option: %s\n", argv[i]);
print_usage(255); print_usage(255);
@ -948,13 +867,12 @@ main(int argc, char **argv)
sigint.sa_flags = SA_RESETHAND; sigint.sa_flags = SA_RESETHAND;
sigaction(SIGINT, &sigint, NULL); sigaction(SIGINT, &sigint, NULL);
if (!window->wait_for_configure) redraw(window, NULL, 0);
redraw(window, NULL, 0);
while (running && ret != -1) while (running && ret != -1)
ret = wl_display_dispatch(display->display); ret = wl_display_dispatch(display->display);
fprintf(stderr, "simple-damage exiting\n"); fprintf(stderr, "simple-shm exiting\n");
destroy_window(window); destroy_window(window);
destroy_display(display); destroy_display(display);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -2,29 +2,27 @@
* Copyright © 2011 Benjamin Franzke * Copyright © 2011 Benjamin Franzke
* Copyright © 2010 Intel Corporation * Copyright © 2010 Intel Corporation
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 <config.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -33,189 +31,46 @@
#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 "xdg-shell-client-protocol.h" #include "xdg-shell-client-protocol.h"
#include "fullscreen-shell-client-protocol.h"
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) #include <sys/types.h>
#define FMT(fmt, bpp, r, g, b, a) { WL_SHM_FORMAT_ ## fmt, #fmt, bpp, { r, g, b, a } } #include "ivi-application-client-protocol.h"
#define IVI_SURFACE_ID 9000
#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_shell *shell;
struct wl_seat *seat; struct _wl_fullscreen_shell *fshell;
struct wl_keyboard *keyboard;
struct wl_shm *shm; struct wl_shm *shm;
const struct format *format; uint32_t formats;
bool paint_format; struct ivi_application *ivi_application;
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 ivi_surface *ivi_surface;
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 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;
static void
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 +84,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,164 +111,52 @@ 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 static void
keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, handle_configure(void *data, struct xdg_surface *surface,
uint32_t format, int fd, uint32_t size) int32_t width, int32_t height,
struct wl_array *states, uint32_t serial)
{ {
/* Just so we dont leak the keymap fd */
close(fd);
}
static void
keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface,
struct wl_array *keys)
{
}
static void
keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface)
{
}
static void
keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t time, uint32_t key,
uint32_t state)
{
struct display *d = data;
if (key == KEY_F11 && state) {
if (d->window->fullscreen)
xdg_toplevel_unset_fullscreen(d->window->xdg_toplevel);
else
xdg_toplevel_set_fullscreen(d->window->xdg_toplevel, NULL);
} else if (key == KEY_ESC && state) {
running = 0;
}
}
static void
keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t mods_depressed,
uint32_t mods_latched, uint32_t mods_locked,
uint32_t group)
{
}
static const struct wl_keyboard_listener keyboard_listener = {
keyboard_handle_keymap,
keyboard_handle_enter,
keyboard_handle_leave,
keyboard_handle_key,
keyboard_handle_modifiers,
};
static void
seat_handle_capabilities(void *data, struct wl_seat *seat,
enum wl_seat_capability caps)
{
struct display *d = data;
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !d->keyboard) {
d->keyboard = wl_seat_get_keyboard(seat);
wl_keyboard_add_listener(d->keyboard, &keyboard_listener, d);
} else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && d->keyboard) {
wl_keyboard_destroy(d->keyboard);
d->keyboard = NULL;
}
}
static const struct wl_seat_listener seat_listener = {
seat_handle_capabilities,
};
static void
handle_xdg_surface_configure(void *data, struct xdg_surface *surface,
uint32_t serial)
{
struct window *window = data;
xdg_surface_ack_configure(surface, serial); xdg_surface_ack_configure(surface, serial);
if (window->wait_for_configure) {
redraw(window, NULL, 0);
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 static void
handle_xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel) handle_delete(void *data, struct xdg_surface *xdg_surface)
{ {
running = 0; running = 0;
} }
static const struct xdg_toplevel_listener xdg_toplevel_listener = { static const struct xdg_surface_listener xdg_surface_listener = {
handle_xdg_toplevel_configure, handle_configure,
handle_xdg_toplevel_close, handle_delete,
};
static void
handle_ivi_surface_configure(void *data, struct ivi_surface *ivi_surface,
int32_t width, int32_t height)
{
/* Simple-shm is resizable */
}
static const struct ivi_surface_listener ivi_surface_listener = {
handle_ivi_surface_configure,
}; };
static struct window * 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 = calloc(1, sizeof *window);
if (!window) if (!window)
return NULL; return NULL;
@ -426,56 +164,56 @@ 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->shell) {
window->xdg_surface = window->xdg_surface =
xdg_wm_base_get_xdg_surface(display->wm_base, xdg_shell_get_xdg_surface(display->shell,
window->surface); window->surface);
assert(window->xdg_surface); assert(window->xdg_surface);
xdg_surface_add_listener(window->xdg_surface, xdg_surface_add_listener(window->xdg_surface,
&xdg_surface_listener, window); &xdg_surface_listener, window);
window->xdg_toplevel = xdg_surface_set_title(window->xdg_surface, "simple-shm");
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-shm"); } else if (display->fshell) {
xdg_toplevel_set_app_id(window->xdg_toplevel, _wl_fullscreen_shell_present_surface(display->fshell,
"org.freedesktop.weston.simple-shm"); window->surface,
_WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT,
NULL);
} else if (display->ivi_application ) {
uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
window->ivi_surface =
ivi_application_surface_create(display->ivi_application,
id_ivisurf, window->surface);
if (window->ivi_surface == NULL) {
fprintf(stderr, "Failed to create ivi_client_surface\n");
abort();
}
ivi_surface_add_listener(window->ivi_surface,
&ivi_surface_listener, window);
wl_surface_commit(window->surface);
window->wait_for_configure = true;
} 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)
xdg_toplevel_destroy(window->xdg_toplevel);
if (window->xdg_surface) if (window->xdg_surface)
xdg_surface_destroy(window->xdg_surface); xdg_surface_destroy(window->xdg_surface);
wl_surface_destroy(window->surface); wl_surface_destroy(window->surface);
@ -485,34 +223,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 +295,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 +303,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 +311,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 +335,7 @@ 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) d->formats |= (1 << format);
d->has_format = true;
} }
struct wl_shm_listener shm_listener = { struct wl_shm_listener shm_listener = {
@ -736,15 +343,21 @@ struct wl_shm_listener shm_listener = {
}; };
static void static void
xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial) xdg_shell_ping(void *data, struct xdg_shell *shell, uint32_t serial)
{ {
xdg_wm_base_pong(shell, serial); xdg_shell_pong(shell, serial);
} }
static const struct xdg_wm_base_listener xdg_wm_base_listener = { static const struct xdg_shell_listener xdg_shell_listener = {
xdg_wm_base_ping, xdg_shell_ping,
}; };
#define XDG_VERSION 5 /* The version of xdg-shell that we implement */
#ifdef static_assert
static_assert(XDG_VERSION == XDG_SHELL_VERSION_CURRENT,
"Interface version doesn't match implementation version");
#endif
static void static void
registry_handle_global(void *data, struct wl_registry *registry, registry_handle_global(void *data, struct wl_registry *registry,
uint32_t id, const char *interface, uint32_t version) uint32_t id, const char *interface, uint32_t version)
@ -755,19 +368,24 @@ 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, "xdg_shell") == 0) {
d->wm_base = wl_registry_bind(registry, d->shell = wl_registry_bind(registry,
id, &xdg_wm_base_interface, 1); id, &xdg_shell_interface, 1);
xdg_wm_base_add_listener(d->wm_base, &xdg_wm_base_listener, d); xdg_shell_use_unstable_version(d->shell, XDG_VERSION);
} else if (strcmp(interface, "wl_seat") == 0) { xdg_shell_add_listener(d->shell, &xdg_shell_listener, d);
d->seat = wl_registry_bind(registry, id, } else if (strcmp(interface, "_wl_fullscreen_shell") == 0) {
&wl_seat_interface, 1); d->fshell = wl_registry_bind(registry,
wl_seat_add_listener(d->seat, &seat_listener, d); id, &_wl_fullscreen_shell_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);
wl_shm_add_listener(d->shm, &shm_listener, d); wl_shm_add_listener(d->shm, &shm_listener, d);
} }
else if (strcmp(interface, "ivi_application") == 0) {
d->ivi_application =
wl_registry_bind(registry, id,
&ivi_application_interface, 1);
}
} }
static void static void
@ -782,11 +400,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 +412,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->formats = 0;
display->paint_format = paint_format;
display->has_format= false;
display->registry = wl_display_get_registry(display->display); display->registry = wl_display_get_registry(display->display);
wl_registry_add_listener(display->registry, wl_registry_add_listener(display->registry,
&registry_listener, display); &registry_listener, display);
@ -848,9 +464,8 @@ create_display(const struct format *format, bool paint_format)
* technique. * technique.
*/ */
if (!display->has_format) { if (!(display->formats & (1 << WL_SHM_FORMAT_XRGB8888))) {
fprintf(stderr, "Format '%s' not supported by compositor.\n", fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n");
format->string);
exit(1); exit(1);
} }
@ -863,8 +478,11 @@ 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); xdg_shell_destroy(display->shell);
if (display->fshell)
_wl_fullscreen_shell_release(display->fshell);
if (display->compositor) if (display->compositor)
wl_compositor_destroy(display->compositor); wl_compositor_destroy(display->compositor);
@ -881,86 +499,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;
@ -970,14 +521,18 @@ main(int argc, char **argv)
wl_surface_damage(window->surface, 0, 0, wl_surface_damage(window->surface, 0, 0,
window->width, window->height); window->width, window->height);
if (!window->wait_for_configure) redraw(window, NULL, 0);
redraw(window, NULL, 0);
while (running && ret != -1) while (running && ret != -1)
ret = wl_display_dispatch(display->display); ret = wl_display_dispatch(display->display);
fprintf(stderr, "simple-shm exiting\n"); fprintf(stderr, "simple-shm exiting\n");
if (window->display->ivi_application) {
ivi_surface_destroy(window->ivi_surface);
ivi_application_destroy(window->display->ivi_application);
}
destroy_window(window); destroy_window(window);
destroy_display(display); destroy_display(display);

View file

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

View file

@ -1,46 +1,40 @@
/* /*
* 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 to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 <config.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#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/os-compatibility.h"
#include "shared/xalloc.h"
#include "shared/os-compatibility.h"
#include "xdg-shell-client-protocol.h" #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
struct seat { struct seat {
struct touch *touch; struct touch *touch;
@ -48,92 +42,54 @@ struct 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 +98,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 +128,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 +147,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 +239,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 +272,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 +295,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 +308,7 @@ touch_create(int width, int height)
touch->display = wl_display_connect(NULL); touch->display = wl_display_connect(NULL);
assert(touch->display); assert(touch->display);
touch->has_argb = false; touch->has_argb = 0;
touch->buffer = NULL;
touch->registry = wl_display_get_registry(touch->display); touch->registry = wl_display_get_registry(touch->display);
wl_registry_add_listener(touch->registry, &registry_listener, touch); wl_registry_add_listener(touch->registry, &registry_listener, touch);
wl_display_dispatch(touch->display); wl_display_dispatch(touch->display);
@ -421,59 +319,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 +351,8 @@ main(int argc, char **argv)
touch = touch_create(600, 500); touch = touch_create(600, 500);
while (ret != -1 && touch->running) while (ret != -1)
ret = wl_display_dispatch(touch->display); ret = wl_display_dispatch(touch->display);
destroy_touch(touch);
return 0; return 0;
} }

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

@ -1,24 +1,23 @@
/* /*
* Copyright © 2010 Kristian Høgsberg * Copyright © 2010 Kristian Høgsberg
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 "config.h"
@ -29,7 +28,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>
@ -202,6 +200,8 @@ redraw_handler(struct widget *widget, void *data)
render(smoke, surface); render(smoke, surface);
window_damage(smoke->window, 0, 0, smoke->width, smoke->height);
cairo_surface_destroy(surface); cairo_surface_destroy(surface);
widget_schedule_redraw(smoke->widget); widget_schedule_redraw(smoke->widget);
@ -261,7 +261,7 @@ resize_handler(struct widget *widget,
{ {
struct smoke *smoke = data; struct smoke *smoke = data;
/* Don't resize me */ /* Dont resize me */
widget_set_size(smoke->widget, smoke->width, smoke->height); widget_set_size(smoke->widget, smoke->width, smoke->height);
} }
@ -274,8 +274,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 +284,6 @@ int main(int argc, char *argv[])
smoke.window = window_create(d); smoke.window = window_create(d);
smoke.widget = window_add_widget(smoke.window, &smoke); smoke.widget = window_add_widget(smoke.window, &smoke);
window_set_title(smoke.window, "smoke"); window_set_title(smoke.window, "smoke");
window_set_appid(smoke.window, "org.freedesktop.weston.smoke");
window_set_buffer_type(smoke.window, WINDOW_BUFFER_TYPE_SHM); window_set_buffer_type(smoke.window, WINDOW_BUFFER_TYPE_SHM);
clock_gettime(CLOCK_MONOTONIC, &ts); clock_gettime(CLOCK_MONOTONIC, &ts);

View file

@ -1,58 +1,43 @@
/* /*
* Copyright © 2013 Collabora Ltd. * Copyright © 2013 Collabora Ltd.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and
* copy of this software and associated documentation files (the "Software"), * its documentation for any purpose is hereby granted without fee, provided
* to deal in the Software without restriction, including without limitation * that the above copyright notice appear in all copies and that both that
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * copyright notice and this permission notice appear in supporting
* and/or sell copies of the Software, and to permit persons to whom the * documentation, and that the name of the copyright holders not be used in
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* paragraph) shall be included in all copies or substantial portions of the * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* Software. * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* 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 "config.h"
#include <assert.h> #include <assert.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#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 "shared/xalloc.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 +58,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 +102,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 +129,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 +145,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:
@ -235,7 +181,7 @@ fullscreen_handler(struct window *window, void *data)
static void static void
draw_string(cairo_t *cr, draw_string(cairo_t *cr,
const char *fmt, ...) WL_PRINTF(2, 3); const char *fmt, ...) __attribute__((format (gnu_printf, 2, 3)));
static void static void
draw_string(cairo_t *cr, draw_string(cairo_t *cr,
@ -249,7 +195,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,21 +243,26 @@ 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);
/* Draw background. */ /* Draw background. */
cairo_push_group(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
set_window_background_colour(cr, window); set_window_background_colour(cr, window);
cairo_rectangle(cr, 0, 0, allocation.width, allocation.height); cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
cairo_fill(cr); cairo_fill(cr);
cairo_pop_group_to_source(cr);
cairo_paint(cr);
/* Print the instructions. */ /* Print the instructions. */
cairo_move_to(cr, 5, 15); cairo_move_to(cr, 5, 15);
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
@ -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,26 @@ 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);
#ifdef HAVE_PANGO
g_type_init();
#endif
stacking.display = display_create(&argc, argv); stacking.display = display_create(&argc, argv);
if (stacking.display == NULL) { if (stacking.display == NULL) {
fprintf(stderr, "Failed to create display: %s\n", fprintf(stderr, "Failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }
display_set_user_data(stacking.display, &stacking); display_set_user_data(stacking.display, &stacking);
create_window(&stacking, NULL); stacking.root_window = new_window(&stacking, NULL);
display_run(stacking.display); display_run(stacking.display);
wl_list_for_each_safe(stacking_window, tmp, &stacking.windows, link) window_destroy(stacking.root_window);
destroy_window(stacking_window);
display_destroy(stacking.display); display_destroy(stacking.display);
return 0; return 0;

View file

@ -3,24 +3,23 @@
* Copyright © 2011 Benjamin Franzke * Copyright © 2011 Benjamin Franzke
* Copyright © 2012-2013 Collabora, Ltd. * Copyright © 2012-2013 Collabora, Ltd.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 "config.h"
@ -32,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>
@ -42,9 +40,6 @@
#include <EGL/egl.h> #include <EGL/egl.h>
#include <EGL/eglext.h> #include <EGL/eglext.h>
#include "shared/helpers.h"
#include "shared/xalloc.h"
#include <libweston/zalloc.h>
#include "window.h" #include "window.h"
#if 0 #if 0
@ -56,8 +51,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 },
@ -218,7 +213,7 @@ egl_state_create(struct wl_display *display)
EGLint major, minor, n; EGLint major, minor, n;
EGLBoolean ret; EGLBoolean ret;
egl = zalloc(sizeof *egl); egl = calloc(1, sizeof *egl);
assert(egl); assert(egl);
egl->dpy = egl->dpy =
@ -296,7 +291,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 +320,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);
} }
@ -501,7 +496,8 @@ triangle_create(struct window *window, struct egl_state *egl)
{ {
struct triangle *tri; struct triangle *tri;
tri = xzalloc(sizeof *tri); tri = xmalloc(sizeof *tri);
memset(tri, 0, sizeof *tri);
tri->egl = egl; tri->egl = egl;
tri->widget = window_add_subsurface(window, tri, tri->widget = window_add_subsurface(window, tri,
@ -519,8 +515,7 @@ static void
triangle_destroy(struct triangle *tri) triangle_destroy(struct triangle *tri)
{ {
if (tri->egl_surface) if (tri->egl_surface)
weston_platform_destroy_egl_surface(tri->egl->dpy, eglDestroySurface(tri->egl->dpy, tri->egl_surface);
tri->egl_surface);
if (tri->egl_window) if (tri->egl_window)
wl_egl_window_destroy(tri->egl_window); wl_egl_window_destroy(tri->egl_window);
@ -723,7 +718,8 @@ demoapp_create(struct display *display)
{ {
struct demoapp *app; struct demoapp *app;
app = xzalloc(sizeof *app); app = xmalloc(sizeof *app);
memset(app, 0, sizeof *app);
app->egl = egl_state_create(display_get_display(display)); app->egl = egl_state_create(display_get_display(display));
@ -733,8 +729,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 +785,7 @@ main(int argc, char *argv[])
display = display_create(&argc, argv); display = display_create(&argc, argv);
if (display == NULL) { if (display == NULL) {
fprintf(stderr, "failed to create display: %s\n", fprintf(stderr, "failed to create display: %m\n");
strerror(errno));
return -1; return -1;
} }

View file

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

View file

@ -1,29 +1,27 @@
/* /*
* Copyright © 2008 Kristian Høgsberg * Copyright © 2008 Kristian Høgsberg
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 <config.h>
#include <signal.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -39,26 +37,21 @@
#include <sys/epoll.h> #include <sys/epoll.h>
#include <wchar.h> #include <wchar.h>
#include <locale.h> #include <locale.h>
#include <errno.h>
#include <linux/input.h> #include <linux/input.h>
#include <wayland-client.h> #include <wayland-client.h>
#include <libweston/config-parser.h> #include "../shared/config-parser.h"
#include "shared/helpers.h"
#include "shared/xalloc.h"
#include "window.h" #include "window.h"
static bool option_fullscreen; static int option_fullscreen;
static bool 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);
@ -128,7 +121,6 @@ init_state_machine(struct utf8_state_machine *machine)
machine->state = utf8state_start; machine->state = utf8state_start;
machine->len = 0; machine->len = 0;
machine->s.ch = 0; machine->s.ch = 0;
machine->unicode = 0;
} }
static enum utf8_state static enum utf8_state
@ -140,28 +132,28 @@ utf8_next_char(struct utf8_state_machine *machine, unsigned char c)
case utf8state_reject: case utf8state_reject:
machine->s.ch = 0; machine->s.ch = 0;
machine->len = 0; machine->len = 0;
if (c == 0xC0 || c == 0xC1) { if(c == 0xC0 || c == 0xC1) {
/* overlong encoding, reject */ /* overlong encoding, reject */
machine->state = utf8state_reject; machine->state = utf8state_reject;
} else if ((c & 0x80) == 0) { } else if((c & 0x80) == 0) {
/* single byte, accept */ /* single byte, accept */
machine->s.byte[machine->len++] = c; machine->s.byte[machine->len++] = c;
machine->state = utf8state_accept; machine->state = utf8state_accept;
machine->unicode = c; machine->unicode = c;
} else if ((c & 0xC0) == 0x80) { } else if((c & 0xC0) == 0x80) {
/* parser out of sync, ignore byte */ /* parser out of sync, ignore byte */
machine->state = utf8state_start; machine->state = utf8state_start;
} else if ((c & 0xE0) == 0xC0) { } else if((c & 0xE0) == 0xC0) {
/* start of two byte sequence */ /* start of two byte sequence */
machine->s.byte[machine->len++] = c; machine->s.byte[machine->len++] = c;
machine->state = utf8state_expect1; machine->state = utf8state_expect1;
machine->unicode = c & 0x1f; machine->unicode = c & 0x1f;
} else if ((c & 0xF0) == 0xE0) { } else if((c & 0xF0) == 0xE0) {
/* start of three byte sequence */ /* start of three byte sequence */
machine->s.byte[machine->len++] = c; machine->s.byte[machine->len++] = c;
machine->state = utf8state_expect2; machine->state = utf8state_expect2;
machine->unicode = c & 0x0f; machine->unicode = c & 0x0f;
} else if ((c & 0xF8) == 0xF0) { } else if((c & 0xF8) == 0xF0) {
/* start of four byte sequence */ /* start of four byte sequence */
machine->s.byte[machine->len++] = c; machine->s.byte[machine->len++] = c;
machine->state = utf8state_expect3; machine->state = utf8state_expect3;
@ -174,7 +166,7 @@ utf8_next_char(struct utf8_state_machine *machine, unsigned char c)
case utf8state_expect3: case utf8state_expect3:
machine->s.byte[machine->len++] = c; machine->s.byte[machine->len++] = c;
machine->unicode = (machine->unicode << 6) | (c & 0x3f); machine->unicode = (machine->unicode << 6) | (c & 0x3f);
if ((c & 0xC0) == 0x80) { if((c & 0xC0) == 0x80) {
/* all good, continue */ /* all good, continue */
machine->state = utf8state_expect2; machine->state = utf8state_expect2;
} else { } else {
@ -185,7 +177,7 @@ utf8_next_char(struct utf8_state_machine *machine, unsigned char c)
case utf8state_expect2: case utf8state_expect2:
machine->s.byte[machine->len++] = c; machine->s.byte[machine->len++] = c;
machine->unicode = (machine->unicode << 6) | (c & 0x3f); machine->unicode = (machine->unicode << 6) | (c & 0x3f);
if ((c & 0xC0) == 0x80) { if((c & 0xC0) == 0x80) {
/* all good, continue */ /* all good, continue */
machine->state = utf8state_expect1; machine->state = utf8state_expect1;
} else { } else {
@ -196,7 +188,7 @@ utf8_next_char(struct utf8_state_machine *machine, unsigned char c)
case utf8state_expect1: case utf8state_expect1:
machine->s.byte[machine->len++] = c; machine->s.byte[machine->len++] = c;
machine->unicode = (machine->unicode << 6) | (c & 0x3f); machine->unicode = (machine->unicode << 6) | (c & 0x3f);
if ((c & 0xC0) == 0x80) { if((c & 0xC0) == 0x80) {
/* all good, accept */ /* all good, accept */
machine->state = utf8state_accept; machine->state = utf8state_accept;
} else { } else {
@ -484,7 +476,6 @@ struct terminal {
int selection_start_row, selection_start_col; int selection_start_row, selection_start_col;
int selection_end_row, selection_end_col; int selection_end_row, selection_end_col;
struct wl_list link; struct wl_list link;
int pace_pipe;
}; };
/* Create default tab stops, every 8 characters */ /* Create default tab stops, every 8 characters */
@ -667,7 +658,7 @@ terminal_scroll_window(struct terminal *terminal, int d)
// scrolling range is inclusive // scrolling range is inclusive
window_height = terminal->margin_bottom - terminal->margin_top + 1; window_height = terminal->margin_bottom - terminal->margin_top + 1;
d = d % (window_height + 1); d = d % (window_height + 1);
if (d < 0) { if(d < 0) {
d = 0 - d; d = 0 - d;
to_row = terminal->margin_bottom; to_row = terminal->margin_bottom;
from_row = terminal->margin_bottom - d; from_row = terminal->margin_bottom - d;
@ -708,7 +699,7 @@ terminal_scroll_window(struct terminal *terminal, int d)
static void static void
terminal_scroll(struct terminal *terminal, int d) terminal_scroll(struct terminal *terminal, int d)
{ {
if (terminal->margin_top == 0 && terminal->margin_bottom == terminal->height - 1) if(terminal->margin_top == 0 && terminal->margin_bottom == terminal->height - 1)
terminal_scroll_buffer(terminal, d); terminal_scroll_buffer(terminal, d);
else else
terminal_scroll_window(terminal, d); terminal_scroll_window(terminal, d);
@ -864,13 +855,9 @@ resize_handler(struct widget *widget,
struct terminal *terminal = data; struct terminal *terminal = data;
int32_t columns, rows, m; int32_t columns, rows, m;
if (terminal->pace_pipe >= 0) {
close(terminal->pace_pipe);
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)) {
@ -953,7 +940,7 @@ terminal_send_selection(struct terminal *terminal, int fd)
close(fd); close(fd);
return; return;
} }
for (row = terminal->selection_start_row; row < terminal->height; row++) { for (row = 0; row < terminal->height; row++) {
p_row = terminal_get_row(terminal, row); p_row = terminal_get_row(terminal, row);
for (col = 0; col < terminal->width; col++) { for (col = 0; col < terminal->width; col++) {
if (p_row[col].ch == 0x200B) /* space glyph */ if (p_row[col].ch == 0x200B) /* space glyph */
@ -1125,9 +1112,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;
@ -1307,8 +1294,6 @@ handle_osc(struct terminal *terminal)
break; break;
case 7: /* shell cwd as uri */ case 7: /* shell cwd as uri */
break; break;
case 777: /* Desktop notifications */
break;
default: default:
fprintf(stderr, "Unknown OSC escape code %d, text %s\n", fprintf(stderr, "Unknown OSC escape code %d, text %s\n",
code, p); code, p);
@ -1345,12 +1330,12 @@ handle_escape(struct terminal *terminal)
} }
switch (*p) { switch (*p) {
case '@': /* ICH - Insert <count> blank characters */ case '@': /* ICH */
count = set[0] ? args[0] : 1; count = set[0] ? args[0] : 1;
if (count == 0) count = 1; if (count == 0) count = 1;
terminal_shift_line(terminal, count); terminal_shift_line(terminal, count);
break; break;
case 'A': /* CUU - Move cursor up <count> rows */ case 'A': /* CUU */
count = set[0] ? args[0] : 1; count = set[0] ? args[0] : 1;
if (count == 0) count = 1; if (count == 0) count = 1;
if (terminal->row - count >= terminal->margin_top) if (terminal->row - count >= terminal->margin_top)
@ -1358,7 +1343,7 @@ handle_escape(struct terminal *terminal)
else else
terminal->row = terminal->margin_top; terminal->row = terminal->margin_top;
break; break;
case 'B': /* CUD - Move cursor down <count> rows */ case 'B': /* CUD */
count = set[0] ? args[0] : 1; count = set[0] ? args[0] : 1;
if (count == 0) count = 1; if (count == 0) count = 1;
if (terminal->row + count <= terminal->margin_bottom) if (terminal->row + count <= terminal->margin_bottom)
@ -1366,7 +1351,7 @@ handle_escape(struct terminal *terminal)
else else
terminal->row = terminal->margin_bottom; terminal->row = terminal->margin_bottom;
break; break;
case 'C': /* CUF - Move cursor right by <count> columns */ case 'C': /* CUF */
count = set[0] ? args[0] : 1; count = set[0] ? args[0] : 1;
if (count == 0) count = 1; if (count == 0) count = 1;
if ((terminal->column + count) < terminal->width) if ((terminal->column + count) < terminal->width)
@ -1374,7 +1359,7 @@ handle_escape(struct terminal *terminal)
else else
terminal->column = terminal->width - 1; terminal->column = terminal->width - 1;
break; break;
case 'D': /* CUB - Move cursor left <count> columns */ case 'D': /* CUB */
count = set[0] ? args[0] : 1; count = set[0] ? args[0] : 1;
if (count == 0) count = 1; if (count == 0) count = 1;
if ((terminal->column - count) >= 0) if ((terminal->column - count) >= 0)
@ -1382,7 +1367,7 @@ handle_escape(struct terminal *terminal)
else else
terminal->column = 0; terminal->column = 0;
break; break;
case 'E': /* CNL - Move cursor down <count> rows, to column 1 */ case 'E': /* CNL */
count = set[0] ? args[0] : 1; count = set[0] ? args[0] : 1;
if (terminal->row + count <= terminal->margin_bottom) if (terminal->row + count <= terminal->margin_bottom)
terminal->row += count; terminal->row += count;
@ -1390,7 +1375,7 @@ handle_escape(struct terminal *terminal)
terminal->row = terminal->margin_bottom; terminal->row = terminal->margin_bottom;
terminal->column = 0; terminal->column = 0;
break; break;
case 'F': /* CPL - Move cursour up <count> rows, to column 1 */ case 'F': /* CPL */
count = set[0] ? args[0] : 1; count = set[0] ? args[0] : 1;
if (terminal->row - count >= terminal->margin_top) if (terminal->row - count >= terminal->margin_top)
terminal->row -= count; terminal->row -= count;
@ -1398,14 +1383,14 @@ handle_escape(struct terminal *terminal)
terminal->row = terminal->margin_top; terminal->row = terminal->margin_top;
terminal->column = 0; terminal->column = 0;
break; break;
case 'G': /* CHA - Move cursor to column <y> in current row */ case 'G': /* CHA */
y = set[0] ? args[0] : 1; y = set[0] ? args[0] : 1;
y = y <= 0 ? 1 : y > terminal->width ? terminal->width : y; y = y <= 0 ? 1 : y > terminal->width ? terminal->width : y;
terminal->column = y - 1; terminal->column = y - 1;
break; break;
case 'f': /* HVP - Move cursor to <x, y> */ case 'f': /* HVP */
case 'H': /* CUP - Move cursor to <x, y> (origin at 1,1) */ case 'H': /* CUP */
x = (set[1] ? args[1] : 1) - 1; x = (set[1] ? args[1] : 1) - 1;
x = x < 0 ? 0 : x = x < 0 ? 0 :
(x >= terminal->width ? terminal->width - 1 : x); (x >= terminal->width ? terminal->width - 1 : x);
@ -1432,7 +1417,7 @@ handle_escape(struct terminal *terminal)
} }
terminal->column--; terminal->column--;
break; break;
case 'J': /* ED - Erase display */ case 'J': /* ED */
row = terminal_get_row(terminal, terminal->row); row = terminal_get_row(terminal, terminal->row);
attr_row = terminal_get_attr_row(terminal, terminal->row); attr_row = terminal_get_attr_row(terminal, terminal->row);
if (!set[0] || args[0] == 0 || args[0] > 2) { if (!set[0] || args[0] == 0 || args[0] > 2) {
@ -1461,7 +1446,7 @@ handle_escape(struct terminal *terminal)
terminal->end - terminal->start); terminal->end - terminal->start);
} }
break; break;
case 'K': /* EL - Erase line */ case 'K': /* EL */
row = terminal_get_row(terminal, terminal->row); row = terminal_get_row(terminal, terminal->row);
attr_row = terminal_get_attr_row(terminal, terminal->row); attr_row = terminal_get_attr_row(terminal, terminal->row);
if (!set[0] || args[0] == 0 || args[0] > 2) { if (!set[0] || args[0] == 0 || args[0] > 2) {
@ -1477,7 +1462,7 @@ handle_escape(struct terminal *terminal)
attr_init(attr_row, terminal->curr_attr, terminal->width); attr_init(attr_row, terminal->curr_attr, terminal->width);
} }
break; break;
case 'L': /* IL - Insert <count> blank lines */ case 'L': /* IL */
count = set[0] ? args[0] : 1; count = set[0] ? args[0] : 1;
if (count == 0) count = 1; if (count == 0) count = 1;
if (terminal->row >= terminal->margin_top && if (terminal->row >= terminal->margin_top &&
@ -1494,7 +1479,7 @@ handle_escape(struct terminal *terminal)
terminal->curr_attr, terminal->width); terminal->curr_attr, terminal->width);
} }
break; break;
case 'M': /* DL - Delete <count> lines */ case 'M': /* DL */
count = set[0] ? args[0] : 1; count = set[0] ? args[0] : 1;
if (count == 0) count = 1; if (count == 0) count = 1;
if (terminal->row >= terminal->margin_top && if (terminal->row >= terminal->margin_top &&
@ -1509,7 +1494,7 @@ handle_escape(struct terminal *terminal)
0, terminal->data_pitch); 0, terminal->data_pitch);
} }
break; break;
case 'P': /* DCH - Delete <count> characters on current line */ case 'P': /* DCH */
count = set[0] ? args[0] : 1; count = set[0] ? args[0] : 1;
if (count == 0) count = 1; if (count == 0) count = 1;
terminal_shift_line(terminal, 0 - count); terminal_shift_line(terminal, 0 - count);
@ -1520,7 +1505,7 @@ handle_escape(struct terminal *terminal)
case 'T': /* SD */ case 'T': /* SD */
terminal_scroll(terminal, 0 - (set[0] ? args[0] : 1)); terminal_scroll(terminal, 0 - (set[0] ? args[0] : 1));
break; break;
case 'X': /* ECH - Erase <count> characters on current line */ case 'X': /* ECH */
count = set[0] ? args[0] : 1; count = set[0] ? args[0] : 1;
if (count == 0) count = 1; if (count == 0) count = 1;
if ((terminal->column + count) > terminal->width) if ((terminal->column + count) > terminal->width)
@ -1539,7 +1524,7 @@ handle_escape(struct terminal *terminal)
} }
terminal->column++; terminal->column++;
break; break;
case '`': /* HPA - Move cursor to <y> column in current row */ case '`': /* HPA */
y = set[0] ? args[0] : 1; y = set[0] ? args[0] : 1;
y = y <= 0 ? 1 : y > terminal->width ? terminal->width : y; y = y <= 0 ? 1 : y > terminal->width ? terminal->width : y;
@ -1553,34 +1538,34 @@ handle_escape(struct terminal *terminal)
handle_char(terminal, terminal->last_char); handle_char(terminal, terminal->last_char);
terminal->last_char.byte[0] = 0; terminal->last_char.byte[0] = 0;
break; break;
case 'c': /* Primary DA - Answer "I am a VT102" */ case 'c': /* Primary DA */
terminal_write(terminal, "\e[?6c", 5); terminal_write(terminal, "\e[?6c", 5);
break; break;
case 'd': /* VPA - Move cursor to <x> row, current column */ case 'd': /* VPA */
x = set[0] ? args[0] : 1; x = set[0] ? args[0] : 1;
x = x <= 0 ? 1 : x > terminal->height ? terminal->height : x; x = x <= 0 ? 1 : x > terminal->height ? terminal->height : x;
terminal->row = x - 1; terminal->row = x - 1;
break; break;
case 'g': /* TBC - Clear tab stop(s) */ case 'g': /* TBC */
if (!set[0] || args[0] == 0) { if (!set[0] || args[0] == 0) {
terminal->tab_ruler[terminal->column] = 0; terminal->tab_ruler[terminal->column] = 0;
} else if (args[0] == 3) { } else if (args[0] == 3) {
memset(terminal->tab_ruler, 0, terminal->width); memset(terminal->tab_ruler, 0, terminal->width);
} }
break; break;
case 'h': /* SM - Set mode */ case 'h': /* SM */
for (i = 0; i < 10 && set[i]; i++) { for(i = 0; i < 10 && set[i]; i++) {
handle_term_parameter(terminal, args[i], 1); handle_term_parameter(terminal, args[i], 1);
} }
break; break;
case 'l': /* RM - Reset mode */ case 'l': /* RM */
for (i = 0; i < 10 && set[i]; i++) { for(i = 0; i < 10 && set[i]; i++) {
handle_term_parameter(terminal, args[i], 0); handle_term_parameter(terminal, args[i], 0);
} }
break; break;
case 'm': /* SGR - Set attributes */ case 'm': /* SGR */
for (i = 0; i < 10; i++) { for(i = 0; i < 10; i++) {
if (i <= 7 && set[i] && set[i + 1] && if (i <= 7 && set[i] && set[i + 1] &&
set[i + 2] && args[i + 1] == 5) set[i + 2] && args[i + 1] == 5)
{ {
@ -1592,9 +1577,9 @@ handle_escape(struct terminal *terminal)
break; break;
} }
} }
if (set[i]) { if(set[i]) {
handle_sgr(terminal, args[i]); handle_sgr(terminal, args[i]);
} else if (i == 0) { } else if(i == 0) {
handle_sgr(terminal, 0); handle_sgr(terminal, 0);
break; break;
} else { } else {
@ -1602,7 +1587,7 @@ handle_escape(struct terminal *terminal)
} }
} }
break; break;
case 'n': /* DSR - Status report */ case 'n': /* DSR */
i = set[0] ? args[0] : 0; i = set[0] ? args[0] : 0;
if (i == 0 || i == 5) { if (i == 0 || i == 5) {
terminal_write(terminal, "\e[0n", 4); terminal_write(terminal, "\e[0n", 4);
@ -1614,8 +1599,8 @@ handle_escape(struct terminal *terminal)
terminal_write(terminal, response, strlen(response)); terminal_write(terminal, response, strlen(response));
} }
break; break;
case 'r': /* DECSTBM - Set scrolling region */ case 'r':
if (!set[0]) { if(!set[0]) {
terminal->margin_top = 0; terminal->margin_top = 0;
terminal->margin_bottom = terminal->height-1; terminal->margin_bottom = terminal->height-1;
terminal->row = 0; terminal->row = 0;
@ -1627,21 +1612,21 @@ handle_escape(struct terminal *terminal)
bottom = (set[1] ? args[1] : 1) - 1; bottom = (set[1] ? args[1] : 1) - 1;
bottom = bottom < 0 ? 0 : bottom = bottom < 0 ? 0 :
(bottom >= terminal->height ? terminal->height - 1 : bottom); (bottom >= terminal->height ? terminal->height - 1 : bottom);
if (bottom > top) { if(bottom > top) {
terminal->margin_top = top; terminal->margin_top = top;
terminal->margin_bottom = bottom; terminal->margin_bottom = bottom;
} else { } else {
terminal->margin_top = 0; terminal->margin_top = 0;
terminal->margin_bottom = terminal->height-1; terminal->margin_bottom = terminal->height-1;
} }
if (terminal->origin_mode) if(terminal->origin_mode)
terminal->row = terminal->margin_top; terminal->row = terminal->margin_top;
else else
terminal->row = 0; terminal->row = 0;
terminal->column = 0; terminal->column = 0;
} }
break; break;
case 's': /* Save cursor location */ case 's':
terminal->saved_row = terminal->row; terminal->saved_row = terminal->row;
terminal->saved_column = terminal->column; terminal->saved_column = terminal->column;
break; break;
@ -1688,8 +1673,7 @@ handle_escape(struct terminal *terminal)
fprintf(stderr, "Unimplemented windowOp %d\n", args[0]); fprintf(stderr, "Unimplemented windowOp %d\n", args[0]);
break; break;
} }
break; case 'u':
case 'u': /* Restore cursor location */
terminal->row = terminal->saved_row; terminal->row = terminal->saved_row;
terminal->column = terminal->saved_column; terminal->column = terminal->saved_column;
break; break;
@ -1703,30 +1687,30 @@ static void
handle_non_csi_escape(struct terminal *terminal, char code) handle_non_csi_escape(struct terminal *terminal, char code)
{ {
switch(code) { switch(code) {
case 'M': /* RI - Reverse linefeed */ case 'M': /* RI */
terminal->row -= 1; terminal->row -= 1;
if (terminal->row < terminal->margin_top) { if(terminal->row < terminal->margin_top) {
terminal->row = terminal->margin_top; terminal->row = terminal->margin_top;
terminal_scroll(terminal, -1); terminal_scroll(terminal, -1);
} }
break; break;
case 'E': /* NEL - Newline */ case 'E': /* NEL */
terminal->column = 0; terminal->column = 0;
FALLTHROUGH; // fallthrough
case 'D': /* IND - Linefeed */ case 'D': /* IND */
terminal->row += 1; terminal->row += 1;
if (terminal->row > terminal->margin_bottom) { if(terminal->row > terminal->margin_bottom) {
terminal->row = terminal->margin_bottom; terminal->row = terminal->margin_bottom;
terminal_scroll(terminal, +1); terminal_scroll(terminal, +1);
} }
break; break;
case 'c': /* RIS - Reset*/ case 'c': /* RIS */
terminal_init(terminal); terminal_init(terminal);
break; break;
case 'H': /* HTS - Set tab stop at current column */ case 'H': /* HTS */
terminal->tab_ruler[terminal->column] = 1; terminal->tab_ruler[terminal->column] = 1;
break; break;
case '7': /* DECSC - Save current state */ case '7': /* DECSC */
terminal->saved_row = terminal->row; terminal->saved_row = terminal->row;
terminal->saved_column = terminal->column; terminal->saved_column = terminal->column;
terminal->saved_attr = terminal->curr_attr; terminal->saved_attr = terminal->curr_attr;
@ -1735,7 +1719,7 @@ handle_non_csi_escape(struct terminal *terminal, char code)
terminal->saved_g0 = terminal->g0; terminal->saved_g0 = terminal->g0;
terminal->saved_g1 = terminal->g1; terminal->saved_g1 = terminal->g1;
break; break;
case '8': /* DECRC - Restore state most recently saved by ESC 7 */ case '8': /* DECRC */
terminal->row = terminal->saved_row; terminal->row = terminal->saved_row;
terminal->column = terminal->saved_column; terminal->column = terminal->saved_column;
terminal->curr_attr = terminal->saved_attr; terminal->curr_attr = terminal->saved_attr;
@ -1744,10 +1728,10 @@ handle_non_csi_escape(struct terminal *terminal, char code)
terminal->g0 = terminal->saved_g0; terminal->g0 = terminal->saved_g0;
terminal->g1 = terminal->saved_g1; terminal->g1 = terminal->saved_g1;
break; break;
case '=': /* DECPAM - Set application keypad mode */ case '=': /* DECPAM */
terminal->key_mode = KM_APPLICATION; terminal->key_mode = KM_APPLICATION;
break; break;
case '>': /* DECPNM - Set numeric keypad mode */ case '>': /* DECPNM */
terminal->key_mode = KM_NORMAL; terminal->key_mode = KM_NORMAL;
break; break;
default: default:
@ -1767,7 +1751,7 @@ handle_special_escape(struct terminal *terminal, char special, char code)
/* fill with 'E', no cheap way to do this */ /* fill with 'E', no cheap way to do this */
memset(terminal->data, 0, terminal->data_pitch * terminal->height); memset(terminal->data, 0, terminal->data_pitch * terminal->height);
numChars = terminal->width * terminal->height; numChars = terminal->width * terminal->height;
for (i = 0; i < numChars; i++) { for(i = 0; i < numChars; i++) {
terminal->data[i].byte[0] = 'E'; terminal->data[i].byte[0] = 'E';
} }
break; break;
@ -1855,19 +1839,19 @@ handle_sgr(struct terminal *terminal, int code)
terminal->curr_attr.bg = terminal->color_scheme->default_attr.bg; terminal->curr_attr.bg = terminal->color_scheme->default_attr.bg;
break; break;
default: default:
if (code >= 30 && code <= 37) { if(code >= 30 && code <= 37) {
terminal->curr_attr.fg = code - 30; terminal->curr_attr.fg = code - 30;
if (terminal->curr_attr.a & ATTRMASK_BOLD) if (terminal->curr_attr.a & ATTRMASK_BOLD)
terminal->curr_attr.fg += 8; terminal->curr_attr.fg += 8;
} else if (code >= 40 && code <= 47) { } else if(code >= 40 && code <= 47) {
terminal->curr_attr.bg = code - 40; terminal->curr_attr.bg = code - 40;
} else if (code >= 90 && code <= 97) { } else if (code >= 90 && code <= 97) {
terminal->curr_attr.fg = code - 90 + 8; terminal->curr_attr.fg = code - 90 + 8;
} else if (code >= 100 && code <= 107) { } else if (code >= 100 && code <= 107) {
terminal->curr_attr.bg = code - 100 + 8; terminal->curr_attr.bg = code - 100 + 8;
} else if (code >= 256 && code < 512) { } else if(code >= 256 && code < 512) {
terminal->curr_attr.fg = code - 256; terminal->curr_attr.fg = code - 256;
} else if (code >= 512 && code < 768) { } else if(code >= 512 && code < 768) {
terminal->curr_attr.bg = code - 512; terminal->curr_attr.bg = code - 512;
} else { } else {
fprintf(stderr, "Unknown SGR code: %d\n", code); fprintf(stderr, "Unknown SGR code: %d\n", code);
@ -1894,7 +1878,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 +2193,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";
@ -2286,9 +2251,6 @@ terminal_copy(struct terminal *terminal, struct input *input)
{ {
terminal->selection = terminal->selection =
display_create_data_source(terminal->display); display_create_data_source(terminal->display);
if (!terminal->selection)
return;
wl_data_source_offer(terminal->selection, wl_data_source_offer(terminal->selection,
"text/plain;charset=utf-8"); "text/plain;charset=utf-8");
wl_data_source_add_listener(terminal->selection, wl_data_source_add_listener(terminal->selection,
@ -2615,7 +2577,7 @@ static int wordsep(int ch)
{ {
const char extra[] = "-,./?%&#:_=+@~"; const char extra[] = "-,./?%&#:_=+@~";
if (ch > 127 || ch < 0) if (ch > 127)
return 1; return 1;
return ch == 0 || !(isalpha(ch) || isdigit(ch) || strchr(extra, ch)); return ch == 0 || !(isalpha(ch) || isdigit(ch) || strchr(extra, ch));
@ -2631,7 +2593,7 @@ recompute_selection(struct terminal *terminal)
int side_margin, top_margin; int side_margin, top_margin;
int start_x, end_x; int start_x, end_x;
int cw, ch; int cw, ch;
union utf8_char *data = NULL; union utf8_char *data;
cw = terminal->average_width; cw = terminal->average_width;
ch = terminal->extents.height; ch = terminal->extents.height;
@ -2950,8 +2912,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 +2984,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 +3009,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
@ -3071,52 +3020,21 @@ terminal_run(struct terminal *terminal, const char *path)
{ {
int master; int master;
pid_t pid; pid_t pid;
int pipes[2];
/* Awkwardness: There's a sticky race condition here. If
* anything prints after the forkpty() but before the window has
* a size then we'll segfault. So we make a pipe and wait on
* it before actually exec()ing the terminal. The resize
* handler closes it in the parent process and the child continues
* on to launch a shell.
*
* The reason we don't just do terminal_run() after the window
* has a size is that we'd prefer to perform the fork() before
* the process opens a wayland connection.
*/
if (pipe(pipes) == -1) {
fprintf(stderr, "Can't create pipe for pacing.\n");
exit(EXIT_FAILURE);
}
pid = forkpty(&master, NULL, NULL, NULL); pid = forkpty(&master, NULL, NULL, NULL);
if (pid == 0) { if (pid == 0) {
int ret;
close(pipes[1]);
do {
char tmp;
ret = read(pipes[0], &tmp, 1);
} while (ret == -1 && errno == EINTR);
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;
} }
close(pipes[0]);
terminal->master = master; terminal->master = master;
terminal->pace_pipe = pipes[1];
fcntl(master, F_SETFL, O_NONBLOCK); fcntl(master, F_SETFL, O_NONBLOCK);
terminal->io_task.run = io_handler; terminal->io_task.run = io_handler;
display_watch_fd(terminal->display, terminal->master, display_watch_fd(terminal->display, terminal->master,
@ -3124,8 +3042,6 @@ terminal_run(struct terminal *terminal, const char *path)
if (option_fullscreen) if (option_fullscreen)
window_set_fullscreen(terminal->window, 1); window_set_fullscreen(terminal->window, 1);
else if (option_maximize)
window_set_maximized(terminal->window, 1);
else else
terminal_resize(terminal, 80, 24); terminal_resize(terminal, 80, 24);
@ -3134,7 +3050,6 @@ terminal_run(struct terminal *terminal, const char *path)
static const struct weston_option terminal_options[] = { static const struct weston_option terminal_options[] = {
{ WESTON_OPTION_BOOLEAN, "fullscreen", 'f', &option_fullscreen }, { WESTON_OPTION_BOOLEAN, "fullscreen", 'f', &option_fullscreen },
{ WESTON_OPTION_BOOLEAN, "maximized", 'm', &option_maximize },
{ WESTON_OPTION_STRING, "font", 0, &option_font }, { WESTON_OPTION_STRING, "font", 0, &option_font },
{ WESTON_OPTION_INTEGER, "font-size", 0, &option_font_size }, { WESTON_OPTION_INTEGER, "font-size", 0, &option_font_size },
{ WESTON_OPTION_STRING, "shell", 0, &option_shell }, { WESTON_OPTION_STRING, "shell", 0, &option_shell },
@ -3143,9 +3058,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 +3069,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);
@ -3169,27 +3083,15 @@ int main(int argc, char *argv[])
ARRAY_LENGTH(terminal_options), &argc, argv) > 1) { ARRAY_LENGTH(terminal_options), &argc, argv) > 1) {
printf("Usage: %s [OPTIONS]\n" printf("Usage: %s [OPTIONS]\n"
" --fullscreen or -f\n" " --fullscreen or -f\n"
" --maximized or -m\n"
" --font=NAME\n" " --font=NAME\n"
" --font-size=SIZE\n" " --font-size=SIZE\n"
" --shell=NAME\n", argv[0]); " --shell=NAME\n", argv[0]);
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 +3102,5 @@ int main(int argc, char *argv[])
display_run(d); display_run(d);
wl_list_for_each_safe(terminal, tmp, &terminal_list, link)
terminal_destroy(terminal);
display_destroy(d);
return 0; return 0;
} }

View file

@ -1,972 +0,0 @@
/*
* Copyright 2012 Intel Corporation
* Copyright 2017-2018 Collabora, Ltd.
* Copyright 2017-2018 General Electric Company
*
* 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 <cairo.h>
#include <math.h>
#include <assert.h>
#include <getopt.h>
#include <errno.h>
#include <wayland-client.h>
#include "clients/window.h"
#include "shared/helpers.h"
#include <libweston/matrix.h>
#include "weston-touch-calibration-client-protocol.h"
enum exit_code {
CAL_EXIT_SUCCESS = 0,
CAL_EXIT_ERROR = 1,
CAL_EXIT_CANCELLED = 2,
};
static int debug_;
static int verbose_;
#define pr_ver(...) do { \
if (verbose_) \
printf(__VA_ARGS__); \
} while (0)
#define pr_dbg(...) do { \
if (debug_) \
fprintf(stderr, __VA_ARGS__); \
} while (0)
static void
pr_err(const char *fmt, ...) WL_PRINTF(1, 2);
/* Our points for the calibration must be not be on a line */
static const struct {
float x_ratio, y_ratio;
} test_ratios[] = {
{ 0.15, 0.10 }, /* three points for calibration */
{ 0.85, 0.13 },
{ 0.20, 0.80 },
{ 0.70, 0.75 } /* and one for verification */
};
#define NR_SAMPLES ((int)ARRAY_LENGTH(test_ratios))
struct point {
double x;
double y;
};
struct sample {
int ind;
struct point drawn; /**< drawn point, pixels */
struct weston_touch_coordinate *pending;
struct point drawn_cal; /**< drawn point, converted */
bool conv_done;
struct point touched; /**< touch point, normalized */
bool touch_done;
};
struct poly {
struct color {
double r, g, b, a;
} color;
int n_verts;
const struct point *verts;
};
/** Touch event handling state machine
*
* Only a complete down->up->frame sequence should be accepted with user
* feedback "right", and anything that deviates from that (invalid_touch,
* cancel, multiple touch-downs) needs to undo the current sample and
* possibly show user feedback "wrong".
*
* \<STATE\>
* - \<triggers\>: \<actions\>
*
* IDLE
* - touch down: sample, -> DOWN
* - touch up: no-op
* - frame: no-op
* - invalid_touch: (undo), wrong, -> WAIT
* - cancel: no-op
* DOWN (first touch down)
* - touch down: undo, wrong, -> WAIT
* - touch up: -> UP
* - frame: no-op
* - invalid_touch: undo, wrong, -> WAIT
* - cancel: undo, -> IDLE
* UP (first touch was down and up)
* - touch down: undo, wrong, -> WAIT
* - touch up: no-op
* - frame: right, touch finish, -> WAIT
* - invalid_touch: undo, wrong, -> WAIT
* - cancel: undo, -> IDLE
* WAIT (show user feedback)
* - touch down: no-op
* - touch up: no-op
* - frame, cancel, timer: if num_tp == 0 && timer_done -> IDLE
* - invalid_touch: no-op
*/
enum touch_state {
STATE_IDLE,
STATE_DOWN,
STATE_UP,
STATE_WAIT
};
struct calibrator {
struct sample samples[NR_SAMPLES];
int current_sample;
struct display *display;
struct weston_touch_calibration *calibration;
struct weston_touch_calibrator *calibrator;
struct window *window;
struct widget *widget;
int n_devices_listed;
char *match_name;
char *device_name;
int width;
int height;
bool cancelled;
const struct poly *current_poly;
bool exiting;
struct toytimer wait_timer;
bool timer_pending;
enum touch_state state;
int num_tp; /* touch points down count */
};
static struct sample *
current_sample(struct calibrator *cal)
{
return &cal->samples[cal->current_sample];
}
static void
sample_start(struct calibrator *cal, int i)
{
struct sample *s = &cal->samples[i];
assert(i >= 0 && i < NR_SAMPLES);
s->ind = i;
s->drawn.x = round(test_ratios[i].x_ratio * cal->width);
s->drawn.y = round(test_ratios[i].y_ratio * cal->height);
s->pending = NULL;
s->conv_done = false;
s->touch_done = false;
cal->current_sample = i;
}
static struct point
wire_to_point(uint32_t xu, uint32_t yu)
{
struct point p = {
.x = (double)xu / 0xffffffff,
.y = (double)yu / 0xffffffff
};
return p;
}
static void
sample_touch_down(struct calibrator *cal, uint32_t xu, uint32_t yu)
{
struct sample *s = current_sample(cal);
s->touched = wire_to_point(xu, yu);
s->touch_done = true;
pr_dbg("Down[%d] (%f, %f)\n", s->ind, s->touched.x, s->touched.y);
}
static void
coordinate_result_handler(void *data, struct weston_touch_coordinate *interface,
uint32_t xu, uint32_t yu)
{
struct sample *s = data;
weston_touch_coordinate_destroy(s->pending);
s->pending = NULL;
s->drawn_cal = wire_to_point(xu, yu);
s->conv_done = true;
pr_dbg("Conv[%d] (%f, %f)\n", s->ind, s->drawn_cal.x, s->drawn_cal.y);
}
struct weston_touch_coordinate_listener coordinate_listener = {
coordinate_result_handler
};
static void
sample_undo(struct calibrator *cal)
{
struct sample *s = current_sample(cal);
pr_dbg("Undo[%d]\n", s->ind);
s->touch_done = false;
s->conv_done = false;
if (s->pending) {
weston_touch_coordinate_destroy(s->pending);
s->pending = NULL;
}
}
static void
sample_finish(struct calibrator *cal)
{
struct sample *s = current_sample(cal);
pr_dbg("Finish[%d]\n", s->ind);
assert(!s->pending && !s->conv_done);
s->pending = weston_touch_calibrator_convert(cal->calibrator,
(int32_t)s->drawn.x,
(int32_t)s->drawn.y);
weston_touch_coordinate_add_listener(s->pending,
&coordinate_listener, s);
if (cal->current_sample + 1 < NR_SAMPLES) {
sample_start(cal, cal->current_sample + 1);
} else {
pr_dbg("got all touches\n");
cal->exiting = true;
}
}
/*
* Calibration algorithm:
*
* The equation we want to apply at event time where x' and y' are the
* calibrated co-ordinates.
*
* x' = Ax + By + C
* y' = Dx + Ey + F
*
* For example "zero calibration" would be A=1.0 B=0.0 C=0.0, D=0.0, E=1.0,
* and F=0.0.
*
* With 6 unknowns we need 6 equations to find the constants:
*
* x1' = Ax1 + By1 + C
* y1' = Dx1 + Ey1 + F
* ...
* x3' = Ax3 + By3 + C
* y3' = Dx3 + Ey3 + F
*
* In matrix form:
*
* x1' x1 y1 1 A
* x2' = x2 y2 1 x B
* x3' x3 y3 1 C
*
* So making the matrix M we can find the constants with:
*
* A x1'
* B = M^-1 x x2'
* C x3'
*
* (and similarly for D, E and F)
*
* For the calibration the desired values x, y are the same values at which
* we've drawn at.
*
*/
static int
compute_calibration(struct calibrator *cal, float *result)
{
struct weston_matrix m;
struct weston_matrix inverse;
struct weston_vector x_calib;
struct weston_vector y_calib;
int i;
assert(NR_SAMPLES >= 3);
/*
* x1 y1 1 0
* x2 y2 1 0
* x3 y3 1 0
* 0 0 0 1
*/
weston_matrix_init(&m);
for (i = 0; i < 3; i++) {
m.M.col[0].el[i] = cal->samples[i].touched.x;
m.M.col[1].el[i] = cal->samples[i].touched.y;
m.M.col[2].el[i] = 1.0f;
}
m.type = WESTON_MATRIX_TRANSFORM_OTHER;
if (weston_matrix_invert(&inverse, &m) < 0) {
pr_err("non-invertible matrix during computation\n");
return -1;
}
for (i = 0; i < 3; i++) {
x_calib.v.el[i] = cal->samples[i].drawn_cal.x;
y_calib.v.el[i] = cal->samples[i].drawn_cal.y;
}
x_calib.v.el[3] = 0.0f;
y_calib.v.el[3] = 0.0f;
/* Multiples into the vector */
weston_matrix_transform(&inverse, &x_calib);
weston_matrix_transform(&inverse, &y_calib);
for (i = 0; i < 3; i++)
result[i] = x_calib.v.el[i];
for (i = 0; i < 3; i++)
result[i + 3] = y_calib.v.el[i];
return 0;
}
static int
verify_calibration(struct calibrator *cal, const float *r)
{
double thr = 0.1; /* accepted error radius */
struct point e; /* expected value; error */
const struct sample *s = &cal->samples[3];
/* transform raw touches through the matrix */
e.x = r[0] * s->touched.x + r[1] * s->touched.y + r[2];
e.y = r[3] * s->touched.x + r[4] * s->touched.y + r[5];
/* compute error */
e.x -= s->drawn_cal.x;
e.y -= s->drawn_cal.y;
pr_dbg("calibration test error: %f, %f\n", e.x, e.y);
if (e.x * e.x + e.y * e.y < thr * thr)
return 0;
pr_err("Calibration verification failed, too large error.\n");
return -1;
}
static void
send_calibration(struct calibrator *cal, float *values)
{
struct wl_array matrix;
float *f;
int i;
wl_array_init(&matrix);
for (i = 0; i < 6; i++) {
f = wl_array_add(&matrix, sizeof *f);
*f = values[i];
}
weston_touch_calibration_save(cal->calibration,
cal->device_name, &matrix);
wl_array_release(&matrix);
}
static const struct point cross_verts[] = {
{ 0.1, 0.2 },
{ 0.2, 0.1 },
{ 0.5, 0.4 },
{ 0.8, 0.1 },
{ 0.9, 0.2 },
{ 0.6, 0.5 },
{ 0.9, 0.8 },
{ 0.8, 0.9 },
{ 0.5, 0.6 },
{ 0.2, 0.9 },
{ 0.1, 0.8 },
{ 0.4, 0.5 },
};
/* a red cross, for "wrong" */
static const struct poly cross = {
.color = { 0.7, 0.0, 0.0, 1.0 },
.n_verts = ARRAY_LENGTH(cross_verts),
.verts = cross_verts
};
static const struct point check_verts[] = {
{ 0.5, 0.7 },
{ 0.8, 0.1 },
{ 0.9, 0.1 },
{ 0.55, 0.8 },
{ 0.45, 0.8 },
{ 0.3, 0.5 },
{ 0.4, 0.5 }
};
/* a green check mark, for "right" */
static const struct poly check = {
.color = { 0.0, 0.7, 0.0, 1.0 },
.n_verts = ARRAY_LENGTH(check_verts),
.verts = check_verts
};
static void
draw_poly(cairo_t *cr, const struct poly *poly)
{
int i;
cairo_set_source_rgba(cr, poly->color.r, poly->color.g,
poly->color.b, poly->color.a);
cairo_move_to(cr, poly->verts[0].x, poly->verts[0].y);
for (i = 1; i < poly->n_verts; i++)
cairo_line_to(cr, poly->verts[i].x, poly->verts[i].y);
cairo_close_path(cr);
cairo_fill(cr);
}
static void
feedback_show(struct calibrator *cal, const struct poly *what)
{
cal->current_poly = what;
widget_schedule_redraw(cal->widget);
toytimer_arm_once_usec(&cal->wait_timer, 1000 * 1000);
cal->timer_pending = true;
}
static void
feedback_hide(struct calibrator *cal)
{
cal->current_poly = NULL;
widget_schedule_redraw(cal->widget);
}
static void
try_enter_state_idle(struct calibrator *cal)
{
if (cal->num_tp != 0)
return;
if (cal->timer_pending)
return;
cal->state = STATE_IDLE;
feedback_hide(cal);
if (cal->exiting)
display_exit(cal->display);
}
static void
enter_state_wait(struct calibrator *cal)
{
assert(cal->timer_pending);
cal->state = STATE_WAIT;
}
static void
wait_timer_done(struct toytimer *tt)
{
struct calibrator *cal = container_of(tt, struct calibrator, wait_timer);
assert(cal->state == STATE_WAIT);
cal->timer_pending = false;
try_enter_state_idle(cal);
}
static void
redraw_handler(struct widget *widget, void *data)
{
struct calibrator *cal = data;
struct sample *s = current_sample(cal);
struct rectangle allocation;
cairo_surface_t *surface;
cairo_t *cr;
widget_get_allocation(cal->widget, &allocation);
assert(allocation.width == cal->width);
assert(allocation.height == cal->height);
surface = window_get_surface(cal->window);
cr = cairo_create(surface);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
cairo_paint(cr);
if (!cal->current_poly) {
cairo_translate(cr, s->drawn.x, s->drawn.y);
cairo_set_line_width(cr, 2.0);
cairo_set_source_rgb(cr, 0.7, 0.0, 0.0);
cairo_move_to(cr, 0, -10.0);
cairo_line_to(cr, 0, 10.0);
cairo_stroke(cr);
cairo_move_to(cr, -10.0, 0);
cairo_line_to(cr, 10.0, 0.0);
cairo_stroke(cr);
} else {
cairo_scale(cr, allocation.width, allocation.height);
draw_poly(cr, cal->current_poly);
}
cairo_destroy(cr);
cairo_surface_destroy(surface);
}
static struct calibrator *
calibrator_create(struct display *display, const char *match_name)
{
struct calibrator *cal;
cal = zalloc(sizeof *cal);
if (!cal)
abort();
cal->match_name = match_name ? strdup(match_name) : NULL;
cal->window = window_create_custom(display);
cal->widget = window_add_widget(cal->window, cal);
window_inhibit_redraw(cal->window);
window_set_title(cal->window, "Touchscreen calibrator");
window_set_appid(cal->window,
"org.freedesktop.weston.touchscreen-calibrator");
cal->display = display;
widget_set_redraw_handler(cal->widget, redraw_handler);
toytimer_init(&cal->wait_timer, CLOCK_MONOTONIC,
display, wait_timer_done);
cal->state = STATE_IDLE;
cal->num_tp = 0;
return cal;
}
static void
configure_handler(void *data, struct weston_touch_calibrator *interface,
int32_t width, int32_t height)
{
struct calibrator *cal = data;
pr_dbg("Configure calibrator window to size %ix%i\n", width, height);
cal->width = width;
cal->height = height;
window_schedule_resize(cal->window, width, height);
window_uninhibit_redraw(cal->window);
sample_start(cal, 0);
widget_schedule_redraw(cal->widget);
}
static void
cancel_calibration_handler(void *data, struct weston_touch_calibrator *interface)
{
struct calibrator *cal = data;
pr_dbg("calibration cancelled by the display server, quitting.\n");
cal->cancelled = true;
display_exit(cal->display);
}
static void
invalid_touch_handler(void *data, struct weston_touch_calibrator *interface)
{
struct calibrator *cal = data;
pr_dbg("invalid touch\n");
switch (cal->state) {
case STATE_IDLE:
case STATE_DOWN:
case STATE_UP:
sample_undo(cal);
feedback_show(cal, &cross);
enter_state_wait(cal);
break;
case STATE_WAIT:
/* no-op */
break;
}
}
static void
down_handler(void *data, struct weston_touch_calibrator *interface,
uint32_t time, int32_t id, uint32_t xu, uint32_t yu)
{
struct calibrator *cal = data;
cal->num_tp++;
switch (cal->state) {
case STATE_IDLE:
sample_touch_down(cal, xu, yu);
cal->state = STATE_DOWN;
break;
case STATE_DOWN:
case STATE_UP:
sample_undo(cal);
feedback_show(cal, &cross);
enter_state_wait(cal);
break;
case STATE_WAIT:
/* no-op */
break;
}
if (cal->current_poly)
return;
}
static void
up_handler(void *data, struct weston_touch_calibrator *interface,
uint32_t time, int32_t id)
{
struct calibrator *cal = data;
cal->num_tp--;
if (cal->num_tp < 0) {
pr_dbg("Unmatched touch up.\n");
cal->num_tp = 0;
}
switch (cal->state) {
case STATE_DOWN:
cal->state = STATE_UP;
break;
case STATE_IDLE:
case STATE_UP:
case STATE_WAIT:
/* no-op */
break;
}
}
static void
motion_handler(void *data, struct weston_touch_calibrator *interface,
uint32_t time, int32_t id, uint32_t xu, uint32_t yu)
{
/* motion is ignored */
}
static void
frame_handler(void *data, struct weston_touch_calibrator *interface)
{
struct calibrator *cal = data;
switch (cal->state) {
case STATE_IDLE:
case STATE_DOWN:
/* no-op */
break;
case STATE_UP:
feedback_show(cal, &check);
sample_finish(cal);
enter_state_wait(cal);
break;
case STATE_WAIT:
try_enter_state_idle(cal);
break;
}
}
static void
cancel_handler(void *data, struct weston_touch_calibrator *interface)
{
struct calibrator *cal = data;
cal->num_tp = 0;
switch (cal->state) {
case STATE_IDLE:
/* no-op */
break;
case STATE_DOWN:
case STATE_UP:
sample_undo(cal);
try_enter_state_idle(cal);
break;
case STATE_WAIT:
try_enter_state_idle(cal);
break;
}
}
struct weston_touch_calibrator_listener calibrator_listener = {
configure_handler,
cancel_calibration_handler,
invalid_touch_handler,
down_handler,
up_handler,
motion_handler,
frame_handler,
cancel_handler
};
static void
calibrator_show(struct calibrator *cal)
{
struct wl_surface *surface = window_get_wl_surface(cal->window);
cal->calibrator =
weston_touch_calibration_create_calibrator(cal->calibration,
surface,
cal->device_name);
weston_touch_calibrator_add_listener(cal->calibrator,
&calibrator_listener, cal);
}
static void
calibrator_destroy(struct calibrator *cal)
{
toytimer_fini(&cal->wait_timer);
if (cal->calibrator)
weston_touch_calibrator_destroy(cal->calibrator);
if (cal->calibration)
weston_touch_calibration_destroy(cal->calibration);
if (cal->widget)
widget_destroy(cal->widget);
if (cal->window)
window_destroy(cal->window);
free(cal->match_name);
free(cal->device_name);
free(cal);
}
static void
touch_device_handler(void *data, struct weston_touch_calibration *c,
const char *device, const char *head)
{
struct calibrator *cal = data;
cal->n_devices_listed++;
if (!cal->match_name) {
printf("device \"%s\" - head \"%s\"\n", device, head);
return;
}
if (cal->device_name)
return;
if (strcmp(cal->match_name, device) == 0 ||
strcmp(cal->match_name, head) == 0)
cal->device_name = strdup(device);
}
struct weston_touch_calibration_listener touch_calibration_listener = {
touch_device_handler
};
static void
global_handler(struct display *display, uint32_t name,
const char *interface, uint32_t version, void *data)
{
struct calibrator *cal = data;
if (strcmp(interface, "weston_touch_calibration") == 0) {
cal->calibration = display_bind(display, name,
&weston_touch_calibration_interface, 1);
weston_touch_calibration_add_listener(cal->calibration,
&touch_calibration_listener,
cal);
}
}
static int
calibrator_run(struct calibrator *cal)
{
struct wl_display *dpy;
struct sample *s;
bool wait;
int i;
int ret;
float result[6];
calibrator_show(cal);
display_run(cal->display);
if (cal->cancelled)
return CAL_EXIT_CANCELLED;
/* remove the window, no more input events */
widget_destroy(cal->widget);
cal->widget = NULL;
window_destroy(cal->window);
cal->window = NULL;
/* wait for all conversions to return */
dpy = display_get_display(cal->display);
do {
wait = false;
for (i = 0; i < NR_SAMPLES; i++)
if (cal->samples[i].pending)
wait = true;
if (wait) {
ret = wl_display_roundtrip(dpy);
if (ret < 0)
return CAL_EXIT_ERROR;
}
} while (wait);
for (i = 0; i < NR_SAMPLES; i++) {
s = &cal->samples[i];
if (!s->conv_done || !s->touch_done)
return CAL_EXIT_ERROR;
}
if (compute_calibration(cal, result) < 0)
return CAL_EXIT_ERROR;
if (verify_calibration(cal, result) < 0)
return CAL_EXIT_ERROR;
pr_ver("Calibration values:");
for (i = 0; i < 6; i++)
pr_ver(" %f", result[i]);
pr_ver("\n");
send_calibration(cal, result);
ret = wl_display_roundtrip(dpy);
if (ret < 0)
return CAL_EXIT_ERROR;
return CAL_EXIT_SUCCESS;
}
static void
pr_err(const char *fmt, ...)
{
va_list argp;
va_start(argp, fmt);
fprintf(stderr, "%s error: ", program_invocation_short_name);
vfprintf(stderr, fmt, argp);
va_end(argp);
}
static void
help(void)
{
fprintf(stderr, "Compute a touchscreen calibration matrix for "
"a Wayland compositor by\n"
"having the user touch points on the screen.\n\n");
fprintf(stderr, "Usage: %s [options...] name\n\n",
program_invocation_short_name);
fprintf(stderr,
"Where 'name' can be a touch device sys path or a head name.\n"
"If 'name' is not given, all devices available for "
"calibration will be listed.\n"
"If 'name' is given, it must be exactly as listed.\n"
"Options:\n"
" --debug Print messages to help debugging.\n"
" -h, --help Display this help message\n"
" -v, --verbose Print list header and calibration result.\n");
}
int
main(int argc, char *argv[])
{
struct display *display;
struct calibrator *cal;
int c;
char *match_name = NULL;
int exit_code = CAL_EXIT_SUCCESS;
static const struct option opts[] = {
{ "help", no_argument, NULL, 'h' },
{ "debug", no_argument, &debug_, 1 },
{ "verbose", no_argument, &verbose_, 1 },
{ 0, 0, NULL, 0 }
};
while ((c = getopt_long(argc, argv, "hv", opts, NULL)) != -1) {
switch (c) {
case 'h':
help();
return CAL_EXIT_SUCCESS;
case 'v':
verbose_ = 1;
break;
case 0:
break;
default:
return CAL_EXIT_ERROR;
}
}
if (optind < argc)
match_name = argv[optind++];
if (optind < argc) {
pr_err("extra arguments given.\n\n");
help();
return CAL_EXIT_ERROR;
}
display = display_create(&argc, argv);
if (!display)
return CAL_EXIT_ERROR;
cal = calibrator_create(display, match_name);
if (!cal)
return CAL_EXIT_ERROR;
display_set_user_data(display, cal);
display_set_global_handler(display, global_handler);
if (!match_name)
pr_ver("Available touch devices:\n");
/* Roundtrip to get list of available touch devices,
* first globals, then touch_device events */
wl_display_roundtrip(display_get_display(display));
wl_display_roundtrip(display_get_display(display));
if (!cal->calibration) {
exit_code = CAL_EXIT_ERROR;
pr_err("the Wayland server does not expose the calibration interface.\n");
} else if (cal->device_name) {
exit_code = calibrator_run(cal);
} else if (match_name) {
exit_code = CAL_EXIT_ERROR;
pr_err("\"%s\" was not found.\n", match_name);
} else if (cal->n_devices_listed == 0) {
fprintf(stderr, "No devices listed.\n");
}
calibrator_destroy(cal);
display_destroy(display);
return exit_code;
}

View file

@ -2,24 +2,23 @@
* Copyright © 2008 Kristian Høgsberg * Copyright © 2008 Kristian Høgsberg
* Copyright © 2012 Intel Corporation * Copyright © 2012 Intel Corporation
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 "config.h"
@ -29,7 +28,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 +225,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 +262,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 +272,6 @@ int main(int argc, char *argv[])
window_add_widget(transformed.window, &transformed); window_add_widget(transformed.window, &transformed);
window_set_title(transformed.window, "Transformed"); window_set_title(transformed.window, "Transformed");
window_set_appid(transformed.window,
"org.freedesktop.weston.transformed");
widget_set_transparent(transformed.widget, 0); widget_set_transparent(transformed.widget, 0);
widget_set_default_cursor(transformed.widget, CURSOR_BLANK); widget_set_default_cursor(transformed.widget, CURSOR_BLANK);

View file

@ -1,502 +0,0 @@
/*
* Copyright © 2017 Pekka Paalanen <pq@iki.fi>
* Copyright © 2018 Zodiac Inflight Innovations
*
* 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 <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <wayland-client.h>
#include "shared/helpers.h"
#include <libweston/zalloc.h>
#include "weston-debug-client-protocol.h"
struct debug_app {
struct {
bool help;
bool list;
bool bind_all;
char *output;
char *outfd;
} opt;
int out_fd;
struct wl_display *dpy;
struct wl_registry *registry;
struct weston_debug_v1 *debug_iface;
struct wl_list stream_list;
};
struct debug_stream {
struct wl_list link;
bool should_bind;
char *name;
char *desc;
struct weston_debug_stream_v1 *obj;
};
/**
* Called either through stream_find in response to an advertisement
* event (see comment on stream_find) when we have all the information,
* or directly from option parsing to make a placeholder entry when the
* stream was explicitly named on the command line to bind to.
*/
static struct debug_stream *
stream_alloc(struct debug_app *app, const char *name, const char *desc)
{
struct debug_stream *stream;
stream = zalloc(sizeof *stream);
if (!stream)
return NULL;
stream->name = strdup(name);
if (!stream->name) {
free(stream);
return NULL;
}
if (desc) {
stream->desc = strdup(desc);
if (!stream->desc) {
free(stream->name);
free(stream);
return NULL;
}
}
stream->should_bind = app->opt.bind_all;
wl_list_insert(app->stream_list.prev, &stream->link);
return stream;
}
/**
* Called in response to a stream advertisement event. If our stream was
* manually specified on the command line, then it will already have a
* dummy entry in stream_list: we fill in its description and return.
* If there's no entry in the list, we make a new one and return that.
*/
static struct debug_stream *
stream_find(struct debug_app *app, const char *name, const char *desc)
{
struct debug_stream *stream;
wl_list_for_each(stream, &app->stream_list, link) {
if (strcmp(stream->name, name) == 0) {
assert(stream->desc == NULL);
if (desc)
stream->desc = strdup(desc);
return stream;
}
}
return stream_alloc(app, name, desc);
}
static void
stream_destroy(struct debug_stream *stream)
{
if (stream->obj)
weston_debug_stream_v1_destroy(stream->obj);
wl_list_remove(&stream->link);
free(stream->desc);
free(stream->name);
free(stream);
}
static void
destroy_streams(struct debug_app *app)
{
struct debug_stream *stream;
struct debug_stream *tmp;
wl_list_for_each_safe(stream, tmp, &app->stream_list, link)
stream_destroy(stream);
}
static void
debug_advertise(void *data, struct weston_debug_v1 *debug, const char *name,
const char *desc)
{
struct debug_app *app = data;
(void) stream_find(app, name, desc);
}
static const struct weston_debug_v1_listener debug_listener = {
debug_advertise,
};
static void
global_handler(void *data, struct wl_registry *registry, uint32_t id,
const char *interface, uint32_t version)
{
struct debug_app *app = data;
uint32_t myver;
assert(app->registry == registry);
if (!strcmp(interface, weston_debug_v1_interface.name)) {
if (app->debug_iface)
return;
myver = MIN(1, version);
app->debug_iface =
wl_registry_bind(registry, id,
&weston_debug_v1_interface, myver);
weston_debug_v1_add_listener(app->debug_iface, &debug_listener,
app);
}
}
static void
global_remove_handler(void *data, struct wl_registry *registry, uint32_t name)
{
}
static const struct wl_registry_listener registry_listener = {
global_handler,
global_remove_handler
};
static void
handle_stream_complete(void *data, struct weston_debug_stream_v1 *obj)
{
struct debug_stream *stream = data;
assert(stream->obj == obj);
stream_destroy(stream);
}
static void
handle_stream_failure(void *data, struct weston_debug_stream_v1 *obj,
const char *msg)
{
struct debug_stream *stream = data;
assert(stream->obj == obj);
fprintf(stderr, "Debug stream '%s' aborted: %s\n", stream->name, msg);
stream_destroy(stream);
}
static const struct weston_debug_stream_v1_listener stream_listener = {
handle_stream_complete,
handle_stream_failure
};
static void
start_streams(struct debug_app *app)
{
struct debug_stream *stream;
wl_list_for_each(stream, &app->stream_list, link) {
if (!stream->should_bind)
continue;
stream->obj = weston_debug_v1_subscribe(app->debug_iface,
stream->name,
app->out_fd);
weston_debug_stream_v1_add_listener(stream->obj,
&stream_listener, stream);
}
}
static void
list_streams(struct debug_app *app)
{
struct debug_stream *stream;
fprintf(stderr, "Available debug streams:\n");
wl_list_for_each(stream, &app->stream_list, link) {
if (stream->should_bind && stream->desc) {
fprintf(stderr, " %s [will bind]\n", stream->name);
fprintf(stderr, " %s\n", stream->desc);
} else if (stream->should_bind) {
fprintf(stderr, " %s [wanted but not found]\n",
stream->name);
} else {
fprintf(stderr, " %s [will not bind]\n",
stream->name);
fprintf(stderr, " %s\n", stream->desc);
}
}
}
static int
setup_out_fd(const char *output, const char *outfd)
{
int fd = -1;
int flags;
assert(!(output && outfd));
if (output) {
if (strcmp(output, "-") == 0) {
fd = STDOUT_FILENO;
} else {
fd = open(output,
O_WRONLY | O_APPEND | O_CREAT, 0644);
if (fd < 0) {
fprintf(stderr,
"Error: opening file '%s' failed: %s\n",
output, strerror(errno));
}
return fd;
}
} else if (outfd) {
fd = atoi(outfd);
} else {
fd = STDOUT_FILENO;
}
flags = fcntl(fd, F_GETFL);
if (flags == -1) {
fprintf(stderr,
"Error: cannot use file descriptor %d: %s\n", fd,
strerror(errno));
return -1;
}
if ((flags & O_ACCMODE) != O_WRONLY &&
(flags & O_ACCMODE) != O_RDWR) {
fprintf(stderr,
"Error: file descriptor %d is not writable.\n", fd);
return -1;
}
return fd;
}
static void
print_help(void)
{
fprintf(stderr,
"Usage: weston-debug [options] [names]\n"
"Where options may be:\n"
" -h, --help\n"
" This help text, and exit with success.\n"
" -l, --list\n"
" Print a list of available debug streams to stderr.\n"
" -a, --all-streams\n"
" Bind to all available streams.\n"
" -o FILE, --output FILE\n"
" Direct output to file named FILE. Use - for stdout.\n"
" Stdout is the default. Mutually exclusive with -f.\n"
" -f FD, --outfd FD\n"
" Direct output to the file descriptor FD.\n"
" Stdout (1) is the default. Mutually exclusive with -o.\n"
"Names are whatever debug stream names the compositor supports.\n"
);
}
static int
parse_cmdline(struct debug_app *app, int argc, char **argv)
{
static const struct option opts[] = {
{ "help", no_argument, NULL, 'h' },
{ "list", no_argument, NULL, 'l' },
{ "all-streams", no_argument, NULL, 'a' },
{ "output", required_argument, NULL, 'o' },
{ "outfd", required_argument, NULL, 'f' },
{ 0 }
};
static const char optstr[] = "hlao:f:";
int c;
bool failed = false;
while (1) {
c = getopt_long(argc, argv, optstr, opts, NULL);
if (c == -1)
break;
switch (c) {
case 'h':
app->opt.help = true;
break;
case 'l':
app->opt.list = true;
break;
case 'a':
app->opt.bind_all = true;
break;
case 'o':
free(app->opt.output);
app->opt.output = strdup(optarg);
break;
case 'f':
free(app->opt.outfd);
app->opt.outfd = strdup(optarg);
break;
case '?':
failed = true;
break;
default:
fprintf(stderr, "huh? getopt => %c (%d)\n", c, c);
failed = true;
}
}
if (failed)
return -1;
while (optind < argc) {
struct debug_stream *stream =
stream_alloc(app, argv[optind++], NULL);
stream->should_bind = true;
}
return 0;
}
int
main(int argc, char **argv)
{
struct debug_app app = {};
int ret = 0;
wl_list_init(&app.stream_list);
app.out_fd = -1;
if (parse_cmdline(&app, argc, argv) < 0) {
ret = 1;
goto out_parse;
}
if (app.opt.help) {
print_help();
goto out_parse;
}
if (!app.opt.list && !app.opt.bind_all &&
wl_list_empty(&app.stream_list)) {
fprintf(stderr, "Error: no options given.\n\n");
ret = 1;
print_help();
goto out_parse;
}
if (app.opt.bind_all && !wl_list_empty(&app.stream_list)) {
fprintf(stderr, "Error: --all and specific stream names cannot be used simultaneously.\n");
ret = 1;
goto out_parse;
}
if (app.opt.output && app.opt.outfd) {
fprintf(stderr, "Error: options --output and --outfd cannot be used simultaneously.\n");
ret = 1;
goto out_parse;
}
app.out_fd = setup_out_fd(app.opt.output, app.opt.outfd);
if (app.out_fd < 0) {
ret = 1;
goto out_parse;
}
app.dpy = wl_display_connect(NULL);
if (!app.dpy) {
fprintf(stderr, "Error: Could not connect to Wayland display: %s\n",
strerror(errno));
ret = 1;
goto out_parse;
}
app.registry = wl_display_get_registry(app.dpy);
wl_registry_add_listener(app.registry, &registry_listener, &app);
wl_display_roundtrip(app.dpy);
if (!app.debug_iface) {
ret = 1;
fprintf(stderr,
"The Wayland server does not support %s interface.\n",
weston_debug_v1_interface.name);
goto out_conn;
}
wl_display_roundtrip(app.dpy); /* for weston_debug_v1::advertise */
if (app.opt.list)
list_streams(&app);
start_streams(&app);
weston_debug_v1_destroy(app.debug_iface);
while (1) {
struct debug_stream *stream;
bool empty = true;
wl_list_for_each(stream, &app.stream_list, link) {
if (stream->obj) {
empty = false;
break;
}
}
if (empty)
break;
if (wl_display_dispatch(app.dpy) < 0) {
ret = 1;
break;
}
}
out_conn:
destroy_streams(&app);
/* Wait for server to close all files */
wl_display_roundtrip(app.dpy);
wl_registry_destroy(app.registry);
wl_display_disconnect(app.dpy);
out_parse:
if (app.out_fd != -1)
close(app.out_fd);
destroy_streams(&app);
free(app.opt.output);
free(app.opt.outfd);
return ret;
}

735
clients/weston-info.c Normal file
View file

@ -0,0 +1,735 @@
/*
* Copyright © 2012 Philipp Brüschweiler
*
* 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 <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <wayland-client.h>
#include "../shared/os-compatibility.h"
#include "presentation_timing-client-protocol.h"
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
typedef void (*print_info_t)(void *info);
typedef void (*destroy_info_t)(void *info);
struct global_info {
struct wl_list link;
uint32_t id;
uint32_t version;
char *interface;
print_info_t print;
destroy_info_t destroy;
};
struct output_mode {
struct wl_list link;
uint32_t flags;
int32_t width, height;
int32_t refresh;
};
struct output_info {
struct global_info global;
struct wl_output *output;
struct {
int32_t x, y;
int32_t physical_width, physical_height;
enum wl_output_subpixel subpixel;
enum wl_output_transform output_transform;
char *make;
char *model;
} geometry;
struct wl_list modes;
};
struct shm_format {
struct wl_list link;
uint32_t format;
};
struct shm_info {
struct global_info global;
struct wl_shm *shm;
struct wl_list formats;
};
struct seat_info {
struct global_info global;
struct wl_seat *seat;
struct weston_info *info;
uint32_t capabilities;
char *name;
int32_t repeat_rate;
int32_t repeat_delay;
};
struct presentation_info {
struct global_info global;
struct presentation *presentation;
clockid_t clk_id;
};
struct weston_info {
struct wl_display *display;
struct wl_registry *registry;
struct wl_list infos;
bool roundtrip_needed;
};
static void *
fail_on_null(void *p)
{
if (p == NULL) {
fprintf(stderr, "%s: out of memory\n", program_invocation_short_name);
exit(EXIT_FAILURE);
}
return p;
}
static void *
xmalloc(size_t s)
{
return fail_on_null(malloc(s));
}
static void *
xzalloc(size_t s)
{
return fail_on_null(calloc(1, s));
}
static char *
xstrdup(const char *s)
{
return fail_on_null(strdup(s));
}
static void
print_global_info(void *data)
{
struct global_info *global = data;
printf("interface: '%s', version: %u, name: %u\n",
global->interface, global->version, global->id);
}
static void
init_global_info(struct weston_info *info,
struct global_info *global, uint32_t id,
const char *interface, uint32_t version)
{
global->id = id;
global->version = version;
global->interface = xstrdup(interface);
wl_list_insert(info->infos.prev, &global->link);
}
static void
print_output_info(void *data)
{
struct output_info *output = data;
struct output_mode *mode;
const char *subpixel_orientation;
const char *transform;
print_global_info(data);
switch (output->geometry.subpixel) {
case WL_OUTPUT_SUBPIXEL_UNKNOWN:
subpixel_orientation = "unknown";
break;
case WL_OUTPUT_SUBPIXEL_NONE:
subpixel_orientation = "none";
break;
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
subpixel_orientation = "horizontal rgb";
break;
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
subpixel_orientation = "horizontal bgr";
break;
case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
subpixel_orientation = "vertical rgb";
break;
case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
subpixel_orientation = "vertical bgr";
break;
default:
fprintf(stderr, "unknown subpixel orientation %u\n",
output->geometry.subpixel);
subpixel_orientation = "unexpected value";
break;
}
switch (output->geometry.output_transform) {
case WL_OUTPUT_TRANSFORM_NORMAL:
transform = "normal";
break;
case WL_OUTPUT_TRANSFORM_90:
transform = "90°";
break;
case WL_OUTPUT_TRANSFORM_180:
transform = "180°";
break;
case WL_OUTPUT_TRANSFORM_270:
transform = "270°";
break;
case WL_OUTPUT_TRANSFORM_FLIPPED:
transform = "flipped";
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
transform = "flipped 90°";
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
transform = "flipped 180°";
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
transform = "flipped 270°";
break;
default:
fprintf(stderr, "unknown output transform %u\n",
output->geometry.output_transform);
transform = "unexpected value";
break;
}
printf("\tx: %d, y: %d,\n",
output->geometry.x, output->geometry.y);
printf("\tphysical_width: %d mm, physical_height: %d mm,\n",
output->geometry.physical_width,
output->geometry.physical_height);
printf("\tmake: '%s', model: '%s',\n",
output->geometry.make, output->geometry.model);
printf("\tsubpixel_orientation: %s, output_transform: %s,\n",
subpixel_orientation, transform);
wl_list_for_each(mode, &output->modes, link) {
printf("\tmode:\n");
printf("\t\twidth: %d px, height: %d px, refresh: %.f Hz,\n",
mode->width, mode->height,
(float) mode->refresh / 1000);
printf("\t\tflags:");
if (mode->flags & WL_OUTPUT_MODE_CURRENT)
printf(" current");
if (mode->flags & WL_OUTPUT_MODE_PREFERRED)
printf(" preferred");
printf("\n");
}
}
static void
print_shm_info(void *data)
{
struct shm_info *shm = data;
struct shm_format *format;
print_global_info(data);
printf("\tformats:");
wl_list_for_each(format, &shm->formats, link)
switch (format->format) {
case WL_SHM_FORMAT_ARGB8888:
printf(" ARGB8888");
break;
case WL_SHM_FORMAT_XRGB8888:
printf(" XRGB8888");
break;
case WL_SHM_FORMAT_RGB565:
printf(" RGB565");
break;
default:
printf(" unknown(%08x)", format->format);
break;
}
printf("\n");
}
static void
print_seat_info(void *data)
{
struct seat_info *seat = data;
print_global_info(data);
printf("\tname: %s\n", seat->name);
printf("\tcapabilities:");
if (seat->capabilities & WL_SEAT_CAPABILITY_POINTER)
printf(" pointer");
if (seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD)
printf(" keyboard");
if (seat->capabilities & WL_SEAT_CAPABILITY_TOUCH)
printf(" touch");
printf("\n");
if (seat->repeat_rate > 0)
printf("\tkeyboard repeat rate: %d\n", seat->repeat_rate);
if (seat->repeat_delay > 0)
printf("\tkeyboard repeat delay: %d\n", seat->repeat_delay);
}
static void
keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
uint32_t format, int fd, uint32_t size)
{
}
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)
{
}
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 void
keyboard_handle_repeat_info(void *data, struct wl_keyboard *keyboard,
int32_t rate, int32_t delay)
{
struct seat_info *seat = data;
seat->repeat_rate = rate;
seat->repeat_delay = delay;
}
static const struct wl_keyboard_listener keyboard_listener = {
keyboard_handle_keymap,
keyboard_handle_enter,
keyboard_handle_leave,
keyboard_handle_key,
keyboard_handle_modifiers,
keyboard_handle_repeat_info,
};
static void
seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
enum wl_seat_capability caps)
{
struct seat_info *seat = data;
seat->capabilities = caps;
/* we want listen for repeat_info from wl_keyboard, but only
* do so if the seat info is >= 4 and if we actually have a
* keyboard */
if (seat->global.version < 4)
return;
if (caps & WL_SEAT_CAPABILITY_KEYBOARD) {
struct wl_keyboard *keyboard;
keyboard = wl_seat_get_keyboard(seat->seat);
wl_keyboard_add_listener(keyboard, &keyboard_listener,
seat);
seat->info->roundtrip_needed = true;
}
}
static void
seat_handle_name(void *data, struct wl_seat *wl_seat,
const char *name)
{
struct seat_info *seat = data;
seat->name = xstrdup(name);
}
static const struct wl_seat_listener seat_listener = {
seat_handle_capabilities,
seat_handle_name,
};
static void
destroy_seat_info(void *data)
{
struct seat_info *seat = data;
wl_seat_destroy(seat->seat);
if (seat->name != NULL)
free(seat->name);
}
static void
add_seat_info(struct weston_info *info, uint32_t id, uint32_t version)
{
struct seat_info *seat = xzalloc(sizeof *seat);
/* required to set roundtrip_needed to true in capabilities
* handler */
seat->info = info;
init_global_info(info, &seat->global, id, "wl_seat", version);
seat->global.print = print_seat_info;
seat->global.destroy = destroy_seat_info;
seat->seat = wl_registry_bind(info->registry,
id, &wl_seat_interface, MIN(version, 4));
wl_seat_add_listener(seat->seat, &seat_listener, seat);
seat->repeat_rate = seat->repeat_delay = -1;
info->roundtrip_needed = true;
}
static void
shm_handle_format(void *data, struct wl_shm *wl_shm, uint32_t format)
{
struct shm_info *shm = data;
struct shm_format *shm_format = xzalloc(sizeof *shm_format);
wl_list_insert(&shm->formats, &shm_format->link);
shm_format->format = format;
}
static const struct wl_shm_listener shm_listener = {
shm_handle_format,
};
static void
destroy_shm_info(void *data)
{
struct shm_info *shm = data;
struct shm_format *format, *tmp;
wl_list_for_each_safe(format, tmp, &shm->formats, link) {
wl_list_remove(&format->link);
free(format);
}
wl_shm_destroy(shm->shm);
}
static void
add_shm_info(struct weston_info *info, uint32_t id, uint32_t version)
{
struct shm_info *shm = xzalloc(sizeof *shm);
init_global_info(info, &shm->global, id, "wl_shm", version);
shm->global.print = print_shm_info;
shm->global.destroy = destroy_shm_info;
wl_list_init(&shm->formats);
shm->shm = wl_registry_bind(info->registry,
id, &wl_shm_interface, 1);
wl_shm_add_listener(shm->shm, &shm_listener, shm);
info->roundtrip_needed = true;
}
static void
output_handle_geometry(void *data, struct wl_output *wl_output,
int32_t x, int32_t y,
int32_t physical_width, int32_t physical_height,
int32_t subpixel,
const char *make, const char *model,
int32_t output_transform)
{
struct output_info *output = data;
output->geometry.x = x;
output->geometry.y = y;
output->geometry.physical_width = physical_width;
output->geometry.physical_height = physical_height;
output->geometry.subpixel = subpixel;
output->geometry.make = xstrdup(make);
output->geometry.model = xstrdup(model);
output->geometry.output_transform = output_transform;
}
static void
output_handle_mode(void *data, struct wl_output *wl_output,
uint32_t flags, int32_t width, int32_t height,
int32_t refresh)
{
struct output_info *output = data;
struct output_mode *mode = xmalloc(sizeof *mode);
mode->flags = flags;
mode->width = width;
mode->height = height;
mode->refresh = refresh;
wl_list_insert(output->modes.prev, &mode->link);
}
static const struct wl_output_listener output_listener = {
output_handle_geometry,
output_handle_mode,
};
static void
destroy_output_info(void *data)
{
struct output_info *output = data;
struct output_mode *mode, *tmp;
wl_output_destroy(output->output);
if (output->geometry.make != NULL)
free(output->geometry.make);
if (output->geometry.model != NULL)
free(output->geometry.model);
wl_list_for_each_safe(mode, tmp, &output->modes, link) {
wl_list_remove(&mode->link);
free(mode);
}
}
static void
add_output_info(struct weston_info *info, uint32_t id, uint32_t version)
{
struct output_info *output = xzalloc(sizeof *output);
init_global_info(info, &output->global, id, "wl_output", version);
output->global.print = print_output_info;
output->global.destroy = destroy_output_info;
wl_list_init(&output->modes);
output->output = wl_registry_bind(info->registry, id,
&wl_output_interface, 1);
wl_output_add_listener(output->output, &output_listener,
output);
info->roundtrip_needed = true;
}
static void
destroy_presentation_info(void *info)
{
struct presentation_info *prinfo = info;
presentation_destroy(prinfo->presentation);
}
static const char *
clock_name(clockid_t clk_id)
{
static const char *names[] = {
[CLOCK_REALTIME] = "CLOCK_REALTIME",
[CLOCK_MONOTONIC] = "CLOCK_MONOTONIC",
[CLOCK_MONOTONIC_RAW] = "CLOCK_MONOTONIC_RAW",
[CLOCK_REALTIME_COARSE] = "CLOCK_REALTIME_COARSE",
[CLOCK_MONOTONIC_COARSE] = "CLOCK_MONOTONIC_COARSE",
[CLOCK_BOOTTIME] = "CLOCK_BOOTTIME",
};
if (clk_id < 0 || (unsigned)clk_id >= ARRAY_LENGTH(names))
return "unknown";
return names[clk_id];
}
static void
print_presentation_info(void *info)
{
struct presentation_info *prinfo = info;
print_global_info(info);
printf("\tpresentation clock id: %d (%s)\n",
prinfo->clk_id, clock_name(prinfo->clk_id));
}
static void
presentation_handle_clock_id(void *data, struct presentation *presentation,
uint32_t clk_id)
{
struct presentation_info *prinfo = data;
prinfo->clk_id = clk_id;
}
static const struct presentation_listener presentation_listener = {
presentation_handle_clock_id
};
static void
add_presentation_info(struct weston_info *info, uint32_t id, uint32_t version)
{
struct presentation_info *prinfo = xzalloc(sizeof *prinfo);
init_global_info(info, &prinfo->global, id, "presentation", version);
prinfo->global.print = print_presentation_info;
prinfo->global.destroy = destroy_presentation_info;
prinfo->clk_id = -1;
prinfo->presentation = wl_registry_bind(info->registry, id,
&presentation_interface, 1);
presentation_add_listener(prinfo->presentation, &presentation_listener,
prinfo);
info->roundtrip_needed = true;
}
static void
destroy_global_info(void *data)
{
}
static void
add_global_info(struct weston_info *info, uint32_t id,
const char *interface, uint32_t version)
{
struct global_info *global = xzalloc(sizeof *global);
init_global_info(info, global, id, interface, version);
global->print = print_global_info;
global->destroy = destroy_global_info;
}
static void
global_handler(void *data, struct wl_registry *registry, uint32_t id,
const char *interface, uint32_t version)
{
struct weston_info *info = data;
if (!strcmp(interface, "wl_seat"))
add_seat_info(info, id, version);
else if (!strcmp(interface, "wl_shm"))
add_shm_info(info, id, version);
else if (!strcmp(interface, "wl_output"))
add_output_info(info, id, version);
else if (!strcmp(interface, "presentation"))
add_presentation_info(info, id, version);
else
add_global_info(info, id, interface, version);
}
static void
global_remove_handler(void *data, struct wl_registry *registry, uint32_t name)
{
}
static const struct wl_registry_listener registry_listener = {
global_handler,
global_remove_handler
};
static void
print_infos(struct wl_list *infos)
{
struct global_info *info;
wl_list_for_each(info, infos, link)
info->print(info);
}
static void
destroy_info(void *data)
{
struct global_info *global = data;
global->destroy(data);
wl_list_remove(&global->link);
free(global->interface);
free(data);
}
static void
destroy_infos(struct wl_list *infos)
{
struct global_info *info, *tmp;
wl_list_for_each_safe(info, tmp, infos, link)
destroy_info(info);
}
int
main(int argc, char **argv)
{
struct weston_info info;
info.display = wl_display_connect(NULL);
if (!info.display) {
fprintf(stderr, "failed to create display: %m\n");
return -1;
}
wl_list_init(&info.infos);
info.registry = wl_display_get_registry(info.display);
wl_registry_add_listener(info.registry, &registry_listener, &info);
do {
info.roundtrip_needed = false;
wl_display_roundtrip(info.display);
} while (info.roundtrip_needed);
print_infos(&info.infos);
destroy_infos(&info.infos);
wl_registry_destroy(info.registry);
wl_display_disconnect(info.display);
return 0;
}

View file

@ -1,42 +1,38 @@
/* /*
* Copyright © 2012 Intel Corporation * Copyright © 2012 Intel Corporation
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and
* copy of this software and associated documentation files (the "Software"), * its documentation for any purpose is hereby granted without fee, provided
* to deal in the Software without restriction, including without limitation * that the above copyright notice appear in all copies and that both that
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * copyright notice and this permission notice appear in supporting
* and/or sell copies of the Software, and to permit persons to whom the * documentation, and that the name of the copyright holders not be used in
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* paragraph) shall be included in all copies or substantial portions of the * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* Software. * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* 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 <config.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#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>
#include "window.h" #include "window.h"
#include "input-method-unstable-v1-client-protocol.h" #include "input-method-client-protocol.h"
#include "shared/helpers.h"
enum compose_state { enum compose_state {
state_normal, state_normal,
@ -57,8 +53,8 @@ typedef void (*keyboard_input_key_handler_t)(struct simple_im *keyboard,
enum wl_keyboard_key_state state); enum wl_keyboard_key_state state);
struct simple_im { struct simple_im {
struct zwp_input_method_v1 *input_method; struct wl_input_method *input_method;
struct zwp_input_method_context_v1 *context; struct wl_input_method_context *context;
struct wl_display *display; struct wl_display *display;
struct wl_registry *registry; struct wl_registry *registry;
struct wl_keyboard *keyboard; struct wl_keyboard *keyboard;
@ -106,11 +102,9 @@ 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 wl_input_method_context *context,
const char *text, const char *text,
uint32_t cursor, uint32_t cursor,
uint32_t anchor) uint32_t anchor)
@ -120,7 +114,7 @@ handle_surrounding_text(void *data,
static void static void
handle_reset(void *data, handle_reset(void *data,
struct zwp_input_method_context_v1 *context) struct wl_input_method_context *context)
{ {
struct simple_im *keyboard = data; struct simple_im *keyboard = data;
@ -131,7 +125,7 @@ handle_reset(void *data,
static void static void
handle_content_type(void *data, handle_content_type(void *data,
struct zwp_input_method_context_v1 *context, struct wl_input_method_context *context,
uint32_t hint, uint32_t hint,
uint32_t purpose) uint32_t purpose)
{ {
@ -139,7 +133,7 @@ handle_content_type(void *data,
static void static void
handle_invoke_action(void *data, handle_invoke_action(void *data,
struct zwp_input_method_context_v1 *context, struct wl_input_method_context *context,
uint32_t button, uint32_t button,
uint32_t index) uint32_t index)
{ {
@ -147,7 +141,7 @@ handle_invoke_action(void *data,
static void static void
handle_commit_state(void *data, handle_commit_state(void *data,
struct zwp_input_method_context_v1 *context, struct wl_input_method_context *context,
uint32_t serial) uint32_t serial)
{ {
struct simple_im *keyboard = data; struct simple_im *keyboard = data;
@ -157,12 +151,12 @@ handle_commit_state(void *data,
static void static void
handle_preferred_language(void *data, handle_preferred_language(void *data,
struct zwp_input_method_context_v1 *context, struct wl_input_method_context *context,
const char *language) const char *language)
{ {
} }
static const struct zwp_input_method_context_v1_listener input_method_context_listener = { static const struct wl_input_method_context_listener input_method_context_listener = {
handle_surrounding_text, handle_surrounding_text,
handle_reset, handle_reset,
handle_content_type, handle_content_type,
@ -196,19 +190,19 @@ input_method_keyboard_keymap(void *data,
xkb_keymap_new_from_string(keyboard->xkb_context, xkb_keymap_new_from_string(keyboard->xkb_context,
map_str, map_str,
XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_FORMAT_TEXT_V1,
XKB_KEYMAP_COMPILE_NO_FLAGS); 0);
munmap(map_str, size); munmap(map_str, size);
close(fd); close(fd);
if (!keyboard->keymap) { if (!keyboard->keymap) {
fprintf(stderr, "Failed to compile keymap\n"); fprintf(stderr, "failed to compile keymap\n");
return; return;
} }
keyboard->state = xkb_state_new(keyboard->keymap); keyboard->state = xkb_state_new(keyboard->keymap);
if (!keyboard->state) { if (!keyboard->state) {
fprintf(stderr, "Failed to create XKB state\n"); fprintf(stderr, "failed to create XKB state\n");
xkb_keymap_unref(keyboard->keymap); xkb_keymap_unref(keyboard->keymap);
return; return;
} }
@ -261,7 +255,7 @@ input_method_keyboard_modifiers(void *data,
uint32_t group) uint32_t group)
{ {
struct simple_im *keyboard = data; struct simple_im *keyboard = data;
struct zwp_input_method_context_v1 *context = keyboard->context; struct wl_input_method_context *context = keyboard->context;
xkb_mod_mask_t mask; xkb_mod_mask_t mask;
xkb_state_update_mask(keyboard->state, mods_depressed, xkb_state_update_mask(keyboard->state, mods_depressed,
@ -278,9 +272,9 @@ input_method_keyboard_modifiers(void *data,
if (mask & keyboard->shift_mask) if (mask & keyboard->shift_mask)
keyboard->modifiers |= MOD_SHIFT_MASK; keyboard->modifiers |= MOD_SHIFT_MASK;
zwp_input_method_context_v1_modifiers(context, serial, wl_input_method_context_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 = {
@ -293,23 +287,23 @@ static const struct wl_keyboard_listener input_method_keyboard_listener = {
static void static void
input_method_activate(void *data, input_method_activate(void *data,
struct zwp_input_method_v1 *input_method, struct wl_input_method *input_method,
struct zwp_input_method_context_v1 *context) struct wl_input_method_context *context)
{ {
struct simple_im *keyboard = data; struct simple_im *keyboard = data;
if (keyboard->context) if (keyboard->context)
zwp_input_method_context_v1_destroy(keyboard->context); wl_input_method_context_destroy(keyboard->context);
keyboard->compose_state = state_normal; keyboard->compose_state = state_normal;
keyboard->serial = 0; keyboard->serial = 0;
keyboard->context = context; keyboard->context = context;
zwp_input_method_context_v1_add_listener(context, wl_input_method_context_add_listener(context,
&input_method_context_listener, &input_method_context_listener,
keyboard); keyboard);
keyboard->keyboard = zwp_input_method_context_v1_grab_keyboard(context); keyboard->keyboard = wl_input_method_context_grab_keyboard(context);
wl_keyboard_add_listener(keyboard->keyboard, wl_keyboard_add_listener(keyboard->keyboard,
&input_method_keyboard_listener, &input_method_keyboard_listener,
keyboard); keyboard);
@ -317,19 +311,19 @@ input_method_activate(void *data,
static void static void
input_method_deactivate(void *data, input_method_deactivate(void *data,
struct zwp_input_method_v1 *input_method, struct wl_input_method *input_method,
struct zwp_input_method_context_v1 *context) struct wl_input_method_context *context)
{ {
struct simple_im *keyboard = data; struct simple_im *keyboard = data;
if (!keyboard->context) if (!keyboard->context)
return; return;
zwp_input_method_context_v1_destroy(keyboard->context); wl_input_method_context_destroy(keyboard->context);
keyboard->context = NULL; keyboard->context = NULL;
} }
static const struct zwp_input_method_v1_listener input_method_listener = { static const struct wl_input_method_listener input_method_listener = {
input_method_activate, input_method_activate,
input_method_deactivate input_method_deactivate
}; };
@ -340,12 +334,12 @@ registry_handle_global(void *data, struct wl_registry *registry,
{ {
struct simple_im *keyboard = data; struct simple_im *keyboard = data;
if (!strcmp(interface, "zwp_input_method_v1")) { if (!strcmp(interface, "wl_input_method")) {
keyboard->input_method = keyboard->input_method =
wl_registry_bind(registry, name, wl_registry_bind(registry, name,
&zwp_input_method_v1_interface, 1); &wl_input_method_interface, 1);
zwp_input_method_v1_add_listener(keyboard->input_method, wl_input_method_add_listener(keyboard->input_method,
&input_method_listener, keyboard); &input_method_listener, keyboard);
} }
} }
@ -384,7 +378,7 @@ simple_im_key_handler(struct simple_im *keyboard,
uint32_t serial, uint32_t time, uint32_t key, uint32_t sym, uint32_t serial, uint32_t time, uint32_t key, uint32_t sym,
enum wl_keyboard_key_state state) enum wl_keyboard_key_state state)
{ {
struct zwp_input_method_context_v1 *context = keyboard->context; struct wl_input_method_context *context = keyboard->context;
char text[64]; char text[64];
if (sym == XKB_KEY_Multi_key && if (sym == XKB_KEY_Multi_key &&
@ -397,18 +391,14 @@ 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;
for (i = 0; i < ARRAY_LENGTH(ignore_keys_on_compose); i++) { for (i = 0; i < sizeof(ignore_keys_on_compose) / sizeof(ignore_keys_on_compose[0]); i++) {
if (sym == ignore_keys_on_compose[i]) { if (sym == ignore_keys_on_compose[i]) {
zwp_input_method_context_v1_key(context, wl_input_method_context_key(context, keyboard->serial, time, key, state);
keyboard->serial,
time,
key,
state);
return; return;
} }
} }
@ -418,21 +408,21 @@ simple_im_key_handler(struct simple_im *keyboard,
keyboard->compose_seq.keys[i] = sym; keyboard->compose_seq.keys[i] = sym;
cs = bsearch (&keyboard->compose_seq, compose_seqs, cs = bsearch (&keyboard->compose_seq, compose_seqs,
ARRAY_LENGTH(compose_seqs), sizeof(compose_seqs) / sizeof(compose_seqs[0]),
sizeof(compose_seqs[0]), compare_compose_keys); sizeof(compose_seqs[0]), compare_compose_keys);
if (cs) { if (cs) {
if (cs->keys[i + 1] == 0) { if (cs->keys[i + 1] == 0) {
zwp_input_method_context_v1_preedit_cursor(keyboard->context, wl_input_method_context_preedit_cursor(keyboard->context,
0); 0);
zwp_input_method_context_v1_preedit_string(keyboard->context, wl_input_method_context_preedit_string(keyboard->context,
keyboard->serial, keyboard->serial,
"", ""); "", "");
zwp_input_method_context_v1_cursor_position(keyboard->context, wl_input_method_context_cursor_position(keyboard->context,
0, 0); 0, 0);
zwp_input_method_context_v1_commit_string(keyboard->context, wl_input_method_context_commit_string(keyboard->context,
keyboard->serial, keyboard->serial,
cs->text); cs->text);
keyboard->compose_state = state_normal; keyboard->compose_state = state_normal;
} else { } else {
uint32_t j = 0, idx = 0; uint32_t j = 0, idx = 0;
@ -441,12 +431,12 @@ simple_im_key_handler(struct simple_im *keyboard,
idx += xkb_keysym_to_utf8(cs->keys[j], text + idx, sizeof(text) - idx); idx += xkb_keysym_to_utf8(cs->keys[j], text + idx, sizeof(text) - idx);
} }
zwp_input_method_context_v1_preedit_cursor(keyboard->context, wl_input_method_context_preedit_cursor(keyboard->context,
strlen(text)); strlen(text));
zwp_input_method_context_v1_preedit_string(keyboard->context, wl_input_method_context_preedit_string(keyboard->context,
keyboard->serial, keyboard->serial,
text, text,
text); text);
} }
} else { } else {
uint32_t j = 0, idx = 0; uint32_t j = 0, idx = 0;
@ -454,55 +444,47 @@ simple_im_key_handler(struct simple_im *keyboard,
for (; j <= i; j++) { for (; j <= i; j++) {
idx += xkb_keysym_to_utf8(keyboard->compose_seq.keys[j], text + idx, sizeof(text) - idx); idx += xkb_keysym_to_utf8(keyboard->compose_seq.keys[j], text + idx, sizeof(text) - idx);
} }
zwp_input_method_context_v1_preedit_cursor(keyboard->context, wl_input_method_context_preedit_cursor(keyboard->context,
0); 0);
zwp_input_method_context_v1_preedit_string(keyboard->context, wl_input_method_context_preedit_string(keyboard->context,
keyboard->serial, keyboard->serial,
"", ""); "", "");
zwp_input_method_context_v1_cursor_position(keyboard->context, wl_input_method_context_cursor_position(keyboard->context,
0, 0); 0, 0);
zwp_input_method_context_v1_commit_string(keyboard->context, wl_input_method_context_commit_string(keyboard->context,
keyboard->serial, keyboard->serial,
text); text);
keyboard->compose_state = state_normal; keyboard->compose_state = state_normal;
} }
return; return;
} }
if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0) { if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0) {
zwp_input_method_context_v1_key(context, serial, time, key, state); wl_input_method_context_key(context, serial, time, key, state);
return; return;
} }
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
return; return;
zwp_input_method_context_v1_cursor_position(keyboard->context, wl_input_method_context_cursor_position(keyboard->context,
0, 0); 0, 0);
zwp_input_method_context_v1_commit_string(keyboard->context, wl_input_method_context_commit_string(keyboard->context,
keyboard->serial, keyboard->serial,
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;
} }
@ -512,10 +494,10 @@ main(int argc, char *argv[])
wl_display_roundtrip(simple_im.display); wl_display_roundtrip(simple_im.display);
if (simple_im.input_method == NULL) { if (simple_im.input_method == NULL) {
fprintf(stderr, "No input_method global\n"); fprintf(stderr, "No input_method global\n");
return -1; exit(1);
} }
simple_im.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); simple_im.xkb_context = xkb_context_new(0);
if (simple_im.xkb_context == NULL) { if (simple_im.xkb_context == NULL) {
fprintf(stderr, "Failed to create XKB context\n"); fprintf(stderr, "Failed to create XKB context\n");
return -1; return -1;
@ -524,34 +506,12 @@ 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; exit(1);
} }
return 0; return 0;

File diff suppressed because it is too large Load diff

View file

@ -1,24 +1,23 @@
/* /*
* Copyright © 2008 Kristian Høgsberg * Copyright © 2008 Kristian Høgsberg
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission to use, copy, modify, distribute, and sell this software and its
* copy of this software and associated documentation files (the "Software"), * documentation for any purpose is hereby granted without fee, provided that
* to deal in the Software without restriction, including without limitation * the above copyright notice appear in all copies and that both that copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice and this permission notice appear in supporting documentation, and
* and/or sell copies of the Software, and to permit persons to whom the * that the name of the copyright holders not be used in advertising or
* Software is furnished to do so, subject to the following conditions: * 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 above copyright notice and this permission notice (including the next * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* paragraph) shall be included in all copies or substantial portions of the * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* Software. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * OF THIS SOFTWARE.
* 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 _WINDOW_H_ #ifndef _WINDOW_H_
@ -26,22 +25,24 @@
#include "config.h" #include "config.h"
#include <stdint.h>
#include <time.h>
#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"
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
#define container_of(ptr, type, member) ({ \
const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
struct window; struct window;
struct widget; 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);
@ -55,6 +56,17 @@ struct rectangle {
int32_t height; int32_t height;
}; };
void *
fail_on_null(void *p);
void *
xmalloc(size_t s);
void *
xzalloc(size_t s);
char *
xstrdup(const char *s);
void *
xrealloc(char *p, size_t s);
struct display * struct display *
display_create(int *argc, char *argv[]); display_create(int *argc, char *argv[]);
@ -73,12 +85,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 +128,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,
@ -150,9 +180,6 @@ display_run(struct display *d);
void void
display_exit(struct display *d); display_exit(struct display *d);
int
display_get_data_device_manager_version(struct display *d);
enum cursor_type { enum cursor_type {
CURSOR_BOTTOM_LEFT, CURSOR_BOTTOM_LEFT,
CURSOR_BOTTOM_RIGHT, CURSOR_BOTTOM_RIGHT,
@ -167,9 +194,6 @@ enum cursor_type {
CURSOR_IBEAM, CURSOR_IBEAM,
CURSOR_HAND1, CURSOR_HAND1,
CURSOR_WATCH, CURSOR_WATCH,
CURSOR_DND_MOVE,
CURSOR_DND_COPY,
CURSOR_DND_FORBIDDEN,
CURSOR_BLANK CURSOR_BLANK
}; };
@ -199,29 +223,6 @@ typedef void (*window_output_handler_t)(struct window *window, struct output *ou
typedef void (*window_state_changed_handler_t)(struct window *window, typedef void (*window_state_changed_handler_t)(struct window *window,
void *data); void *data);
typedef void (*window_locked_pointer_motion_handler_t)(struct window *window,
struct input *input,
uint32_t time,
float x, float y,
void *data);
typedef void (*locked_pointer_locked_handler_t)(struct window *window,
struct input *input,
void *data);
typedef void (*locked_pointer_unlocked_handler_t)(struct window *window,
struct input *input,
void *data);
typedef void (*confined_pointer_confined_handler_t)(struct window *window,
struct input *input,
void *data);
typedef void (*confined_pointer_unconfined_handler_t)(struct window *window,
struct input *input,
void *data);
typedef void (*widget_resize_handler_t)(struct widget *widget, typedef void (*widget_resize_handler_t)(struct widget *widget,
int32_t width, int32_t height, int32_t width, int32_t height,
void *data); void *data);
@ -261,87 +262,15 @@ typedef void (*widget_touch_motion_handler_t)(struct widget *widget,
float x, float x,
float y, float y,
void *data); void *data);
typedef void (*widget_touch_frame_handler_t)(struct widget *widget, typedef void (*widget_touch_frame_handler_t)(struct widget *widget,
struct input *input, void *data); struct input *input, void *data);
typedef void (*widget_touch_cancel_handler_t)(struct widget *widget, typedef void (*widget_touch_cancel_handler_t)(struct widget *widget,
struct input *input, void *data); struct input *input, void *data);
typedef void (*widget_axis_handler_t)(struct widget *widget, typedef void (*widget_axis_handler_t)(struct widget *widget,
struct input *input, uint32_t time, struct input *input, uint32_t time,
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,
struct input *input,
void *data);
typedef void (*widget_axis_source_handler_t)(struct widget *widget,
struct input *input,
uint32_t source,
void *data);
typedef void (*widget_axis_stop_handler_t)(struct widget *widget,
struct input *input,
uint32_t time,
uint32_t axis,
void *data);
typedef void (*widget_axis_discrete_handler_t)(struct widget *widget,
struct input *input,
uint32_t axis,
int32_t discrete,
void *data);
struct window * struct window *
window_create(struct display *display); window_create(struct display *display);
@ -358,6 +287,11 @@ window_has_focus(struct window *window);
typedef void (*menu_func_t)(void *data, struct input *input, int index); typedef void (*menu_func_t)(void *data, struct input *input, int index);
struct window *
window_create_menu(struct display *display,
struct input *input, uint32_t time,
menu_func_t func, const char **entries, int count,
void *user_data);
void void
window_show_menu(struct display *display, window_show_menu(struct display *display,
struct input *input, uint32_t time, struct window *parent, struct input *input, uint32_t time, struct window *parent,
@ -414,34 +348,9 @@ window_schedule_redraw(struct window *window);
void void
window_schedule_resize(struct window *window, int width, int height); window_schedule_resize(struct window *window, int width, int height);
int
window_lock_pointer(struct window *window, struct input *input);
void void
window_unlock_pointer(struct window *window); window_damage(struct window *window, int32_t x, int32_t y,
int32_t width, int32_t height);
void
widget_set_locked_pointer_cursor_hint(struct widget *widget,
float x, float y);
int
window_confine_pointer_to_rectangles(struct window *window,
struct input *input,
struct rectangle *rectangles,
int num_rectangles);
void
window_update_confine_rectangles(struct window *window,
struct rectangle *rectangles,
int num_rectangles);
int
window_confine_pointer_to_widget(struct window *window,
struct widget *widget,
struct input *input);
void
window_unconfine_pointer(struct window *window);
cairo_surface_t * cairo_surface_t *
window_get_surface(struct window *window); window_get_surface(struct window *window);
@ -453,6 +362,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,
}; };
@ -519,62 +429,23 @@ void
window_set_state_changed_handler(struct window *window, window_set_state_changed_handler(struct window *window,
window_state_changed_handler_t handler); window_state_changed_handler_t handler);
void
window_set_pointer_locked_handler(struct window *window,
locked_pointer_locked_handler_t locked,
locked_pointer_unlocked_handler_t unlocked);
void
window_set_pointer_confined_handler(struct window *window,
confined_pointer_confined_handler_t confined,
confined_pointer_unconfined_handler_t unconfined);
void
window_set_locked_pointer_motion_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 +461,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 +482,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);
@ -659,57 +525,10 @@ void
widget_set_axis_handler(struct widget *widget, widget_set_axis_handler(struct widget *widget,
widget_axis_handler_t handler); widget_axis_handler_t handler);
void void
widget_set_pointer_frame_handler(struct widget *widget,
widget_pointer_frame_handler_t handler);
void
widget_set_axis_handlers(struct widget *widget,
widget_axis_handler_t axis_handler,
widget_axis_source_handler_t axis_source_handler,
widget_axis_stop_handler_t axis_stop_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
window_inhibit_redraw(struct window *window);
void
window_uninhibit_redraw(struct window *window);
void
widget_schedule_redraw(struct widget *widget); 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,42 +634,4 @@ 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;
typedef void (*toytimer_cb)(struct toytimer *);
struct toytimer {
struct display *display;
struct task tsk;
int fd;
toytimer_cb callback;
};
void
toytimer_init(struct toytimer *tt, clockid_t clock, struct display *display,
toytimer_cb callback);
void
toytimer_fini(struct toytimer *tt);
void
toytimer_arm(struct toytimer *tt, const struct itimerspec *its);
void
toytimer_arm_once_usec(struct toytimer *tt, uint32_t usec);
void
toytimer_disarm(struct toytimer *tt);
#endif #endif

148
clients/wscreensaver-glue.c Normal file
View file

@ -0,0 +1,148 @@
/*
* Copyright © 2011 Collabora, Ltd.
*
* 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 "wscreensaver-glue.h"
double frand(double f)
{
double r = random();
return r * f / (double)RAND_MAX;
}
void clear_gl_error(void)
{
while (glGetError() != GL_NO_ERROR)
;
}
void check_gl_error(const char *msg)
{
const char *emsg;
int err = glGetError();
switch (err)
{
case GL_NO_ERROR:
return;
#define ERR(tok) case tok: emsg = #tok; break;
ERR(GL_INVALID_ENUM)
ERR(GL_INVALID_VALUE)
ERR(GL_INVALID_OPERATION)
ERR(GL_STACK_OVERFLOW)
ERR(GL_STACK_UNDERFLOW)
ERR(GL_OUT_OF_MEMORY)
#undef ERR
default:
fprintf(stderr, "%s: %s: unknown GL error 0x%04x\n",
progname, msg, err);
exit(1);
}
fprintf(stderr, "%s: %s: GL error %s\n", progname, msg, emsg);
exit(1);
}
static void
read_xpm_color(uint32_t *ctable, const char *line)
{
unsigned char key;
char cstr[10];
char *end;
uint32_t value;
if (sscanf(line, "%1c c %9s", &key, cstr) < 2) {
fprintf(stderr, "%s: error in XPM color definition '%s'\n",
progname, line);
return;
}
value = strtol(&cstr[1], &end, 16);
if (strcmp(cstr, "None") == 0)
ctable[key] = 0x00000000;
else if (cstr[0] != '#' || !(cstr[1] != '\0' && *end == '\0')) {
fprintf(stderr, "%s: error interpreting XPM color '%s'\n",
progname, cstr);
return;
} else {
ctable[key] = value | 0xff000000;
}
}
static void
read_xpm_row(char *data, const char *line, uint32_t *ctable, int width)
{
uint32_t *pixel = (uint32_t *)data;
uint8_t *p = (uint8_t *)line;
int i;
for (i = 0; i < width; ++i)
pixel[i] = ctable[p[i]];
}
XImage *xpm_to_ximage(char **xpm_data)
{
XImage *xi;
int colors;
int cpp;
int i;
uint32_t ctable[256] = { 0 };
xi = malloc(sizeof *xi);
if (!xi)
return NULL;
xi->data = NULL;
if (sscanf(xpm_data[0], "%d %d %d %d", &xi->width,
&xi->height, &colors, &cpp) < 4)
goto errout;
if (xi->width < 1 || xi->height < 1 || cpp != 1)
goto errout;
xi->bytes_per_line = xi->width * sizeof(uint32_t);
xi->data = malloc(xi->height * xi->bytes_per_line);
if (!xi->data)
goto errout;
for (i = 0; i < colors; ++i)
read_xpm_color(ctable, xpm_data[i + 1]);
for (i = 0; i < xi->height; ++i)
read_xpm_row(xi->data + i * xi->bytes_per_line,
xpm_data[i + colors + 1], ctable, xi->width);
return xi;
errout:
fprintf(stderr, "%s: error processing XPM data.\n", progname);
XDestroyImage(xi);
return NULL;
}
void XDestroyImage(XImage *xi)
{
free(xi->data);
free(xi);
}

120
clients/wscreensaver-glue.h Normal file
View file

@ -0,0 +1,120 @@
/*
* Copyright © 2011 Collabora, Ltd.
*
* 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.
*/
#ifndef WSCREENSAVER_GLUE_H
#define WSCREENSAVER_GLUE_H
/*
* This file is glue, that tries to avoid changing glmatrix.c from the
* original too much, hopefully easing the porting of other (GL)
* xscreensaver "hacks".
*/
#include "wscreensaver.h"
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <math.h>
#include <assert.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include "window.h"
#define ENTRYPOINT static
typedef bool Bool;
#define True true
#define False false
typedef struct ModeInfo ModeInfo;
#define MI_DISPLAY(mi) NULL
#define MI_WINDOW(mi) (mi)
#define MI_SCREEN(mi) ((mi)->instance_number)
#define MI_WIDTH(mi) ((mi)->width)
#define MI_HEIGHT(mi) ((mi)->height)
#define MI_IS_WIREFRAME(mi) 0
#define MI_NUM_SCREENS(mi) 16
typedef EGLContext GLXContext;
double frand(double f);
void clear_gl_error(void);
void check_gl_error(const char *msg);
static inline void
glXMakeCurrent(void *dummy, ModeInfo *mi, EGLContext ctx)
{
assert(mi->eglctx == ctx);
}
static inline void
glXSwapBuffers(void *dummy, ModeInfo *mi)
{
mi->swap_buffers = 1;
}
static inline void
do_fps(ModeInfo *mi)
{
}
/* just enough XImage to satisfy glmatrix.c */
typedef struct _XImage {
int width;
int height;
char *data;
int bytes_per_line;
} XImage;
XImage *xpm_to_ximage(char **xpm_data);
void XDestroyImage(XImage *xi);
static inline unsigned long
XGetPixel(XImage *xi, int x, int y)
{
return *(uint32_t *)(xi->data + xi->bytes_per_line * y + 4 * x);
}
static inline void
XPutPixel(XImage *xi, int x, int y, unsigned long pixel)
{
*(uint32_t *)(xi->data + xi->bytes_per_line * y + 4 * x) = pixel;
}
/*
* override glViewport from the plugin, so we can set it up properly
* rendering to a regular decorated Wayland window.
*/
#ifdef glViewport
#undef glViewport
#endif
#define glViewport(x,y,w,h) do {} while (0)
#endif /* WSCREENSAVER_GLUE_H */

348
clients/wscreensaver.c Normal file
View file

@ -0,0 +1,348 @@
/*
* Copyright © 2011 Collabora, Ltd.
*
* 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 "wscreensaver.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <GL/gl.h>
#include <EGL/eglext.h>
#include <wayland-client.h>
#include "desktop-shell-client-protocol.h"
#include "window.h"
extern struct wscreensaver_plugin glmatrix_screensaver;
static const struct wscreensaver_plugin * const plugins[] = {
&glmatrix_screensaver,
NULL
};
const char *progname = NULL;
static int demo_mode;
struct wscreensaver {
struct screensaver *interface;
struct display *display;
struct ModeInfo *demomode;
struct {
EGLDisplay display;
EGLConfig config;
} egl;
const struct wscreensaver_plugin *plugin;
};
static void
frame_callback(void *data, struct wl_callback *callback, uint32_t time)
{
struct ModeInfo *mi = data;
window_schedule_redraw(mi->window);
wl_callback_destroy(callback);
}
static const struct wl_callback_listener listener = {
frame_callback
};
static void
redraw_handler(struct widget *widget, void *data)
{
struct ModeInfo *mi = data;
struct wscreensaver *wscr = mi->priv;
struct rectangle drawarea;
struct rectangle winarea;
struct wl_callback *callback;
int bottom;
mi->swap_buffers = 0;
widget_get_allocation(mi->widget, &drawarea);
window_get_allocation(mi->window, &winarea);
if (display_acquire_window_surface(wscr->display,
mi->window,
mi->eglctx) < 0) {
fprintf(stderr, "%s: unable to acquire window surface",
progname);
return;
}
bottom = winarea.height - (drawarea.height + drawarea.y);
glViewport(drawarea.x, bottom, drawarea.width, drawarea.height);
glScissor(drawarea.x, bottom, drawarea.width, drawarea.height);
glEnable(GL_SCISSOR_TEST);
if (mi->width != drawarea.width || mi->height != drawarea.height) {
mi->width = drawarea.width;
mi->height = drawarea.height;
wscr->plugin->reshape(mi, mi->width, mi->height);
}
wscr->plugin->draw(mi);
if (mi->swap_buffers == 0)
fprintf(stderr, "%s: swapBuffers not called\n", progname);
display_release_window_surface(wscr->display, mi->window);
callback = wl_surface_frame(window_get_wl_surface(mi->window));
wl_callback_add_listener(callback, &listener, mi);
}
static void
init_frand(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
srandom(tv.tv_sec * 100 + tv.tv_usec / 10000);
}
WL_EXPORT EGLContext *
init_GL(struct ModeInfo *mi)
{
struct wscreensaver *wscr = mi->priv;
EGLContext *pctx;
pctx = malloc(sizeof *pctx);
if (!pctx)
return NULL;
if (mi->eglctx != EGL_NO_CONTEXT) {
fprintf(stderr, "%s: multiple GL contexts are not supported",
progname);
goto errout;
}
mi->eglctx = eglCreateContext(wscr->egl.display, wscr->egl.config,
EGL_NO_CONTEXT, NULL);
if (mi->eglctx == EGL_NO_CONTEXT) {
fprintf(stderr, "%s: init_GL failed to create EGL context\n",
progname);
goto errout;
}
if (!eglMakeCurrent(wscr->egl.display, NULL, NULL, mi->eglctx)) {
fprintf(stderr, "%s: init_GL failed on eglMakeCurrent\n",
progname);
goto errout;
}
glClearColor(0.0, 0.0, 0.0, 1.0);
*pctx = mi->eglctx;
return pctx;
errout:
free(pctx);
return NULL;
}
static struct ModeInfo *
create_wscreensaver_instance(struct wscreensaver *screensaver,
struct wl_output *output, int width, int height)
{
static int instance;
struct ModeInfo *mi;
struct rectangle drawarea;
mi = calloc(1, sizeof *mi);
if (!mi)
return NULL;
if (demo_mode)
mi->window = window_create(screensaver->display);
else
mi->window = window_create_custom(screensaver->display);
if (!mi->window) {
fprintf(stderr, "%s: creating a window failed.\n", progname);
free(mi);
return NULL;
}
window_set_title(mi->window, progname);
if (screensaver->interface && !demo_mode) {
mi->widget = window_add_widget(mi->window, mi);
screensaver_set_surface(screensaver->interface,
window_get_wl_surface(mi->window),
output);
} else {
mi->widget = window_frame_create(mi->window, mi);
}
widget_set_redraw_handler(mi->widget, redraw_handler);
mi->priv = screensaver;
mi->eglctx = EGL_NO_CONTEXT;
mi->instance_number = instance++; /* XXX */
widget_get_allocation(mi->widget, &drawarea);
mi->width = drawarea.width;
mi->height = drawarea.height;
screensaver->plugin->init(mi);
window_schedule_resize(mi->window, width, height);
return mi;
}
static void
handle_output_destroy(struct output *output, void *data)
{
/* struct ModeInfo *mi = data;
* TODO */
}
static void
handle_output_configure(struct output *output, void *data)
{
struct wscreensaver *screensaver = data;
struct ModeInfo *mi;
struct rectangle area;
/* skip existing outputs */
if (output_get_user_data(output))
return;
output_get_allocation(output, &area);
mi = create_wscreensaver_instance(screensaver,
output_get_wl_output(output),
area.width, area.height);
output_set_user_data(output, mi);
output_set_destroy_handler(output, handle_output_destroy);
}
static int
init_wscreensaver(struct wscreensaver *wscr, struct display *display)
{
int size;
const char prefix[] = "wscreensaver::";
char *str;
display_set_user_data(display, wscr);
wscr->display = display;
wscr->plugin = plugins[0];
size = sizeof(prefix) + strlen(wscr->plugin->name);
str = malloc(size);
if (!str) {
fprintf(stderr, "init: out of memory\n");
return -1;
}
snprintf(str, size, "%s%s", prefix, wscr->plugin->name);
progname = str;
wscr->egl.display = display_get_egl_display(wscr->display);
if (!wscr->egl.display) {
fprintf(stderr, "init: no EGL display\n");
return -1;
}
eglBindAPI(EGL_OPENGL_API);
wscr->egl.config = display_get_argb_egl_config(wscr->display);
if (demo_mode) {
struct wl_output *o =
output_get_wl_output(display_get_output(display));
/* only one instance */
wscr->demomode =
create_wscreensaver_instance(wscr, o, 400, 300);
return 0;
}
display_set_output_configure_handler(display, handle_output_configure);
return 0;
}
static void
global_handler(struct display *display, uint32_t name,
const char *interface, uint32_t version, void *data)
{
struct wscreensaver *screensaver = data;
if (!strcmp(interface, "screensaver")) {
screensaver->interface =
display_bind(display, name, &screensaver_interface, 1);
}
}
static const struct weston_option wscreensaver_options[] = {
{ WESTON_OPTION_BOOLEAN, "demo", 0, &demo_mode },
};
int main(int argc, char *argv[])
{
struct display *d;
struct wscreensaver screensaver = { 0 };
init_frand();
if (parse_options(wscreensaver_options,
ARRAY_LENGTH(wscreensaver_options), &argc, argv) > 1) {
printf("Usage: %s [OPTIONS]\n --demo for demo mode\n",
argv[0]);
exit(1);
}
d = display_create(&argc, argv);
if (d == NULL) {
fprintf(stderr, "failed to create display: %m\n");
return EXIT_FAILURE;
}
if (!demo_mode) {
/* iterates already known globals immediately */
display_set_user_data(d, &screensaver);
display_set_global_handler(d, global_handler);
if (!screensaver.interface) {
fprintf(stderr,
"Server did not offer screensaver interface,"
" exiting.\n");
return EXIT_FAILURE;
}
}
if (init_wscreensaver(&screensaver, d) < 0) {
fprintf(stderr, "wscreensaver init failed.\n");
return EXIT_FAILURE;
}
display_run(d);
free((void *)progname);
return EXIT_SUCCESS;
}

63
clients/wscreensaver.h Normal file
View file

@ -0,0 +1,63 @@
/*
* Copyright © 2011 Collabora, Ltd.
*
* 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.
*/
#ifndef WSCREENSAVER_H
#define WSCREENSAVER_H
#include "config.h"
#define MESA_EGL_NO_X11_HEADERS
#include <EGL/egl.h>
extern const char *progname;
struct wscreensaver;
struct ModeInfo {
struct wscreensaver *priv;
EGLContext eglctx;
int swap_buffers;
struct window *window;
struct widget *widget;
int instance_number;
int width;
int height;
unsigned long polygon_count;
int fps_p;
};
struct wscreensaver_plugin {
const char *name;
void (*init)(struct ModeInfo *mi);
void (*draw)(struct ModeInfo *mi);
void (*reshape)(struct ModeInfo *mi, int w, int h);
/* void (*refresh)(struct ModeInfo *mi);
void (*finish)(struct ModeInfo *mi);*/
};
EGLContext *
init_GL(struct ModeInfo *mi);
#endif /* WSCREENSAVER_H */

559
configure.ac Normal file
View file

@ -0,0 +1,559 @@
m4_define([weston_major_version], [1])
m4_define([weston_minor_version], [7])
m4_define([weston_micro_version], [92])
m4_define([weston_version],
[weston_major_version.weston_minor_version.weston_micro_version])
AC_PREREQ([2.64])
AC_INIT([weston],
[weston_version],
[https://bugs.freedesktop.org/enter_bug.cgi?product=Wayland&component=weston&version=weston_version],
[weston],
[http://wayland.freedesktop.org])
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_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
AC_USE_SYSTEM_EXTENSIONS
AC_SYS_LARGEFILE
AM_INIT_AUTOMAKE([1.11 parallel-tests foreign no-dist-gzip dist-xz color-tests subdir-objects])
AM_SILENT_RULES([yes])
# Check for programs
AC_PROG_CC
AC_PROG_SED
# Initialize libtool
LT_PREREQ([2.2])
LT_INIT([disable-static])
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()
AC_CHECK_FUNC([dlopen], [],
AC_CHECK_LIB([dl], [dlopen], DLOPEN_LIBS="-ldl"))
AC_SUBST(DLOPEN_LIBS)
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_HEADERS([execinfo.h])
AC_CHECK_FUNCS([mkostemp strchrnul initgroups posix_fallocate])
COMPOSITOR_MODULES="wayland-server >= 1.7.92 pixman-1 >= 0.25.2"
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 >= 7.10 glesv2])
PKG_CHECK_MODULES([EGL_TESTS], [egl >= 7.10 glesv2 wayland-client wayland-egl])
fi
AC_ARG_ENABLE(xkbcommon,
AS_HELP_STRING([--disable-xkbcommon], [Disable libxkbcommon
support: This is only useful in environments
where you do not have a hardware keyboard. If
libxkbcommon support is disabled clients will not
be sent a keymap and and must know how to
interpret the keycode sent for any key event.]),,
enable_xkbcommon=yes)
if test x$enable_xkbcommon = xyes; then
AC_DEFINE(ENABLE_XKBCOMMON, [1], [Build Weston with libxkbcommon support])
COMPOSITOR_MODULES="$COMPOSITOR_MODULES xkbcommon >= 0.3.0"
fi
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 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
PKG_CHECK_MODULES(LIBDRM, [libdrm],
[AC_DEFINE(HAVE_LIBDRM, 1, [Define if libdrm is available]) have_libdrm=yes], have_libdrm=no)
AC_ARG_ENABLE(x11-compositor, [ --enable-x11-compositor],,
enable_x11_compositor=yes)
AM_CONDITIONAL(ENABLE_X11_COMPOSITOR, test x$enable_x11_compositor = xyes)
if test x$enable_x11_compositor = xyes; then
PKG_CHECK_MODULES([XCB], xcb)
xcb_save_LIBS=$LIBS
xcb_save_CFLAGS=$CFLAGS
CFLAGS=$XCB_CFLAGS
LIBS=$XCB_LIBS
AC_CHECK_FUNCS([xcb_poll_for_queued_event])
LIBS=$xcb_save_LIBS
CFLAGS=$xcb_save_CFLAGS
X11_COMPOSITOR_MODULES="x11 x11-xcb xcb-shm"
PKG_CHECK_MODULES(X11_COMPOSITOR_XKB, [xcb-xkb],
[have_xcb_xkb="yes"], [have_xcb_xkb="no"])
if test "x$have_xcb_xkb" = xyes; then
# Most versions of XCB have totally broken XKB bindings, where the
# events don't work. Make sure we can actually use them.
xcb_xkb_save_CFLAGS=$CFLAGS
CFLAGS=$X11_COMPOSITOR_XKB_CFLAGS
AC_CHECK_MEMBER([struct xcb_xkb_state_notify_event_t.xkbType],
[], [have_xcb_xkb=no], [[#include <xcb/xkb.h>]])
CFLAGS=$xcb_xkb_save_CFLAGS
fi
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 mtdev >= 1.1.0])
fi
PKG_CHECK_MODULES(LIBINPUT_BACKEND, [libinput >= 0.8.0])
PKG_CHECK_MODULES(COMPOSITOR, [$COMPOSITOR_MODULES])
AC_ARG_ENABLE(wayland-compositor, [ --enable-wayland-compositor],,
enable_wayland_compositor=yes)
AM_CONDITIONAL(ENABLE_WAYLAND_COMPOSITOR,
test x$enable_wayland_compositor = xyes -a x$enable_egl = xyes)
if test x$enable_wayland_compositor = xyes -a x$enable_egl = xyes; then
AC_DEFINE([BUILD_WAYLAND_COMPOSITOR], [1],
[Build the Wayland (nested) compositor])
PKG_CHECK_MODULES(WAYLAND_COMPOSITOR, [wayland-client >= 1.5.91 wayland-egl wayland-cursor])
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(rpi-compositor,
AS_HELP_STRING([--disable-rpi-compositor],
[do not build the Raspberry Pi backend]),,
enable_rpi_compositor=yes)
AM_CONDITIONAL(ENABLE_RPI_COMPOSITOR, test "x$enable_rpi_compositor" = "xyes")
have_bcm_host="no"
if test "x$enable_rpi_compositor" = "xyes"; then
AC_DEFINE([BUILD_RPI_COMPOSITOR], [1], [Build the compositor for Raspberry Pi])
PKG_CHECK_MODULES(RPI_COMPOSITOR, [libudev >= 136 mtdev >= 1.1.0])
PKG_CHECK_MODULES(RPI_BCM_HOST, [bcm_host],
[have_bcm_host="yes"
AC_DEFINE([HAVE_BCM_HOST], [1], [have Raspberry Pi BCM headers])],
[AC_MSG_WARN([Raspberry Pi BCM host libraries not found, will use stubs instead.])])
fi
AM_CONDITIONAL(INSTALL_RPI_COMPOSITOR, test "x$have_bcm_host" = "xyes")
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 mtdev >= 1.1.0])
])
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, [freerdp >= 1.1.0])
SAVED_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $RDP_COMPOSITOR_CFLAGS"
AC_CHECK_HEADERS([freerdp/version.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"
else
if test "x$with_cairo" = "xglesv2"; then
cairo_modules="cairo-glesv2"
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])
PKG_CHECK_MODULES(WEBP, [libwebp], [have_webp=yes], [have_webp=no])
AS_IF([test "x$have_webp" = "xyes"],
[AC_DEFINE([HAVE_WEBP], [1], [Have webp])])
AC_ARG_ENABLE(vaapi-recorder, [ --enable-vaapi-recorder],,
enable_vaapi_recorder=auto)
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)
AC_CHECK_LIB([jpeg], [jpeg_CreateDecompress], have_jpeglib=yes)
if test x$have_jpeglib = xyes; then
JPEG_LIBS="-ljpeg"
else
AC_ERROR([libjpeg not found])
fi
AC_SUBST(JPEG_LIBS)
PKG_CHECK_MODULES(CAIRO, [cairo])
PKG_CHECK_MODULES(TEST_CLIENT, [wayland-client >= 1.7.92])
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 >= 7.10 glesv2 wayland-client wayland-egl wayland-cursor])
fi
AC_ARG_ENABLE(clients, [ --enable-clients],, enable_clients=yes)
AM_CONDITIONAL(BUILD_CLIENTS, test x$enable_clients = xyes)
if test x$enable_clients = xyes; then
AC_DEFINE([BUILD_CLIENTS], [1], [Build the Wayland clients])
PKG_CHECK_MODULES(CLIENT, [wayland-client >= 1.5.91 cairo >= 1.10.0 xkbcommon wayland-cursor])
PKG_CHECK_MODULES(SERVER, [wayland-server])
PKG_CHECK_MODULES(WESTON_INFO, [wayland-client >= 1.5.91])
# 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 >= 7.10 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], [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])])
PKG_CHECK_MODULES(SYSTEMD_LOGIN, [libsystemd-login >= 198],
[have_systemd_login=yes], [have_systemd_login=no])
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")
PKG_CHECK_MODULES(SYSTEMD_LOGIN_209, [libsystemd-login >= 209],
[have_systemd_login_209=yes], [have_systemd_login_209=no])
AS_IF([test "x$have_systemd_login_209" = "xyes"],
[AC_DEFINE([HAVE_SYSTEMD_LOGIN_209], [1], [Have systemd-login >= 209])])
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
AC_CHECK_LIB([pam], [pam_open_session], [have_pam=yes], [have_pam=no])
if test x$have_pam == xno; then
AC_ERROR([weston-launch requires pam])
fi
PAM_LIBS=-lpam
AC_SUBST(PAM_LIBS)
fi
if test x$enable_egl = xyes; then
PKG_CHECK_MODULES(GLU, [glu], [have_glu=yes], [have_glu=no])
fi
AM_CONDITIONAL(HAVE_GLU, test "x$have_glu" = "xyes")
AM_CONDITIONAL(HAVE_PANGO, test "x$have_pango" = "xyes")
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)
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)
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")
# 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-missing-field-initializers -g -fvisibility=hidden \
-Wstrict-prototypes -Wmissing-prototypes -Wsign-compare"
fi
AC_SUBST(GCC_CFLAGS)
AC_ARG_ENABLE(libunwind,
AS_HELP_STRING([--disable-libunwind],
[Disable libunwind usage for backtraces]),,
enable_libunwind=auto)
AM_CONDITIONAL(HAVE_LIBUNWIND, [test "x$enable_libunwind" = xyes])
if test "x$enable_libunwind" != "xno"; then
PKG_CHECK_MODULES(LIBUNWIND,
libunwind,
have_libunwind=yes,
have_libunwind=no)
if test "x$have_libunwind" = "xno" -a "x$enable_libunwind" = "xyes"; then
AC_MSG_ERROR([libunwind support explicitly requested, but libunwind couldn't be found])
fi
if test "x$have_libunwind" = "xyes"; then
enable_libunwind=yes
AC_DEFINE(HAVE_LIBUNWIND, 1, [Have libunwind support])
fi
fi
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"])
PKG_CHECK_MODULES(LCMS, lcms2,
[have_lcms=yes], [have_lcms=no])
if test "x$have_lcms" = xyes; then
AC_DEFINE(HAVE_LCMS, 1, [Have lcms support])
fi
AM_CONDITIONAL(HAVE_LCMS, [test "x$have_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_CONFIG_FILES([Makefile src/version.h src/weston.pc])
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}
libxkbcommon ${enable_xkbcommon}
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}
weston-launch utility ${enable_weston_launch}
systemd-login support ${have_systemd_login}
DRM Compositor ${enable_drm_compositor}
X11 Compositor ${enable_x11_compositor}
Wayland Compositor ${enable_wayland_compositor}
Headless Compositor ${enable_headless_compositor}
RPI Compositor ${enable_rpi_compositor}
FBDEV Compositor ${enable_fbdev_compositor}
RDP Compositor ${enable_rdp_compositor}
Screen Sharing ${enable_screen_sharing}
Raspberry Pi BCM headers ${have_bcm_host}
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}
GLU Support ${have_glu}
LCMS2 Support ${have_lcms}
libwebp Support ${have_webp}
libunwind Support ${have_libunwind}
VA H.264 encoding Support ${have_libva}
])

View file

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

View file

@ -33,24 +33,5 @@ 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
For the SVG icons:
© 2016 Samsung Electronics Co., Ltd
This work is dual-licenced under both the MIT "Expat" License and the
Creative Commons Attribution-Share Alike 3.0 United States License, and
may be redistributed under either (or both) licenses as desired. See
Weston's COPYING for details of the MIT license. To view a copy of the
CC-SA-3.0 licence, visit http://creativecommons.org/licenses/by-sa/3.0/
or send a letter to Creative Commons, 171 Second Street, Suite 300, San
Francisco, California 94105, USA.
icons.svg
icon_terminal.png
icon_editor.png
icon_flower.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 B

After

Width:  |  Height:  |  Size: 161 B

File diff suppressed because it is too large Load diff

Before

Width:  |  Height:  |  Size: 47 KiB

View file

@ -1,30 +0,0 @@
install_data(
[
'background.png',
'border.png',
'fullscreen.png',
'home.png',
'icon_editor.png',
'icon_flower.png',
'icon_ivi_clickdot.png',
'icon_ivi_flower.png',
'icon_ivi_simple-egl.png',
'icon_ivi_simple-egl-vertical.png',
'icon_ivi_simple-shm.png',
'icon_ivi_smoke.png',
'icon_terminal.png',
'icon_window.png',
'panel.png',
'pattern.png',
'random.png',
'sidebyside.png',
'sign_close.png',
'sign_maximize.png',
'sign_minimize.png',
'terminal.png',
'tiling.png',
'wayland.png',
'wayland.svg',
],
install_dir: dir_data / 'weston'
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 825 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 B

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 B

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

After

Width:  |  Height:  |  Size: 191 B

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