pax_global_header00006660000000000000000000000064146623776730014537gustar00rootroot0000000000000052 comment=a9fec8dd65977c57f4039ced34327204d9b9d779 wayland-1.23.1/000077500000000000000000000000001466237767300132625ustar00rootroot00000000000000wayland-1.23.1/.editorconfig000066400000000000000000000005211466237767300157350ustar00rootroot00000000000000root = 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 = tab indent_size = 2 tab_width = 8 [*.py] indent_style = space indent_size = 4 [*.yml] indent_style = space indent_size = 2 max_line_length = off wayland-1.23.1/.gitignore000066400000000000000000000000721466237767300152510ustar00rootroot00000000000000*.announce *.sig *.swp *.log *.tar.xz *~ cscope.out ctags wayland-1.23.1/.gitlab-ci.yml000066400000000000000000000240231466237767300157170ustar00rootroot00000000000000# This file uses the freedesktop ci-templates to build Wayland and run our # tests in CI. # # ci-templates uses a multi-stage build process. First, the base container # image is built which contains the core distribution, the toolchain, and # all our build dependencies. This container is aggressively cached; if a # container image matching $FDO_DISTRIBUTION_TAG is found in either the # upstream repo (wayland/weston) or the user's downstream repo, it is # reused for the build. This gives us predictability of build and far # quicker runtimes, however it means that any changes to the base container # must also change $FDO_DISTRIBUTION_TAG. When changing this, please use # the current date as well as a unique build identifier. # # After the container is either rebuilt (tag mismatch) or reused (tag # previously used), the build stage executes within this container. # # The final stage is used to expose documentation and coverage information, # including publishing documentation to the public site when built on the # main branch. # # Apart from the 'variables', 'include', and 'stages' top-level anchors, # everything not beginning with a dot ('.') is the name of a job which will # be executed as part of CI, unless the rules specify that it should not be # run. # # Variables prefixed with CI_ are generally provided by GitLab itself; # variables prefixed with FDO_ and templates prefixed by .fdo are provided # by the ci-templates. # # For more information on GitLab CI, including the YAML syntax, see: # https://docs.gitlab.com/ee/ci/yaml/README.html # # Note that freedesktop.org uses the 'Community Edition' of GitLab, so features # marked as 'premium' or 'ultimate' are not available to us. # # For more information on ci-templates, see: # - documentation at https://freedesktop.pages.freedesktop.org/ci-templates/ # - repo at https://gitlab.freedesktop.org/freedesktop/ci-templates/ include: - project: 'freedesktop/ci-templates' # Here we use a fixed ref in order to isolate ourselves from ci-templates # API changes. If you need new features from ci-templates you must bump # this to the current SHA you require from the ci-templates repo, however # be aware that you may need to account for API changes when doing so. ref: b791bd48996e3ced9ca13f1c5ee82be8540b8adb file: - '/templates/debian.yml' - '/templates/freebsd.yml' - '/templates/ci-fairy.yml' variables: FDO_UPSTREAM_REPO: wayland/wayland FDO_REPO_SUFFIX: "$BUILD_OS/$BUILD_ARCH" # Define the build stages. These are used for UI grouping as well as # dependencies. stages: - "Merge request checks" - "Base container" - "Build and test" - "Other build configurations" .ci-rules: rules: - when: on_success # Base variables used for anything using a Debian environment .os-debian: variables: BUILD_OS: debian FDO_DISTRIBUTION_VERSION: bookworm FDO_DISTRIBUTION_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build' FDO_DISTRIBUTION_EXEC: 'pip3 install --break-system-packages meson~=0.57.2' # bump this tag every time you change something which requires rebuilding the # base image FDO_DISTRIBUTION_TAG: "2024-03-28.2" .debian-x86_64: extends: - .os-debian variables: BUILD_ARCH: "x86-64" .debian-aarch64: extends: - .os-debian variables: BUILD_ARCH: "aarch64" .debian-armv7: extends: - .os-debian variables: BUILD_ARCH: "armv7" # Does not inherit .ci-rules as we only want it to run in MR context. check-commit: extends: - .fdo.ci-fairy stage: "Merge request checks" rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' when: always - when: never script: - ci-fairy check-commits --signed-off-by --junit-xml=results.xml variables: GIT_DEPTH: 100 artifacts: reports: junit: results.xml # Build our base container image, which contains the core distribution, the # toolchain, and all our build dependencies. This will be reused in the build # stage. x86_64-debian-container_prep: extends: - .ci-rules - .debian-x86_64 - .fdo.container-build@debian stage: "Base container" variables: GIT_STRATEGY: none aarch64-debian-container_prep: extends: - .ci-rules - .debian-aarch64 - .fdo.container-build@debian tags: - aarch64 stage: "Base container" variables: GIT_STRATEGY: none armv7-debian-container_prep: extends: - .ci-rules - .debian-armv7 - .fdo.container-build@debian tags: - aarch64 stage: "Base container" variables: GIT_STRATEGY: none FDO_BASE_IMAGE: "arm32v7/debian:$FDO_DISTRIBUTION_VERSION" # Core build environment. .build-env: variables: MESON_BUILD_TYPE: "-Dbuildtype=debug -Doptimization=0 -Db_sanitize=address,undefined" # See https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/154 ASAN_OPTIONS: "detect_odr_violation=0" before_script: - export BUILD_ID="wayland-$CI_JOB_NAME" - export PREFIX="${CI_PROJECT_DIR}/prefix-${BUILD_ID}" - export BUILDDIR="${CI_PROJECT_DIR}/build-${BUILD_ID}" - mkdir "$BUILDDIR" "$PREFIX" # Build variants to be stacked on as required. .build-release: stage: "Other build configurations" variables: MESON_BUILD_TYPE: "-Dbuildtype=release" # OS/architecture-specific variants .build-env-debian-x86_64: extends: - .fdo.suffixed-image@debian - .debian-x86_64 - .build-env needs: - job: x86_64-debian-container_prep artifacts: false .build-env-debian-aarch64: extends: - .fdo.suffixed-image@debian - .debian-aarch64 - .build-env variables: # At least with the versions we have, the LSan runtime makes fork unusably # slow on AArch64, which is bad news since the test suite decides to fork # for every single subtest. For now, in order to get AArch64 builds and # tests into CI, just assume that we're not going to leak any more on # AArch64 than we would on ARMv7 or x86-64. ASAN_OPTIONS: "detect_leaks=0,detect_odr_violation=0" tags: - aarch64 needs: - job: aarch64-debian-container_prep artifacts: false .build-env-debian-armv7: extends: - .fdo.suffixed-image@debian - .debian-armv7 - .build-env tags: - aarch64 needs: - job: armv7-debian-container_prep artifacts: false # Full build and test. .do-build: extends: - .ci-rules stage: "Build and test" script: - cd "$BUILDDIR" - meson --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons --fatal-meson-warnings -Dwerror=true ${MESON_BUILD_TYPE} .. - ninja -k0 -j${FDO_CI_CONCURRENT:-4} - meson test --num-processes ${FDO_CI_CONCURRENT:-4} - ninja clean artifacts: name: wayland-$CI_JOB_NAME when: always paths: - build-*/meson-logs - prefix-* reports: junit: build-*/meson-logs/testlog.junit.xml # Full build and test. .do-build-qemu: extends: - .ci-rules stage: "Build and test" script: # Start the VM and copy our workspace to the VM - /app/vmctl start - scp -r $PWD "vm:" # The `set +e is needed to ensure that we always copy the meson logs back to # the workspace to see details about the failed tests. - | set +e /app/vmctl exec "pkg info; cd $CI_PROJECT_NAME ; meson $BUILDDIR --prefix=$PREFIX $MESON_BUILD_TYPE $MESON_ARGS && ninja -C $BUILDDIR -j${FDO_CI_CONCURRENT:-4}" /app/vmctl exec "meson test --print-errorlogs -C $BUILDDIR --num-processes ${FDO_CI_CONCURRENT:-4}" && touch .tests-successful set -ex scp -r vm:$BUILDDIR/meson-logs . /app/vmctl exec "ninja -C $BUILDDIR install" mkdir -p $PREFIX && scp -r vm:$PREFIX/ $PREFIX/ # Finally, shut down the VM. - /app/vmctl stop - test -f .tests-successful || exit 1 artifacts: name: wayland-$CI_JOB_NAME when: always paths: - meson-logs - prefix-* reports: junit: meson-logs/testlog.junit.xml # Full build and test. x86_64-debian-build: extends: - .build-env-debian-x86_64 - .do-build x86_64-release-debian-build: extends: - .build-env-debian-x86_64 - .do-build - .build-release aarch64-debian-build: extends: - .build-env-debian-aarch64 - .do-build aarch64-release-debian-build: extends: - .build-env-debian-aarch64 - .do-build - .build-release armv7-debian-build: extends: - .build-env-debian-armv7 - .do-build armv7-release-debian-build: extends: - .build-env-debian-armv7 - .do-build - .build-release # Base variables used for anything using a FreeBSD environment .os-freebsd: variables: BUILD_OS: freebsd FDO_DISTRIBUTION_VERSION: "13.2" FDO_DISTRIBUTION_PACKAGES: 'libxslt meson ninja pkgconf expat libffi libepoll-shim libxml2' # bump this tag every time you change something which requires rebuilding the # base image FDO_DISTRIBUTION_TAG: "2023-08-02.0" # Don't build documentation since installing the required tools massively # increases the VM image (and therefore container) size. MESON_ARGS: "--fatal-meson-warnings -Dwerror=true -Ddocumentation=false" .freebsd-x86_64: extends: - .os-freebsd variables: BUILD_ARCH: "x86_64" x86_64-freebsd-container_prep: extends: - .ci-rules - .freebsd-x86_64 - .fdo.qemu-build@freebsd@x86_64 stage: "Base container" variables: GIT_STRATEGY: none .build-env-freebsd-x86_64: variables: # Compiling with ASan+UBSan appears to trigger an infinite loop in the # compiler shipped with FreeBSD 13.0, so we only use UBSan here. # Additionally, sanitizers can't be used with b_lundef on FreeBSD. MESON_BUILD_TYPE: "-Dbuildtype=debug -Db_sanitize=undefined -Db_lundef=false" extends: - .fdo.suffixed-image@freebsd - .freebsd-x86_64 - .build-env needs: - job: x86_64-freebsd-container_prep artifacts: false # Full build and test. x86_64-freebsd-build: extends: - .build-env-freebsd-x86_64 - .do-build-qemu x86_64-release-freebsd-build: extends: - .build-env-freebsd-x86_64 - .do-build-qemu - .build-release wayland-1.23.1/.gitlab/000077500000000000000000000000001466237767300146025ustar00rootroot00000000000000wayland-1.23.1/.gitlab/issue_templates/000077500000000000000000000000001466237767300200105ustar00rootroot00000000000000wayland-1.23.1/.gitlab/issue_templates/default.md000066400000000000000000000004501466237767300217550ustar00rootroot00000000000000 wayland-1.23.1/.mailmap000066400000000000000000000003001466237767300146740ustar00rootroot00000000000000Faith Ekstrand Faith Ekstrand Faith Ekstrand wayland-1.23.1/.triage-policies.yml000066400000000000000000000026411466237767300171460ustar00rootroot00000000000000# This is a set of bugbot commands for issues and merge requests - setting any of the # bugbot::foo labels will trigger gitlab-triage to run with this ruleset (well, the # one we have on the main branch at the time) # # Note that for adding labels, the label must first created in the project. resource_rules: issues: rules: - name: "Close bugs that aren't Wayland bugs" conditions: labels: - "bugbot::not-wayland" actions: remove_labels: - "bugbot::not-wayland" comment: | Thank you for the report, but your issue does not look like it would belong here. Sorry. This repository is for the Wayland protocol specification and the low-level C library that deals with the protocol. This issue here is a bug not with the protocol itself but with either - your compositor or desktop environment's implementation of the Wayland protocol and surrounding functionality, - the individual application that triggers this issue, or - the kernel driver used by your hardware Please file the issue against your compositor/desktop environment, the application or the kernel drivers instead, whichever seems more likely to you. If you are not sure, file an issue against the application. status: "close" merge_requests: rules: [] wayland-1.23.1/CONTRIBUTING.md000066400000000000000000000324301466237767300155150ustar00rootroot00000000000000Contributing to Wayland ======================= Sending patches --------------- Patches should be sent via [GitLab merge requests](https://docs.gitlab.com/ce/gitlab-basics/add-merge-request.html). Wayland is [hosted on freedesktop.org's GitLab](https://gitlab.freedesktop.org/wayland/wayland/): in order to submit code, you should create an account on this GitLab instance, fork the core Wayland repository, push your changes to a branch in your new repository, and then submit these patches for review through a merge request. Wayland 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/). Some old patches continue to be sent this way, and we may accept small new patches sent to the list, but please send all new patches through GitLab merge requests. Formatting and separating commits --------------------------------- Unlike many projects using GitHub and GitLab, Wayland 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: connection: plug a fd leak plug another fd leak connection: init fds to -1 close all fds refactor checks into a new function don't close fds we handed out we aim to have a clean history which only reflects the final state, broken up into functional groupings: connection: Refactor out closure allocation connection: Clear fds we shouldn't close to -1 connection: Make wl_closure_destroy() close fds of undispatched closures 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: protocol: Support scaled outputs and surfaces and doc: generate server documentation from XML too 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 should also include a Signed-off-by line with your name and email address. If you're not the patch's original author, you should also gather S-o-b's by them (and/or whomever gave the patch to you.) 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. We won't reject patches that lack S-o-b, but it is strongly recommended. 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 Wayland 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 elsewhere 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 implemented 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); ``` 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 ========= Wayland 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, Wayland 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 wayland-1.23.1/COPYING000066400000000000000000000024741466237767300143240ustar00rootroot00000000000000Copyright © 2008-2012 Kristian Høgsberg Copyright © 2010-2012 Intel Corporation Copyright © 2011 Benjamin Franzke Copyright © 2012 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. --- The above is the version of the MIT "Expat" License used by X.org: http://cgit.freedesktop.org/xorg/xserver/tree/COPYING wayland-1.23.1/README.md000066400000000000000000000025431466237767300145450ustar00rootroot00000000000000# Wayland Wayland is a project to define a protocol for a compositor to talk to its clients as well as a library implementation of the protocol. The compositor can be a standalone display server running on Linux kernel modesetting and evdev input devices, an X application, or a wayland client itself. The clients can be traditional applications, X servers (rootless or fullscreen) or other display servers. The wayland protocol is essentially only about input handling and buffer management. The compositor receives input events and forwards them to the relevant client. The clients creates buffers and renders into them and notifies the compositor when it needs to redraw. The protocol also handles drag and drop, selections, window management and other interactions that must go through the compositor. However, the protocol does not handle rendering, which is one of the features that makes wayland so simple. All clients are expected to handle rendering themselves, typically through cairo or OpenGL. Building the wayland libraries is fairly simple, aside from libffi, they don't have many dependencies: $ git clone https://gitlab.freedesktop.org/wayland/wayland $ cd wayland $ meson build/ --prefix=PREFIX $ ninja -C build/ install where PREFIX is where you want to install the libraries. See https://wayland.freedesktop.org for documentation. wayland-1.23.1/cursor/000077500000000000000000000000001466237767300145775ustar00rootroot00000000000000wayland-1.23.1/cursor/convert_font.c000066400000000000000000000326231466237767300174570ustar00rootroot00000000000000/* * Copyright © 2012 Philipp Brüschweiler * * 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. */ /* * This is a small, hacky tool to extract cursors from a .pcf file. * The information about the file format has been gathered from * http://fontforge.org/pcf-format.html */ #include #include #include #include #include #include #include #include #include #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) struct glyph { char *name; int16_t left_bearing, right_bearing, ascent, descent; int16_t width, height; int16_t hotx, hoty; int32_t data_format; char *data; }; static struct { int count; struct glyph *glyphs; } extracted_font = {0, NULL}; #define PCF_PROPERTIES (1<<0) #define PCF_ACCELERATORS (1<<1) #define PCF_METRICS (1<<2) #define PCF_BITMAPS (1<<3) #define PCF_INK_METRICS (1<<4) #define PCF_BDF_ENCODINGS (1<<5) #define PCF_SWIDTHS (1<<6) #define PCF_GLYPH_NAMES (1<<7) #define PCF_BDF_ACCELERATORS (1<<8) #define PCF_DEFAULT_FORMAT 0x00000000 #define PCF_INKBOUNDS 0x00000200 #define PCF_ACCEL_W_INKBOUNDS 0x00000100 #define PCF_COMPRESSED_METRICS 0x00000100 #define PCF_FORMAT_MASK 0xffffff00 struct pcf_header { char header[4]; int32_t table_count; struct toc_entry { int32_t type; int32_t format; int32_t size; int32_t offset; } tables[0]; }; struct compressed_metrics { uint8_t left_sided_bearing; uint8_t right_side_bearing; uint8_t character_width; uint8_t character_ascent; uint8_t character_descent; }; struct uncompressed_metrics { int16_t left_sided_bearing; int16_t right_side_bearing; int16_t character_width; int16_t character_ascent; int16_t character_descent; uint16_t character_attributes; }; struct metrics { int32_t format; union { struct { int16_t count; struct compressed_metrics compressed_metrics[0]; } compressed; struct { int32_t count; struct uncompressed_metrics uncompressed_metrics[0]; } uncompressed; }; }; struct glyph_names { int32_t format; int32_t glyph_count; int32_t offsets[0]; }; struct bitmaps { int32_t format; int32_t glyph_count; int32_t offsets[0]; }; static void handle_compressed_metrics(int32_t count, struct compressed_metrics *m) { printf("metrics count: %d\n", count); extracted_font.count = count; extracted_font.glyphs = calloc(count, sizeof(struct glyph)); int i; for (i = 0; i < count; ++i) { struct glyph *glyph = &extracted_font.glyphs[i]; glyph->left_bearing = ((int16_t) m[i].left_sided_bearing) - 0x80; glyph->right_bearing = ((int16_t) m[i].right_side_bearing) - 0x80; glyph->width = ((int16_t) m[i].character_width) - 0x80; glyph->ascent = ((int16_t) m[i].character_ascent) - 0x80; glyph->descent = ((int16_t) m[i].character_descent) - 0x80; /* computed stuff */ glyph->height = glyph->ascent + glyph->descent; glyph->hotx = -glyph->left_bearing; glyph->hoty = glyph->ascent; } } static void handle_metrics(void *metricbuf) { struct metrics *metrics = metricbuf; printf("metric format: %x\n", metrics->format); if ((metrics->format & PCF_FORMAT_MASK) == PCF_DEFAULT_FORMAT) { printf("todo...\n"); } else if ((metrics->format & PCF_FORMAT_MASK) == PCF_COMPRESSED_METRICS) { handle_compressed_metrics( metrics->compressed.count, &metrics->compressed.compressed_metrics[0]); } else { printf("incompatible format\n"); abort(); } } static void handle_glyph_names(struct glyph_names *names) { printf("glyph count %d\n", names->glyph_count); if (names->glyph_count != extracted_font.count) { abort(); } printf("glyph names format %x\n", names->format); void *names_start = ((void*) names) + sizeof(struct glyph_names) + (names->glyph_count + 1) * sizeof(int32_t); int i; for (i = 0; i < names->glyph_count; ++i) { int32_t start = names->offsets[i]; int32_t end = names->offsets[i+1]; char *name = names_start + start; extracted_font.glyphs[i].name = calloc(1, end - start + 1); memcpy(extracted_font.glyphs[i].name, name, end - start); } } static void handle_bitmaps(struct bitmaps *bitmaps) { printf("bitmaps count %d\n", bitmaps->glyph_count); if (bitmaps->glyph_count != extracted_font.count) { abort(); } printf("format %x\n", bitmaps->format); if (bitmaps->format != 2) { printf("format not yet supported\n"); abort(); } void *bitmaps_start = ((void*) bitmaps) + sizeof(struct bitmaps) + (bitmaps->glyph_count + 4) * sizeof(int32_t); int i; for (i = 0; i < bitmaps->glyph_count; ++i) { int32_t offset = bitmaps->offsets[i]; struct glyph *glyph = &extracted_font.glyphs[i]; glyph->data_format = bitmaps->format; glyph->data = bitmaps_start + offset; } } static void handle_pcf(void *fontbuf) { struct pcf_header *header = fontbuf; printf("tablecount %d\n", header->table_count); int i; for (i = 0; i < header->table_count; ++i) { struct toc_entry *entry = &header->tables[i]; printf("type: %d\n", entry->type); if (entry->type == PCF_METRICS) { handle_metrics(fontbuf + entry->offset); } else if (entry->type == PCF_GLYPH_NAMES) { handle_glyph_names(fontbuf + entry->offset); } else if (entry->type == PCF_BITMAPS) { handle_bitmaps(fontbuf + entry->offset); } } } static char get_glyph_pixel(struct glyph *glyph, int x, int y) { int absx = glyph->hotx + x; int absy = glyph->hoty + y; if (absx < 0 || absx >= glyph->width || absy < 0 || absy >= glyph->height) return 0; int stride = (glyph->width + 31) / 32 * 4; unsigned char block = glyph->data[absy * stride + (absx/8)]; int idx = absx % 8; return (block >> idx) & 1; } static struct { uint32_t *data; size_t capacity, size; } data_buffer; static void init_data_buffer() { data_buffer.data = malloc(sizeof(uint32_t) * 10); data_buffer.capacity = 10; data_buffer.size = 0; } static void add_pixel(uint32_t pixel) { if (data_buffer.size == data_buffer.capacity) { data_buffer.capacity *= 2; data_buffer.data = realloc(data_buffer.data, sizeof(uint32_t) * data_buffer.capacity); } data_buffer.data[data_buffer.size++] = pixel; } struct reconstructed_glyph { int32_t width, height; int32_t hotspot_x, hotspot_y; size_t offset; char *name; }; static void reconstruct_glyph(struct glyph *cursor, struct glyph *mask, char *name, struct reconstructed_glyph *glyph) { int minx = min(-cursor->hotx, -mask->hotx); int maxx = max(cursor->right_bearing, mask->right_bearing); int miny = min(-cursor->hoty, -mask->hoty); int maxy = max(cursor->height - cursor->hoty, mask->height - mask->hoty); int width = maxx - minx; int height = maxy - miny; glyph->name = strdup(name); glyph->width = width; glyph->height = height; glyph->hotspot_x = -minx; glyph->hotspot_y = -miny; glyph->offset = data_buffer.size; int x, y; for (y = miny; y < maxy; ++y) { for (x = minx; x < maxx; ++x) { char alpha = get_glyph_pixel(mask, x, y); if (alpha) { char color = get_glyph_pixel(cursor, x, y); if (color) add_pixel(0xff000000); else add_pixel(0xffffffff); } else { add_pixel(0); } } } } /* * Originally from * http://cgit.freedesktop.org/xorg/lib/libXfont/tree/src/builtins/fonts.c * Changed to the MIT "Expat" style license for Wayland.. */ static const char cursor_licence[] = "/*\n" "* Copyright 1999 SuSE, Inc.\n" "*\n" "* Permission is hereby granted, free of charge, to any person obtaining\n" "* a copy of this software and associated documentation files (the\n" "* \"Software\"), to deal in the Software without restriction, including\n" "* without limitation the rights to use, copy, modify, merge, publish,\n" "* distribute, sublicense, and/or sell copies of the Software, and to\n" "* permit persons to whom the Software is furnished to do so, subject to\n" "* the following conditions:\n" "*\n" "* The above copyright notice and this permission notice (including the\n" "* next paragraph) shall be included in all copies or substantial\n" "* portions of the Software.\n" "*\n" "* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n" "* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n" "* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n" "* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n" "* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n" "* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n" "* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n" "* SOFTWARE.\n" "*\n" "* Author: Keith Packard, SuSE, Inc.\n" "*/\n"; static void write_output_file(struct reconstructed_glyph *glyphs, int n) { int i, j, counter, size; FILE *file = fopen("cursor-data.h", "w"); uint32_t *data; fprintf(file, "%s\n", cursor_licence); fprintf(file, "static uint32_t cursor_data[] = {\n\t"); counter = 0; for (i = 0; i < n; ++i) { data = data_buffer.data + glyphs[i].offset; size = glyphs[i].width * glyphs[i].height; for (j = 0; j < size; ++j) { fprintf(file, "0x%08x, ", data[j]); if (++counter % 6 == 0) fprintf(file, "\n\t"); } } fprintf(file, "\n};\n\n"); fprintf(file, "static struct {\n" "\tchar *name;\n" "\tint width, height;\n" "\tint hotspot_x, hotspot_y;\n" "\tsize_t offset;\n" "} cursor_metadata[] = {\n"); for (i = 0; i < n; ++i) fprintf(file, "\t{ \"%s\", %d, %d, %d, %d, %zu },\n", glyphs[i].name, glyphs[i].width, glyphs[i].height, glyphs[i].hotspot_x, glyphs[i].hotspot_y, glyphs[i].offset); fprintf(file, "};"); fclose(file); } struct glyph * find_mask_glyph(char *name) { const char mask[] = "_mask"; const int masklen = strlen(mask); int len = strlen(name); int i; for (i = 0; i < extracted_font.count; ++i) { struct glyph *g = &extracted_font.glyphs[i]; int l2 = strlen(g->name); if ((l2 == len + masklen) && (memcmp(g->name, name, len) == 0) && (memcmp(g->name + len, mask, masklen) == 0)) { return g; } } return NULL; } static void output_all_cursors() { int i, j; struct reconstructed_glyph *glyphs = malloc(sizeof(struct reconstructed_glyph) * extracted_font.count/2); j = 0; for (i = 0; i < extracted_font.count; ++i) { struct glyph *g = &extracted_font.glyphs[i]; if (strstr(g->name, "_mask")) continue; struct glyph *mask = find_mask_glyph(g->name); reconstruct_glyph(g, mask, g->name, &glyphs[j]); j++; } write_output_file(glyphs, extracted_font.count/2); } static void find_cursor_and_mask(const char *name, struct glyph **cursor, struct glyph **mask) { int i; char mask_name[100]; sprintf(mask_name, "%s_mask", name); *cursor = *mask = NULL; for (i = 0; i < extracted_font.count && (!*mask || !*cursor); ++i) { struct glyph *g = &extracted_font.glyphs[i]; if (!strcmp(name, g->name)) *cursor = g; else if (!strcmp(mask_name, g->name)) *mask = g; } } static struct { char *target_name, *source_name; } interesting_cursors[] = { { "bottom_left_corner", "bottom_left_corner" }, { "bottom_right_corner", "bottom_right_corner" }, { "bottom_side", "bottom_side" }, { "grabbing", "fleur" }, { "left_ptr", "left_ptr" }, { "left_side", "left_side" }, { "right_side", "right_side" }, { "top_left_corner", "top_left_corner" }, { "top_right_corner", "top_right_corner" }, { "top_side", "top_side" }, { "xterm", "xterm" }, { "hand1", "hand1" }, { "watch", "watch" } }; static void output_interesting_cursors() { int i; int n = sizeof(interesting_cursors) / sizeof(interesting_cursors[0]); struct reconstructed_glyph *glyphs = malloc(n * sizeof(*glyphs)); if (!glyphs) { printf("reconstructed_glyph malloc failed\n"); abort(); } for (i = 0; i < n; ++i) { struct glyph *cursor, *mask; find_cursor_and_mask(interesting_cursors[i].source_name, &cursor, &mask); if (!cursor) { printf("no cursor for %s\n", interesting_cursors[i].source_name); abort(); } if (!mask) { printf("no mask for %s\n", interesting_cursors[i].source_name); abort(); } reconstruct_glyph(cursor, mask, interesting_cursors[i].target_name, &glyphs[i]); } write_output_file(glyphs, n); } int main() { const char filename[] = "cursor.pcf"; int fd = open(filename, O_RDONLY); struct stat filestat; fstat(fd, &filestat); void *fontbuf = mmap(NULL, filestat.st_size, PROT_READ, MAP_PRIVATE, fd, 0); handle_pcf(fontbuf); init_data_buffer(); //output_all_cursors(); output_interesting_cursors(); } wayland-1.23.1/cursor/cursor-data.h000066400000000000000000001141571466237767300172050ustar00rootroot00000000000000/* * Copyright 1999 SuSE, Inc. * * 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. * * Author: Keith Packard, SuSE, Inc. */ #include static uint32_t cursor_data[] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }; static struct cursor_metadata { char *name; int width, height; int hotspot_x, hotspot_y; size_t offset; } cursor_metadata[] = { { "bottom_left_corner", 16, 16, 1, 14, 0 }, { "bottom_right_corner", 16, 16, 14, 14, 256 }, { "bottom_side", 15, 16, 7, 14, 512 }, { "grabbing", 16, 16, 8, 8, 752 }, { "left_ptr", 10, 16, 1, 1, 1008 }, { "left_side", 16, 15, 1, 7, 1168 }, { "right_side", 16, 15, 14, 7, 1408 }, { "top_left_corner", 16, 16, 1, 1, 1648 }, { "top_right_corner", 16, 16, 14, 1, 1904 }, { "top_side", 15, 16, 7, 1, 2160 }, { "xterm", 9, 16, 4, 8, 2400 }, { "hand1", 13, 16, 12, 0, 2544 }, { "watch", 16, 16, 15, 9, 2752 }, /* https://www.freedesktop.org/wiki/Specifications/cursor-spec/ */ { "sw-resize", 16, 16, 1, 14, 0 }, { "se-resize", 16, 16, 14, 14, 256 }, { "s-resize", 15, 16, 7, 14, 512 }, { "all-scroll", 16, 16, 8, 8, 752 }, { "default", 10, 16, 1, 1, 1008 }, { "w-resize", 16, 15, 1, 7, 1168 }, { "e-resize", 16, 15, 14, 7, 1408 }, { "nw-resize", 16, 16, 1, 1, 1648 }, { "ne-resize", 16, 16, 14, 1, 1904 }, { "n-resize", 15, 16, 7, 1, 2160 }, { "text", 9, 16, 4, 8, 2400 }, { "pointer", 13, 16, 12, 0, 2544 }, { "wait", 16, 16, 15, 9, 2752 }, }; wayland-1.23.1/cursor/cursor.pcf000066400000000000000000000336001466237767300166100ustar00rootroot00000000000000fcpdl$ D)@p* h-dP7  *65:A HkSN`Nmv COPYRIGHTThese "glyphs" are unencumberedPOINT_SIZEFONTcursorWEIGHTRESOLUTIONRESOLUTION_XRESOLUTION_YX_HEIGHTQUAD_WIDTH zysr}|}|rrzysrzyyxxx|{yxzzyyyyyyyyyy{zzy{zrrrrzyzyyxrr~~ttzzxxyxxxwvrrxx||vuyy|{|{yxsrwvxxzyzx}|yyqq}|}|vuyxzzwvyyyyzysrzyyx}|yxwvqq}|8xHp\ L\L LD8x 8 p , h D 8 x 8 x (`X@x8`(h ` `4lTL<|<x0p(h(hH4t$d< d !4!d!!!".\"D8<>>>><8????0<p8??|>Z<xxx<Z0xxxGDDDEEEEDDDG}}}}}}}}####c??08???00111 1@111000?? 8p@@@@@@DHP@??@_PWUTUUUTWP_@00xx3100008888????3$y$"14<??9wmofs?5557u|` XG@@@@XVUU[Y@@??@@@@@@@@@@@@B!EQJ)Th P@Ph TJ)EQB!f3m{ov7l_??_lv7{omf3@`PH DB!B!DH P`@9qq9xxaa???88999988???0x300003x0@0<@ `x~?@0< @ `x>?p8 aa ??37??>==>??73?? ??&$ >7#??80 ??;;  ? x???????88W<|?|)# ?~pp"0A @??|1`@@@@`0  0`|?q```Cap88U    UU'39<??<93'???10``?C#?#C""??x@$ @ H ( <A~???"****"??0` lll``8x?1R^0 @? !aG| 9|00000000|x8((l8p < 00@00127210@000""???"""#""""?   ?www???>|||||||||||8 ?x?  ??   0880?x? ?? >8|||||||||||>>8|||||||8{{{{{{{{{{ >`pxxxx|~~0~<"""#$(0?ww ; ,?!'%'%''!!?  | | ~ @@@   `H $ ``08||f366<88 0`Ca`0 8<8pcp8<@@@@@@@@@@@@>00   ???8p??c####???80??00011@1 111100p8 @PHD@@@@@@??>w>]kIAAA88|| 2 LC@@@@@@@v??y0!0??ww|88888888|  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$BB (9O^rw (3CN^eqw  )6HTeq #-8HQ_ix (/;@JYmw&8O]p+0:AMT`o !*8AOU`fqX_cursorX_cursor_maskarrowarrow_maskbased_arrow_downbased_arrow_down_maskbased_arrow_upbased_arrow_up_maskboatboat_maskbogositybogosity_maskbottom_left_cornerbottom_left_corner_maskbottom_right_cornerbottom_right_corner_maskbottom_sidebottom_side_maskbottom_teebottom_tee_maskbox_spiralbox_spiral_maskcenter_ptrcenter_ptr_maskcirclecircle_maskclockclock_maskcoffee_mugcoffee_mug_maskcrosscross_maskcross_reversecross_reverse_maskcrosshaircrosshair_maskdiamond_crossdiamond_cross_maskdotdot_maskdotboxdotbox_maskdouble_arrowdouble_arrow_maskdraft_largedraft_large_maskdraft_smalldraft_small_maskdraped_boxdraped_box_maskexchangeexchange_maskfleurfleur_maskgobblergobbler_maskgumbygumby_maskhand1hand1_maskhand2hand2_maskheartheart_maskiconicon_maskiron_crossiron_cross_maskleft_ptrleft_ptr_maskleft_sideleft_side_maskleft_teeleft_tee_maskleftbuttonleftbutton_maskll_anglell_angle_masklr_anglelr_angle_maskmanman_maskmiddlebuttonmiddlebutton_maskmousemouse_maskpencilpencil_maskpiratepirate_maskplusplus_maskquestion_arrowquestion_arrow_maskright_ptrright_ptr_maskright_sideright_side_maskright_teeright_tee_maskrightbuttonrightbutton_maskrtl_logortl_logo_masksailboatsailboat_masksb_down_arrowsb_down_arrow_masksb_h_double_arrowsb_h_double_arrow_masksb_left_arrowsb_left_arrow_masksb_right_arrowsb_right_arrow_masksb_up_arrowsb_up_arrow_masksb_v_double_arrowsb_v_double_arrow_maskshuttleshuttle_masksizingsizing_maskspiderspider_maskspraycanspraycan_maskstarstar_masktargettarget_masktcrosstcross_masktop_left_arrowtop_left_arrow_masktop_left_cornertop_left_corner_masktop_right_cornertop_right_corner_masktop_sidetop_side_masktop_teetop_tee_masktrektrek_maskul_angleul_angle_maskumbrellaumbrella_maskur_angleur_angle_maskwatchwatch_maskxtermxterm_mask wayland-1.23.1/cursor/meson.build000066400000000000000000000026441466237767300167470ustar00rootroot00000000000000icondir = get_option('icon_directory') if icondir == '' icondir = join_paths(get_option('prefix'), get_option('datadir'), 'icons') endif if wayland_version[0] != '1' # The versioning used for the shared libraries assumes that the major # version of Wayland as a whole will increase to 2 if and only if there # is an ABI break, at which point we should probably bump the SONAME of # all libraries to .so.2. For more details see # https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/177 error('We probably need to bump the SONAME of libwayland-cursor') endif wayland_cursor = library( 'wayland-cursor', sources: [ 'wayland-cursor.c', 'os-compatibility.c', 'xcursor.c', ], # To avoid an unnecessary SONAME bump, wayland 1.x.y produces # libwayland-cursor.so.0.x.y. version: '.'.join(['0', wayland_version[1], wayland_version[2]]), dependencies: [ wayland_client_dep ], c_args: [ '-DICONDIR="@0@"'.format(icondir) ], install: true, ) install_headers('wayland-cursor.h') pkgconfig.generate( name: 'Wayland Cursor', description: 'Wayland cursor helper library', version: meson.project_version(), libraries: wayland_cursor, filebase: 'wayland-cursor', ) wayland_cursor_dep = declare_dependency( link_with: wayland_cursor, include_directories: [ root_inc, include_directories('.') ], ) if meson.version().version_compare('>= 0.54.0') meson.override_dependency('wayland-cursor', wayland_cursor_dep) endif wayland-1.23.1/cursor/os-compatibility.c000066400000000000000000000130301466237767300202300ustar00rootroot00000000000000/* * Copyright © 2012 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. */ #define _GNU_SOURCE #include "config.h" #include #include #include #include #include #include #include #include #ifdef HAVE_MEMFD_CREATE #include #endif /* Fallback to no flag when missing the definition */ #ifndef MFD_NOEXEC_SEAL #define MFD_NOEXEC_SEAL 0 #endif #include "os-compatibility.h" #ifndef HAVE_MKOSTEMP static int set_cloexec_or_close(int fd) { long flags; if (fd == -1) return -1; flags = fcntl(fd, F_GETFD); if (flags == -1) goto err; if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) goto err; return fd; err: close(fd); return -1; } #endif static int create_tmpfile_cloexec(char *tmpname) { int fd; #ifdef HAVE_MKOSTEMP fd = mkostemp(tmpname, O_CLOEXEC); if (fd >= 0) unlink(tmpname); #else fd = mkstemp(tmpname); if (fd >= 0) { fd = set_cloexec_or_close(fd); unlink(tmpname); } #endif return fd; } /* * Create a new, unique, anonymous file of the given size, and * return the file descriptor for it. The file descriptor is set * CLOEXEC. The file is immediately suitable for mmap()'ing * the given size at offset zero. * * The file should not have a permanent backing store like a disk, * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. * * The file name is deleted from the file system. * * The file is suitable for buffer sharing between processes by * transmitting the file descriptor over Unix sockets using the * SCM_RIGHTS methods. * * If the C library implements posix_fallocate(), it is used to * guarantee that disk space is available for the file at the * given size. If disk space is insufficient, errno is set to ENOSPC. * If posix_fallocate() is not supported, program may receive * SIGBUS on accessing mmap()'ed file contents instead. * * If the C library implements memfd_create(), it is used to create the * file purely in memory, without any backing file name on the file * system, and then sealing off the possibility of shrinking it. This * can then be checked before accessing mmap()'ed file contents, to * make sure SIGBUS can't happen. It also avoids requiring * XDG_RUNTIME_DIR. */ int os_create_anonymous_file(off_t size) { static const char template[] = "/wayland-cursor-shared-XXXXXX"; const char *path; char *name; size_t name_size; int fd; #ifdef HAVE_MEMFD_CREATE /* * Linux kernels older than 6.3 reject MFD_NOEXEC_SEAL with EINVAL. * Try first *with* it, and if that fails, try again *without* it. */ errno = 0; fd = memfd_create( "wayland-cursor", MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_NOEXEC_SEAL); if (fd < 0 && errno == EINVAL && MFD_NOEXEC_SEAL != 0) { fd = memfd_create( "wayland-cursor", MFD_CLOEXEC | MFD_ALLOW_SEALING); } if (fd >= 0) { /* We can add this seal before calling posix_fallocate(), as * the file is currently zero-sized anyway. * * There is also no need to check for the return value, we * couldn't do anything with it anyway. */ fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL); } else #endif { path = getenv("XDG_RUNTIME_DIR"); if (!path || path[0] != '/') { errno = ENOENT; return -1; } name_size = strlen(path) + sizeof(template); name = malloc(name_size); if (!name) return -1; snprintf(name, name_size, "%s%s", path, template); fd = create_tmpfile_cloexec(name); free(name); if (fd < 0) return -1; } if (os_resize_anonymous_file(fd, size) < 0) { close(fd); return -1; } return fd; } int os_resize_anonymous_file(int fd, off_t size) { #ifdef HAVE_POSIX_FALLOCATE sigset_t mask; sigset_t old_mask; /* * posix_fallocate() might be interrupted, so we need to check * for EINTR and retry in that case. * However, in the presence of an alarm, the interrupt may trigger * repeatedly and prevent a large posix_fallocate() to ever complete * successfully, so we need to first block SIGALRM to prevent * this. */ sigemptyset(&mask); sigaddset(&mask, SIGALRM); sigprocmask(SIG_BLOCK, &mask, &old_mask); /* * Filesystems that do not support fallocate will return EINVAL or * EOPNOTSUPP. In this case we need to fall back to ftruncate */ do { errno = posix_fallocate(fd, 0, size); } while (errno == EINTR); sigprocmask(SIG_SETMASK, &old_mask, NULL); if (errno == 0) return 0; else if (errno != EINVAL && errno != EOPNOTSUPP) return -1; #endif if (ftruncate(fd, size) < 0) return -1; return 0; } wayland-1.23.1/cursor/os-compatibility.h000066400000000000000000000025261466237767300202450ustar00rootroot00000000000000/* * Copyright © 2012 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. */ #ifndef OS_COMPATIBILITY_H #define OS_COMPATIBILITY_H #include int os_create_anonymous_file(off_t size); int os_resize_anonymous_file(int fd, off_t size); #endif /* OS_COMPATIBILITY_H */ wayland-1.23.1/cursor/wayland-cursor.c000066400000000000000000000275261466237767300177310ustar00rootroot00000000000000/* * Copyright © 2012 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 "xcursor.h" #include "wayland-cursor.h" #include "wayland-client.h" #include #include #include #include #include #include #include #include #include "os-compatibility.h" #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) struct shm_pool { struct wl_shm_pool *pool; int fd; unsigned int size; unsigned int used; char *data; }; static struct shm_pool * shm_pool_create(struct wl_shm *shm, int size) { struct shm_pool *pool; pool = malloc(sizeof *pool); if (!pool) return NULL; pool->fd = os_create_anonymous_file(size); if (pool->fd < 0) goto err_free; pool->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, pool->fd, 0); if (pool->data == MAP_FAILED) goto err_close; pool->pool = wl_shm_create_pool(shm, pool->fd, size); pool->size = size; pool->used = 0; return pool; err_close: close(pool->fd); err_free: free(pool); return NULL; } static int shm_pool_resize(struct shm_pool *pool, int size) { if (os_resize_anonymous_file(pool->fd, size) < 0) return 0; wl_shm_pool_resize(pool->pool, size); munmap(pool->data, pool->size); pool->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, pool->fd, 0); if (pool->data == MAP_FAILED) return 0; pool->size = size; return 1; } static int shm_pool_allocate(struct shm_pool *pool, int size) { int offset; if (pool->used + size > pool->size) if (!shm_pool_resize(pool, 2 * pool->size + size)) return -1; offset = pool->used; pool->used += size; return offset; } static void shm_pool_destroy(struct shm_pool *pool) { munmap(pool->data, pool->size); wl_shm_pool_destroy(pool->pool); close(pool->fd); free(pool); } struct wl_cursor_theme { unsigned int cursor_count; struct wl_cursor **cursors; struct wl_shm *shm; struct shm_pool *pool; int size; }; struct cursor_image { struct wl_cursor_image image; struct wl_cursor_theme *theme; struct wl_buffer *buffer; int offset; /* data offset of this image in the shm pool */ }; struct cursor { struct wl_cursor cursor; uint32_t total_delay; /* length of the animation in ms */ }; /** Get an shm buffer for a cursor image * * \param image The cursor image * \return An shm buffer for the cursor image. The user should not destroy * the returned buffer. */ WL_EXPORT struct wl_buffer * wl_cursor_image_get_buffer(struct wl_cursor_image *image) { struct cursor_image *img = (struct cursor_image *) image; struct wl_cursor_theme *theme = img->theme; if (!img->buffer) { img->buffer = wl_shm_pool_create_buffer(theme->pool->pool, img->offset, image->width, image->height, image->width * 4, WL_SHM_FORMAT_ARGB8888); }; return img->buffer; } static void wl_cursor_image_destroy(struct wl_cursor_image *image) { struct cursor_image *img = (struct cursor_image *) image; if (img->buffer) wl_buffer_destroy(img->buffer); free(img); } static void wl_cursor_destroy(struct wl_cursor *cursor) { unsigned int i; for (i = 0; i < cursor->image_count; i++) wl_cursor_image_destroy(cursor->images[i]); free(cursor->images); free(cursor->name); free(cursor); } #include "cursor-data.h" static struct wl_cursor * wl_cursor_create_from_data(struct cursor_metadata *metadata, struct wl_cursor_theme *theme) { struct cursor *cursor; struct cursor_image *image; int size; cursor = malloc(sizeof *cursor); if (!cursor) return NULL; cursor->cursor.image_count = 1; cursor->cursor.images = malloc(sizeof *cursor->cursor.images); if (!cursor->cursor.images) goto err_free_cursor; cursor->cursor.name = strdup(metadata->name); cursor->total_delay = 0; image = malloc(sizeof *image); if (!image) goto err_free_images; cursor->cursor.images[0] = (struct wl_cursor_image *) image; image->theme = theme; image->buffer = NULL; image->image.width = metadata->width; image->image.height = metadata->height; image->image.hotspot_x = metadata->hotspot_x; image->image.hotspot_y = metadata->hotspot_y; image->image.delay = 0; size = metadata->width * metadata->height * sizeof(uint32_t); image->offset = shm_pool_allocate(theme->pool, size); if (image->offset < 0) goto err_free_image; memcpy(theme->pool->data + image->offset, cursor_data + metadata->offset, size); return &cursor->cursor; err_free_image: free(image); err_free_images: free(cursor->cursor.name); free(cursor->cursor.images); err_free_cursor: free(cursor); return NULL; } static void load_fallback_theme(struct wl_cursor_theme *theme) { uint32_t i; theme->cursor_count = ARRAY_LENGTH(cursor_metadata); theme->cursors = malloc(theme->cursor_count * sizeof(*theme->cursors)); if (theme->cursors == NULL) { theme->cursor_count = 0; return; } for (i = 0; i < theme->cursor_count; ++i) { theme->cursors[i] = wl_cursor_create_from_data(&cursor_metadata[i], theme); if (theme->cursors[i] == NULL) break; } theme->cursor_count = i; } static struct wl_cursor * wl_cursor_create_from_xcursor_images(struct xcursor_images *images, struct wl_cursor_theme *theme) { struct cursor *cursor; struct cursor_image *image; int i, size; cursor = malloc(sizeof *cursor); if (!cursor) return NULL; cursor->cursor.images = malloc(images->nimage * sizeof cursor->cursor.images[0]); if (!cursor->cursor.images) { free(cursor); return NULL; } cursor->cursor.name = strdup(images->name); cursor->total_delay = 0; for (i = 0; i < images->nimage; i++) { image = malloc(sizeof *image); if (image == NULL) break; image->theme = theme; image->buffer = NULL; image->image.width = images->images[i]->width; image->image.height = images->images[i]->height; image->image.hotspot_x = images->images[i]->xhot; image->image.hotspot_y = images->images[i]->yhot; image->image.delay = images->images[i]->delay; size = image->image.width * image->image.height * 4; image->offset = shm_pool_allocate(theme->pool, size); if (image->offset < 0) { free(image); break; } /* copy pixels to shm pool */ memcpy(theme->pool->data + image->offset, images->images[i]->pixels, size); cursor->total_delay += image->image.delay; cursor->cursor.images[i] = (struct wl_cursor_image *) image; } cursor->cursor.image_count = i; if (cursor->cursor.image_count == 0) { free(cursor->cursor.name); free(cursor->cursor.images); free(cursor); return NULL; } return &cursor->cursor; } static void load_callback(struct xcursor_images *images, void *data) { struct wl_cursor_theme *theme = data; struct wl_cursor *cursor; if (wl_cursor_theme_get_cursor(theme, images->name)) { xcursor_images_destroy(images); return; } cursor = wl_cursor_create_from_xcursor_images(images, theme); if (cursor) { theme->cursor_count++; theme->cursors = realloc(theme->cursors, theme->cursor_count * sizeof theme->cursors[0]); if (theme->cursors == NULL) { theme->cursor_count--; free(cursor); } else { theme->cursors[theme->cursor_count - 1] = cursor; } } xcursor_images_destroy(images); } /** Load a cursor theme to memory shared with the compositor * * \param name The name of the cursor theme to load. If %NULL, the default * theme will be loaded. * \param size Desired size of the cursor images. * \param shm The compositor's shm interface. * * \return An object representing the theme that should be destroyed with * wl_cursor_theme_destroy() or %NULL on error. If no theme with the given * name exists, a default theme will be loaded. */ WL_EXPORT struct wl_cursor_theme * wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm) { struct wl_cursor_theme *theme; theme = malloc(sizeof *theme); if (!theme) return NULL; if (!name) name = "default"; theme->size = size; theme->cursor_count = 0; theme->cursors = NULL; theme->pool = shm_pool_create(shm, size * size * 4); if (!theme->pool) goto out_error_pool; xcursor_load_theme(name, size, load_callback, theme); if (theme->cursor_count == 0) xcursor_load_theme(NULL, size, load_callback, theme); if (theme->cursor_count == 0) load_fallback_theme(theme); return theme; out_error_pool: free(theme); return NULL; } /** Destroys a cursor theme object * * \param theme The cursor theme to be destroyed */ WL_EXPORT void wl_cursor_theme_destroy(struct wl_cursor_theme *theme) { unsigned int i; for (i = 0; i < theme->cursor_count; i++) wl_cursor_destroy(theme->cursors[i]); shm_pool_destroy(theme->pool); free(theme->cursors); free(theme); } /** Get the cursor for a given name from a cursor theme * * \param theme The cursor theme * \param name Name of the desired cursor * \return The theme's cursor of the given name or %NULL if there is no * such cursor */ WL_EXPORT struct wl_cursor * wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme, const char *name) { unsigned int i; for (i = 0; i < theme->cursor_count; i++) { if (strcmp(name, theme->cursors[i]->name) == 0) return theme->cursors[i]; } return NULL; } /** Find the frame for a given elapsed time in a cursor animation * as well as the time left until next cursor change. * * \param cursor The cursor * \param time Elapsed time in ms since the beginning of the animation * \param duration pointer to uint32_t to store time left for this image or * zero if the cursor won't change. * * \return The index of the image that should be displayed for the * given time in the cursor animation. */ WL_EXPORT int wl_cursor_frame_and_duration(struct wl_cursor *cursor, uint32_t time, uint32_t *duration) { struct cursor *cur = (struct cursor *) cursor; uint32_t t; int i; if (cur->cursor.image_count == 1 || cur->total_delay == 0) { if (duration) *duration = 0; return 0; } i = 0; t = time % cur->total_delay; /* If there is a 0 delay in the image set then this * loop breaks on it and we display that cursor until * time % cursor->total_delay wraps again. * Since a 0 delay is silly, and we've never actually * seen one in a cursor file, we haven't bothered to * "fix" this. */ while (t - cur->cursor.images[i]->delay < t) t -= cur->cursor.images[i++]->delay; if (!duration) return i; /* Make sure we don't accidentally tell the caller this is * a static cursor image. */ if (t >= cur->cursor.images[i]->delay) *duration = 1; else *duration = cur->cursor.images[i]->delay - t; return i; } /** Find the frame for a given elapsed time in a cursor animation * * \param cursor The cursor * \param time Elapsed time in ms since the beginning of the animation * * \return The index of the image that should be displayed for the * given time in the cursor animation. */ WL_EXPORT int wl_cursor_frame(struct wl_cursor *cursor, uint32_t time) { return wl_cursor_frame_and_duration(cursor, time, NULL); } wayland-1.23.1/cursor/wayland-cursor.h000066400000000000000000000051401466237767300177220ustar00rootroot00000000000000/* * Copyright © 2012 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. */ #ifndef WAYLAND_CURSOR_H #define WAYLAND_CURSOR_H #include #ifdef __cplusplus extern "C" { #endif struct wl_cursor_theme; struct wl_buffer; struct wl_shm; /** A still image part of a cursor * * Use `wl_cursor_image_get_buffer()` to get the corresponding `struct * wl_buffer` to attach to your `struct wl_surface`. */ struct wl_cursor_image { /** Actual width */ uint32_t width; /** Actual height */ uint32_t height; /** Hot spot x (must be inside image) */ uint32_t hotspot_x; /** Hot spot y (must be inside image) */ uint32_t hotspot_y; /** Animation delay to next frame (ms) */ uint32_t delay; }; /** A cursor, as returned by `wl_cursor_theme_get_cursor()` */ struct wl_cursor { /** How many images there are in this cursor’s animation */ unsigned int image_count; /** The array of still images composing this animation */ struct wl_cursor_image **images; /** The name of this cursor */ char *name; }; struct wl_cursor_theme * wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm); void wl_cursor_theme_destroy(struct wl_cursor_theme *theme); struct wl_cursor * wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme, const char *name); struct wl_buffer * wl_cursor_image_get_buffer(struct wl_cursor_image *image); int wl_cursor_frame(struct wl_cursor *cursor, uint32_t time); int wl_cursor_frame_and_duration(struct wl_cursor *cursor, uint32_t time, uint32_t *duration); #ifdef __cplusplus } #endif #endif wayland-1.23.1/cursor/xcursor.c000066400000000000000000000466121466237767300164610ustar00rootroot00000000000000/* * Copyright © 2002 Keith Packard * * 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. */ #define _GNU_SOURCE #include "xcursor.h" #include #include #include #include #include /* * Cursor files start with a header. The header * contains a magic number, a version number and a * table of contents which has type and offset information * for the remaining tables in the file. * * File minor versions increment for compatible changes * File major versions increment for incompatible changes (never, we hope) * * Chunks of the same type are always upward compatible. Incompatible * changes are made with new chunk types; the old data can remain under * the old type. Upward compatible changes can add header data as the * header lengths are specified in the file. * * File: * FileHeader * LISTofChunk * * FileHeader: * CARD32 magic magic number * CARD32 header bytes in file header * CARD32 version file version * CARD32 ntoc number of toc entries * LISTofFileToc toc table of contents * * FileToc: * CARD32 type entry type * CARD32 subtype entry subtype (size for images) * CARD32 position absolute file position */ #define XCURSOR_MAGIC 0x72756358 /* "Xcur" LSBFirst */ /* * This version number is stored in cursor files; changes to the * file format require updating this version number */ #define XCURSOR_FILE_MAJOR 1 #define XCURSOR_FILE_MINOR 0 #define XCURSOR_FILE_VERSION ((XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR)) #define XCURSOR_FILE_HEADER_LEN (4 * 4) #define XCURSOR_FILE_TOC_LEN (3 * 4) struct xcursor_file_toc { uint32_t type; /* chunk type */ uint32_t subtype; /* subtype (size for images) */ uint32_t position; /* absolute position in file */ }; struct xcursor_file_header { uint32_t magic; /* magic number */ uint32_t header; /* byte length of header */ uint32_t version; /* file version number */ uint32_t ntoc; /* number of toc entries */ struct xcursor_file_toc *tocs; /* table of contents */ }; /* * The rest of the file is a list of chunks, each tagged by type * and version. * * Chunk: * ChunkHeader * * * * ChunkHeader: * CARD32 header bytes in chunk header + type header * CARD32 type chunk type * CARD32 subtype chunk subtype * CARD32 version chunk type version */ #define XCURSOR_CHUNK_HEADER_LEN (4 * 4) struct xcursor_chunk_header { uint32_t header; /* bytes in chunk header */ uint32_t type; /* chunk type */ uint32_t subtype; /* chunk subtype (size for images) */ uint32_t version; /* version of this type */ }; /* * Each cursor image occupies a separate image chunk. * The length of the image header follows the chunk header * so that future versions can extend the header without * breaking older applications * * Image: * ChunkHeader header chunk header * CARD32 width actual width * CARD32 height actual height * CARD32 xhot hot spot x * CARD32 yhot hot spot y * CARD32 delay animation delay * LISTofCARD32 pixels ARGB pixels */ #define XCURSOR_IMAGE_TYPE 0xfffd0002 #define XCURSOR_IMAGE_VERSION 1 #define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5*4)) #define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */ /* * From libXcursor/src/file.c */ static struct xcursor_image * xcursor_image_create(int width, int height) { struct xcursor_image *image; if (width < 0 || height < 0) return NULL; if (width > XCURSOR_IMAGE_MAX_SIZE || height > XCURSOR_IMAGE_MAX_SIZE) return NULL; image = malloc(sizeof(struct xcursor_image) + width * height * sizeof(uint32_t)); if (!image) return NULL; image->version = XCURSOR_IMAGE_VERSION; image->pixels = (uint32_t *) (image + 1); image->size = width > height ? width : height; image->width = width; image->height = height; image->delay = 0; return image; } static void xcursor_image_destroy(struct xcursor_image *image) { free(image); } static struct xcursor_images * xcursor_images_create(int size) { struct xcursor_images *images; images = malloc(sizeof(struct xcursor_images) + size * sizeof(struct xcursor_image *)); if (!images) return NULL; images->nimage = 0; images->images = (struct xcursor_image **) (images + 1); images->name = NULL; return images; } void xcursor_images_destroy(struct xcursor_images *images) { int n; if (!images) return; for (n = 0; n < images->nimage; n++) xcursor_image_destroy(images->images[n]); free(images->name); free(images); } static bool xcursor_read_uint(FILE *file, uint32_t *u) { unsigned char bytes[4]; if (!file || !u) return false; if (fread(bytes, 1, 4, file) != 4) return false; *u = ((uint32_t)(bytes[0]) << 0) | ((uint32_t)(bytes[1]) << 8) | ((uint32_t)(bytes[2]) << 16) | ((uint32_t)(bytes[3]) << 24); return true; } static void xcursor_file_header_destroy(struct xcursor_file_header *file_header) { free(file_header); } static struct xcursor_file_header * xcursor_file_header_create(uint32_t ntoc) { struct xcursor_file_header *file_header; if (ntoc > 0x10000) return NULL; file_header = malloc(sizeof(struct xcursor_file_header) + ntoc * sizeof(struct xcursor_file_toc)); if (!file_header) return NULL; file_header->magic = XCURSOR_MAGIC; file_header->header = XCURSOR_FILE_HEADER_LEN; file_header->version = XCURSOR_FILE_VERSION; file_header->ntoc = ntoc; file_header->tocs = (struct xcursor_file_toc *) (file_header + 1); return file_header; } static struct xcursor_file_header * xcursor_read_file_header(FILE *file) { struct xcursor_file_header head, *file_header; uint32_t skip; unsigned int n; if (!file) return NULL; if (!xcursor_read_uint(file, &head.magic)) return NULL; if (head.magic != XCURSOR_MAGIC) return NULL; if (!xcursor_read_uint(file, &head.header)) return NULL; if (!xcursor_read_uint(file, &head.version)) return NULL; if (!xcursor_read_uint(file, &head.ntoc)) return NULL; skip = head.header - XCURSOR_FILE_HEADER_LEN; if (skip) if (fseek(file, skip, SEEK_CUR) == EOF) return NULL; file_header = xcursor_file_header_create(head.ntoc); if (!file_header) return NULL; file_header->magic = head.magic; file_header->header = head.header; file_header->version = head.version; file_header->ntoc = head.ntoc; for (n = 0; n < file_header->ntoc; n++) { if (!xcursor_read_uint(file, &file_header->tocs[n].type)) break; if (!xcursor_read_uint(file, &file_header->tocs[n].subtype)) break; if (!xcursor_read_uint(file, &file_header->tocs[n].position)) break; } if (n != file_header->ntoc) { xcursor_file_header_destroy(file_header); return NULL; } return file_header; } static bool xcursor_seek_to_toc(FILE *file, struct xcursor_file_header *file_header, int toc) { if (!file || !file_header || fseek(file, file_header->tocs[toc].position, SEEK_SET) == EOF) return false; return true; } static bool xcursor_file_read_chunk_header(FILE *file, struct xcursor_file_header *file_header, int toc, struct xcursor_chunk_header *chunk_header) { if (!file || !file_header || !chunk_header) return false; if (!xcursor_seek_to_toc(file, file_header, toc)) return false; if (!xcursor_read_uint(file, &chunk_header->header)) return false; if (!xcursor_read_uint(file, &chunk_header->type)) return false; if (!xcursor_read_uint(file, &chunk_header->subtype)) return false; if (!xcursor_read_uint(file, &chunk_header->version)) return false; /* sanity check */ if (chunk_header->type != file_header->tocs[toc].type || chunk_header->subtype != file_header->tocs[toc].subtype) return false; return true; } static uint32_t dist(uint32_t a, uint32_t b) { return a > b ? a - b : b - a; } static uint32_t xcursor_file_best_size(struct xcursor_file_header *file_header, uint32_t size, int *nsizesp) { unsigned int n; int nsizes = 0; uint32_t best_size = 0; uint32_t this_size; if (!file_header || !nsizesp) return 0; for (n = 0; n < file_header->ntoc; n++) { if (file_header->tocs[n].type != XCURSOR_IMAGE_TYPE) continue; this_size = file_header->tocs[n].subtype; if (!best_size || dist(this_size, size) < dist(best_size, size)) { best_size = this_size; nsizes = 1; } else if (this_size == best_size) { nsizes++; } } *nsizesp = nsizes; return best_size; } static int xcursor_find_image_toc(struct xcursor_file_header *file_header, uint32_t size, int count) { unsigned int toc; uint32_t this_size; if (!file_header) return 0; for (toc = 0; toc < file_header->ntoc; toc++) { if (file_header->tocs[toc].type != XCURSOR_IMAGE_TYPE) continue; this_size = file_header->tocs[toc].subtype; if (this_size != size) continue; if (!count) break; count--; } if (toc == file_header->ntoc) return -1; return toc; } static struct xcursor_image * xcursor_read_image(FILE *file, struct xcursor_file_header *file_header, int toc) { struct xcursor_chunk_header chunk_header; struct xcursor_image head; struct xcursor_image *image; int n; uint32_t *p; if (!file || !file_header) return NULL; if (!xcursor_file_read_chunk_header(file, file_header, toc, &chunk_header)) return NULL; if (!xcursor_read_uint(file, &head.width)) return NULL; if (!xcursor_read_uint(file, &head.height)) return NULL; if (!xcursor_read_uint(file, &head.xhot)) return NULL; if (!xcursor_read_uint(file, &head.yhot)) return NULL; if (!xcursor_read_uint(file, &head.delay)) return NULL; /* sanity check data */ if (head.width > XCURSOR_IMAGE_MAX_SIZE || head.height > XCURSOR_IMAGE_MAX_SIZE) return NULL; if (head.width == 0 || head.height == 0) return NULL; if (head.xhot > head.width || head.yhot > head.height) return NULL; /* Create the image and initialize it */ image = xcursor_image_create(head.width, head.height); if (image == NULL) return NULL; if (chunk_header.version < image->version) image->version = chunk_header.version; image->size = chunk_header.subtype; image->xhot = head.xhot; image->yhot = head.yhot; image->delay = head.delay; n = image->width * image->height; p = image->pixels; while (n--) { if (!xcursor_read_uint(file, p)) { xcursor_image_destroy(image); return NULL; } p++; } return image; } static struct xcursor_images * xcursor_xc_file_load_images(FILE *file, int size) { struct xcursor_file_header *file_header; uint32_t best_size; int nsize; struct xcursor_images *images; int n; int toc; if (!file || size < 0) return NULL; file_header = xcursor_read_file_header(file); if (!file_header) return NULL; best_size = xcursor_file_best_size(file_header, (uint32_t) size, &nsize); if (!best_size) { xcursor_file_header_destroy(file_header); return NULL; } images = xcursor_images_create(nsize); if (!images) { xcursor_file_header_destroy(file_header); return NULL; } for (n = 0; n < nsize; n++) { toc = xcursor_find_image_toc(file_header, best_size, n); if (toc < 0) break; images->images[images->nimage] = xcursor_read_image(file, file_header, toc); if (!images->images[images->nimage]) break; images->nimage++; } xcursor_file_header_destroy(file_header); if (images->nimage != nsize) { xcursor_images_destroy(images); images = NULL; } return images; } /* * From libXcursor/src/library.c */ #ifndef ICONDIR #define ICONDIR "/usr/X11R6/lib/X11/icons" #endif #ifndef XCURSORPATH #define XCURSORPATH "~/.icons:/usr/share/icons:/usr/share/pixmaps:~/.cursors:/usr/share/cursors/xorg-x11:"ICONDIR #endif #define XDG_DATA_HOME_FALLBACK "~/.local/share" #define CURSORDIR "/icons" /** Get search path for cursor themes * * This function builds the list of directories to look for cursor * themes in. The format is PATH-like: directories are separated by * colons. * * The memory block returned by this function is allocated on the heap * and must be freed by the caller. */ static char * xcursor_library_path(void) { const char *env_var, *suffix; char *path; size_t path_size; env_var = getenv("XCURSOR_PATH"); if (env_var) return strdup(env_var); env_var = getenv("XDG_DATA_HOME"); if (!env_var || env_var[0] != '/') env_var = XDG_DATA_HOME_FALLBACK; suffix = CURSORDIR ":" XCURSORPATH; path_size = strlen(env_var) + strlen(suffix) + 1; path = malloc(path_size); if (!path) return NULL; snprintf(path, path_size, "%s%s", env_var, suffix); return path; } static char * xcursor_build_theme_dir(const char *dir, const char *theme) { const char *colon; const char *tcolon; char *full; const char *home, *homesep; int dirlen; int homelen; int themelen; size_t full_size; if (!dir || !theme) return NULL; colon = strchr(dir, ':'); if (!colon) colon = dir + strlen(dir); dirlen = colon - dir; tcolon = strchr(theme, ':'); if (!tcolon) tcolon = theme + strlen(theme); themelen = tcolon - theme; home = ""; homelen = 0; homesep = ""; if (*dir == '~') { home = getenv("HOME"); if (!home) return NULL; homelen = strlen(home); homesep = "/"; dir++; dirlen--; } /* * add space for any needed directory separators, one per component, * and one for the trailing null */ full_size = 1 + homelen + 1 + dirlen + 1 + themelen + 1; full = malloc(full_size); if (!full) return NULL; snprintf(full, full_size, "%s%s%.*s/%.*s", home, homesep, dirlen, dir, themelen, theme); return full; } static char * xcursor_build_fullname(const char *dir, const char *subdir, const char *file) { char *full; size_t full_size; int ret; if (!dir || !subdir || !file) return NULL; full_size = strlen(dir) + 1 + strlen(subdir) + 1 + strlen(file) + 1; full = malloc(full_size); if (!full) return NULL; ret = snprintf(full, full_size, "%s/%s/%s", dir, subdir, file); if (ret < 0) { free(full); return NULL; } return full; } static const char * xcursor_next_path(const char *path) { char *colon = strchr(path, ':'); if (!colon) return NULL; return colon + 1; } static bool xcursor_white(char c) { return c == ' ' || c == '\t' || c == '\n'; } static bool xcursor_sep(char c) { return c == ';' || c == ','; } static char * xcursor_theme_inherits(const char *full) { char *line = NULL; size_t line_size = 0; char *result = NULL; FILE *f; if (!full) return NULL; f = fopen(full, "r"); if (!f) return NULL; while (getline(&line, &line_size, f) >= 0) { const char *l; char *r; if (strncmp(line, "Inherits", 8)) continue; l = line + 8; while (*l == ' ') l++; if (*l != '=') continue; l++; while (*l == ' ') l++; result = malloc(strlen(l) + 1); if (!result) break; r = result; while (*l) { while (xcursor_sep(*l) || xcursor_white(*l)) l++; if (!*l) break; if (r != result) *r++ = ':'; while (*l && !xcursor_white(*l) && !xcursor_sep(*l)) *r++ = *l++; } *r++ = '\0'; break; } fclose(f); free(line); return result; } static void load_all_cursors_from_dir(const char *path, int size, void (*load_callback)(struct xcursor_images *, void *), void *user_data) { FILE *f; DIR *dir = opendir(path); struct dirent *ent; char *full; struct xcursor_images *images; if (!dir) return; for (ent = readdir(dir); ent; ent = readdir(dir)) { #ifdef _DIRENT_HAVE_D_TYPE if (ent->d_type != DT_UNKNOWN && ent->d_type != DT_REG && ent->d_type != DT_LNK) continue; #endif full = xcursor_build_fullname(path, "", ent->d_name); if (!full) continue; f = fopen(full, "r"); if (!f) { free(full); continue; } images = xcursor_xc_file_load_images(f, size); if (images) { images->name = strdup(ent->d_name); load_callback(images, user_data); } fclose(f); free(full); } closedir(dir); } struct xcursor_nodelist { size_t nodelen; const char *node; struct xcursor_nodelist *next; }; static bool nodelist_contains(struct xcursor_nodelist *nodelist, const char *s, size_t ss) { struct xcursor_nodelist *vi; for (vi = nodelist; vi && vi->node; vi = vi->next) { if (vi->nodelen == ss && !strncmp(s, vi->node, vi->nodelen)) return true; } return false; } static void xcursor_load_theme_protected(const char *theme, int size, void (*load_callback)(struct xcursor_images *, void *), void *user_data, struct xcursor_nodelist *visited_nodes) { char *full, *dir; char *inherits = NULL; const char *path, *i; char *xcursor_path; size_t si; struct xcursor_nodelist current_node; if (!theme) theme = "default"; current_node.next = visited_nodes; current_node.node = theme; current_node.nodelen = strlen(theme); visited_nodes = ¤t_node; xcursor_path = xcursor_library_path(); for (path = xcursor_path; path; path = xcursor_next_path(path)) { dir = xcursor_build_theme_dir(path, theme); if (!dir) continue; full = xcursor_build_fullname(dir, "cursors", ""); load_all_cursors_from_dir(full, size, load_callback, user_data); free(full); if (!inherits) { full = xcursor_build_fullname(dir, "", "index.theme"); inherits = xcursor_theme_inherits(full); free(full); } free(dir); } for (i = inherits; i; i = xcursor_next_path(i)) { si = strlen(i); if (nodelist_contains(visited_nodes, i, si)) continue; xcursor_load_theme_protected(i, size, load_callback, user_data, visited_nodes); } free(inherits); free(xcursor_path); } /** Load all the cursor of a theme * * This function loads all the cursor images of a given theme and its * inherited themes. Each cursor is loaded into an struct xcursor_images object * which is passed to the caller's load callback. If a cursor appears * more than once across all the inherited themes, the load callback * will be called multiple times, with possibly different struct xcursor_images * object which have the same name. The user is expected to destroy the * struct xcursor_images objects passed to the callback with * xcursor_images_destroy(). * * \param theme The name of theme that should be loaded * \param size The desired size of the cursor images * \param load_callback A callback function that will be called * for each cursor loaded. The first parameter is the struct xcursor_images * object representing the loaded cursor and the second is a pointer * to data provided by the user. * \param user_data The data that should be passed to the load callback */ void xcursor_load_theme(const char *theme, int size, void (*load_callback)(struct xcursor_images *, void *), void *user_data) { xcursor_load_theme_protected(theme, size, load_callback, user_data, NULL); } wayland-1.23.1/cursor/xcursor.h000066400000000000000000000040271466237767300164600ustar00rootroot00000000000000/* * Copyright © 2002 Keith Packard * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef XCURSOR_H #define XCURSOR_H #include struct xcursor_image { uint32_t version; /* version of the image data */ uint32_t size; /* nominal size for matching */ uint32_t width; /* actual width */ uint32_t height; /* actual height */ uint32_t xhot; /* hot spot x (must be inside image) */ uint32_t yhot; /* hot spot y (must be inside image) */ uint32_t delay; /* animation delay to next frame (ms) */ uint32_t *pixels; /* pointer to pixels */ }; /* * Other data structures exposed by the library API */ struct xcursor_images { int nimage; /* number of images */ struct xcursor_image **images; /* array of XcursorImage pointers */ char *name; /* name used to load images */ }; void xcursor_images_destroy(struct xcursor_images *images); void xcursor_load_theme(const char *theme, int size, void (*load_callback)(struct xcursor_images *, void *), void *user_data); #endif wayland-1.23.1/doc/000077500000000000000000000000001466237767300140275ustar00rootroot00000000000000wayland-1.23.1/doc/doxygen/000077500000000000000000000000001466237767300155045ustar00rootroot00000000000000wayland-1.23.1/doc/doxygen/.gitignore000066400000000000000000000000511466237767300174700ustar00rootroot00000000000000doxygen_sqlite3.db html/ wayland.doxygen wayland-1.23.1/doc/doxygen/dot/000077500000000000000000000000001466237767300162725ustar00rootroot00000000000000wayland-1.23.1/doc/doxygen/dot/wayland-architecture.gv000066400000000000000000000022601466237767300227470ustar00rootroot00000000000000digraph arch_wayland { edge[ fontname="DejaVu Sans", dir="both", arrowtail="dot", arrowsize=.5, fontname="DejaVu Sans", fontsize="18", ] node[ color=none, margin=0, fontname="DejaVu Sans", fontsize="18", ] c1 [label=<
Wayland Client
>, URL="#c1"] c2 [label=<
Wayland Client
>, URL="#c2"] comp [tooltip="Wayland Compositor", label=<

Wayland
Compositor

>, URL="#comp"] impl [tooltip="KMS evdev Kernel", label=<
KMSevdev
Kernel
>, URL="#impl"] c1 -> comp [taillabel="③", labeldistance=2.5, URL="#step_3"]; c2 -> comp; comp -> c1 [label="②", URL="#step_2"]; comp -> c2; comp -> impl [xlabel = "④", URL="#step_4"]; comp -> impl [style = invis, label=" "]; impl -> comp [xlabel = "①", URL="#step_1"]; c1 -> c2 [style=invis]; } wayland-1.23.1/doc/doxygen/dot/x-architecture.gv000066400000000000000000000035251466237767300215640ustar00rootroot00000000000000digraph arch_x { edge[ fontname="DejaVu Sans", dir="both", arrowtail="dot", arrowsize=.5, fontname="DejaVu Sans", fontsize="18", ] node[ shape="none", color=none, margin=0, fontname="DejaVu Sans", fontsize="18", ] { rank=same; c1 [label=<
X Client
>, URL="#c1"] c3 [label=<
X Client
>, URL="#c3"] } c2 [label=<
X Client
>, URL="#c2"] { rank=same; xserver [tooltip="X Server", label=<

X Server

>, URL="#xserver"] comp [tooltip="Compositor", label=<

Compositor

>, URL="#comp"] } impl [tooltip="KMS evdev Kernel", label=<
KMSevdev
Kernel
>, URL="#impl"] c1 -> xserver [taillabel="③", labeldistance=2, URL="#step_3"]; c2 -> xserver; c3 -> xserver; xserver -> c1 [taillabel="②", labeldistance=2, URL="#step_2"]; xserver -> c2; xserver -> c3; xserver -> impl [taillabel="⑥", labeldistance=1.75, URL="#step_6"]; xserver -> impl [style=invis, label=" "]; impl -> xserver [taillabel="①", labeldistance=1.75, URL="#step_1"]; xserver -> comp [style=invis]; xserver -> comp [taillabel="④", labeldistance=1.75, labelangle=-45, URL="#step_4"]; comp -> xserver [taillabel="⑤", URL="#step_5"]; comp -> xserver [style=invis] c1 -> c2 [style=invis]; c3 -> c2 [style=invis]; } wayland-1.23.1/doc/doxygen/gen-doxygen.py000077500000000000000000000064221466237767300203110ustar00rootroot00000000000000#!/usr/bin/env python3 import argparse import datetime import errno import os import subprocess import sys # Custom configuration for each documentation format doxygen_templates = { 'xml': [ 'GENERATE_XML=YES\n', 'XML_OUTPUT={format}/{section}\n', 'INPUT= {files}\n', ], 'html': [ 'GENERATE_HTML=YES\n', 'HTML_OUTPUT={format}/{section}\n', 'PROJECT_NAME=\"Wayland {section} API\"\n', 'INPUT= {files}\n', ], 'man': [ 'GENERATE_MAN=YES\n', 'MAN_OUTPUT={format}\n', 'MAN_SUBDIR=.\n', 'JAVADOC_AUTOBRIEF=NO\n', 'INPUT= {files}\n', ], } def load_doxygen_file(doxyfile): with open(doxyfile, 'r') as f: res = f.readlines() return res def get_template(outformat): for (k,v) in doxygen_templates.items(): if outformat.startswith(k): return v def gen_doxygen_file(data, outformat, section, files): for l in get_template(outformat): data.append(l.format(format=outformat, section=section, files=' '.join(files))) return data parser = argparse.ArgumentParser(description='Generate docs with Doxygen') parser.add_argument('doxygen_file', help='The doxygen file to use') parser.add_argument('files', help='The list of files to parse', metavar='FILES', nargs='+') parser.add_argument('--builddir', help='The build directory', metavar='DIR', default='.') parser.add_argument('--section', help='The section to build', metavar='NAME', default='Client') parser.add_argument('--output-format', help='The output format: xml, html, man', metavar='FORMAT', default='xml') parser.add_argument('--stamp', help='Stamp file to output', metavar='STAMP_FILE', nargs='?', type=argparse.FileType('w')) args = parser.parse_args() # Merge the doxyfile with our custom templates conf = load_doxygen_file(args.doxygen_file) conf = gen_doxygen_file(conf, args.output_format, args.section, args.files) # Doxygen is not clever enough to create the directories it # needs beforehand try: os.makedirs(os.path.join(args.builddir, args.output_format)) except OSError as e: if e.errno != errno.EEXIST: raise e # Run Doxygen with the generated doxyfile cmd = subprocess.Popen(['doxygen', '-'], stdin=subprocess.PIPE) cmd.stdin.write(''.join(conf).encode('utf-8')) cmd.stdin.close() if cmd.wait() != 0: sys.exit(1) # This is a bit of a hack; Doxygen will generate way more files than we # want to install, but there's no way to know how many at configuration # time. Since we want to install only the wl_* man pages anyway, we can # delete the other files and let Meson install the whole man3 subdirectory if args.output_format.startswith('man'): manpath = os.path.join(args.builddir, args.output_format) for filename in os.listdir(manpath): full_path = os.path.join(manpath, filename) if not filename.startswith('wl_'): os.remove(full_path) if args.stamp: args.stamp.write(str(datetime.datetime.now())) wayland-1.23.1/doc/doxygen/mainpage.dox000066400000000000000000000013601466237767300200010ustar00rootroot00000000000000/** * @mainpage * Wayland protocol API documentation. * * This documentation is available for the Server- and the Client-side APIs. * * - Server-side API * - Client-side API * - Cursor helper library API * * Further documentation about the architecture and principles of Wayland is * available in the * Wayland Book * * @section ifaces Interfaces * For the list of available interfaces, please see the * modules list. * * @section protocols Protocols * For the list of protocols, please see the * Related Pages. * */ wayland-1.23.1/doc/doxygen/meson.build000066400000000000000000000053261466237767300176540ustar00rootroot00000000000000# Here be dragons dot_gv = { 'wayland-architecture': files('dot/wayland-architecture.gv'), 'x-architecture': files('dot/x-architecture.gv'), } # This is a workaround for Meson's custom_target() directive, which # currently does not support outputs pointing to a sub-directory # XXX: try turning these into maps, so they can be indexed with picture name dot_png = [] dot_map = [] doxygen_conf = configuration_data() doxygen_conf.set('VERSION', meson.project_version()) doxygen_conf.set('top_builddir', meson.project_build_root()) wayland_doxygen = configure_file( input: 'wayland.doxygen.in', output: 'wayland.doxygen', configuration: doxygen_conf, ) shared_files = files([ '../../src/wayland-util.h', ]) client_files = files([ '../../src/wayland-client.c', '../../src/wayland-client.h', '../../src/wayland-client-core.h', ]) server_files = files([ '../../src/event-loop.c', '../../src/wayland-server.c', '../../src/wayland-server.h', '../../src/wayland-server-core.h', '../../src/wayland-shm.c', ]) cursor_files = files([ '../../cursor/wayland-cursor.c', '../../cursor/wayland-cursor.h', ]) extra_client_files = [ 'mainpage.dox', wayland_client_protocol_h, ] extra_server_files = [ 'mainpage.dox', wayland_server_protocol_h, ] extra_cursor_files = [ 'mainpage.dox', ] gen_doxygen = find_program('gen-doxygen.py') subdir('xml') formats = { 'html': { 'Client': shared_files + client_files + extra_client_files, 'Server': shared_files + server_files + extra_server_files, 'Cursor': shared_files + cursor_files + extra_cursor_files, }, } foreach f_name, sections: formats foreach s_name, s_files: sections t_name = '@0@-@1@-doc'.format(f_name, s_name) # We do not really need an output file, but Meson # will complain if one is not set, so we use a # dummy 'stamp' file stamp = join_paths(meson.current_build_dir(), '@0@.stamp'.format(t_name)) custom_target( t_name, command: [ gen_doxygen, # XXX pass doxygen path as argument '--builddir=@OUTDIR@', '--section=@0@'.format(s_name), '--output-format=@0@'.format(f_name), '--stamp=@0@'.format(stamp), wayland_doxygen, '@INPUT@', ], input: s_files, output: '@0@.stamp'.format(t_name), depends: [dot_png, dot_map], build_by_default: true, ) endforeach endforeach man_files = shared_files + server_files + client_files + cursor_files stamp = join_paths(meson.current_build_dir(), 'man3.stamp') custom_target( 'man-pages-3', command: [ gen_doxygen, '--builddir=@OUTDIR@', '--output-format=man3', '--stamp=@0@'.format(stamp), wayland_doxygen, '@INPUT@', ], input: man_files, output: 'man3', build_by_default: true, install: true, install_dir: join_paths(get_option('prefix'), get_option('mandir')), ) wayland-1.23.1/doc/doxygen/wayland.doxygen.in000066400000000000000000000013731466237767300211530ustar00rootroot00000000000000# Wayland-specific overrides PROJECT_NAME = "Wayland" PROJECT_NUMBER = @VERSION@ OUTPUT_DIRECTORY = @top_builddir@/doc/doxygen JAVADOC_AUTOBRIEF = YES TAB_SIZE = 8 QUIET = YES HTML_TIMESTAMP = YES GENERATE_LATEX = NO MAN_LINKS = NO PREDEFINED = WL_EXPORT= \ WL_PRINTF(x,y)= MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES DOT_MULTI_TARGETS = YES ALIASES += comment{1}="/* \1 */" OPTIMIZE_OUTPUT_FOR_C = YES EXTRACT_ALL = YES EXTRACT_STATIC = YES # These must be set in the Makefile GENERATE_HTML = NO GENERATE_XML = NO GENERATE_MAN = NO wayland-1.23.1/doc/doxygen/xml/000077500000000000000000000000001466237767300163045ustar00rootroot00000000000000wayland-1.23.1/doc/doxygen/xml/Client/000077500000000000000000000000001466237767300175225ustar00rootroot00000000000000wayland-1.23.1/doc/doxygen/xml/Client/meson.build000066400000000000000000000006161466237767300216670ustar00rootroot00000000000000tgt = custom_target( 'xml-Client-doc', command: [ gen_doxygen, # XXX pass doxygen path as argument '--builddir=@OUTDIR@', '--section=Client', '--output-format=xml', wayland_doxygen, '@INPUT@', ], input: [ shared_files, client_files ], output: [ 'combine.xslt', 'index.xml' ], depends: [dot_png, dot_map] ) doxygen_Client_combine_xslt = tgt[0] doxygen_Client_index_xml = tgt[1] wayland-1.23.1/doc/doxygen/xml/Server/000077500000000000000000000000001466237767300175525ustar00rootroot00000000000000wayland-1.23.1/doc/doxygen/xml/Server/meson.build000066400000000000000000000006161466237767300217170ustar00rootroot00000000000000tgt = custom_target( 'xml-Server-doc', command: [ gen_doxygen, # XXX pass doxygen path as argument '--builddir=@OUTDIR@', '--section=Server', '--output-format=xml', wayland_doxygen, '@INPUT@', ], input: [ shared_files, server_files ], output: [ 'combine.xslt', 'index.xml' ], depends: [dot_png, dot_map] ) doxygen_Server_combine_xslt = tgt[0] doxygen_Server_index_xml = tgt[1] wayland-1.23.1/doc/doxygen/xml/meson.build000066400000000000000000000010161466237767300204440ustar00rootroot00000000000000# dot_png: list of PNG targets # dot_map: list of MAP targets foreach name, infile: dot_gv dot_png += custom_target( name + '.png', command: [ dot, '-Tpng', '-o@OUTPUT@', '@INPUT@' ], input: infile, output: name + '.png', install: true, install_dir: join_paths(publican_install_prefix, publican_html_dir, 'images') ) dot_map += custom_target( name + '.map', command: [ dot, '-Tcmapx_np', '-o@OUTPUT@', '@INPUT@' ], input: infile, output: name + '.map', ) endforeach subdir('Client') subdir('Server') wayland-1.23.1/doc/meson.build000066400000000000000000000023471466237767300161770ustar00rootroot00000000000000if not get_option('libraries') error('-Ddocumentation=true requires -Dlibraries=true') endif dot = find_program('dot') doxygen = find_program('doxygen') xsltproc = find_program('xsltproc') xmlto = find_program('xmlto') cmd = run_command(doxygen, '--version', check: true) message('doxygen: ' + cmd.stdout().strip()) vers = cmd.stdout().strip() if vers.version_compare('< 1.6.0') error('Doxygen 1.6 or later is required for building documentation, found @0@.'.format(vers)) endif cmd = run_command(dot, '-V', check: true) message('dot: ' + cmd.stderr().strip()) vers = cmd.stderr().split('version')[1].strip().split(' ')[0] if vers.version_compare('< 2.26.0') error('Dot (Graphviz) 2.26 or later is required for building documentation, found @0@.'.format(vers)) endif manpage_xsl = 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl' cmd = run_command(xsltproc, '--nonet', manpage_xsl, check: false) if cmd.returncode() != 0 error('The style sheet for man pages providing "@0@" was not found.'.format(manpage_xsl)) endif publican_install_prefix = join_paths( get_option('prefix'), get_option('datadir'), 'doc', meson.project_name(), 'Wayland', 'en-US' ) publican_html_dir = 'html' subdir('doxygen') subdir('publican') wayland-1.23.1/doc/publican/000077500000000000000000000000001466237767300156245ustar00rootroot00000000000000wayland-1.23.1/doc/publican/.gitignore000066400000000000000000000000411466237767300176070ustar00rootroot00000000000000Wayland en-US/ publican-copy.cfg wayland-1.23.1/doc/publican/doxygen-to-publican.xsl000066400000000000000000000107161466237767300222510ustar00rootroot00000000000000
Functions
Returns: See also: Since: Note: -
<xsl:value-of select="compoundname" /> <xsl:if test="normalize-space(briefdescription) != ''"> - <xsl:apply-templates select="briefdescription" /> </xsl:if>
wayland-1.23.1/doc/publican/merge-mapcoords.xsl000066400000000000000000000044121466237767300214410ustar00rootroot00000000000000 %BOOK_ENTITIES; ]> ]]> wayland-1.23.1/doc/publican/meson.build000066400000000000000000000013541466237767300177710ustar00rootroot00000000000000merge_mapcoords_xsl = files('merge-mapcoords.xsl') subdir('sources') custom_target( 'Wayland-docbook-html', command: [ xmlto, '--skip-validation', '--stringparam', 'chunker.output.encoding=UTF-8', '--stringparam', 'chunk.section.depth=0', '--stringparam', 'toc.section.depth=1', '--stringparam', 'generate.consistent.ids=1', '--stringparam', 'html.stylesheet=css/default.css', '-o', '@OUTPUT@', 'html', '@INPUT@' ], input: publican_processed_main, output: publican_html_dir, depend_files: publican_copied_sources, depends: [ publican_processed_targets, ClientAPI_xml, ServerAPI_xml, ProtocolSpec_xml, ProtocolInterfaces_xml ], build_by_default: true, install: true, install_dir: publican_install_prefix ) wayland-1.23.1/doc/publican/protocol-interfaces-to-docbook.xsl000066400000000000000000000030151466237767300243730ustar00rootroot00000000000000 %BOOK_ENTITIES; ]> ]]>
Interfaces The protocol includes several interfaces which are used for interacting with the server. Each interface provides requests, events, and errors (which are really just special events) as described above. Specific compositor implementations may have their own interfaces provided as extensions, but there are several which are always expected to be present. Core interfaces:
wayland-1.23.1/doc/publican/protocol-to-docbook.xsl000066400000000000000000000151721466237767300222610ustar00rootroot00000000000000 %BOOK_ENTITIES; ]> ]]> Wayland Protocol Specification
<xsl:value-of select="@name" /> <!-- only show summary if it exists --> <xsl:if test="description/@summary"> - <xsl:value-of select="description/@summary" /> </xsl:if>
Requests provided by <xsl:value-of select="@name" />
Events provided by <xsl:value-of select="@name" />
Enums provided by <xsl:value-of select="@name" />
- - - id for the new - :: :: () -
<xsl:value-of select="../@name"/>::<xsl:value-of select="@name" /> <xsl:if test="description/@summary"> - <xsl:value-of select="description/@summary" /> </xsl:if>
<xsl:value-of select="../@name"/>::<xsl:value-of select="@name" /> <xsl:if test="@bitfield"> - bitfield </xsl:if> <xsl:if test="description/@summary"> - <xsl:value-of select="description/@summary" /> </xsl:if>
wayland-1.23.1/doc/publican/sources/000077500000000000000000000000001466237767300173075ustar00rootroot00000000000000wayland-1.23.1/doc/publican/sources/Architecture.xml000066400000000000000000000333061466237767300224600ustar00rootroot00000000000000 %BOOK_ENTITIES; ]> Wayland Architecture
X vs. Wayland Architecture A good way to understand the Wayland architecture and how it is different from X is to follow an event from the input device to the point where the change it affects appears on screen. This is where we are now with X:
X architecture diagram
The kernel gets an event from an input device and sends it to X through the evdev input driver. The kernel does all the hard work here by driving the device and translating the different device specific event protocols to the linux evdev input event standard. The X server determines which window the event affects and sends it to the clients that have selected for the event in question on that window. The X server doesn't actually know how to do this right, since the window location on screen is controlled by the compositor and may be transformed in a number of ways that the X server doesn't understand (scaled down, rotated, wobbling, etc). The client looks at the event and decides what to do. Often the UI will have to change in response to the event - perhaps a check box was clicked or the pointer entered a button that must be highlighted. Thus the client sends a rendering request back to the X server. When the X server receives the rendering request, it sends it to the driver to let it program the hardware to do the rendering. The X server also calculates the bounding region of the rendering, and sends that to the compositor as a damage event. The damage event tells the compositor that something changed in the window and that it has to recomposite the part of the screen where that window is visible. The compositor is responsible for rendering the entire screen contents based on its scenegraph and the contents of the X windows. Yet, it has to go through the X server to render this. The X server receives the rendering requests from the compositor and either copies the compositor back buffer to the front buffer or does a pageflip. In the general case, the X server has to do this step so it can account for overlapping windows, which may require clipping and determine whether or not it can page flip. However, for a compositor, which is always fullscreen, this is another unnecessary context switch. As suggested above, there are a few problems with this approach. The X server doesn't have the information to decide which window should receive the event, nor can it transform the screen coordinates to window-local coordinates. And even though X has handed responsibility for the final painting of the screen to the compositing manager, X still controls the front buffer and modesetting. Most of the complexity that the X server used to handle is now available in the kernel or self contained libraries (KMS, evdev, mesa, fontconfig, freetype, cairo, Qt etc). In general, the X server is now just a middle man that introduces an extra step between applications and the compositor and an extra step between the compositor and the hardware. In Wayland the compositor is the display server. We transfer the control of KMS and evdev to the compositor. The Wayland protocol lets the compositor send the input events directly to the clients and lets the client send the damage event directly to the compositor:
Wayland architecture diagram
The kernel gets an event and sends it to the compositor. This is similar to the X case, which is great, since we get to reuse all the input drivers in the kernel. The compositor looks through its scenegraph to determine which window should receive the event. The scenegraph corresponds to what's on screen and the compositor understands the transformations that it may have applied to the elements in the scenegraph. Thus, the compositor can pick the right window and transform the screen coordinates to window-local coordinates, by applying the inverse transformations. The types of transformation that can be applied to a window is only restricted to what the compositor can do, as long as it can compute the inverse transformation for the input events. As in the X case, when the client receives the event, it updates the UI in response. But in the Wayland case, the rendering happens in the client, and the client just sends a request to the compositor to indicate the region that was updated. The compositor collects damage requests from its clients and then recomposites the screen. The compositor can then directly issue an ioctl to schedule a pageflip with KMS.
Wayland Rendering One of the details I left out in the above overview is how clients actually render under Wayland. By removing the X server from the picture we also removed the mechanism by which X clients typically render. But there's another mechanism that we're already using with DRI2 under X: direct rendering. With direct rendering, the client and the server share a video memory buffer. The client links to a rendering library such as OpenGL that knows how to program the hardware and renders directly into the buffer. The compositor in turn can take the buffer and use it as a texture when it composites the desktop. After the initial setup, the client only needs to tell the compositor which buffer to use and when and where it has rendered new content into it. This leaves an application with two ways to update its window contents: Render the new content into a new buffer and tell the compositor to use that instead of the old buffer. The application can allocate a new buffer every time it needs to update the window contents or it can keep two (or more) buffers around and cycle between them. The buffer management is entirely under application control. Render the new content into the buffer that it previously told the compositor to to use. While it's possible to just render directly into the buffer shared with the compositor, this might race with the compositor. What can happen is that repainting the window contents could be interrupted by the compositor repainting the desktop. If the application gets interrupted just after clearing the window but before rendering the contents, the compositor will texture from a blank buffer. The result is that the application window will flicker between a blank window or half-rendered content. The traditional way to avoid this is to render the new content into a back buffer and then copy from there into the compositor surface. The back buffer can be allocated on the fly and just big enough to hold the new content, or the application can keep a buffer around. Again, this is under application control. In either case, the application must tell the compositor which area of the surface holds new contents. When the application renders directly to the shared buffer, the compositor needs to be noticed that there is new content. But also when exchanging buffers, the compositor doesn't assume anything changed, and needs a request from the application before it will repaint the desktop. The idea that even if an application passes a new buffer to the compositor, only a small part of the buffer may be different, like a blinking cursor or a spinner.
Hardware Enabling for Wayland Typically, hardware enabling includes modesetting/display and EGL/GLES2. On top of that Wayland needs a way to share buffers efficiently between processes. There are two sides to that, the client side and the server side. On the client side we've defined a Wayland EGL platform. In the EGL model, that consists of the native types (EGLNativeDisplayType, EGLNativeWindowType and EGLNativePixmapType) and a way to create those types. In other words, it's the glue code that binds the EGL stack and its buffer sharing mechanism to the generic Wayland API. The EGL stack is expected to provide an implementation of the Wayland EGL platform. The full API is in the wayland-egl.h header. The open source implementation in the mesa EGL stack is in wayland-egl.c and platform_wayland.c. Under the hood, the EGL stack is expected to define a vendor-specific protocol extension that lets the client side EGL stack communicate buffer details with the compositor in order to share buffers. The point of the wayland-egl.h API is to abstract that away and just let the client create an EGLSurface for a Wayland surface and start rendering. The open source stack uses the drm Wayland extension, which lets the client discover the drm device to use and authenticate and then share drm (GEM) buffers with the compositor. The server side of Wayland is the compositor and core UX for the vertical, typically integrating task switcher, app launcher, lock screen in one monolithic application. The server runs on top of a modesetting API (kernel modesetting, OpenWF Display or similar) and composites the final UI using a mix of EGL/GLES2 compositor and hardware overlays if available. Enabling modesetting, EGL/GLES2 and overlays is something that should be part of standard hardware bringup. The extra requirement for Wayland enabling is the EGL_WL_bind_wayland_display extension that lets the compositor create an EGLImage from a generic Wayland shared buffer. It's similar to the EGL_KHR_image_pixmap extension to create an EGLImage from an X pixmap. The extension has a setup step where you have to bind the EGL display to a Wayland display. Then as the compositor receives generic Wayland buffers from the clients (typically when the client calls eglSwapBuffers), it will be able to pass the struct wl_buffer pointer to eglCreateImageKHR as the EGLClientBuffer argument and with EGL_WAYLAND_BUFFER_WL as the target. This will create an EGLImage, which can then be used by the compositor as a texture or passed to the modesetting code to use as an overlay plane. Again, this is implemented by the vendor specific protocol extension, which on the server side will receive the driver specific details about the shared buffer and turn that into an EGL image when the user calls eglCreateImageKHR.
wayland-1.23.1/doc/publican/sources/Author_Group.xml000066400000000000000000000007261466237767300224540ustar00rootroot00000000000000 %BOOK_ENTITIES; ]> Kristian Høgsberg Intel Corporation krh@bitplanet.net wayland-1.23.1/doc/publican/sources/Book_Info.xml000066400000000000000000000050441466237767300217010ustar00rootroot00000000000000 %BOOK_ENTITIES; ]> Wayland The Wayland Protocol Documentation 0.1 1 0 Wayland is a protocol for a compositor to talk to its clients as well as a C library implementation of that protocol. The compositor can be a standalone display server running on Linux kernel modesetting and evdev input devices, an X application, or a Wayland client itself. The clients can be traditional applications, X servers (rootless or fullscreen) or other display servers. Wayland logo Copyright &YEAR; &HOLDER; 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. wayland-1.23.1/doc/publican/sources/Client.xml000066400000000000000000000106261466237767300212540ustar00rootroot00000000000000 %BOOK_ENTITIES; ]> Client API
Introduction The open-source reference implementation of Wayland protocol is split in two C libraries, libwayland-client and libwayland-server. Their main responsibility is to handle the Inter-process communication (IPC) with each other, therefore guaranteeing the protocol objects marshaling and messages synchronization. A client uses libwayland-client to communicate with one or more wayland servers. A wl_display object is created and manages each open connection to a server. At least one wl_event_queue object is created for each wl_display, this holds events as they are received from the server until they can be processed. Multi-threading is supported by creating an additional wl_event_queue for each additional thread, each object can have it's events placed in a particular queue, so potentially a different thread could be made to handle the events for each object created. Though some convenience functions are provided, libwayland-client is designed to allow the calling code to wait for events, so that different polling mechanisms can be used. A file descriptor is provided, when it becomes ready for reading the calling code can ask libwayland-client to read the available events from it into the wl_event_queue objects. The library only provides low-level access to the wayland objects. Each object created by the client is represented by a wl_proxy object that this library creates. This includes the id that is actually communicated over the socket to the server, a void* data pointer that is intended to point at a client's representation of the object, and a pointer to a static wl_interface object, which is generated from the xml and identifies the object's class and can be used for introspection into the messages and events. Messages are sent by calling wl_proxy_marshal. This will write a message to the socket, by using the message id and the wl_interface to identify the types of each argument and convert them into stream format. Most software will call type-safe wrappers generated from the xml description of the Wayland protocols. For instance the C header file generated from the xml defines the following inline function to transmit the wl_surface::attach message: static inline void wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32_t x, int32_t y) { wl_proxy_marshal((struct wl_proxy *) wl_surface, WL_SURFACE_ATTACH, buffer, x, y); } Events (messages from the server) are handled by calling a "dispatcher" callback the client stores in the wl_proxy for each event. A language binding for a string-based interpreter, such as CPython, might have a dispatcher that uses the event name from the wl_interface to identify the function to call. The default dispatcher uses the message id number to index an array of functions pointers, called a wl_listener, and the wl_interface to convert data from the stream into arguments to the function. The C header file generated from the xml defines a per-class structure that forces the function pointers to be of the correct type, for instance the wl_surface::enter event defines this pointer in the wl_surface_listener object: struct wl_surface_listener { void (*enter)(void *data, struct wl_surface *, struct wl_output *); ... }
&doxygen;
wayland-1.23.1/doc/publican/sources/Compositors.xml000066400000000000000000000111141466237767300223500ustar00rootroot00000000000000 %BOOK_ENTITIES; ]> Types of Compositors Compositors come in different types, depending on which role they play in the overall architecture of the OS. For instance, a system compositor can be used for booting the system, handling multiple user switching, a possible console terminal emulator and so forth. A different compositor, a session compositor would provide the actual desktop environment. There are many ways for different types of compositors to co-exist. In this section, we introduce three types of Wayland compositors relying on libwayland-server.
System Compositor A system compositor can run from early boot until shutdown. It effectively replaces the kernel vt system, and can tie in with the systems graphical boot setup and multiseat support. A system compositor can host different types of session compositors, and let us switch between multiple sessions (fast user switching, or secure/personal desktop switching). A linux implementation of a system compositor will typically use libudev, egl, kms, evdev and cairo. For fullscreen clients, the system compositor can reprogram the video scanout address to read directly from the client provided buffer.
Session Compositor A session compositor is responsible for a single user session. If a system compositor is present, the session compositor will run nested under the system compositor. Nesting is feasible because the protocol is asynchronous; roundtrips would be too expensive when nesting is involved. If no system compositor is present, a session compositor can run directly on the hardware. X applications can continue working under a session compositor by means of a root-less X server that is activated on demand. Possible examples for session compositors include gnome-shell moblin kwin kmscon rdp session Weston with X11 or Wayland backend is a session compositor nested in another session compositor. fullscreen X session under Wayland
Embedding Compositor X11 lets clients embed windows from other clients, or lets clients copy pixmap contents rendered by another client into their window. This is often used for applets in a panel, browser plugins and similar. Wayland doesn't directly allow this, but clients can communicate GEM buffer names out-of-band, for example, using D-Bus, or command line arguments when the panel launches the applet. Another option is to use a nested Wayland instance. For this, the Wayland server will have to be a library that the host application links to. The host application will then pass the Wayland server socket name to the embedded application, and will need to implement the Wayland compositor interface. The host application composites the client surfaces as part of it's window, that is, in the web page or in the panel. The benefit of nesting the Wayland server is that it provides the requests the embedded client needs to inform the host about buffer updates and a mechanism for forwarding input events from the host application. An example for this kind of setup is firefox embedding the flash player as a kind of special-purpose compositor.
wayland-1.23.1/doc/publican/sources/Foreword.xml000066400000000000000000000015771466237767300216320ustar00rootroot00000000000000 %BOOK_ENTITIES; ]> Preface This document describes the (i) Wayland architecture, (ii) Wayland model of operation and (iii) its library API. Also, the Wayland protocol specification is shown in the Appendix. This document is aimed primarily at Wayland developers and those looking to program with it; it does not cover application development. There have been many contributors to this document and since this is only the first edition many errors are expected to be found. We appreciate corrections. Yours, the Wayland open-source community November 2012 wayland-1.23.1/doc/publican/sources/Introduction.xml000066400000000000000000000130021466237767300225060ustar00rootroot00000000000000 %BOOK_ENTITIES; ]> Introduction
Motivation Most Linux and Unix-based systems rely on the X Window System (or simply X) as the low-level protocol for building bitmap graphics interfaces. On these systems, the X stack has grown to encompass functionality arguably belonging in client libraries, helper libraries, or the host operating system kernel. Support for things like PCI resource management, display configuration management, direct rendering, and memory management has been integrated into the X stack, imposing limitations like limited support for standalone applications, duplication in other projects (e.g. the Linux fb layer or the DirectFB project), and high levels of complexity for systems combining multiple elements (for example radeon memory map handling between the fb driver and X driver, or VT switching). Moreover, X has grown to incorporate modern features like offscreen rendering and scene composition, but subject to the limitations of the X architecture. For example, the X implementation of composition adds additional context switches and makes things like input redirection difficult. X architecture diagram The diagram above illustrates the central role of the X server and compositor in operations, and the steps required to get contents on to the screen. Over time, X developers came to understand the shortcomings of this approach and worked to split things up. Over the past several years, a lot of functionality has moved out of the X server and into client-side libraries or kernel drivers. One of the first components to move out was font rendering, with freetype and fontconfig providing an alternative to the core X fonts. Direct rendering OpenGL as a graphics driver in a client side library went through some iterations, ending up as DRI2, which abstracted most of the direct rendering buffer management from client code. Then cairo came along and provided a modern 2D rendering library independent of X, and compositing managers took over control of the rendering of the desktop as toolkits like GTK+ and Qt moved away from using X APIs for rendering. Recently, memory and display management have moved to the Linux kernel, further reducing the scope of X and its driver stack. The end result is a highly modular graphics stack.
The compositing manager as the display server Wayland is a new display server and compositing protocol, and Weston is the implementation of this protocol which builds on top of all the components above. We are trying to distill out the functionality in the X server that is still used by the modern Linux desktop. This turns out to be not a whole lot. Applications can allocate their own off-screen buffers and render their window contents directly, using hardware accelerated libraries like libGL, or high quality software implementations like those found in Cairo. In the end, what’s needed is a way to present the resulting window surface for display, and a way to receive and arbitrate input among multiple clients. This is what Wayland provides, by piecing together the components already in the eco-system in a slightly different way. X will always be relevant, in the same way Fortran compilers and VRML browsers are, but it’s time that we think about moving it out of the critical path and provide it as an optional component for legacy applications. Overall, the philosophy of Wayland is to provide clients with a way to manage windows and how their contents is displayed. Rendering is left to clients, and system wide memory management interfaces are used to pass buffer handles between clients and the compositing manager. Wayland architecture diagram The figure above illustrates how Wayland clients interact with a Wayland server. Note that window management and composition are handled entirely in the server, significantly reducing complexity while marginally improving performance through reduced context switching. The resulting system is easier to build and extend than a similar X system, because often changes need only be made in one place. Or in the case of protocol extensions, two (rather than 3 or 4 in the X case where window management and/or composition handling may also need to be updated).
wayland-1.23.1/doc/publican/sources/Preface.xml000066400000000000000000000007561466237767300214060ustar00rootroot00000000000000 %BOOK_ENTITIES; ]> Acknowledgments TODO: Kristian has to fill up this with one or two paragraphs and a small "thank you": http://en.wikipedia.org/wiki/Preface Best, Kristian Høgsberg wayland-1.23.1/doc/publican/sources/Protocol.xml000066400000000000000000000560301466237767300216360ustar00rootroot00000000000000 %BOOK_ENTITIES; ]> Wayland Protocol and Model of Operation
Basic Principles The Wayland protocol is an asynchronous object oriented protocol. All requests are method invocations on some object. The requests include an object ID that uniquely identifies an object on the server. Each object implements an interface and the requests include an opcode that identifies which method in the interface to invoke. The protocol is message-based. A message sent by a client to the server is called request. A message from the server to a client is called event. A message has a number of arguments, each of which has a certain type (see for a list of argument types). Additionally, the protocol can specify enums which associate names to specific numeric enumeration values. These are primarily just descriptive in nature: at the wire format level enums are just integers. But they also serve a secondary purpose to enhance type safety or otherwise add context for use in language bindings or other such code. This latter usage is only supported so long as code written before these attributes were introduced still works after; in other words, adding an enum should not break API, otherwise it puts backwards compatibility at risk. enums can be defined as just a set of integers, or as bitfields. This is specified via the bitfield boolean attribute in the enum definition. If this attribute is true, the enum is intended to be accessed primarily using bitwise operations, for example when arbitrarily many choices of the enum can be ORed together; if it is false, or the attribute is omitted, then the enum arguments are a just a sequence of numerical values. The enum attribute can be used on either uint or int arguments, however if the enum is defined as a bitfield, it can only be used on uint args. The server sends back events to the client, each event is emitted from an object. Events can be error conditions. The event includes the object ID and the event opcode, from which the client can determine the type of event. Events are generated both in response to requests (in which case the request and the event constitutes a round trip) or spontaneously when the server state changes. State is broadcast on connect, events are sent out when state changes. Clients must listen for these changes and cache the state. There is no need (or mechanism) to query server state. The server will broadcast the presence of a number of global objects, which in turn will broadcast their current state.
Code Generation The interfaces, requests and events are defined in protocol/wayland.xml. This xml is used to generate the function prototypes that can be used by clients and compositors. The protocol entry points are generated as inline functions which just wrap the wl_proxy_* functions. The inline functions aren't part of the library ABI and language bindings should generate their own stubs for the protocol entry points from the xml.
Wire Format The protocol is sent over a UNIX domain stream socket, where the endpoint usually is named wayland-0 (although it can be changed via WAYLAND_DISPLAY in the environment). Beginning in Wayland 1.15, implementations can optionally support server socket endpoints located at arbitrary locations in the filesystem by setting WAYLAND_DISPLAY to the absolute path at which the server endpoint listens. Every message is structured as 32-bit words; values are represented in the host's byte-order. The message header has 2 words in it: The first word is the sender's object ID (32-bit). The second has 2 parts of 16-bit. The upper 16-bits are the message size in bytes, starting at the header (i.e. it has a minimum value of 8).The lower is the request/event opcode. The payload describes the request/event arguments. Every argument is always aligned to 32-bits. Where padding is required, the value of padding bytes is undefined. There is no prefix that describes the type, but it is inferred implicitly from the xml specification. The representation of argument types are as follows: int uint The value is the 32-bit value of the signed/unsigned int. fixed Signed 24.8 decimal numbers. It is a signed decimal type which offers a sign bit, 23 bits of integer precision and 8 bits of decimal precision. This is exposed as an opaque struct with conversion helpers to and from double and int on the C API side. string Starts with an unsigned 32-bit length (including null terminator), followed by the string contents, including terminating null byte, then padding to a 32-bit boundary. A null value is represented with a length of 0. object 32-bit object ID. A null value is represented with an ID of 0. new_id The 32-bit object ID. Generally, the interface used for the new object is inferred from the xml, but in the case where it's not specified, a new_id is preceded by a string specifying the interface name, and a uint specifying the version. array Starts with 32-bit array size in bytes, followed by the array contents verbatim, and finally padding to a 32-bit boundary. fd The file descriptor is not stored in the message buffer, but in the ancillary data of the UNIX domain socket message (msg_control). The protocol does not specify the exact position of the ancillary data in the stream, except that the order of file descriptors is the same as the order of messages and fd arguments within messages on the wire. In particular, it means that any byte of the stream, even the message header, may carry the ancillary data with file descriptors. Clients and compositors should queue incoming data until they have whole messages to process, as file descriptors may arrive earlier or later than the corresponding data bytes.
Versioning Every interface is versioned and every protocol object implements a particular version of its interface. For global objects, the maximum version supported by the server is advertised with the global and the actual version of the created protocol object is determined by the version argument passed to wl_registry.bind(). For objects that are not globals, their version is inferred from the object that created them. In order to keep things sane, this has a few implications for interface versions: The object creation hierarchy must be a tree. Otherwise, inferring object versions from the parent object becomes a much more difficult to properly track. When the version of an interface increases, so does the version of its parent (recursively until you get to a global interface) A global interface's version number acts like a counter for all of its child interfaces. Whenever a child interface gets modified, the global parent's interface version number also increases (see above). The child interface then takes on the same version number as the new version of its parent global interface. To illustrate the above, consider the wl_compositor interface. It has two children, wl_surface and wl_region. As of wayland version 1.2, wl_surface and wl_compositor are both at version 3. If something is added to the wl_region interface, both wl_region and wl_compositor will get bumpped to version 4. If, afterwards, wl_surface is changed, both wl_compositor and wl_surface will be at version 5. In this way the global interface version is used as a sort of "counter" for all of its child interfaces. This makes it very simple to know the version of the child given the version of its parent. The child is at the highest possible interface version that is less than or equal to its parent's version. It is worth noting a particular exception to the above versioning scheme. The wl_display (and, by extension, wl_registry) interface cannot change because it is the core protocol object and its version is never advertised nor is there a mechanism to request a different version.
Connect Time There is no fixed connection setup information, the server emits multiple events at connect time, to indicate the presence and properties of global objects: outputs, compositor, input devices.
Security and Authentication mostly about access to underlying buffers, need new drm auth mechanism (the grant-to ioctl idea), need to check the cmd stream? getting the server socket depends on the compositor type, could be a system wide name, through fd passing on the session dbus. or the client is forked by the compositor and the fd is already opened.
Creating Objects Each object has a unique ID. The IDs are allocated by the entity creating the object (either client or server). IDs allocated by the client are in the range [1, 0xfeffffff] while IDs allocated by the server are in the range [0xff000000, 0xffffffff]. The 0 ID is reserved to represent a null or non-existent object. For efficiency purposes, the IDs are densely packed in the sense that the ID N will not be used until N-1 has been used. This ordering is not merely a guideline, but a strict requirement, and there are implementations of the protocol that rigorously enforce this rule, including the ubiquitous libwayland.
Compositor The compositor is a global object, advertised at connect time. See for the protocol description.
Surfaces A surface manages a rectangular grid of pixels that clients create for displaying their content to the screen. Clients don't know the global position of their surfaces, and cannot access other clients' surfaces. Once the client has finished writing pixels, it 'commits' the buffer; this permits the compositor to access the buffer and read the pixels. When the compositor is finished, it releases the buffer back to the client. See for the protocol description.
Input A seat represents a group of input devices including mice, keyboards and touchscreens. It has a keyboard and pointer focus. Seats are global objects. Pointer events are delivered in surface-local coordinates. The compositor maintains an implicit grab when a button is pressed, to ensure that the corresponding button release event gets delivered to the same surface. But there is no way for clients to take an explicit grab. Instead, surfaces can be mapped as 'popup', which combines transient window semantics with a pointer grab. To avoid race conditions, input events that are likely to trigger further requests (such as button presses, key events, pointer motions) carry serial numbers, and requests such as wl_surface.set_popup require that the serial number of the triggering event is specified. The server maintains a monotonically increasing counter for these serial numbers. Input events also carry timestamps with millisecond granularity. Their base is undefined, so they can't be compared against system time (as obtained with clock_gettime or gettimeofday). They can be compared with each other though, and for instance be used to identify sequences of button presses as double or triple clicks. See for the protocol description. Talk about: keyboard map, change events xkb on Wayland multi pointer Wayland A surface can change the pointer image when the surface is the pointer focus of the input device. Wayland doesn't automatically change the pointer image when a pointer enters a surface, but expects the application to set the cursor it wants in response to the pointer focus and motion events. The rationale is that a client has to manage changing pointer images for UI elements within the surface in response to motion events anyway, so we'll make that the only mechanism for setting or changing the pointer image. If the server receives a request to set the pointer image after the surface loses pointer focus, the request is ignored. To the client this will look like it successfully set the pointer image. Setting the pointer image to NULL causes the cursor to be hidden. The compositor will revert the pointer image back to a default image when no surface has the pointer focus for that device. What if the pointer moves from one window which has set a special pointer image to a surface that doesn't set an image in response to the motion event? The new surface will be stuck with the special pointer image. We can't just revert the pointer image on leaving a surface, since if we immediately enter a surface that sets a different image, the image will flicker. If a client does not set a pointer image when the pointer enters a surface, the pointer stays with the image set by the last surface that changed it, possibly even hidden. Such a client is likely just broken.
Output An output is a global object, advertised at connect time or as it comes and goes. See for the protocol description. laid out in a big (compositor) coordinate system basically xrandr over Wayland geometry needs position in compositor coordinate system events to advertise available modes, requests to move and change modes
Data sharing between clients The Wayland protocol provides clients a mechanism for sharing data that allows the implementation of copy-paste and drag-and-drop. The client providing the data creates a wl_data_source object and the clients obtaining the data will see it as wl_data_offer object. This interface allows the clients to agree on a mutually supported mime type and transfer the data via a file descriptor that is passed through the protocol. The next section explains the negotiation between data source and data offer objects. explains how these objects are created and passed to different clients using the wl_data_device interface that implements copy-paste and drag-and-drop support. See , , and for protocol descriptions. MIME is defined in RFC's 2045-2049. A registry of MIME types is maintained by the Internet Assigned Numbers Authority (IANA).
Data negotiation A client providing data to other clients will create a wl_data_source object and advertise the mime types for the formats it supports for that data through the wl_data_source.offer request. On the receiving end, the data offer object will generate one wl_data_offer.offer event for each supported mime type. The actual data transfer happens when the receiving client sends a wl_data_offer.receive request. This request takes a mime type and a file descriptor as arguments. This request will generate a wl_data_source.send event on the sending client with the same arguments, and the latter client is expected to write its data to the given file descriptor using the chosen mime type.
Data devices Data devices glue data sources and offers together. A data device is associated with a wl_seat and is obtained by the clients using the wl_data_device_manager factory object, which is also responsible for creating data sources. Clients are informed of new data offers through the wl_data_device.data_offer event. After this event is generated the data offer will advertise the available mime types. New data offers are introduced prior to their use for copy-paste or drag-and-drop.
Selection Each data device has a selection data source. Clients create a data source object using the device manager and may set it as the current selection for a given data device. Whenever the current selection changes, the client with keyboard focus receives a wl_data_device.selection event. This event is also generated on a client immediately before it receives keyboard focus. The data offer is introduced with wl_data_device.data_offer event before the selection event.
Drag and Drop A drag-and-drop operation is started using the wl_data_device.start_drag request. This requests causes a pointer grab that will generate enter, motion and leave events on the data device. A data source is supplied as argument to start_drag, and data offers associated with it are supplied to clients surfaces under the pointer in the wl_data_device.enter event. The data offer is introduced to the client prior to the enter event with the wl_data_device.data_offer event. Clients are expected to provide feedback to the data sending client by calling the wl_data_offer.accept request with a mime type it accepts. If none of the advertised mime types is supported by the receiving client, it should supply NULL to the accept request. The accept request causes the sending client to receive a wl_data_source.target event with the chosen mime type. When the drag ends, the receiving client receives a wl_data_device.drop event at which it is expected to transfer the data using the wl_data_offer.receive request.
wayland-1.23.1/doc/publican/sources/Revision_History.xml000066400000000000000000000002511466237767300233460ustar00rootroot00000000000000 1-0 krh Initial version wayland-1.23.1/doc/publican/sources/Server.xml000066400000000000000000000042631466237767300213040ustar00rootroot00000000000000 %BOOK_ENTITIES; ]> Server API
Introduction The open-source reference implementation of Wayland protocol is split in two C libraries, libwayland-client and libwayland-server. Their main responsibility is to handle the Inter-process communication (IPC) with each other, therefore guaranteeing the protocol objects marshaling and messages synchronization. The server library is designed to work much like libwayland-client, although it is considerably complicated due to the server needing to support multiple versions of the protocol. It is best to learn libwayland-client first. Each open socket to a client is represented by a wl_client. The equivalent of the wl_proxy that libwayland-client uses to represent an object is wl_resource for client-created objects, and wl_global for objects created by the server. Often a server is also a client for another Wayland server, and thus must link with both libwayland-client and libwayland-server. This produces some type name conflicts (such as the client wl_display and server wl_display, but the duplicate-but-not-the-same types are opaque, and accessed only inside the correct library where it came from. Naturally that means that the program writer needs to always know if a pointer to a wl_display is for the server or client side and use the corresponding functions.
&doxygen;
wayland-1.23.1/doc/publican/sources/Wayland.ent000066400000000000000000000002141466237767300214130ustar00rootroot00000000000000 wayland-1.23.1/doc/publican/sources/Wayland.xml000066400000000000000000000021501466237767300214260ustar00rootroot00000000000000 %BOOK_ENTITIES; ]> wayland-1.23.1/doc/publican/sources/Xwayland.xml000066400000000000000000000204361466237767300216250ustar00rootroot00000000000000 %BOOK_ENTITIES; ]> X11 Application Support
Introduction Being able to run existing X11 applications is crucial for the adoption of Wayland, especially on desktops, as there will always be X11 applications that have not been or cannot be converted into Wayland applications, and throwing them all away would be prohibitive. Therefore a Wayland compositor often needs to support running X11 applications. X11 and Wayland are different enough that there is no "simple" way to translate between them. Most of X11 is uninteresting to a Wayland compositor. That, combined with the gigantic implementation effort needed to support X11, makes it intractable to just write X11 support directly in a Wayland compositor. The implementation would be nothing short of a real X11 server. Therefore, Wayland compositors should use Xwayland, the X11 server that lives in the Xorg server source code repository and shares most of the implementation with the Xorg server. Xwayland is a complete X11 server, just like Xorg is, but instead of driving the displays and opening input devices, it acts as a Wayland client. The rest of this chapter talks about how Xwayland works. For integration and architecture reasons, while Xwayland is a Wayland client of the Wayland compositor, the Wayland compositor is an X11 client of Xwayland. This circular dependency requires special care from the Wayland compositor.
Two Modes for Foreign Windows In general, windows from a foreign window system can be presented in one of two ways: rootless and rootful (not rootless). In rootful mode, the foreign window system as a whole is represented as a window (or more) of its own. You have a native window, inside which all the foreign windows are. The advantage of this approach in Xwayland's case is that you can run your favourite X11 window manager to manage your X11 applications. The disadvantage is that the foreign windows do not integrate with the native desktop. Therefore this mode is not usually used. In rootless mode, each foreign window is a first-class resident among the native windows. Foreign windows are not confined inside a native window but act as if they were native windows. The advantage is that one can freely stack and mix native and foreign windows, which is not possible in rootful mode. The disadvantage is that this mode is harder to implement and fundamental differences in window systems may prevent some things from working. With rootless Xwayland, the Wayland compositor must take the role as the X11 window manager, and one cannot use any other X11 window manager in its place. This chapter concentrates on the rootless mode, and ignores the rootful mode.
Architecture A Wayland compositor usually takes care of launching Xwayland. Xwayland works in cooperation with a Wayland compositor as follows:
Xwayland architecture diagram
An X11 application connects to Xwayland just like it would connect to any X server. Xwayland processes all the X11 requests. On the other end, Xwayland is a Wayland client that connects to the Wayland compositor. The X11 window manager (XWM) is an integral part of the Wayland compositor. XWM uses the usual X11 window management protocol to manage all X11 windows in Xwayland. Most importantly, XWM acts as a bridge between Xwayland window state and the Wayland compositor's window manager (WWM). This way WWM can manage all windows, both native Wayland and X11 (Xwayland) windows. This is very important for a coherent user experience. Since Xwayland uses Wayland for input and output, it does not have any use for the device drivers that Xorg uses. None of the xf86-video-* or xf86-input-* modules are used. There also is no configuration file for the Xwayland server. For optional hardware accelerated rendering, Xwayland uses GLAMOR. A Wayland compositor usually spawns only one Xwayland instance. This is because many X11 applications assume they can communicate with other X11 applications through the X server, and this requires a shared X server instance. This also means that Xwayland does not protect nor isolate X11 clients from each other, unless the Wayland compositor specifically chooses to break the X11 client intercommunications by spawning application specific Xwayland instances. X11 clients are naturally isolated from Wayland clients. Xwayland compatibility compared to a native X server will probably never reach 100%. Desktop environment (DE) components, specifically X11 window managers, are practically never supported. An X11 window manager would not know about native Wayland windows, so it could manage only X11 windows. On the other hand, there must be an XWM that reserves the exclusive window manager role so that the Wayland compositor could show the X11 windows appropriately. For other DE components, like pagers and panels, adding the necessary interfaces to support them in WWM through XWM is often considered not worthwhile.
X Window Manager (XWM) From the X11 point of view, the X window manager (XWM) living inside a Wayland compositor is just like any other window manager. The difference is mostly in which process it resides in, and the few extra conventions in the X11 protocol to support Wayland window management (WWM) specifically. There are two separate asynchronous communication channels between Xwayland and a Wayland compositor: one uses the Wayland protocol, and the other one, solely for XWM, uses X11 protocol. This setting demands great care from the XWM implementation to avoid (random) deadlocks with Xwayland. It is often nearly impossible to prove that synchronous or blocking X11 calls from XWM cannot cause a deadlock, and therefore it is strongly recommended to make all X11 communications asynchronous. All Wayland communications are already asynchronous by design.
Window identification In Xwayland, an X11 window may have a corresponding wl_surface object in Wayland. The wl_surface object is used for input and output: it is referenced by input events and used to provide the X11 window content to the Wayland compositor. The X11 window and the wl_surface live in different protocol streams, and they need to be matched for XWM to do its job. When Xwayland creates a wl_surface on Wayland, it will also send an X11 ClientMessage of type atom "WL_SURFACE_ID" to the X11 window carrying the wl_surface Wayland object ID as the first 32-bit data element. This is how XWM can associate a wl_surface with an X11 window. Note that the request to create a wl_surface and the ID message may arrive in any order in the Wayland compositor.
wayland-1.23.1/doc/publican/sources/css/000077500000000000000000000000001466237767300200775ustar00rootroot00000000000000wayland-1.23.1/doc/publican/sources/css/brand.css000066400000000000000000000004261466237767300217010ustar00rootroot00000000000000/*headings*/ h1, h2, h3, h4, h5, h6, div.producttitle, div.subtitle, div.author div.author, div.translator div.translator, div.othercredit div.othercredit, div.editor div.editor, div.contrib div.contrib, .title, .titlepage .edition, .titlepage .releaseinfo { color: #336699; } wayland-1.23.1/doc/publican/sources/css/common.css000066400000000000000000000610661466237767300221120ustar00rootroot00000000000000* { widows: 4 !important; orphans: 4 !important; } body, h1, h2, h3, h4, h5, h6, pre, li, div { line-height: 1.29em; } body { background-color: white; margin:0 auto; font-family: "liberation sans", "Myriad ", "Bitstream Vera Sans", "Lucida Grande", "Luxi Sans", "Trebuchet MS", helvetica, verdana, arial, sans-serif; font-size: 14px; max-width: 770px; color: black; } body.toc_embeded { /*for web hosting system only*/ margin-left: 300px; } object.toc, iframe.toc { /*for web hosting system only*/ border-style: none; position: fixed; width: 290px; height: 99.99%; top: 0; left: 0; z-index: 100; border-style: none; border-right:1px solid #999; } /* Hide web menu */ body.notoc { margin-left: 3em; } iframe.notoc { border-style:none; border: none; padding: 0px; position:fixed; width: 21px; height: 29px; top: 0px; left:0; overflow: hidden; margin: 0px; margin-left: -3px; } /* End hide web menu */ /* desktop styles */ body.desktop { margin-left: 26em; } body.desktop .book > .toc { display:block; width:24em; height:99.99%; position:fixed; overflow:auto; top:0px; left:0px; /* padding-left:1em; */ background-color:#EEEEEE; font-size: 12px; } body.pdf { max-width: 100%; } .toc { line-height:1.35em; } .toc .glossary, .toc .chapter, .toc .appendix { margin-top:1em; } .toc .part { margin-top:1em; display:block; } span.glossary, span.appendix { display:block; margin-top:0.5em; } div { padding-top:0px; } div.section { page-break-inside: avoid; } p, div.para { padding-top: 0px; margin-top: 1em; padding-bottom: 0px; margin-bottom: 1em; } div.formalpara { padding-top: 0px; margin-top: 1em; padding-bottom: 0px; margin-bottom: 1em; } .varlistentry div.para { page-break-before: avoid; } /*Links*/ a { outline: none; } a:link { text-decoration: none; border-bottom: 1px dotted ; color:#3366cc; } body.pdf a:link { word-wrap: break-word; } a:visited { text-decoration:none; border-bottom: 1px dotted ; color:#003366; } div.longdesc-link { float:right; color:#999; } .toc a, .qandaset a { font-weight:normal; border:none; } .toc a:hover, .qandaset a:hover { border-bottom: 1px dotted; } /*headings*/ h1, h2, h3, h4, h5, h6 { color: #336699; margin-top: 0px; margin-bottom: 0px; background-color: transparent; margin-bottom: 0px; margin-top: 20px; page-break-inside: avoid; page-break-after: avoid; word-wrap: break-word; } h1 { font-size: 22px; } .titlepage h1.title { text-align:left; } .book > .titlepage h1.title { text-align: center; } .article > .titlepage h1.title, .article > .titlepage h2.title { text-align: center; } .set .titlepage > div > div > h1.title { text-align: center; } .part > .titlepage h1.title { text-align: center; font-size: 24px; } div.producttitle { margin-top: 0px; margin-bottom: 20px; font-size: 48px; font-weight: bold; /* background: #003d6e url(../images/h1-bg.png) top left repeat-x; */ color: #336699; text-align: center; padding-top: 12px; } .titlepage .corpauthor { margin-top: 1em; text-align: center; } .section h1.title { font-size: 18px; padding: 0px; color: #336699; text-align: left; background: white; } h2 { font-size: 20px; margin-top: 30px; } .book div.subtitle, .book h2.subtitle, .book h3.subtitle { margin-top: 1em; margin-bottom: 1em; font-size: 18px; text-align: center; } div.subtitle { color: #336699; font-weight: bold; } h1.legalnotice { font-size: 24px; } .preface > div > div > div > h2.title, .preface > div > div > div > h1.title { margin-top: 1em; font-size: 24px; } .appendix h2 { font-size: 24px; } h3 { font-size: 14px; padding-top:0px; padding-bottom: 0px; margin-bottom: 0px; } h4 { font-size: 14px; padding-top:0px; padding-bottom:0px; } h5 { font-size: 14px; } h6 { font-size: 14px; margin-bottom: 0px; } .abstract h6 { margin-top:1em; margin-bottom:.5em; font-size: 24px; } .index > div > div > div > h2.title { font-size: 24px; } .chapter > div > div > div > h2.title { font-size: 24px; } .section > div > div > div > h2.title { font-size: 21px; page-break-inside: avoid; page-break-before: avoid; page-break-after: avoid; } .section > div > div > div > h3.title { font-size: 17px; } /*element rules*/ hr { border-collapse: collapse; border-style:none; border-top: 1px dotted #ccc; width:100%; } /* web site rules */ ul.languages, .languages li { display:inline; padding:0px; } .languages li a { padding:0px .5em; text-decoration: none; } .languages li p, .languages li div.para { display:inline; } .languages li a:link, .languages li a:visited { color:#444; } .languages li a:hover, .languages li a:focus, .languages li a:active { color:black; } ul.languages { display:block; background-color:#eee; padding:.5em; } /*supporting stylesheets*/ /*unique to the webpage only*/ .books { position:relative; } .versions li { width:100%; clear:both; display:block; } a.version { font-size: 20px; text-decoration:none; width:100%; display:block; padding:1em 0px .2em 0px; clear:both; } a.version:before { content:"Version"; font-size: smaller; } a.version:visited, a.version:link { color:#666; } a.version:focus, a.version:hover { color:black; } .books { display:block; position:relative; clear:both; width:100%; } .books li { display:block; width:200px; float:left; position:relative; clear: none ; } .books .html { width:170px; display:block; } .books .pdf { position:absolute; left:170px; top:0px; font-size: smaller; } .books .pdf:link, .books .pdf:visited { color:#555; } .books .pdf:hover, .books .pdf:focus { color:#000; } .books li a { text-decoration:none; } .books li a:hover { color:black; } /*products*/ .products li { display: block; width:300px; float:left; } .products li a { width:300px; padding:.5em 0px; } .products ul { clear:both; } /*revision history*/ .revhistory { display:block; } .revhistory table { background-color:transparent; border-color:#fff; padding:0px; margin: 0; border-collapse:collapse; border-style:none; } .revhistory td { text-align :left; padding:0px; border: none; border-top: 1px solid #fff; font-weight: bold; } .revhistory .simplelist td { font-weight: normal; } .revhistory .simplelist { margin-bottom: 1.5em; margin-left: 1em; } .revhistory table th { display: none; } /*credits*/ .authorgroup div { clear:both; text-align: center; } div.author div.author, div.translator div.translator, div.othercredit div.othercredit, div.editor div.editor, div.contrib div.contrib { margin: 0px; padding: 0px; margin-top: 12px; font-size: 14px; font-weight: bold; color: #336699; } div.editedby { margin-top: 15px; margin-bottom: -0.8em; } div.authorgroup .author, div.authorgroup.editor, div.authorgroup.translator, div.authorgroup.othercredit, div.authorgroup.contrib { display: block; font-size: 14px; page-break-inside: avoid; } .revhistory .author { display: inline; } .othercredit h3 { padding-top: 1em; } .othercredit { margin:0px; padding:0px; } .releaseinfo { clear: both; } .copyright { margin-top: 1em; } /* qanda sets */ .answer { margin-bottom:1em; border-bottom:1px dotted #ccc; } .qandaset .toc { border-bottom:1px dotted #ccc; } .question { font-weight:bold; } .answer .data, .question .data { padding-left: 2.6em; } .answer .label, .question .label { float:left; font-weight:bold; } /* inline syntax highlighting */ .perl_Alert { color: #0000ff; } .perl_BaseN { color: #007f00; } .perl_BString { color: #5C3566; } .perl_Char { color: #ff00ff; } .perl_Comment { color: #888888; } .perl_DataType { color: #0000ff; } .perl_DecVal { color: #00007f; } .perl_Error { color: #ff0000; } .perl_Float { color: #00007f; } .perl_Function { color: #007f00; } .perl_IString { color: #5C3566; } .perl_Keyword { color: #002F5D; } .perl_Operator { color: #ffa500; } .perl_Others { color: #b03060; } .perl_RegionMarker { color: #96b9ff; } .perl_Reserved { color: #9b30ff; } .perl_String { color: #5C3566; } .perl_Variable { color: #0000ff; } .perl_Warning { color: #0000ff; } /*Lists*/ ul { list-style-image: url("../images/dot.png"); list-style-type: circle; padding-left: 1.6em; } ul ul { list-style-image: url("../images/dot2.png"); list-style-type: circle; } ol.1 { list-style-type: decimal; } ol.a, ol ol { list-style-type: lower-alpha; } ol.i { list-style-type: lower-roman; } ol.A { list-style-type: upper-alpha; } ol.I { list-style-type: upper-roman; } dt { font-weight:bold; margin-bottom:0px; padding-bottom:0px; } dd { margin:0px; margin-left:2em; padding-top:0px; } li { padding-top: 0px; margin-top: 0px; padding-bottom: 0px; /* margin-bottom: 16px; */ } /*images*/ img { display:block; margin: 2em 0; max-width: 100%; } .inlinemediaobject, .inlinemediaobject img, .inlinemediaobject object { display:inline; margin:0px; overflow: hidden; } .figure { margin-top: 1em; width: 100%; } .figure img, .mediaobject img { display:block; margin: 0em; page-break-inside: avoid; } .figure .title { margin-bottom:2em; padding:0px; } /*document modes*/ .confidential { background-color:#900; color:White; padding:.5em .5em; text-transform:uppercase; text-align:center; } .longdesc-link { display:none; } .longdesc { display:none; } .prompt { padding:0px .3em; } /*user interface styles*/ .screen .replaceable { } .guibutton, .guilabel { font-family: "liberation mono", "bitstream vera mono", "dejavu mono", monospace; font-weight: bold; } .example { background-color: #ffffff; border-left: 3px solid #aaaaaa; padding-top: 1px; padding-bottom: 0.1em; padding-left: 1em; } .equation { border-left: 3px solid #aaaaaa; background-color: #ffffff; padding-top: 1px; padding-bottom: 0.1em; padding-left: 1em; } .equation-contents { margin-left: 4em; } div.title { margin-bottom: 1em; font-weight: 14px; font-weight: bold; color: #336699; page-break-inside: avoid; page-break-after: avoid; word-wrap: break-word; } .example-contents { background-color: #ffffff; } .example-contents .para { /* padding: 10px;*/ } /*terminal/console text*/ .computeroutput, .option { font-family:"liberation mono", "bitstream vera mono", "dejavu mono", monospace; font-weight:bold; } .replaceable { font-style: italic; } .command, .filename, .keycap, .classname, .literal { font-family:"liberation mono", "bitstream vera mono", "dejavu mono", monospace; font-weight:bold; } /* no bold in toc */ .toc * { font-weight: inherit; } .toc H1 { font-weight: bold; } div.programlisting { white-space: pre-wrap; /* css-3 */ white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */ white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ word-wrap: break-word; /* Internet Explorer 5.5+ */ } pre { font-family:"liberation mono", "bitstream vera mono", "dejavu mono", monospace; display:block; background-color: #f5f5f5; color: #000000; /* border: 1px solid #aaaaaa; */ margin-bottom: 1em; padding:.5em 1em; white-space: pre-wrap; /* css-3 */ white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */ white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ word-wrap: break-word; /* Internet Explorer 5.5+ */ font-size: 0.9em; border-style:none; box-shadow: 0 2px 5px #AAAAAA inset; -moz-box-shadow: 0 2px 5px #AAAAAA inset; -webkit-box-shadow: 0 2px 5px #AAAAAA inset; -o-box-shadow: 0 2px 5px #AAAAAA inset; } body.pdf pre { border: 1px solid #AAAAAA; box-shadow: none; -moz-box-shadow: none; -webkit-box-shadow: none; -o-box-shadow: none; } pre .replaceable, pre .keycap { } code { font-family:"liberation mono", "bitstream vera mono", "dejavu mono", monospace; white-space: pre-wrap; word-wrap: break-word; font-weight:bold; } .parameter code { display: inline; white-space: pre-wrap; /* css-3 */ white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */ white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ word-wrap: break-word; /* Internet Explorer 5.5+ */ } code.email { font-weight: normal; font-family: "liberation sans", "Myriad ", "Bitstream Vera Sans", "Lucida Grande", "Luxi Sans", "Trebuchet MS", helvetica, verdana, arial, sans-serif; } /*Notifications*/ div.warning:before { content:url(../images/warning.png); padding-left: 5px; } div.note:before { content:url(../images/note.png); padding-left: 5px; } div.important:before { content:url(../images/important.png); padding-left: 5px; } div.warning, div.note, div.important { color: black; margin: 0px; padding: 0px; background: none; background-color: white; margin-bottom: 1em; border-bottom: 1px solid #aaaaaa; page-break-inside: avoid; } div.admonition_header p { margin: 0px; padding: 0px; color: #eeeeec; padding-top: 0px; padding-bottom: 0px; height: 1.4em; line-height: 1.4em; font-size: 17px; display:inline; } div.admonition_header { background-origin:content-box; clear: both; margin: 0px; padding: 0px; margin-top: -40px; padding-left: 58px; line-height: 1.0px; font-size: 1.0px; } div.warning div.admonition_header { background: url(../images/red.png) top left repeat-x; background-color: #590000; background: -webkit-linear-gradient(#a40000,#590000); background: linear-gradient(#a40000,#590000); } div.note div.admonition_header { background: url(../images/green.png) top right repeat-x; background-color: #597800; background: -webkit-linear-gradient(#769f00,#597800); background: linear-gradient(#769f00,#597800); } div.important div.admonition_header { background: url(../images/yellow.png) top right repeat-x; background-color: #a6710f; background: -webkit-linear-gradient(#d08e13,#a6710f); background: linear-gradient(#d08e13,#a6710f); } div.warning p:first-child, div.warning div.para:first-child, div.note p:first-child, div.note div.para:first-child, div.important p:first-child, div.important div.para:first-child { padding: 0px; margin: 0px; } div.admonition { border: none; border-left: 1px solid #aaaaaa; border-right: 1px solid #aaaaaa; padding:0px; margin:0px; padding-top: 1.5em; padding-bottom: 1em; padding-left: 2em; padding-right: 1em; background-color: #eeeeec; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; } /*Page Title*/ #title { display:block; height:45px; padding-bottom:1em; margin:0px; } #title a.left{ display:inline; border:none; } #title a.left img{ border:none; float:left; margin:0px; margin-top:.7em; } #title a.right { padding-bottom:1em; } #title a.right img { border:none; float:right; margin:0px; margin-top:.7em; } /*Table*/ div.table { /* page-break-inside: avoid; */ } table { border: 1px solid #444; width:100%; border-collapse:collapse; table-layout: fixed; word-wrap: break-word; } table.blockquote, table.simplelist, .calloutlist table { border-style: none; } table th { text-align:left; background-color:#6699cc; padding:.3em .5em; color:white; } table td { padding:.15em .5em; } table tr.even td { background-color:#f5f5f5; } tr:nth-child(even) { background-color: #eeeeee; } table th p:first-child, table td p:first-child, table li p:first-child, table th div.para:first-child, table td div.para:first-child, table li div.para:first-child { margin-top:0px; padding-top:0px; display:inline; } th, td { border-style:none; vertical-align: top; /* border: 1px solid #000; */ } .blockquote td, .simplelist th, .simplelist td { border: none; } table table td { border-bottom:1px dotted #aaa; background-color:white; padding:.6em 0px; } table table { border:1px solid white; } td.remarkval { color:#444; } td.fieldval { font-weight:bold; } .lbname, .lbtype, .lbdescr, .lbdriver, .lbhost { color:white; font-weight:bold; background-color:#999; width:120px; } td.remarkval { width:230px; } td.tname { font-weight:bold; } th.dbfield { width:120px; } th.dbtype { width:70px; } th.dbdefault { width:70px; } th.dbnul { width:70px; } th.dbkey { width:70px; } span.book { margin-top:4em; display:block; font-size: 11pt; } span.book a{ font-weight:bold; } span.chapter { display:block; } table.simplelist td, .calloutlist table td { border-style: none; } table.lt-4-cols.lt-7-rows td { border: none; } /*to simplify layout*/ table.lt-4-cols.gt-14-rows tr:nth-child(odd) { background-color: #fafafa; } /* to keep simple but stripe rows */ .gt-8-cols td { border-left: 1px solid #ccc; } .gt-8-cols td:first-child { border-left: 0; } /* to apply vertical lines to differentiate columns*/ /*Breadcrumbs*/ #breadcrumbs ul li.first:before { content:" "; } #breadcrumbs { color:#900; padding:3px; margin-bottom:25px; } #breadcrumbs ul { margin-left:0; padding-left:0; display:inline; border:none; } #breadcrumbs ul li { margin-left:0; padding-left:2px; border:none; list-style:none; display:inline; } #breadcrumbs ul li:before { content:"\0020 \0020 \0020 \00BB \0020"; color:#333; } dl { margin-top: 0px; margin-left: 28px; } .toc dl { margin-left: 10px; } /*index*/ .glossary h3, .index h3 { font-size: 20px; color:#aaa; margin:0px; } .indexdiv { margin-bottom:1em; } .glossary dt, .index dt { color:#444; padding-top:.5em; } .glossary dl dl dt, .index dl dl dt { color:#777; font-weight:normal; padding-top:0px; } .index dl dl dt:before { content:"- "; color:#ccc; } /*changes*/ .footnote { font-size: 10px; margin: 0px; color: #222; } .footnotes { margin-bottom: 60px; } table .footnote { } sup { margin:0px; padding:0px; font-size: 10px; padding-left:0px; } .footnote { position:relative; } .footnote sup { color: black; left: .4em; } .footnote a:link, .footnote a:visited { text-decoration:none; border: none; } .footnote .para sup { /* position:absolute; */ vertical-align:text-bottom; } a.footnote { padding-right: 0.5em; text-decoration:none; border: none; } .footnote sup a:link, .footnote sup a:visited { color:#92917d; text-decoration:none; } .footnote:hover sup a { text-decoration:none; } .footnote p,.footnote div.para { padding-left:1em; } .footnote a:link, .footnote a:visited before{ color:#00537c; } .footnote a:hover { } /**/ .pdf-break { page-break-before: always; } div.legalnotice { page-break-before: always; } div.abstract { page-break-before: always; /* page-break-after: always;*/ } div.chapter { page-break-before: always; } div.titlepage, div.titlepage > div, div.titlepage > div > div { page-break-inside: avoid; page-break-after: avoid; } div.preface, div.part { page-break-before: always; } div.appendix { page-break-before: always; } div.section { page-break-inside: auto; page-break-before: auto; page-break-after: auto; } dt.varlistentry { page-break-inside: avoid; page-break-after: avoid; } dd { page-break-before: avoid; } div.note .replaceable, div.important .replaceable, div.warning .replaceable, div.note .keycap, div.important .keycap, div.warning .keycap { } ul li p:last-child, ul li para:last-child { margin-bottom:0px; padding-bottom:0px; } /*document navigation*/ .docnav a, .docnav strong { border:none; text-decoration:none; font-weight:normal; } .docnav { list-style:none; margin:0px; padding:0px; position:relative; width:100%; padding-bottom:2em; padding-top:1em; height:2.5em; line-height:2.5em; /* border-top:1px dotted #ccc; background-color: rgba(240, 240, 240, 0.9); -webkitbox-shadow: 0px .15em .5em rgba(0,0,0,0.2); -moz-box-shadow: 0px .15em .5em rgba(0,0,0,0.2); box-shadow: 0px .15em .5em rgba(0,0,0,0.2); */ } .docnav li { list-style:none; margin:0px; padding:0px; display:inline; font-size: 14px; } .docnav li:before { content:" "; } .docnav li.previous, .docnav li.next { position:absolute; top:1.5em; } .docnav li.up, .docnav li.home { margin:0px 1.5em; } .docnav.top li.home { color: #336699; font-size: 22pt; font-weight: bold; } .docnav li.previous { left:0px; text-align:left; } .docnav li.next { right:0px; text-align:right; } .docnav li.previous strong, .docnav li.next strong { height: 17px; display: block; } .docnav { margin:0 auto; text-align:center; } .docnav li.next a strong { background: url(../images/stock-go-forward.png) right 120% no-repeat; padding-top:3px; padding-bottom:4px; padding-right:28px; } .docnav li.previous a strong { background: url(../images/stock-go-back.png) left 120% no-repeat; padding-top:3px; padding-bottom:4px; padding-left:28px; padding-right:0.5em; } .docnav li.home a strong { background: url(../images/stock-home.png) top left no-repeat; padding:5px; padding-left:28px; } .docnav li.up a strong { background: url(../images/stock-go-up.png) top left no-repeat; padding:5px; padding-left:28px; } .docnav a:link, .docnav a:visited { color:#666; } .docnav a:hover, .docnav a:focus, .docnav a:active { color:black; } .docnav a { max-width: 10px; overflow:hidden; } .docnav a:link strong { text-decoration:none; } .docnav { margin:0 auto; text-align:center; } ul.docnav { margin-bottom: 1em; } /* Reports */ .reports ul { list-style:none; margin:0px; padding:0px; } .reports li{ margin:0px; padding:0px; } .reports li.odd { background-color: #eeeeee; margin:0px; padding:0px; } .reports dl { display:inline; margin:0px; padding:0px; float:right; margin-right: 17em; margin-top:-1.3em; } .reports dt { display:inline; margin:0px; padding:0px; } .reports dd { display:inline; margin:0px; padding:0px; padding-right:.5em; } .reports h2, .reports h3{ display:inline; padding-right:.5em; font-size: 14px; font-weight:normal; } .reports div.progress { display:inline; float:right; width:16em; background:#c00 url(../images/shine.png) top left repeat-x; margin:0px; margin-top:-1.3em; padding:0px; border:none; } /*uniform*/ body.results, body.reports { max-width:57em ; padding:0px; } /*Progress Bar*/ div.progress { display:block; float:left; width:16em; background:#c00 url(../images/shine.png) top left repeat-x; height:1em; } div.progress span { height:1em; float:left; } div.progress span.translated { background:#6c3 url(../images/shine.png) top left repeat-x; } div.progress span.fuzzy { background:#ff9f00 url(../images/shine.png) top left repeat-x; } /*Results*/ .results ul { list-style:none; margin:0px; padding:0px; } .results li{ margin:0px; padding:0px; } .results li.odd { background-color: #eeeeee; margin:0px; padding:0px; } .results dl { display:inline; margin:0px; padding:0px; float:right; margin-right: 17em; margin-top:-1.3em; } .results dt { display:inline; margin:0px; padding:0px; } .results dd { display:inline; margin:0px; padding:0px; padding-right:.5em; } .results h2, .results h3 { display:inline; padding-right:.5em; font-size: 14px; font-weight:normal; } .results div.progress { display:inline; float:right; width:16em; background:#c00 url(../images/shine.png) top left repeat-x; margin:0px; margin-top:-1.3em; padding:0px; border:none; } /* Dirty EVIL Mozilla hack for round corners */ pre { -moz-border-radius:11px; -webkit-border-radius:11px; border-radius: 11px; /* page-break-inside: avoid; */ } .example { -moz-border-radius:0px; -webkit-border-radius:0px; border-radius: 0px; page-break-inside: avoid; } /* move these invisible fields out of the flow */ .example > a:first-child, .table > a:first-child { float: left; } .package, .citetitle { font-style: italic; } .titlepage .edition, .titlepage .releaseinfo { color: #336699; background-color: transparent; margin-top: 1em; margin-bottom: 1em; font-size: 20px; font-weight: bold; text-align: center; } span.remark { background-color: #ff00ff; } .draft { background-image: url(../images/watermark-draft.png); background-repeat: repeat-y; background-position: center; } .foreignphrase { font-style: inherit; } dt { clear:both; page-break-inside: avoid; page-break-after: avoid; } dt img { border-style: none; max-width: 112px; } dt object { max-width: 112px; } dt .inlinemediaobject, dt object { display: inline; float: left; margin-bottom: 1em; padding-right: 1em; width: 112px; } dl:after { display: block; clear: both; content: ""; } .toc dd { padding-bottom: 0px; margin-bottom: 1em; padding-left: 1.3em; margin-left: 0px; } div.toc > dl > dt { padding-bottom: 0px; margin-bottom: 0px; margin-top: 1em; } .strikethrough { text-decoration: line-through; } .underline { text-decoration: underline; } .calloutlist img, .callout { padding: 0px; margin: 0px; width: 12pt; display: inline; vertical-align: middle; } li.step > a:first-child { display: block; } .stepalternatives { list-style-image: none; list-style-type: upper-alpha; } .task { /* page-break-inside: avoid; */ } .added { background-color: #99ff99; } .changed { background-color: #ffff77; } .deleted { background-color: #ff4455; text-decoration: line-through; } wayland-1.23.1/doc/publican/sources/css/default.css000066400000000000000000000001221466237767300222300ustar00rootroot00000000000000@import url("common.css"); @import url("overrides.css"); @import url("lang.css"); wayland-1.23.1/doc/publican/sources/css/epub.css000066400000000000000000000021101466237767300215360ustar00rootroot00000000000000/*headings*/ h1, h2, h3, h4, h5, h6, div.producttitle, div.subtitle, div.author div.author, div.translator div.translator, div.othercredit div.othercredit, div.editor div.editor, div.contrib div.contrib, .title, .titlepage .edition { } div.para { margin-top: 1em; } /* inline syntax highlighting */ .perl_Alert { color: #0000ff; } .perl_BaseN { color: #007f00; } .perl_BString { color: #5C3566; } .perl_Char { color: #ff00ff; } .perl_Comment { color: #888888; } .perl_DataType { color: #0000ff; } .perl_DecVal { color: #00007f; } .perl_Error { color: #ff0000; } .perl_Float { color: #00007f; } .perl_Function { color: #007f00; } .perl_IString { color: #5C3566; } .perl_Keyword { color: #002F5D; } .perl_Operator { color: #ffa500; } .perl_Others { color: #b03060; } .perl_RegionMarker { color: #96b9ff; } .perl_Reserved { color: #9b30ff; } .perl_String { color: #5C3566; } .perl_Variable { color: #0000ff; } .perl_Warning { color: #0000ff; } b, strong { font-weight: bolder; } code.command { font-family: monospace; font-weight: bolder; } wayland-1.23.1/doc/publican/sources/css/print.css000066400000000000000000000002771466237767300217530ustar00rootroot00000000000000@import url("common.css"); @import url("overrides.css"); @import url("lang.css"); #tocframe { display: none; } body.toc_embeded { margin-left: 30px; } .producttitle { color: #336699; } wayland-1.23.1/doc/publican/sources/images/000077500000000000000000000000001466237767300205545ustar00rootroot00000000000000wayland-1.23.1/doc/publican/sources/images/icon.svg000066400000000000000000000051241466237767300222270ustar00rootroot00000000000000 wayland-1.23.1/doc/publican/sources/images/wayland.png000066400000000000000000000130211466237767300227160ustar00rootroot00000000000000PNG  IHDRuǐsBIT|d pHYsZZ`yctEXtSoftwarewww.inkscape.org<IDATxyŝ?=33 p&J⭸j1#јUlݨYb(^I!""r00}sQ GUwj>g["nF\S~F_D`.0:X ,kXm>lT.WtA4o/ 1 piVKX=PO:x8{Ϻ u\\xxzSǮ 0X͚? QY#^~5\bS[K ,+4|UKO#.jQ u s0'ۈXU.9{Tvǰ,kpp<)B ދ1JJ]WP"ˆ F^]5O"W*D]htpg߅hF<3^0ȶLv]锚Kk؏E)~H Ez k~cIUS"wS]ޖWP#eRh-!1dJq:b>U!0gAz-EqeuQud Yv(ZE&di c>(9n8Lh&AAlP6YbϏ+8xij<1"%$? S"fvI4VE|lV,K'iڢpz0˄wŜ䖫=z1\F lګqwl# =N5ˁR vΐo{l1(w`2;ݰ`uh"r3<zhYanVVmYteg牡OЩ`h3270Vt` `u5XۼN;#vtBs x: 08O5i0Gril>q7ǁq%pkMp^DT-ENn*Bri!g}OwEMTN>EP8T;[ ȿK՚+73ހe0=z}V'Y0 h+% cNim~}]؜!n"/^5Q=lQ,i f wy/!> UmB/1cPYZJEUzӟS?7+};]{0ĸsnTdwrkN14ꍔ^tuؙr2&{a t, j%%I"{auy0: Xn(?oB@*/꓀LM?Y?6F6)= 6dpaNCp0E'IesBsmAgL?b9:Aj*젌\3^O7/\zlib&ԥQU%~ZM6iD4G (g.osuNS+ŸX7eO~ܹ΋\HYTX3m~0TZ"#C:?W8+^S~;\@̰$= Va pU}"4'!a0>(vix6k^^F6^k^XN#;r#.L=&h+\y֯קFus$.t4:a􁑊Do9A#'; FBX!#tITyB':opQ5~W~<ϰg'C{TQ-~? W+Cpy*) ^/; W{0f2/:'IԀ"\*d:/׷gk\/j~(j wieV. VԮ3v%(;A;Pg-^xEU1Bj3hS$;^/<RSsgAtۡDW+O G`u1(sȧw !v<@LzA cZ|drЂNb:6ubOQ _*T3L masE\^Nzb'Oi/-YKÊO T؉̒AǻS qXS܍Nqߚ^gD]1vpPn|)/W[ˋT{fe ^S#ΰȟ$"0FS!XkBPTA'QO¾g)Aε5oXEZvO~c'򏓉T1mk\`0 "t-V2H{S5m>oƏkLk9UngJ;Q`j-S׮N=LL92 6&;QBZ׭{t0T;kEŞGI P[t>DANTנf{K'kkvLw]/BUtogCQehݩ-+& cJ2xxj{9!ߔ+Jhۯ~;5U_{;B9yK]T~潶Gv2jYT!f Ew~e`mrI 21 eWX]'g1Ï^Z. ~+}dD} "Gr}UK煨+ aȝGgJWuV'oQ#V#$PݫEcJNkjqᡇ<8FI@6uH᳸]7}[iūcU8%|yJ<_7 'jĪި12nt{,^Jx>"@1I>%.a,Kc{mPgSGZA B[EXmSR؂ur`+tвvkx0*%"shݥnkuh%[95x&jIJE}S *T2v4n<EupD}à C)hSqCQyZ̎6(9Dm745b" 7É5kًn.wO#vܕ\mC.bt؛IS{E2;MSzx_,X̃2gʇgtgitu#J^-bCb,`_P9d[JUx;i!l0ns9,_%{3ּe0SgXdBևkBXs_h2U@!KzC D,vJYk BXN+ar=WIFw U90ȅHkp ~=7:fu /sL2#/ Dkul?/,{v\ur(M*QaBP-pDXeiQuÇglNS!p2<D,mT ܋ؑ7{N1mPr }v:a9~S,"~s΄/j XC?ӻ[P 550nvx9I5,_YrxXҎ+j .@XB^/D,}~Q1}<% ,GDAyJ/=!"`-B'Q`*P (nnK%b6`Y$ QGH{d c=ѱ4"č <(3h>1!G=9[7&~]hҘY !v2!QӐiHF4-"Y(`|@ňqq(D=Hu3O"<1c#Y*GKGrVOT#S䎾1X$CXؤc!@ov.@̞:8Qc2#Dm f}k`>>aq6 "$EH&L!,B2Xd` "$EH&L!,B2Xd`W'3--m˖-rNNNzz:ugJ^x{MtɔҚVRJyP6+ysR,))Yvuz5k̙3zG yo322ryVVeee/jsly쏭돶: fXd: :}zQ ` "$EH&L!,B2Xd` "$EH&L!,B2Xdd2poӧnrXb&sbuQbY0Vp6 "$ESX,}}}bWR~Czzz:D"7nܘov``d2fwyکfܸql#Ů¥k^9u$,L!,B2Xdt?iii[lsrre;;llq|zC'''SJkjjZ[[vߍѳyA2ݏR,))Yv-! BtK-yߙn{ggÇO>-v-,9tvvfeeUWWSJSSS_T*.!q|0g5k̙3gܹWۅ_lt<]/YRRbev6sSN]a` "$EH&LL\|YXi 4ieK 7|H)mooJMMMݻwO8QRڵ:EAAAMa}d^z566V.!䁇o̱b6.EL&58վbLxR*v #k"$EH0LbWT$vn UUU3gVUU~\dz Bt:]UUՅ kjjt:Y`AEEHhnn$/t`޽AAA ߢlkk[p|||ss3!M6о>BHooohh[o022ʕ+.w7Lٟ4J&I9{y99a„3痖>}:>>RJ)++?|JV]bKSJRvU$ xv2en9rw ,(([Ə/g-|`}pp_{ҥ)SL2p)O< qފ٬HHHu!3++,33˦gFF˗ϝ;WXXȷ;R*2w)S,_7ޘ3gKBf͚pHHKKp!$;;{͚5s̙;wիmza&&&n߾o)//RT|Z۶mm6ɨ8{Rfg]ŏRRROn=>#!J~JfXd` "$EH&L!,B2Xd` "$EH&L!,B2Xd` "$EH&L!,B2Xd` "$EH&L!,B2Xd`Tח+vf=z䲱4bWB8`w͙WQtSRR.EwijjYbL&s@o6(PFFF]]ӧO.9&)**Ν;eӦMQ,xb!|<QA2Lݻw|/nId'0y>m"l&LOH&= & d2ٳqiӻϣϟ?|ÇL{7fD"ng- `ٲeG,L!,B2Xd` "$EH&L!,B2Xdq.#5$N !턐7oFEE]-[999=O|zɓYYY bc@'''SJkjjZ[[v 6!t 3_O&!رc999'N X'8zBHSSStt4 JZ\MR*++ !---qqqWoT*KJJ֮]nݺ* +"Beû ӧO EwwwLLlƨ(ʕ+(/^\d P['8ph49s&44Rh Vczzz@@؍M0!##cw={yfA2eٲe۶m[|94))iׯWtpTJH$|^h4 6?Z= !Bn2h4RJ JFZZVlV!L+..7n\qq1TվkNWZ?`7n^p!SXe^F)..6EEEH+A2?~tҥɓ'wvvZE2v]Bȝ;w(mmmr(w8qJڵkT^^VOիWcccry^^JF̔;vyyyÿ\ ,EYYnW\ 8qrzlc t (L!,B2Xdl6׿o}"U΂dN"TB/;vbXE-gn 77W&B,?Em~k<T7=RiӦYւ'A2?mZab`Tx\݃ʹ !nzĄк aĄ ̔H$fY.\RrX{֞տf͚%vSigT*޾}"##WZ%v!?~}?wM>}JSW>>h(jr69۳gO``J$sƍ9s7N_0~ٳg߸q'|P(BBB*++ JIqqq---@ٻwoPP[6 ޴i> @!}ݫ^փwuu)O*,1͍QQQ͕+WVUUQJ/^dJ)!z !0gΜ j4"jmH)5k'h4VӣjmjZxY___a9,,_+l_8t„ %%%F)Tb]áʬX&L!v? 5+A#/lٲm۶-_R}t:]xxT*%H$Q 6?Z=B1M&y0 ɔd#i}B}Lp #Gt8HXdlߟHYx'T6??/5|cddYݾ}{…֛r旼bbbz{{KKK틉+))o4׿o„n!##Ν+,,L&_{w`aδq]Bȝ;w(mmmr\8۽{ĉU*ծ]dT^^V|X\GքϷh4Lh]p˄<\{U[;zk[7Z\3g"cl6 ]ǩ<&83j___kdj}xEH&L!,B2Xd` "$EH&L!,B2Xd` "$EH&L!,B2Xd` "$EH&L!,B2Xd`+~@WW3Jw?J؅RC 1~ &8ok =[neWZ;v; j޽AAA|؅}\3ȓ:;BCC .zzz\L"$EH&L!,B2Xd` "$EH&L!,B2Xd`88n{z쯭L&C'RQu//_JBN !턐7oFEEt-jaˆ3gάrޮ ---m˖-rNNNzz:#ͺ B ?~\"|Xh_`AEE+wʚNpBcccMMN#wdTsq7ܿ?$$Xٳ'00PRUVV---qqq|Ə?{7n ek}' "$$@TN4I8c_Wll,_#mmm .onnw2q777GFF'crrrN8A%Zތ3N:E9rHRRyʕW}NJR,))Yvu;rg$3%%eǎr^^^jj*<+L_XXh gkΓ2888;AL8H$111]*Zt >9'' Xd` "$EH&L!,B2Xd` "$EH&L!,B2X4kܼyHx93/y2l&s׮]z{'v敓9mڴ;jmm%Nj]qT̐!x28 ^` "$EH&L!,B2Xd` "$E?7!b)bϓ|,1Y!,>x@= 0.54.0') meson.override_dependency('wayland-egl', wayland_egl_dep) endif wayland-1.23.1/egl/wayland-egl-abi-check.c000066400000000000000000000236021466237767300202100ustar00rootroot00000000000000/* * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include /* offsetof */ #include /* printf */ #include "wayland-egl-backend.h" /* Current struct wl_egl_window implementation */ /* * Following are previous implementations of wl_egl_window. * * DO NOT EVER CHANGE! */ /* From: 214fc6e850 - Benjamin Franzke : egl: Implement libwayland-egl */ struct wl_egl_window_v0 { struct wl_surface *surface; int width; int height; int dx; int dy; int attached_width; int attached_height; }; /* From: ca3ed3e024 - Ander Conselvan de Oliveira : egl/wayland: Don't invalidate drawable on swap buffers */ struct wl_egl_window_v1 { struct wl_surface *surface; int width; int height; int dx; int dy; int attached_width; int attached_height; void *private; void (*resize_callback)(struct wl_egl_window *, void *); }; /* From: 690ead4a13 - Stencel, Joanna : egl/wayland-egl: Fix for segfault in dri2_wl_destroy_surface. */ #define WL_EGL_WINDOW_VERSION_v2 2 struct wl_egl_window_v2 { struct wl_surface *surface; int width; int height; int dx; int dy; int attached_width; int attached_height; void *private; void (*resize_callback)(struct wl_egl_window *, void *); void (*destroy_window_callback)(void *); }; /* From: 2d5d61bc49 - Miguel A. Vico : wayland-egl: Make wl_egl_window a versioned struct */ #define WL_EGL_WINDOW_VERSION_v3 3 struct wl_egl_window_v3 { const intptr_t version; int width; int height; int dx; int dy; int attached_width; int attached_height; void *driver_private; void (*resize_callback)(struct wl_egl_window *, void *); void (*destroy_window_callback)(void *); struct wl_surface *surface; }; /* This program checks we keep a backwards-compatible struct wl_egl_window * definition whenever it is modified in wayland-egl-backend.h. * * The previous definition should be added above as a new struct * wl_egl_window_vN, and the appropriate checks should be added below */ #define MEMBER_SIZE(type, member) sizeof(((type *)0)->member) #define CHECK_RENAMED_MEMBER(a_ver, b_ver, a_member, b_member) \ do { \ if (offsetof(struct wl_egl_window ## a_ver, a_member) != \ offsetof(struct wl_egl_window ## b_ver, b_member)) { \ printf("Backwards incompatible change detected!\n " \ "offsetof(struct wl_egl_window" #a_ver "::" #a_member ") != " \ "offsetof(struct wl_egl_window" #b_ver "::" #b_member ")\n"); \ return 1; \ } \ \ if (MEMBER_SIZE(struct wl_egl_window ## a_ver, a_member) != \ MEMBER_SIZE(struct wl_egl_window ## b_ver, b_member)) { \ printf("Backwards incompatible change detected!\n " \ "MEMBER_SIZE(struct wl_egl_window" #a_ver "::" #a_member ") != " \ "MEMBER_SIZE(struct wl_egl_window" #b_ver "::" #b_member ")\n"); \ return 1; \ } \ } while (0) #define CHECK_MEMBER(a_ver, b_ver, member) CHECK_RENAMED_MEMBER(a_ver, b_ver, member, member) #define CHECK_MEMBER_CURRENT(a_ver, member) CHECK_MEMBER(a_ver,, member) #define CHECK_SIZE(a_ver, b_ver) \ do { \ if (sizeof(struct wl_egl_window ## a_ver) > \ sizeof(struct wl_egl_window ## b_ver)) { \ printf("Backwards incompatible change detected!\n " \ "sizeof(struct wl_egl_window" #a_ver ") > " \ "sizeof(struct wl_egl_window" #b_ver ")\n"); \ return 1; \ } \ } while (0) #define CHECK_SIZE_CURRENT(a_ver) \ do { \ if (sizeof(struct wl_egl_window ## a_ver) != \ sizeof(struct wl_egl_window)) { \ printf("Backwards incompatible change detected!\n " \ "sizeof(struct wl_egl_window" #a_ver ") != " \ "sizeof(struct wl_egl_window)\n"); \ return 1; \ } \ } while (0) #define CHECK_VERSION(a_ver, b_ver) \ do { \ if ((WL_EGL_WINDOW_VERSION ## a_ver) >= \ (WL_EGL_WINDOW_VERSION ## b_ver)) { \ printf("Backwards incompatible change detected!\n " \ "WL_EGL_WINDOW_VERSION" #a_ver " >= " \ "WL_EGL_WINDOW_VERSION" #b_ver "\n"); \ return 1; \ } \ } while (0) #define CHECK_VERSION_CURRENT(a_ver) \ do { \ if ((WL_EGL_WINDOW_VERSION ## a_ver) != \ (WL_EGL_WINDOW_VERSION)) { \ printf("Backwards incompatible change detected!\n " \ "WL_EGL_WINDOW_VERSION" #a_ver " != " \ "WL_EGL_WINDOW_VERSION\n"); \ return 1; \ } \ } while (0) int main(int argc, char **argv) { /* Check wl_egl_window_v1 ABI against wl_egl_window_v0 */ CHECK_MEMBER(_v0, _v1, surface); CHECK_MEMBER(_v0, _v1, width); CHECK_MEMBER(_v0, _v1, height); CHECK_MEMBER(_v0, _v1, dx); CHECK_MEMBER(_v0, _v1, dy); CHECK_MEMBER(_v0, _v1, attached_width); CHECK_MEMBER(_v0, _v1, attached_height); CHECK_SIZE(_v0, _v1); /* Check wl_egl_window_v2 ABI against wl_egl_window_v1 */ CHECK_MEMBER(_v1, _v2, surface); CHECK_MEMBER(_v1, _v2, width); CHECK_MEMBER(_v1, _v2, height); CHECK_MEMBER(_v1, _v2, dx); CHECK_MEMBER(_v1, _v2, dy); CHECK_MEMBER(_v1, _v2, attached_width); CHECK_MEMBER(_v1, _v2, attached_height); CHECK_MEMBER(_v1, _v2, private); CHECK_MEMBER(_v1, _v2, resize_callback); CHECK_SIZE(_v1, _v2); /* Check wl_egl_window_v3 ABI against wl_egl_window_v2 */ CHECK_RENAMED_MEMBER(_v2, _v3, surface, version); CHECK_MEMBER (_v2, _v3, width); CHECK_MEMBER (_v2, _v3, height); CHECK_MEMBER (_v2, _v3, dx); CHECK_MEMBER (_v2, _v3, dy); CHECK_MEMBER (_v2, _v3, attached_width); CHECK_MEMBER (_v2, _v3, attached_height); CHECK_RENAMED_MEMBER(_v2, _v3, private, driver_private); CHECK_MEMBER (_v2, _v3, resize_callback); CHECK_MEMBER (_v2, _v3, destroy_window_callback); CHECK_SIZE (_v2, _v3); CHECK_VERSION(_v2, _v3); /* Check current wl_egl_window ABI against wl_egl_window_v3 */ CHECK_MEMBER_CURRENT(_v3, version); CHECK_MEMBER_CURRENT(_v3, width); CHECK_MEMBER_CURRENT(_v3, height); CHECK_MEMBER_CURRENT(_v3, dx); CHECK_MEMBER_CURRENT(_v3, dy); CHECK_MEMBER_CURRENT(_v3, attached_width); CHECK_MEMBER_CURRENT(_v3, attached_height); CHECK_MEMBER_CURRENT(_v3, driver_private); CHECK_MEMBER_CURRENT(_v3, resize_callback); CHECK_MEMBER_CURRENT(_v3, destroy_window_callback); CHECK_MEMBER_CURRENT(_v3, surface); CHECK_SIZE_CURRENT (_v3); CHECK_VERSION_CURRENT(_v3); return 0; } wayland-1.23.1/egl/wayland-egl-backend.h000066400000000000000000000035251466237767300200000ustar00rootroot00000000000000/* * Copyright © 2011 Benjamin Franzke * * 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. * * Authors: * Benjamin Franzke */ #ifndef _WAYLAND_EGL_PRIV_H #define _WAYLAND_EGL_PRIV_H #include #ifdef __cplusplus extern "C" { #endif /* * NOTE: This version must be kept in sync with the version field in the * wayland-egl-backend pkgconfig file generated in meson.build. */ #define WL_EGL_WINDOW_VERSION 3 struct wl_surface; struct wl_egl_window { const intptr_t version; int width; int height; int dx; int dy; int attached_width; int attached_height; void *driver_private; void (*resize_callback)(struct wl_egl_window *, void *); void (*destroy_window_callback)(void *); struct wl_surface *surface; }; #ifdef __cplusplus } #endif #endif wayland-1.23.1/egl/wayland-egl-core.h000066400000000000000000000033741466237767300173430ustar00rootroot00000000000000/* * Copyright © 2011 Kristian Høgsberg * Copyright © 2011 Benjamin Franzke * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef WAYLAND_EGL_CORE_H #define WAYLAND_EGL_CORE_H #ifdef __cplusplus extern "C" { #endif #define WL_EGL_PLATFORM 1 struct wl_egl_window; struct wl_surface; struct wl_egl_window * wl_egl_window_create(struct wl_surface *surface, int width, int height); void wl_egl_window_destroy(struct wl_egl_window *egl_window); void wl_egl_window_resize(struct wl_egl_window *egl_window, int width, int height, int dx, int dy); void wl_egl_window_get_attached_size(struct wl_egl_window *egl_window, int *width, int *height); #ifdef __cplusplus } #endif #endif wayland-1.23.1/egl/wayland-egl-symbols-check000077500000000000000000000017501466237767300207270ustar00rootroot00000000000000#!/bin/sh set -eu RET=0 LIB=${WAYLAND_EGL_LIB} if ! test -f "$LIB"; then echo "Test binary \"$LIB\" does not exist" exit 99 fi if ! test -n "$NM"; then echo "nm environment variable not set" exit 99 fi AVAIL_FUNCS="$($NM -D --format=bsd --defined-only $LIB | awk '{print $3}')" # Official ABI, taken from the header. REQ_FUNCS="wl_egl_window_resize wl_egl_window_create wl_egl_window_destroy wl_egl_window_get_attached_size " NEW_ABI=$(echo "$AVAIL_FUNCS" | while read func; do echo "$func" | grep -q "^_" && continue echo "$REQ_FUNCS" | grep -q "^$func$" && continue echo $func done) if test -n "$NEW_ABI"; then echo "New ABI detected - If intentional, update the test." echo "$NEW_ABI" RET=1 fi REMOVED_ABI=$(echo "$REQ_FUNCS" | while read func; do echo "$AVAIL_FUNCS" | grep -q "^$func$" && continue echo $func done) if test -n "$REMOVED_ABI"; then echo "ABI break detected - Required symbol(s) no longer exported!" echo "$REMOVED_ABI" RET=1 fi exit $RET wayland-1.23.1/egl/wayland-egl.c000066400000000000000000000066771466237767300164210ustar00rootroot00000000000000/* * Copyright © 2011 Kristian Høgsberg * Copyright © 2011 Benjamin Franzke * * 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. * * Authors: * Kristian Høgsberg * Benjamin Franzke */ #include #include #include "wayland-egl.h" #include "wayland-egl-backend.h" #include "wayland-util.h" /** Resize the EGL window * * \param egl_window A pointer to a struct wl_egl_window * \param width The new width * \param height The new height * \param dx Offset on the X axis * \param dy Offset on the Y axis * * Note that applications should prefer using the wl_surface.offset request if * the associated wl_surface has the interface version 5 or higher. * * If the wl_surface.offset request is used, applications MUST pass 0 to both * dx and dy. */ WL_EXPORT void wl_egl_window_resize(struct wl_egl_window *egl_window, int width, int height, int dx, int dy) { if (width <= 0 || height <= 0) return; egl_window->width = width; egl_window->height = height; egl_window->dx = dx; egl_window->dy = dy; if (egl_window->resize_callback) egl_window->resize_callback(egl_window, egl_window->driver_private); } WL_EXPORT struct wl_egl_window * wl_egl_window_create(struct wl_surface *surface, int width, int height) { struct wl_egl_window *egl_window; if (width <= 0 || height <= 0) return NULL; egl_window = calloc(1, sizeof *egl_window); if (!egl_window) return NULL; /* Cast away the constness to set the version number. * * We want the const notation since it gives an explicit * feedback to the backend implementation, should it try to * change it. * * The latter in itself is not too surprising as these days APIs * tend to provide bidirectional version field. */ intptr_t *version = (intptr_t *)&egl_window->version; *version = WL_EGL_WINDOW_VERSION; egl_window->surface = surface; egl_window->width = width; egl_window->height = height; return egl_window; } WL_EXPORT void wl_egl_window_destroy(struct wl_egl_window *egl_window) { if (egl_window->destroy_window_callback) egl_window->destroy_window_callback(egl_window->driver_private); free(egl_window); } WL_EXPORT void wl_egl_window_get_attached_size(struct wl_egl_window *egl_window, int *width, int *height) { if (width) *width = egl_window->attached_width; if (height) *height = egl_window->attached_height; } wayland-1.23.1/egl/wayland-egl.h000066400000000000000000000024411466237767300164070ustar00rootroot00000000000000/* * Copyright © 2011 Kristian Høgsberg * Copyright © 2011 Benjamin Franzke * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef WAYLAND_EGL_H #define WAYLAND_EGL_H #include #include "wayland-egl-core.h" #endif wayland-1.23.1/meson.build000066400000000000000000000072471466237767300154360ustar00rootroot00000000000000project( 'wayland', 'c', version: '1.23.1', license: 'MIT', meson_version: '>= 0.57.0', default_options: [ 'warning_level=2', 'buildtype=debugoptimized', 'c_std=c99', ] ) wayland_version = meson.project_version().split('.') config_h = configuration_data() config_h.set_quoted('PACKAGE', meson.project_name()) config_h.set_quoted('PACKAGE_VERSION', meson.project_version()) cc_args = [] if host_machine.system() not in ['freebsd', 'openbsd'] cc_args += ['-D_POSIX_C_SOURCE=200809L'] endif add_project_arguments(cc_args, language: 'c') compiler_flags = [ '-Wno-unused-parameter', '-Wstrict-prototypes', '-Wmissing-prototypes', '-fvisibility=hidden', ] cc = meson.get_compiler('c') add_project_arguments( cc.get_supported_arguments(compiler_flags), language: 'c' ) foreach h: [ 'sys/prctl.h', 'sys/procctl.h', 'sys/ucred.h' ] config_h.set('HAVE_' + h.underscorify().to_upper(), cc.has_header(h)) endforeach have_funcs = [ 'accept4', 'mkostemp', 'posix_fallocate', 'prctl', 'memfd_create', 'mremap', 'strndup', ] foreach f: have_funcs config_h.set('HAVE_' + f.underscorify().to_upper(), cc.has_function(f)) endforeach config_h.set10('HAVE_XUCRED_CR_PID', cc.has_member('struct xucred', 'cr_pid', prefix : '#include ')) have_broken_msg_cmsg_cloexec = false if host_machine.system() == 'freebsd' have_broken_msg_cmsg_cloexec = not cc.compiles(''' #include /* To get __FreeBSD_version. */ #if __FreeBSD_version < 1300502 || \ (__FreeBSD_version >= 1400000 && __FreeBSD_version < 1400006) /* * FreeBSD had a broken implementation of MSG_CMSG_CLOEXEC between 2015 and * 2021. Check if we are compiling against a version that includes the fix * (https://cgit.freebsd.org/src/commit/?id=6ceacebdf52211). */ #error "Broken MSG_CMSG_CLOEXEC" #endif ''', name : 'MSG_CMSG_CLOEXEC works correctly') endif config_h.set10('HAVE_BROKEN_MSG_CMSG_CLOEXEC', have_broken_msg_cmsg_cloexec) if get_option('libraries') if host_machine.system() in ['freebsd', 'openbsd'] # When building for FreeBSD, epoll(7) is provided by a userspace # wrapper around kqueue(2). epoll_dep = dependency('epoll-shim') else # Otherwise, assume that epoll(7) is supported natively. epoll_dep = [] endif ffi_dep = dependency('libffi') decls = [ { 'header': 'sys/signalfd.h', 'symbol': 'SFD_CLOEXEC' }, { 'header': 'sys/timerfd.h', 'symbol': 'TFD_CLOEXEC' }, { 'header': 'time.h', 'symbol': 'CLOCK_MONOTONIC' }, ] foreach d: decls if not cc.has_header_symbol(d['header'], d['symbol'], dependencies: epoll_dep, args: cc_args) error('@0@ is needed to compile Wayland libraries'.format(d['symbol'])) endif endforeach rt_dep = [] if not cc.has_function('clock_gettime', prefix: '#include ') rt_dep = cc.find_library('rt') if not cc.has_function('clock_gettime', prefix: '#include ', dependencies: rt_dep, args: cc_args) error('clock_gettime not found') endif endif endif configure_file( output: 'config.h', configuration: config_h, ) pkgconfig = import('pkgconfig') wayland_protocol_xml = files('protocol/wayland.xml') root_inc = include_directories('.') protocol_inc = include_directories('protocol') src_inc = include_directories('src') subdir('src') if get_option('libraries') subdir('cursor') subdir('egl') endif if get_option('tests') subdir('tests') endif if get_option('documentation') subdir('doc') endif if get_option('scanner') install_data([ 'wayland-scanner.mk', 'protocol/wayland.xml', 'protocol/wayland.dtd', ], install_dir: join_paths(get_option('prefix'), get_option('datadir'), 'wayland'), ) install_data( [ 'wayland-scanner.m4' ], install_dir: join_paths(get_option('prefix'), get_option('datadir'), 'aclocal'), ) endif wayland-1.23.1/meson_options.txt000066400000000000000000000012741466237767300167230ustar00rootroot00000000000000option('libraries', description: 'Compile Wayland libraries', type: 'boolean', value: true) option('scanner', description: 'Compile wayland-scanner binary', type: 'boolean', value: true) option('tests', description: 'Compile Wayland tests', type: 'boolean', value: true) option('documentation', description: 'Build the documentation (requires Doxygen, dot, xmlto, xsltproc)', type: 'boolean', value: true) option('dtd_validation', description: 'Validate the protocol DTD (requires libxml2)', type: 'boolean', value: true) option('icon_directory', description: 'Location used to look for cursors (defaults to ${datadir}/icons if unset)', type: 'string', value: '') wayland-1.23.1/protocol/000077500000000000000000000000001466237767300151235ustar00rootroot00000000000000wayland-1.23.1/protocol/.gitignore000066400000000000000000000000401466237767300171050ustar00rootroot00000000000000wayland.html .wayland.xml.valid wayland-1.23.1/protocol/generate-shm-formats.py000077500000000000000000000122401466237767300215270ustar00rootroot00000000000000#!/usr/bin/env python3 # This script synchronizes wayland.xml's wl_shm.format enum with drm_fourcc.h. # Invoke it to update wayland.xml, then manually check the changes applied. # # Requires Python 3, python-lxml, a C compiler and pkg-config. import os import subprocess import sys import tempfile # We need lxml instead of the standard library because we want # Element.sourceline from lxml import etree as ElementTree proto_dir = os.path.dirname(os.path.realpath(__file__)) wayland_proto = proto_dir + "/wayland.xml" cc = os.getenv("CC", "cc") pkg_config = os.getenv("PKG_CONFIG", "pkg-config") # Find drm_fourcc.h version = subprocess.check_output([pkg_config, "libdrm", "--modversion"]).decode().strip() cflags = subprocess.check_output([pkg_config, "libdrm", "--cflags-only-I"]).decode().strip().split() libdrm_include = None for include_flag in cflags: if not include_flag.startswith("-I"): raise Exception("Expected one include dir for libdrm") include_dir = include_flag[2:] if include_dir.endswith("/libdrm"): libdrm_include = include_dir fourcc_include = libdrm_include + "/drm_fourcc.h" if libdrm_include == None: raise Exception("Failed to find libdrm include dir") print("Using libdrm " + version, file=sys.stderr) def drm_format_to_wl(ident): return ident.replace("DRM_FORMAT_", "").lower() # Collect DRM format constant names ident_list = [] descriptions = {} prev_comment = None with open(fourcc_include) as input_file: for l in input_file.readlines(): l = l.strip() # Collect comments right before format definitions if l.startswith("/*") and l.endswith("*/"): prev_comment = l[2:-2] continue desc = prev_comment prev_comment = None # Recognize format definitions parts = l.split() if len(parts) < 3 or parts[0] != "#define": continue ident = parts[1] if not ident.startswith("DRM_FORMAT_") or ident.startswith( "DRM_FORMAT_MOD_"): continue ident_list.append(ident) # Prefer in-line comments if l.endswith("*/"): desc = l[l.rfind("/*") + 2:-2] if desc != None: descriptions[drm_format_to_wl(ident)] = desc.strip() # Collect DRM format values idents = {} with tempfile.TemporaryDirectory() as work_dir: c_file_name = work_dir + "/print-formats.c" exe_file_name = work_dir + "/print-formats" with open(c_file_name, "w+") as c_file: c_file.write('#include \n') c_file.write('#include \n') c_file.write('#include \n') c_file.write('#include \n') c_file.write('\n') c_file.write('int main(void) {\n') for ident in ident_list: c_file.write('printf("0x%" PRIX64 "\\n", (uint64_t)' + ident + ');\n') c_file.write('}\n') subprocess.check_call([cc, "-Wall", "-Wextra", "-o", exe_file_name, c_file_name] + cflags) output = subprocess.check_output([exe_file_name]).decode().strip() for i, val in enumerate(output.splitlines()): idents[ident_list[i]] = val # We don't need those del idents["DRM_FORMAT_BIG_ENDIAN"] del idents["DRM_FORMAT_INVALID"] del idents["DRM_FORMAT_RESERVED"] # Convert from DRM constants to Wayland wl_shm.format entries formats = {} for ident, val in idents.items(): formats[drm_format_to_wl(ident)] = val.lower() # Special case for ARGB8888 and XRGB8888 formats["argb8888"] = "0" formats["xrgb8888"] = "1" print("Loaded {} formats from drm_fourcc.h".format(len(formats)), file=sys.stderr) tree = ElementTree.parse("wayland.xml") root = tree.getroot() wl_shm_format = root.find("./interface[@name='wl_shm']/enum[@name='format']") if wl_shm_format == None: raise Exception("wl_shm.format not found in wayland.xml") # Remove formats we already know about last_line = None for node in wl_shm_format: if node.tag != "entry": continue fmt = node.attrib["name"] val = node.attrib["value"] if fmt not in formats: raise Exception("Format present in wl_shm.formats but not in " "drm_fourcc.h: " + fmt) if val != formats[fmt]: raise Exception("Format value in wl_shm.formats ({}) differs " "from value in drm_fourcc.h ({}) for format {}" .format(val, formats[fmt], fmt)) del formats[fmt] last_line = node.sourceline if last_line == None: raise Exception("Expected at least one existing wl_shm.format entry") print("Adding {} formats to wayland.xml...".format(len(formats)), file=sys.stderr) # Append new formats new_wayland_proto = wayland_proto + ".new" with open(new_wayland_proto, "w+") as output_file, \ open(wayland_proto) as input_file: for i, l in enumerate(input_file.readlines()): output_file.write(l) if i + 1 == last_line: for fmt, val in formats.items(): output_file.write(' \n') os.rename(new_wayland_proto, wayland_proto) wayland-1.23.1/protocol/tests.xml000066400000000000000000000040101466237767300170020ustar00rootroot00000000000000 Copyright © 2017 Samsung Electronics Co., 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. A trivial interface for fd passing tests. Tells this fd passer object about another one to send events to for more complicated fd leak tests. wayland-1.23.1/protocol/wayland.dtd000066400000000000000000000026641466237767300172670ustar00rootroot00000000000000 wayland-1.23.1/protocol/wayland.xml000066400000000000000000004445451466237767300173240ustar00rootroot00000000000000 Copyright © 2008-2011 Kristian Høgsberg Copyright © 2010-2011 Intel Corporation Copyright © 2012-2013 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. The core global object. This is a special singleton object. It is used for internal Wayland protocol features. The sync request asks the server to emit the 'done' event on the returned wl_callback object. Since requests are handled in-order and events are delivered in-order, this can be used as a barrier to ensure all previous requests and the resulting events have been handled. The object returned by this request will be destroyed by the compositor after the callback is fired and as such the client must not attempt to use it after that point. The callback_data passed in the callback is undefined and should be ignored. This request creates a registry object that allows the client to list and bind the global objects available from the compositor. It should be noted that the server side resources consumed in response to a get_registry request can only be released when the client disconnects, not when the client side proxy is destroyed. Therefore, clients should invoke get_registry as infrequently as possible to avoid wasting memory. The error event is sent out when a fatal (non-recoverable) error has occurred. The object_id argument is the object where the error occurred, most often in response to a request to that object. The code identifies the error and is defined by the object interface. As such, each interface defines its own set of error codes. The message is a brief description of the error, for (debugging) convenience. These errors are global and can be emitted in response to any server request. This event is used internally by the object ID management logic. When a client deletes an object that it had created, the server will send this event to acknowledge that it has seen the delete request. When the client receives this event, it will know that it can safely reuse the object ID. The singleton global registry object. The server has a number of global objects that are available to all clients. These objects typically represent an actual object in the server (for example, an input device) or they are singleton objects that provide extension functionality. When a client creates a registry object, the registry object will emit a global event for each global currently in the registry. Globals come and go as a result of device or monitor hotplugs, reconfiguration or other events, and the registry will send out global and global_remove events to keep the client up to date with the changes. To mark the end of the initial burst of events, the client can use the wl_display.sync request immediately after calling wl_display.get_registry. A client can bind to a global object by using the bind request. This creates a client-side handle that lets the object emit events to the client and lets the client invoke requests on the object. Binds a new, client-created object to the server using the specified name as the identifier. Notify the client of global objects. The event notifies the client that a global object with the given name is now available, and it implements the given version of the given interface. Notify the client of removed global objects. This event notifies the client that the global identified by name is no longer available. If the client bound to the global using the bind request, the client should now destroy that object. The object remains valid and requests to the object will be ignored until the client destroys it, to avoid races between the global going away and a client sending a request to it. Clients can handle the 'done' event to get notified when the related request is done. Note, because wl_callback objects are created from multiple independent factory interfaces, the wl_callback interface is frozen at version 1. Notify the client when the related request is done. A compositor. This object is a singleton global. The compositor is in charge of combining the contents of multiple surfaces into one displayable output. Ask the compositor to create a new surface. Ask the compositor to create a new region. The wl_shm_pool object encapsulates a piece of memory shared between the compositor and client. Through the wl_shm_pool object, the client can allocate shared memory wl_buffer objects. All objects created through the same pool share the same underlying mapped memory. Reusing the mapped memory avoids the setup/teardown overhead and is useful when interactively resizing a surface or for many small buffers. Create a wl_buffer object from the pool. The buffer is created offset bytes into the pool and has width and height as specified. The stride argument specifies the number of bytes from the beginning of one row to the beginning of the next. The format is the pixel format of the buffer and must be one of those advertised through the wl_shm.format event. A buffer will keep a reference to the pool it was created from so it is valid to destroy the pool immediately after creating a buffer from it. Destroy the shared memory pool. The mmapped memory will be released when all buffers that have been created from this pool are gone. This request will cause the server to remap the backing memory for the pool from the file descriptor passed when the pool was created, but using the new size. This request can only be used to make the pool bigger. This request only changes the amount of bytes that are mmapped by the server and does not touch the file corresponding to the file descriptor passed at creation time. It is the client's responsibility to ensure that the file is at least as big as the new pool size. A singleton global object that provides support for shared memory. Clients can create wl_shm_pool objects using the create_pool request. On binding the wl_shm object one or more format events are emitted to inform clients about the valid pixel formats that can be used for buffers. These errors can be emitted in response to wl_shm requests. This describes the memory layout of an individual pixel. All renderers should support argb8888 and xrgb8888 but any other formats are optional and may not be supported by the particular renderer in use. The drm format codes match the macros defined in drm_fourcc.h, except argb8888 and xrgb8888. The formats actually supported by the compositor will be reported by the format event. For all wl_shm formats and unless specified in another protocol extension, pre-multiplied alpha is used for pixel values. Create a new wl_shm_pool object. The pool can be used to create shared memory based buffer objects. The server will mmap size bytes of the passed file descriptor, to use as backing memory for the pool. Informs the client about a valid pixel format that can be used for buffers. Known formats include argb8888 and xrgb8888. Using this request a client can tell the server that it is not going to use the shm object anymore. Objects created via this interface remain unaffected. A buffer provides the content for a wl_surface. Buffers are created through factory interfaces such as wl_shm, wp_linux_buffer_params (from the linux-dmabuf protocol extension) or similar. It has a width and a height and can be attached to a wl_surface, but the mechanism by which a client provides and updates the contents is defined by the buffer factory interface. Color channels are assumed to be electrical rather than optical (in other words, encoded with a transfer function) unless otherwise specified. If the buffer uses a format that has an alpha channel, the alpha channel is assumed to be premultiplied into the electrical color channel values (after transfer function encoding) unless otherwise specified. Note, because wl_buffer objects are created from multiple independent factory interfaces, the wl_buffer interface is frozen at version 1. Destroy a buffer. If and how you need to release the backing storage is defined by the buffer factory interface. For possible side-effects to a surface, see wl_surface.attach. Sent when this wl_buffer is no longer used by the compositor. The client is now free to reuse or destroy this buffer and its backing storage. If a client receives a release event before the frame callback requested in the same wl_surface.commit that attaches this wl_buffer to a surface, then the client is immediately free to reuse the buffer and its backing storage, and does not need a second buffer for the next surface content update. Typically this is possible, when the compositor maintains a copy of the wl_surface contents, e.g. as a GL texture. This is an important optimization for GL(ES) compositors with wl_shm clients. A wl_data_offer represents a piece of data offered for transfer by another client (the source client). It is used by the copy-and-paste and drag-and-drop mechanisms. The offer describes the different mime types that the data can be converted to and provides the mechanism for transferring the data directly from the source client. Indicate that the client can accept the given mime type, or NULL for not accepted. For objects of version 2 or older, this request is used by the client to give feedback whether the client can receive the given mime type, or NULL if none is accepted; the feedback does not determine whether the drag-and-drop operation succeeds or not. For objects of version 3 or newer, this request determines the final result of the drag-and-drop operation. If the end result is that no mime types were accepted, the drag-and-drop operation will be cancelled and the corresponding drag source will receive wl_data_source.cancelled. Clients may still use this event in conjunction with wl_data_source.action for feedback. To transfer the offered data, the client issues this request and indicates the mime type it wants to receive. The transfer happens through the passed file descriptor (typically created with the pipe system call). The source client writes the data in the mime type representation requested and then closes the file descriptor. The receiving client reads from the read end of the pipe until EOF and then closes its end, at which point the transfer is complete. This request may happen multiple times for different mime types, both before and after wl_data_device.drop. Drag-and-drop destination clients may preemptively fetch data or examine it more closely to determine acceptance. Destroy the data offer. Sent immediately after creating the wl_data_offer object. One event per offered mime type. Notifies the compositor that the drag destination successfully finished the drag-and-drop operation. Upon receiving this request, the compositor will emit wl_data_source.dnd_finished on the drag source client. It is a client error to perform other requests than wl_data_offer.destroy after this one. It is also an error to perform this request after a NULL mime type has been set in wl_data_offer.accept or no action was received through wl_data_offer.action. If wl_data_offer.finish request is received for a non drag and drop operation, the invalid_finish protocol error is raised. Sets the actions that the destination side client supports for this operation. This request may trigger the emission of wl_data_source.action and wl_data_offer.action events if the compositor needs to change the selected action. This request can be called multiple times throughout the drag-and-drop operation, typically in response to wl_data_device.enter or wl_data_device.motion events. This request determines the final result of the drag-and-drop operation. If the end result is that no action is accepted, the drag source will receive wl_data_source.cancelled. The dnd_actions argument must contain only values expressed in the wl_data_device_manager.dnd_actions enum, and the preferred_action argument must only contain one of those values set, otherwise it will result in a protocol error. While managing an "ask" action, the destination drag-and-drop client may perform further wl_data_offer.receive requests, and is expected to perform one last wl_data_offer.set_actions request with a preferred action other than "ask" (and optionally wl_data_offer.accept) before requesting wl_data_offer.finish, in order to convey the action selected by the user. If the preferred action is not in the wl_data_offer.source_actions mask, an error will be raised. If the "ask" action is dismissed (e.g. user cancellation), the client is expected to perform wl_data_offer.destroy right away. This request can only be made on drag-and-drop offers, a protocol error will be raised otherwise. This event indicates the actions offered by the data source. It will be sent immediately after creating the wl_data_offer object, or anytime the source side changes its offered actions through wl_data_source.set_actions. This event indicates the action selected by the compositor after matching the source/destination side actions. Only one action (or none) will be offered here. This event can be emitted multiple times during the drag-and-drop operation in response to destination side action changes through wl_data_offer.set_actions. This event will no longer be emitted after wl_data_device.drop happened on the drag-and-drop destination, the client must honor the last action received, or the last preferred one set through wl_data_offer.set_actions when handling an "ask" action. Compositors may also change the selected action on the fly, mainly in response to keyboard modifier changes during the drag-and-drop operation. The most recent action received is always the valid one. Prior to receiving wl_data_device.drop, the chosen action may change (e.g. due to keyboard modifiers being pressed). At the time of receiving wl_data_device.drop the drag-and-drop destination must honor the last action received. Action changes may still happen after wl_data_device.drop, especially on "ask" actions, where the drag-and-drop destination may choose another action afterwards. Action changes happening at this stage are always the result of inter-client negotiation, the compositor shall no longer be able to induce a different action. Upon "ask" actions, it is expected that the drag-and-drop destination may potentially choose a different action and/or mime type, based on wl_data_offer.source_actions and finally chosen by the user (e.g. popping up a menu with the available options). The final wl_data_offer.set_actions and wl_data_offer.accept requests must happen before the call to wl_data_offer.finish. The wl_data_source object is the source side of a wl_data_offer. It is created by the source client in a data transfer and provides a way to describe the offered data and a way to respond to requests to transfer the data. This request adds a mime type to the set of mime types advertised to targets. Can be called several times to offer multiple types. Destroy the data source. Sent when a target accepts pointer_focus or motion events. If a target does not accept any of the offered types, type is NULL. Used for feedback during drag-and-drop. Request for data from the client. Send the data as the specified mime type over the passed file descriptor, then close it. This data source is no longer valid. There are several reasons why this could happen: - The data source has been replaced by another data source. - The drag-and-drop operation was performed, but the drop destination did not accept any of the mime types offered through wl_data_source.target. - The drag-and-drop operation was performed, but the drop destination did not select any of the actions present in the mask offered through wl_data_source.action. - The drag-and-drop operation was performed but didn't happen over a surface. - The compositor cancelled the drag-and-drop operation (e.g. compositor dependent timeouts to avoid stale drag-and-drop transfers). The client should clean up and destroy this data source. For objects of version 2 or older, wl_data_source.cancelled will only be emitted if the data source was replaced by another data source. Sets the actions that the source side client supports for this operation. This request may trigger wl_data_source.action and wl_data_offer.action events if the compositor needs to change the selected action. The dnd_actions argument must contain only values expressed in the wl_data_device_manager.dnd_actions enum, otherwise it will result in a protocol error. This request must be made once only, and can only be made on sources used in drag-and-drop, so it must be performed before wl_data_device.start_drag. Attempting to use the source other than for drag-and-drop will raise a protocol error. The user performed the drop action. This event does not indicate acceptance, wl_data_source.cancelled may still be emitted afterwards if the drop destination does not accept any mime type. However, this event might however not be received if the compositor cancelled the drag-and-drop operation before this event could happen. Note that the data_source may still be used in the future and should not be destroyed here. The drop destination finished interoperating with this data source, so the client is now free to destroy this data source and free all associated data. If the action used to perform the operation was "move", the source can now delete the transferred data. This event indicates the action selected by the compositor after matching the source/destination side actions. Only one action (or none) will be offered here. This event can be emitted multiple times during the drag-and-drop operation, mainly in response to destination side changes through wl_data_offer.set_actions, and as the data device enters/leaves surfaces. It is only possible to receive this event after wl_data_source.dnd_drop_performed if the drag-and-drop operation ended in an "ask" action, in which case the final wl_data_source.action event will happen immediately before wl_data_source.dnd_finished. Compositors may also change the selected action on the fly, mainly in response to keyboard modifier changes during the drag-and-drop operation. The most recent action received is always the valid one. The chosen action may change alongside negotiation (e.g. an "ask" action can turn into a "move" operation), so the effects of the final action must always be applied in wl_data_offer.dnd_finished. Clients can trigger cursor surface changes from this point, so they reflect the current action. There is one wl_data_device per seat which can be obtained from the global wl_data_device_manager singleton. A wl_data_device provides access to inter-client data transfer mechanisms such as copy-and-paste and drag-and-drop. This request asks the compositor to start a drag-and-drop operation on behalf of the client. The source argument is the data source that provides the data for the eventual data transfer. If source is NULL, enter, leave and motion events are sent only to the client that initiated the drag and the client is expected to handle the data passing internally. If source is destroyed, the drag-and-drop session will be cancelled. The origin surface is the surface where the drag originates and the client must have an active implicit grab that matches the serial. The icon surface is an optional (can be NULL) surface that provides an icon to be moved around with the cursor. Initially, the top-left corner of the icon surface is placed at the cursor hotspot, but subsequent wl_surface.offset requests can move the relative position. Attach requests must be confirmed with wl_surface.commit as usual. The icon surface is given the role of a drag-and-drop icon. If the icon surface already has another role, it raises a protocol error. The input region is ignored for wl_surfaces with the role of a drag-and-drop icon. The given source may not be used in any further set_selection or start_drag requests. Attempting to reuse a previously-used source may send a used_source error. This request asks the compositor to set the selection to the data from the source on behalf of the client. To unset the selection, set the source to NULL. The given source may not be used in any further set_selection or start_drag requests. Attempting to reuse a previously-used source may send a used_source error. The data_offer event introduces a new wl_data_offer object, which will subsequently be used in either the data_device.enter event (for drag-and-drop) or the data_device.selection event (for selections). Immediately following the data_device.data_offer event, the new data_offer object will send out data_offer.offer events to describe the mime types it offers. This event is sent when an active drag-and-drop pointer enters a surface owned by the client. The position of the pointer at enter time is provided by the x and y arguments, in surface-local coordinates. This event is sent when the drag-and-drop pointer leaves the surface and the session ends. The client must destroy the wl_data_offer introduced at enter time at this point. This event is sent when the drag-and-drop pointer moves within the currently focused surface. The new position of the pointer is provided by the x and y arguments, in surface-local coordinates. The event is sent when a drag-and-drop operation is ended because the implicit grab is removed. The drag-and-drop destination is expected to honor the last action received through wl_data_offer.action, if the resulting action is "copy" or "move", the destination can still perform wl_data_offer.receive requests, and is expected to end all transfers with a wl_data_offer.finish request. If the resulting action is "ask", the action will not be considered final. The drag-and-drop destination is expected to perform one last wl_data_offer.set_actions request, or wl_data_offer.destroy in order to cancel the operation. The selection event is sent out to notify the client of a new wl_data_offer for the selection for this device. The data_device.data_offer and the data_offer.offer events are sent out immediately before this event to introduce the data offer object. The selection event is sent to a client immediately before receiving keyboard focus and when a new selection is set while the client has keyboard focus. The data_offer is valid until a new data_offer or NULL is received or until the client loses keyboard focus. Switching surface with keyboard focus within the same client doesn't mean a new selection will be sent. The client must destroy the previous selection data_offer, if any, upon receiving this event. This request destroys the data device. The wl_data_device_manager is a singleton global object that provides access to inter-client data transfer mechanisms such as copy-and-paste and drag-and-drop. These mechanisms are tied to a wl_seat and this interface lets a client get a wl_data_device corresponding to a wl_seat. Depending on the version bound, the objects created from the bound wl_data_device_manager object will have different requirements for functioning properly. See wl_data_source.set_actions, wl_data_offer.accept and wl_data_offer.finish for details. Create a new data source. Create a new data device for a given seat. This is a bitmask of the available/preferred actions in a drag-and-drop operation. In the compositor, the selected action is a result of matching the actions offered by the source and destination sides. "action" events with a "none" action will be sent to both source and destination if there is no match. All further checks will effectively happen on (source actions ∩ destination actions). In addition, compositors may also pick different actions in reaction to key modifiers being pressed. One common design that is used in major toolkits (and the behavior recommended for compositors) is: - If no modifiers are pressed, the first match (in bit order) will be used. - Pressing Shift selects "move", if enabled in the mask. - Pressing Control selects "copy", if enabled in the mask. Behavior beyond that is considered implementation-dependent. Compositors may for example bind other modifiers (like Alt/Meta) or drags initiated with other buttons than BTN_LEFT to specific actions (e.g. "ask"). This interface is implemented by servers that provide desktop-style user interfaces. It allows clients to associate a wl_shell_surface with a basic surface. Note! This protocol is deprecated and not intended for production use. For desktop-style user interfaces, use xdg_shell. Compositors and clients should not implement this interface. Create a shell surface for an existing surface. This gives the wl_surface the role of a shell surface. If the wl_surface already has another role, it raises a protocol error. Only one shell surface can be associated with a given surface. An interface that may be implemented by a wl_surface, for implementations that provide a desktop-style user interface. It provides requests to treat surfaces like toplevel, fullscreen or popup windows, move, resize or maximize them, associate metadata like title and class, etc. On the server side the object is automatically destroyed when the related wl_surface is destroyed. On the client side, wl_shell_surface_destroy() must be called before destroying the wl_surface object. A client must respond to a ping event with a pong request or the client may be deemed unresponsive. Start a pointer-driven move of the surface. This request must be used in response to a button press event. The server may ignore move requests depending on the state of the surface (e.g. fullscreen or maximized). These values are used to indicate which edge of a surface is being dragged in a resize operation. The server may use this information to adapt its behavior, e.g. choose an appropriate cursor image. Start a pointer-driven resizing of the surface. This request must be used in response to a button press event. The server may ignore resize requests depending on the state of the surface (e.g. fullscreen or maximized). Map the surface as a toplevel surface. A toplevel surface is not fullscreen, maximized or transient. These flags specify details of the expected behaviour of transient surfaces. Used in the set_transient request. Map the surface relative to an existing surface. The x and y arguments specify the location of the upper left corner of the surface relative to the upper left corner of the parent surface, in surface-local coordinates. The flags argument controls details of the transient behaviour. Hints to indicate to the compositor how to deal with a conflict between the dimensions of the surface and the dimensions of the output. The compositor is free to ignore this parameter. Map the surface as a fullscreen surface. If an output parameter is given then the surface will be made fullscreen on that output. If the client does not specify the output then the compositor will apply its policy - usually choosing the output on which the surface has the biggest surface area. The client may specify a method to resolve a size conflict between the output size and the surface size - this is provided through the method parameter. The framerate parameter is used only when the method is set to "driver", to indicate the preferred framerate. A value of 0 indicates that the client does not care about framerate. The framerate is specified in mHz, that is framerate of 60000 is 60Hz. A method of "scale" or "driver" implies a scaling operation of the surface, either via a direct scaling operation or a change of the output mode. This will override any kind of output scaling, so that mapping a surface with a buffer size equal to the mode can fill the screen independent of buffer_scale. A method of "fill" means we don't scale up the buffer, however any output scale is applied. This means that you may run into an edge case where the application maps a buffer with the same size of the output mode but buffer_scale 1 (thus making a surface larger than the output). In this case it is allowed to downscale the results to fit the screen. The compositor must reply to this request with a configure event with the dimensions for the output on which the surface will be made fullscreen. Map the surface as a popup. A popup surface is a transient surface with an added pointer grab. An existing implicit grab will be changed to owner-events mode, and the popup grab will continue after the implicit grab ends (i.e. releasing the mouse button does not cause the popup to be unmapped). The popup grab continues until the window is destroyed or a mouse button is pressed in any other client's window. A click in any of the client's surfaces is reported as normal, however, clicks in other clients' surfaces will be discarded and trigger the callback. The x and y arguments specify the location of the upper left corner of the surface relative to the upper left corner of the parent surface, in surface-local coordinates. Map the surface as a maximized surface. If an output parameter is given then the surface will be maximized on that output. If the client does not specify the output then the compositor will apply its policy - usually choosing the output on which the surface has the biggest surface area. The compositor will reply with a configure event telling the expected new surface size. The operation is completed on the next buffer attach to this surface. A maximized surface typically fills the entire output it is bound to, except for desktop elements such as panels. This is the main difference between a maximized shell surface and a fullscreen shell surface. The details depend on the compositor implementation. Set a short title for the surface. This string may be used to identify the surface in a task bar, window list, or other user interface elements provided by the compositor. The string must be encoded in UTF-8. Set a class for the surface. The surface class identifies the general class of applications to which the surface belongs. A common convention is to use the file name (or the full path if it is a non-standard location) of the application's .desktop file as the class. Ping a client to check if it is receiving events and sending requests. A client is expected to reply with a pong request. The configure event asks the client to resize its surface. The size is a hint, in the sense that the client is free to ignore it if it doesn't resize, pick a smaller size (to satisfy aspect ratio or resize in steps of NxM pixels). The edges parameter provides a hint about how the surface was resized. The client may use this information to decide how to adjust its content to the new size (e.g. a scrolling area might adjust its content position to leave the viewable content unmoved). The client is free to dismiss all but the last configure event it received. The width and height arguments specify the size of the window in surface-local coordinates. The popup_done event is sent out when a popup grab is broken, that is, when the user clicks a surface that doesn't belong to the client owning the popup surface. A surface is a rectangular area that may be displayed on zero or more outputs, and shown any number of times at the compositor's discretion. They can present wl_buffers, receive user input, and define a local coordinate system. The size of a surface (and relative positions on it) is described in surface-local coordinates, which may differ from the buffer coordinates of the pixel content, in case a buffer_transform or a buffer_scale is used. A surface without a "role" is fairly useless: a compositor does not know where, when or how to present it. The role is the purpose of a wl_surface. Examples of roles are a cursor for a pointer (as set by wl_pointer.set_cursor), a drag icon (wl_data_device.start_drag), a sub-surface (wl_subcompositor.get_subsurface), and a window as defined by a shell protocol (e.g. wl_shell.get_shell_surface). A surface can have only one role at a time. Initially a wl_surface does not have a role. Once a wl_surface is given a role, it is set permanently for the whole lifetime of the wl_surface object. Giving the current role again is allowed, unless explicitly forbidden by the relevant interface specification. Surface roles are given by requests in other interfaces such as wl_pointer.set_cursor. The request should explicitly mention that this request gives a role to a wl_surface. Often, this request also creates a new protocol object that represents the role and adds additional functionality to wl_surface. When a client wants to destroy a wl_surface, they must destroy this role object before the wl_surface, otherwise a defunct_role_object error is sent. Destroying the role object does not remove the role from the wl_surface, but it may stop the wl_surface from "playing the role". For instance, if a wl_subsurface object is destroyed, the wl_surface it was created for will be unmapped and forget its position and z-order. It is allowed to create a wl_subsurface for the same wl_surface again, but it is not allowed to use the wl_surface as a cursor (cursor is a different role than sub-surface, and role switching is not allowed). These errors can be emitted in response to wl_surface requests. Deletes the surface and invalidates its object ID. Set a buffer as the content of this surface. The new size of the surface is calculated based on the buffer size transformed by the inverse buffer_transform and the inverse buffer_scale. This means that at commit time the supplied buffer size must be an integer multiple of the buffer_scale. If that's not the case, an invalid_size error is sent. The x and y arguments specify the location of the new pending buffer's upper left corner, relative to the current buffer's upper left corner, in surface-local coordinates. In other words, the x and y, combined with the new surface size define in which directions the surface's size changes. Setting anything other than 0 as x and y arguments is discouraged, and should instead be replaced with using the separate wl_surface.offset request. When the bound wl_surface version is 5 or higher, passing any non-zero x or y is a protocol violation, and will result in an 'invalid_offset' error being raised. The x and y arguments are ignored and do not change the pending state. To achieve equivalent semantics, use wl_surface.offset. Surface contents are double-buffered state, see wl_surface.commit. The initial surface contents are void; there is no content. wl_surface.attach assigns the given wl_buffer as the pending wl_buffer. wl_surface.commit makes the pending wl_buffer the new surface contents, and the size of the surface becomes the size calculated from the wl_buffer, as described above. After commit, there is no pending buffer until the next attach. Committing a pending wl_buffer allows the compositor to read the pixels in the wl_buffer. The compositor may access the pixels at any time after the wl_surface.commit request. When the compositor will not access the pixels anymore, it will send the wl_buffer.release event. Only after receiving wl_buffer.release, the client may reuse the wl_buffer. A wl_buffer that has been attached and then replaced by another attach instead of committed will not receive a release event, and is not used by the compositor. If a pending wl_buffer has been committed to more than one wl_surface, the delivery of wl_buffer.release events becomes undefined. A well behaved client should not rely on wl_buffer.release events in this case. Alternatively, a client could create multiple wl_buffer objects from the same backing storage or use wp_linux_buffer_release. Destroying the wl_buffer after wl_buffer.release does not change the surface contents. Destroying the wl_buffer before wl_buffer.release is allowed as long as the underlying buffer storage isn't re-used (this can happen e.g. on client process termination). However, if the client destroys the wl_buffer before receiving the wl_buffer.release event and mutates the underlying buffer storage, the surface contents become undefined immediately. If wl_surface.attach is sent with a NULL wl_buffer, the following wl_surface.commit will remove the surface content. If a pending wl_buffer has been destroyed, the result is not specified. Many compositors are known to remove the surface content on the following wl_surface.commit, but this behaviour is not universal. Clients seeking to maximise compatibility should not destroy pending buffers and should ensure that they explicitly remove content from surfaces, even after destroying buffers. This request is used to describe the regions where the pending buffer is different from the current surface contents, and where the surface therefore needs to be repainted. The compositor ignores the parts of the damage that fall outside of the surface. Damage is double-buffered state, see wl_surface.commit. The damage rectangle is specified in surface-local coordinates, where x and y specify the upper left corner of the damage rectangle. The initial value for pending damage is empty: no damage. wl_surface.damage adds pending damage: the new pending damage is the union of old pending damage and the given rectangle. wl_surface.commit assigns pending damage as the current damage, and clears pending damage. The server will clear the current damage as it repaints the surface. Note! New clients should not use this request. Instead damage can be posted with wl_surface.damage_buffer which uses buffer coordinates instead of surface coordinates. Request a notification when it is a good time to start drawing a new frame, by creating a frame callback. This is useful for throttling redrawing operations, and driving animations. When a client is animating on a wl_surface, it can use the 'frame' request to get notified when it is a good time to draw and commit the next frame of animation. If the client commits an update earlier than that, it is likely that some updates will not make it to the display, and the client is wasting resources by drawing too often. The frame request will take effect on the next wl_surface.commit. The notification will only be posted for one frame unless requested again. For a wl_surface, the notifications are posted in the order the frame requests were committed. The server must send the notifications so that a client will not send excessive updates, while still allowing the highest possible update rate for clients that wait for the reply before drawing again. The server should give some time for the client to draw and commit after sending the frame callback events to let it hit the next output refresh. A server should avoid signaling the frame callbacks if the surface is not visible in any way, e.g. the surface is off-screen, or completely obscured by other opaque surfaces. The object returned by this request will be destroyed by the compositor after the callback is fired and as such the client must not attempt to use it after that point. The callback_data passed in the callback is the current time, in milliseconds, with an undefined base. This request sets the region of the surface that contains opaque content. The opaque region is an optimization hint for the compositor that lets it optimize the redrawing of content behind opaque regions. Setting an opaque region is not required for correct behaviour, but marking transparent content as opaque will result in repaint artifacts. The opaque region is specified in surface-local coordinates. The compositor ignores the parts of the opaque region that fall outside of the surface. Opaque region is double-buffered state, see wl_surface.commit. wl_surface.set_opaque_region changes the pending opaque region. wl_surface.commit copies the pending region to the current region. Otherwise, the pending and current regions are never changed. The initial value for an opaque region is empty. Setting the pending opaque region has copy semantics, and the wl_region object can be destroyed immediately. A NULL wl_region causes the pending opaque region to be set to empty. This request sets the region of the surface that can receive pointer and touch events. Input events happening outside of this region will try the next surface in the server surface stack. The compositor ignores the parts of the input region that fall outside of the surface. The input region is specified in surface-local coordinates. Input region is double-buffered state, see wl_surface.commit. wl_surface.set_input_region changes the pending input region. wl_surface.commit copies the pending region to the current region. Otherwise the pending and current regions are never changed, except cursor and icon surfaces are special cases, see wl_pointer.set_cursor and wl_data_device.start_drag. The initial value for an input region is infinite. That means the whole surface will accept input. Setting the pending input region has copy semantics, and the wl_region object can be destroyed immediately. A NULL wl_region causes the input region to be set to infinite. Surface state (input, opaque, and damage regions, attached buffers, etc.) is double-buffered. Protocol requests modify the pending state, as opposed to the active state in use by the compositor. A commit request atomically creates a content update from the pending state, even if the pending state has not been touched. The content update is placed in a queue until it becomes active. After commit, the new pending state is as documented for each related request. When the content update is applied, the wl_buffer is applied before all other state. This means that all coordinates in double-buffered state are relative to the newly attached wl_buffers, except for wl_surface.attach itself. If there is no newly attached wl_buffer, the coordinates are relative to the previous content update. All requests that need a commit to become effective are documented to affect double-buffered state. Other interfaces may add further double-buffered surface state. This is emitted whenever a surface's creation, movement, or resizing results in some part of it being within the scanout region of an output. Note that a surface may be overlapping with zero or more outputs. This is emitted whenever a surface's creation, movement, or resizing results in it no longer having any part of it within the scanout region of an output. Clients should not use the number of outputs the surface is on for frame throttling purposes. The surface might be hidden even if no leave event has been sent, and the compositor might expect new surface content updates even if no enter event has been sent. The frame event should be used instead. This request sets the transformation that the client has already applied to the content of the buffer. The accepted values for the transform parameter are the values for wl_output.transform. The compositor applies the inverse of this transformation whenever it uses the buffer contents. Buffer transform is double-buffered state, see wl_surface.commit. A newly created surface has its buffer transformation set to normal. wl_surface.set_buffer_transform changes the pending buffer transformation. wl_surface.commit copies the pending buffer transformation to the current one. Otherwise, the pending and current values are never changed. The purpose of this request is to allow clients to render content according to the output transform, thus permitting the compositor to use certain optimizations even if the display is rotated. Using hardware overlays and scanning out a client buffer for fullscreen surfaces are examples of such optimizations. Those optimizations are highly dependent on the compositor implementation, so the use of this request should be considered on a case-by-case basis. Note that if the transform value includes 90 or 270 degree rotation, the width of the buffer will become the surface height and the height of the buffer will become the surface width. If transform is not one of the values from the wl_output.transform enum the invalid_transform protocol error is raised. This request sets an optional scaling factor on how the compositor interprets the contents of the buffer attached to the window. Buffer scale is double-buffered state, see wl_surface.commit. A newly created surface has its buffer scale set to 1. wl_surface.set_buffer_scale changes the pending buffer scale. wl_surface.commit copies the pending buffer scale to the current one. Otherwise, the pending and current values are never changed. The purpose of this request is to allow clients to supply higher resolution buffer data for use on high resolution outputs. It is intended that you pick the same buffer scale as the scale of the output that the surface is displayed on. This means the compositor can avoid scaling when rendering the surface on that output. Note that if the scale is larger than 1, then you have to attach a buffer that is larger (by a factor of scale in each dimension) than the desired surface size. If scale is not greater than 0 the invalid_scale protocol error is raised. This request is used to describe the regions where the pending buffer is different from the current surface contents, and where the surface therefore needs to be repainted. The compositor ignores the parts of the damage that fall outside of the surface. Damage is double-buffered state, see wl_surface.commit. The damage rectangle is specified in buffer coordinates, where x and y specify the upper left corner of the damage rectangle. The initial value for pending damage is empty: no damage. wl_surface.damage_buffer adds pending damage: the new pending damage is the union of old pending damage and the given rectangle. wl_surface.commit assigns pending damage as the current damage, and clears pending damage. The server will clear the current damage as it repaints the surface. This request differs from wl_surface.damage in only one way - it takes damage in buffer coordinates instead of surface-local coordinates. While this generally is more intuitive than surface coordinates, it is especially desirable when using wp_viewport or when a drawing library (like EGL) is unaware of buffer scale and buffer transform. Note: Because buffer transformation changes and damage requests may be interleaved in the protocol stream, it is impossible to determine the actual mapping between surface and buffer damage until wl_surface.commit time. Therefore, compositors wishing to take both kinds of damage into account will have to accumulate damage from the two requests separately and only transform from one to the other after receiving the wl_surface.commit. The x and y arguments specify the location of the new pending buffer's upper left corner, relative to the current buffer's upper left corner, in surface-local coordinates. In other words, the x and y, combined with the new surface size define in which directions the surface's size changes. Surface location offset is double-buffered state, see wl_surface.commit. This request is semantically equivalent to and the replaces the x and y arguments in the wl_surface.attach request in wl_surface versions prior to 5. See wl_surface.attach for details. This event indicates the preferred buffer scale for this surface. It is sent whenever the compositor's preference changes. Before receiving this event the preferred buffer scale for this surface is 1. It is intended that scaling aware clients use this event to scale their content and use wl_surface.set_buffer_scale to indicate the scale they have rendered with. This allows clients to supply a higher detail buffer. The compositor shall emit a scale value greater than 0. This event indicates the preferred buffer transform for this surface. It is sent whenever the compositor's preference changes. Before receiving this event the preferred buffer transform for this surface is normal. Applying this transformation to the surface buffer contents and using wl_surface.set_buffer_transform might allow the compositor to use the surface buffer more efficiently. A seat is a group of keyboards, pointer and touch devices. This object is published as a global during start up, or when such a device is hot plugged. A seat typically has a pointer and maintains a keyboard focus and a pointer focus. This is a bitmask of capabilities this seat has; if a member is set, then it is present on the seat. These errors can be emitted in response to wl_seat requests. This is emitted whenever a seat gains or loses the pointer, keyboard or touch capabilities. The argument is a capability enum containing the complete set of capabilities this seat has. When the pointer capability is added, a client may create a wl_pointer object using the wl_seat.get_pointer request. This object will receive pointer events until the capability is removed in the future. When the pointer capability is removed, a client should destroy the wl_pointer objects associated with the seat where the capability was removed, using the wl_pointer.release request. No further pointer events will be received on these objects. In some compositors, if a seat regains the pointer capability and a client has a previously obtained wl_pointer object of version 4 or less, that object may start sending pointer events again. This behavior is considered a misinterpretation of the intended behavior and must not be relied upon by the client. wl_pointer objects of version 5 or later must not send events if created before the most recent event notifying the client of an added pointer capability. The above behavior also applies to wl_keyboard and wl_touch with the keyboard and touch capabilities, respectively. The ID provided will be initialized to the wl_pointer interface for this seat. This request only takes effect if the seat has the pointer capability, or has had the pointer capability in the past. It is a protocol violation to issue this request on a seat that has never had the pointer capability. The missing_capability error will be sent in this case. The ID provided will be initialized to the wl_keyboard interface for this seat. This request only takes effect if the seat has the keyboard capability, or has had the keyboard capability in the past. It is a protocol violation to issue this request on a seat that has never had the keyboard capability. The missing_capability error will be sent in this case. The ID provided will be initialized to the wl_touch interface for this seat. This request only takes effect if the seat has the touch capability, or has had the touch capability in the past. It is a protocol violation to issue this request on a seat that has never had the touch capability. The missing_capability error will be sent in this case. In a multi-seat configuration the seat name can be used by clients to help identify which physical devices the seat represents. The seat name is a UTF-8 string with no convention defined for its contents. Each name is unique among all wl_seat globals. The name is only guaranteed to be unique for the current compositor instance. The same seat names are used for all clients. Thus, the name can be shared across processes to refer to a specific wl_seat global. The name event is sent after binding to the seat global. This event is only sent once per seat object, and the name does not change over the lifetime of the wl_seat global. Compositors may re-use the same seat name if the wl_seat global is destroyed and re-created later. Using this request a client can tell the server that it is not going to use the seat object anymore. The wl_pointer interface represents one or more input devices, such as mice, which control the pointer location and pointer_focus of a seat. The wl_pointer interface generates motion, enter and leave events for the surfaces that the pointer is located over, and button and axis events for button presses, button releases and scrolling. Set the pointer surface, i.e., the surface that contains the pointer image (cursor). This request gives the surface the role of a cursor. If the surface already has another role, it raises a protocol error. The cursor actually changes only if the pointer focus for this device is one of the requesting client's surfaces or the surface parameter is the current pointer surface. If there was a previous surface set with this request it is replaced. If surface is NULL, the pointer image is hidden. The parameters hotspot_x and hotspot_y define the position of the pointer surface relative to the pointer location. Its top-left corner is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the coordinates of the pointer location, in surface-local coordinates. On wl_surface.offset requests to the pointer surface, hotspot_x and hotspot_y are decremented by the x and y parameters passed to the request. The offset must be applied by wl_surface.commit as usual. The hotspot can also be updated by passing the currently set pointer surface to this request with new values for hotspot_x and hotspot_y. The input region is ignored for wl_surfaces with the role of a cursor. When the use as a cursor ends, the wl_surface is unmapped. The serial parameter must match the latest wl_pointer.enter serial number sent to the client. Otherwise the request will be ignored. Notification that this seat's pointer is focused on a certain surface. When a seat's focus enters a surface, the pointer image is undefined and a client should respond to this event by setting an appropriate pointer image with the set_cursor request. Notification that this seat's pointer is no longer focused on a certain surface. The leave notification is sent before the enter notification for the new focus. Notification of pointer location change. The arguments surface_x and surface_y are the location relative to the focused surface. Describes the physical state of a button that produced the button event. Mouse button click and release notifications. The location of the click is given by the last motion or enter event. The time argument is a timestamp with millisecond granularity, with an undefined base. The button is a button code as defined in the Linux kernel's linux/input-event-codes.h header file, e.g. BTN_LEFT. Any 16-bit button code value is reserved for future additions to the kernel's event code list. All other button codes above 0xFFFF are currently undefined but may be used in future versions of this protocol. Describes the axis types of scroll events. Scroll and other axis notifications. For scroll events (vertical and horizontal scroll axes), the value parameter is the length of a vector along the specified axis in a coordinate space identical to those of motion events, representing a relative movement along the specified axis. For devices that support movements non-parallel to axes multiple axis events will be emitted. When applicable, for example for touch pads, the server can choose to emit scroll events where the motion vector is equivalent to a motion event vector. When applicable, a client can transform its content relative to the scroll distance. Using this request a client can tell the server that it is not going to use the pointer object anymore. This request destroys the pointer proxy object, so clients must not call wl_pointer_destroy() after using this request. Indicates the end of a set of events that logically belong together. A client is expected to accumulate the data in all events within the frame before proceeding. All wl_pointer events before a wl_pointer.frame event belong logically together. For example, in a diagonal scroll motion the compositor will send an optional wl_pointer.axis_source event, two wl_pointer.axis events (horizontal and vertical) and finally a wl_pointer.frame event. The client may use this information to calculate a diagonal vector for scrolling. When multiple wl_pointer.axis events occur within the same frame, the motion vector is the combined motion of all events. When a wl_pointer.axis and a wl_pointer.axis_stop event occur within the same frame, this indicates that axis movement in one axis has stopped but continues in the other axis. When multiple wl_pointer.axis_stop events occur within the same frame, this indicates that these axes stopped in the same instance. A wl_pointer.frame event is sent for every logical event group, even if the group only contains a single wl_pointer event. Specifically, a client may get a sequence: motion, frame, button, frame, axis, frame, axis_stop, frame. The wl_pointer.enter and wl_pointer.leave events are logical events generated by the compositor and not the hardware. These events are also grouped by a wl_pointer.frame. When a pointer moves from one surface to another, a compositor should group the wl_pointer.leave event within the same wl_pointer.frame. However, a client must not rely on wl_pointer.leave and wl_pointer.enter being in the same wl_pointer.frame. Compositor-specific policies may require the wl_pointer.leave and wl_pointer.enter event being split across multiple wl_pointer.frame groups. Describes the source types for axis events. This indicates to the client how an axis event was physically generated; a client may adjust the user interface accordingly. For example, scroll events from a "finger" source may be in a smooth coordinate space with kinetic scrolling whereas a "wheel" source may be in discrete steps of a number of lines. The "continuous" axis source is a device generating events in a continuous coordinate space, but using something other than a finger. One example for this source is button-based scrolling where the vertical motion of a device is converted to scroll events while a button is held down. The "wheel tilt" axis source indicates that the actual device is a wheel but the scroll event is not caused by a rotation but a (usually sideways) tilt of the wheel. Source information for scroll and other axes. This event does not occur on its own. It is sent before a wl_pointer.frame event and carries the source information for all events within that frame. The source specifies how this event was generated. If the source is wl_pointer.axis_source.finger, a wl_pointer.axis_stop event will be sent when the user lifts the finger off the device. If the source is wl_pointer.axis_source.wheel, wl_pointer.axis_source.wheel_tilt or wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event may or may not be sent. Whether a compositor sends an axis_stop event for these sources is hardware-specific and implementation-dependent; clients must not rely on receiving an axis_stop event for these scroll sources and should treat scroll sequences from these scroll sources as unterminated by default. This event is optional. If the source is unknown for a particular axis event sequence, no event is sent. Only one wl_pointer.axis_source event is permitted per frame. The order of wl_pointer.axis_discrete and wl_pointer.axis_source is not guaranteed. Stop notification for scroll and other axes. For some wl_pointer.axis_source types, a wl_pointer.axis_stop event is sent to notify a client that the axis sequence has terminated. This enables the client to implement kinetic scrolling. See the wl_pointer.axis_source documentation for information on when this event may be generated. Any wl_pointer.axis events with the same axis_source after this event should be considered as the start of a new axis motion. The timestamp is to be interpreted identical to the timestamp in the wl_pointer.axis event. The timestamp value may be the same as a preceding wl_pointer.axis event. Discrete step information for scroll and other axes. This event carries the axis value of the wl_pointer.axis event in discrete steps (e.g. mouse wheel clicks). This event is deprecated with wl_pointer version 8 - this event is not sent to clients supporting version 8 or later. This event does not occur on its own, it is coupled with a wl_pointer.axis event that represents this axis value on a continuous scale. The protocol guarantees that each axis_discrete event is always followed by exactly one axis event with the same axis number within the same wl_pointer.frame. Note that the protocol allows for other events to occur between the axis_discrete and its coupled axis event, including other axis_discrete or axis events. A wl_pointer.frame must not contain more than one axis_discrete event per axis type. This event is optional; continuous scrolling devices like two-finger scrolling on touchpads do not have discrete steps and do not generate this event. The discrete value carries the directional information. e.g. a value of -2 is two steps towards the negative direction of this axis. The axis number is identical to the axis number in the associated axis event. The order of wl_pointer.axis_discrete and wl_pointer.axis_source is not guaranteed. Discrete high-resolution scroll information. This event carries high-resolution wheel scroll information, with each multiple of 120 representing one logical scroll step (a wheel detent). For example, an axis_value120 of 30 is one quarter of a logical scroll step in the positive direction, a value120 of -240 are two logical scroll steps in the negative direction within the same hardware event. Clients that rely on discrete scrolling should accumulate the value120 to multiples of 120 before processing the event. The value120 must not be zero. This event replaces the wl_pointer.axis_discrete event in clients supporting wl_pointer version 8 or later. Where a wl_pointer.axis_source event occurs in the same wl_pointer.frame, the axis source applies to this event. The order of wl_pointer.axis_value120 and wl_pointer.axis_source is not guaranteed. This specifies the direction of the physical motion that caused a wl_pointer.axis event, relative to the wl_pointer.axis direction. Relative directional information of the entity causing the axis motion. For a wl_pointer.axis event, the wl_pointer.axis_relative_direction event specifies the movement direction of the entity causing the wl_pointer.axis event. For example: - if a user's fingers on a touchpad move down and this causes a wl_pointer.axis vertical_scroll down event, the physical direction is 'identical' - if a user's fingers on a touchpad move down and this causes a wl_pointer.axis vertical_scroll up scroll up event ('natural scrolling'), the physical direction is 'inverted'. A client may use this information to adjust scroll motion of components. Specifically, enabling natural scrolling causes the content to change direction compared to traditional scrolling. Some widgets like volume control sliders should usually match the physical direction regardless of whether natural scrolling is active. This event enables clients to match the scroll direction of a widget to the physical direction. This event does not occur on its own, it is coupled with a wl_pointer.axis event that represents this axis value. The protocol guarantees that each axis_relative_direction event is always followed by exactly one axis event with the same axis number within the same wl_pointer.frame. Note that the protocol allows for other events to occur between the axis_relative_direction and its coupled axis event. The axis number is identical to the axis number in the associated axis event. The order of wl_pointer.axis_relative_direction, wl_pointer.axis_discrete and wl_pointer.axis_source is not guaranteed. The wl_keyboard interface represents one or more keyboards associated with a seat. Each wl_keyboard has the following logical state: - an active surface (possibly null), - the keys currently logically down, - the active modifiers, - the active group. By default, the active surface is null, the keys currently logically down are empty, the active modifiers and the active group are 0. This specifies the format of the keymap provided to the client with the wl_keyboard.keymap event. This event provides a file descriptor to the client which can be memory-mapped in read-only mode to provide a keyboard mapping description. From version 7 onwards, the fd must be mapped with MAP_PRIVATE by the recipient, as MAP_SHARED may fail. Notification that this seat's keyboard focus is on a certain surface. The compositor must send the wl_keyboard.modifiers event after this event. In the wl_keyboard logical state, this event sets the active surface to the surface argument and the keys currently logically down to the keys in the keys argument. The compositor must not send this event if the wl_keyboard already had an active surface immediately before this event. Notification that this seat's keyboard focus is no longer on a certain surface. The leave notification is sent before the enter notification for the new focus. In the wl_keyboard logical state, this event resets all values to their defaults. The compositor must not send this event if the active surface of the wl_keyboard was not equal to the surface argument immediately before this event. Describes the physical state of a key that produced the key event. A key was pressed or released. The time argument is a timestamp with millisecond granularity, with an undefined base. The key is a platform-specific key code that can be interpreted by feeding it to the keyboard mapping (see the keymap event). If this event produces a change in modifiers, then the resulting wl_keyboard.modifiers event must be sent after this event. In the wl_keyboard logical state, this event adds the key to the keys currently logically down (if the state argument is pressed) or removes the key from the keys currently logically down (if the state argument is released). The compositor must not send this event if the wl_keyboard did not have an active surface immediately before this event. The compositor must not send this event if state is pressed (resp. released) and the key was already logically down (resp. was not logically down) immediately before this event. Notifies clients that the modifier and/or group state has changed, and it should update its local state. The compositor may send this event without a surface of the client having keyboard focus, for example to tie modifier information to pointer focus instead. If a modifier event with pressed modifiers is sent without a prior enter event, the client can assume the modifier state is valid until it receives the next wl_keyboard.modifiers event. In order to reset the modifier state again, the compositor can send a wl_keyboard.modifiers event with no pressed modifiers. In the wl_keyboard logical state, this event updates the modifiers and group. Informs the client about the keyboard's repeat rate and delay. This event is sent as soon as the wl_keyboard object has been created, and is guaranteed to be received by the client before any key press event. Negative values for either rate or delay are illegal. A rate of zero will disable any repeating (regardless of the value of delay). This event can be sent later on as well with a new value if necessary, so clients should continue listening for the event past the creation of wl_keyboard. The wl_touch interface represents a touchscreen associated with a seat. Touch interactions can consist of one or more contacts. For each contact, a series of events is generated, starting with a down event, followed by zero or more motion events, and ending with an up event. Events relating to the same contact point can be identified by the ID of the sequence. A new touch point has appeared on the surface. This touch point is assigned a unique ID. Future events from this touch point reference this ID. The ID ceases to be valid after a touch up event and may be reused in the future. The touch point has disappeared. No further events will be sent for this touch point and the touch point's ID is released and may be reused in a future touch down event. A touch point has changed coordinates. Indicates the end of a set of events that logically belong together. A client is expected to accumulate the data in all events within the frame before proceeding. A wl_touch.frame terminates at least one event but otherwise no guarantee is provided about the set of events within a frame. A client must assume that any state not updated in a frame is unchanged from the previously known state. Sent if the compositor decides the touch stream is a global gesture. No further events are sent to the clients from that particular gesture. Touch cancellation applies to all touch points currently active on this client's surface. The client is responsible for finalizing the touch points, future touch points on this surface may reuse the touch point ID. No frame event is required after the cancel event. Sent when a touchpoint has changed its shape. This event does not occur on its own. It is sent before a wl_touch.frame event and carries the new shape information for any previously reported, or new touch points of that frame. Other events describing the touch point such as wl_touch.down, wl_touch.motion or wl_touch.orientation may be sent within the same wl_touch.frame. A client should treat these events as a single logical touch point update. The order of wl_touch.shape, wl_touch.orientation and wl_touch.motion is not guaranteed. A wl_touch.down event is guaranteed to occur before the first wl_touch.shape event for this touch ID but both events may occur within the same wl_touch.frame. A touchpoint shape is approximated by an ellipse through the major and minor axis length. The major axis length describes the longer diameter of the ellipse, while the minor axis length describes the shorter diameter. Major and minor are orthogonal and both are specified in surface-local coordinates. The center of the ellipse is always at the touchpoint location as reported by wl_touch.down or wl_touch.move. This event is only sent by the compositor if the touch device supports shape reports. The client has to make reasonable assumptions about the shape if it did not receive this event. Sent when a touchpoint has changed its orientation. This event does not occur on its own. It is sent before a wl_touch.frame event and carries the new shape information for any previously reported, or new touch points of that frame. Other events describing the touch point such as wl_touch.down, wl_touch.motion or wl_touch.shape may be sent within the same wl_touch.frame. A client should treat these events as a single logical touch point update. The order of wl_touch.shape, wl_touch.orientation and wl_touch.motion is not guaranteed. A wl_touch.down event is guaranteed to occur before the first wl_touch.orientation event for this touch ID but both events may occur within the same wl_touch.frame. The orientation describes the clockwise angle of a touchpoint's major axis to the positive surface y-axis and is normalized to the -180 to +180 degree range. The granularity of orientation depends on the touch device, some devices only support binary rotation values between 0 and 90 degrees. This event is only sent by the compositor if the touch device supports orientation reports. An output describes part of the compositor geometry. The compositor works in the 'compositor coordinate system' and an output corresponds to a rectangular area in that space that is actually visible. This typically corresponds to a monitor that displays part of the compositor space. This object is published as global during start up, or when a monitor is hotplugged. This enumeration describes how the physical pixels on an output are laid out. This describes transformations that clients and compositors apply to buffer contents. The flipped values correspond to an initial flip around a vertical axis followed by rotation. The purpose is mainly to allow clients to render accordingly and tell the compositor, so that for fullscreen surfaces, the compositor will still be able to scan out directly from client surfaces. The geometry event describes geometric properties of the output. The event is sent when binding to the output object and whenever any of the properties change. The physical size can be set to zero if it doesn't make sense for this output (e.g. for projectors or virtual outputs). The geometry event will be followed by a done event (starting from version 2). Clients should use wl_surface.preferred_buffer_transform instead of the transform advertised by this event to find the preferred buffer transform to use for a surface. Note: wl_output only advertises partial information about the output position and identification. Some compositors, for instance those not implementing a desktop-style output layout or those exposing virtual outputs, might fake this information. Instead of using x and y, clients should use xdg_output.logical_position. Instead of using make and model, clients should use name and description. These flags describe properties of an output mode. They are used in the flags bitfield of the mode event. The mode event describes an available mode for the output. The event is sent when binding to the output object and there will always be one mode, the current mode. The event is sent again if an output changes mode, for the mode that is now current. In other words, the current mode is always the last mode that was received with the current flag set. Non-current modes are deprecated. A compositor can decide to only advertise the current mode and never send other modes. Clients should not rely on non-current modes. The size of a mode is given in physical hardware units of the output device. This is not necessarily the same as the output size in the global compositor space. For instance, the output may be scaled, as described in wl_output.scale, or transformed, as described in wl_output.transform. Clients willing to retrieve the output size in the global compositor space should use xdg_output.logical_size instead. The vertical refresh rate can be set to zero if it doesn't make sense for this output (e.g. for virtual outputs). The mode event will be followed by a done event (starting from version 2). Clients should not use the refresh rate to schedule frames. Instead, they should use the wl_surface.frame event or the presentation-time protocol. Note: this information is not always meaningful for all outputs. Some compositors, such as those exposing virtual outputs, might fake the refresh rate or the size. This event is sent after all other properties have been sent after binding to the output object and after any other property changes done after that. This allows changes to the output properties to be seen as atomic, even if they happen via multiple events. This event contains scaling geometry information that is not in the geometry event. It may be sent after binding the output object or if the output scale changes later. The compositor will emit a non-zero, positive value for scale. If it is not sent, the client should assume a scale of 1. A scale larger than 1 means that the compositor will automatically scale surface buffers by this amount when rendering. This is used for very high resolution displays where applications rendering at the native resolution would be too small to be legible. Clients should use wl_surface.preferred_buffer_scale instead of this event to find the preferred buffer scale to use for a surface. The scale event will be followed by a done event. Using this request a client can tell the server that it is not going to use the output object anymore. Many compositors will assign user-friendly names to their outputs, show them to the user, allow the user to refer to an output, etc. The client may wish to know this name as well to offer the user similar behaviors. The name is a UTF-8 string with no convention defined for its contents. Each name is unique among all wl_output globals. The name is only guaranteed to be unique for the compositor instance. The same output name is used for all clients for a given wl_output global. Thus, the name can be shared across processes to refer to a specific wl_output global. The name is not guaranteed to be persistent across sessions, thus cannot be used to reliably identify an output in e.g. configuration files. Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do not assume that the name is a reflection of an underlying DRM connector, X11 connection, etc. The name event is sent after binding the output object. This event is only sent once per output object, and the name does not change over the lifetime of the wl_output global. Compositors may re-use the same output name if the wl_output global is destroyed and re-created later. Compositors should avoid re-using the same name if possible. The name event will be followed by a done event. Many compositors can produce human-readable descriptions of their outputs. The client may wish to know this description as well, e.g. for output selection purposes. The description is a UTF-8 string with no convention defined for its contents. The description is not guaranteed to be unique among all wl_output globals. Examples might include 'Foocorp 11" Display' or 'Virtual X11 output via :1'. The description event is sent after binding the output object and whenever the description changes. The description is optional, and may not be sent at all. The description event will be followed by a done event. A region object describes an area. Region objects are used to describe the opaque and input regions of a surface. Destroy the region. This will invalidate the object ID. Add the specified rectangle to the region. Subtract the specified rectangle from the region. The global interface exposing sub-surface compositing capabilities. A wl_surface, that has sub-surfaces associated, is called the parent surface. Sub-surfaces can be arbitrarily nested and create a tree of sub-surfaces. The root surface in a tree of sub-surfaces is the main surface. The main surface cannot be a sub-surface, because sub-surfaces must always have a parent. A main surface with its sub-surfaces forms a (compound) window. For window management purposes, this set of wl_surface objects is to be considered as a single window, and it should also behave as such. The aim of sub-surfaces is to offload some of the compositing work within a window from clients to the compositor. A prime example is a video player with decorations and video in separate wl_surface objects. This should allow the compositor to pass YUV video buffer processing to dedicated overlay hardware when possible. Informs the server that the client will not be using this protocol object anymore. This does not affect any other objects, wl_subsurface objects included. Create a sub-surface interface for the given surface, and associate it with the given parent surface. This turns a plain wl_surface into a sub-surface. The to-be sub-surface must not already have another role, and it must not have an existing wl_subsurface object. Otherwise the bad_surface protocol error is raised. Adding sub-surfaces to a parent is a double-buffered operation on the parent (see wl_surface.commit). The effect of adding a sub-surface becomes visible on the next time the state of the parent surface is applied. The parent surface must not be one of the child surface's descendants, and the parent must be different from the child surface, otherwise the bad_parent protocol error is raised. This request modifies the behaviour of wl_surface.commit request on the sub-surface, see the documentation on wl_subsurface interface. An additional interface to a wl_surface object, which has been made a sub-surface. A sub-surface has one parent surface. A sub-surface's size and position are not limited to that of the parent. Particularly, a sub-surface is not automatically clipped to its parent's area. A sub-surface becomes mapped, when a non-NULL wl_buffer is applied and the parent surface is mapped. The order of which one happens first is irrelevant. A sub-surface is hidden if the parent becomes hidden, or if a NULL wl_buffer is applied. These rules apply recursively through the tree of surfaces. The behaviour of a wl_surface.commit request on a sub-surface depends on the sub-surface's mode. The possible modes are synchronized and desynchronized, see methods wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized mode caches the wl_surface state to be applied when the parent's state gets applied, and desynchronized mode applies the pending wl_surface state directly. A sub-surface is initially in the synchronized mode. Sub-surfaces also have another kind of state, which is managed by wl_subsurface requests, as opposed to wl_surface requests. This state includes the sub-surface position relative to the parent surface (wl_subsurface.set_position), and the stacking order of the parent and its sub-surfaces (wl_subsurface.place_above and .place_below). This state is applied when the parent surface's wl_surface state is applied, regardless of the sub-surface's mode. As the exception, set_sync and set_desync are effective immediately. The main surface can be thought to be always in desynchronized mode, since it does not have a parent in the sub-surfaces sense. Even if a sub-surface is in desynchronized mode, it will behave as in synchronized mode, if its parent surface behaves as in synchronized mode. This rule is applied recursively throughout the tree of surfaces. This means, that one can set a sub-surface into synchronized mode, and then assume that all its child and grand-child sub-surfaces are synchronized, too, without explicitly setting them. Destroying a sub-surface takes effect immediately. If you need to synchronize the removal of a sub-surface to the parent surface update, unmap the sub-surface first by attaching a NULL wl_buffer, update parent, and then destroy the sub-surface. If the parent wl_surface object is destroyed, the sub-surface is unmapped. A sub-surface never has the keyboard focus of any seat. The wl_surface.offset request is ignored: clients must use set_position instead to move the sub-surface. The sub-surface interface is removed from the wl_surface object that was turned into a sub-surface with a wl_subcompositor.get_subsurface request. The wl_surface's association to the parent is deleted. The wl_surface is unmapped immediately. This schedules a sub-surface position change. The sub-surface will be moved so that its origin (top left corner pixel) will be at the location x, y of the parent surface coordinate system. The coordinates are not restricted to the parent surface area. Negative values are allowed. The scheduled coordinates will take effect whenever the state of the parent surface is applied. If more than one set_position request is invoked by the client before the commit of the parent surface, the position of a new request always replaces the scheduled position from any previous request. The initial position is 0, 0. This sub-surface is taken from the stack, and put back just above the reference surface, changing the z-order of the sub-surfaces. The reference surface must be one of the sibling surfaces, or the parent surface. Using any other surface, including this sub-surface, will cause a protocol error. The z-order is double-buffered. Requests are handled in order and applied immediately to a pending state. The final pending state is copied to the active state the next time the state of the parent surface is applied. A new sub-surface is initially added as the top-most in the stack of its siblings and parent. The sub-surface is placed just below the reference surface. See wl_subsurface.place_above. Change the commit behaviour of the sub-surface to synchronized mode, also described as the parent dependent mode. In synchronized mode, wl_surface.commit on a sub-surface will accumulate the committed state in a cache, but the state will not be applied and hence will not change the compositor output. The cached state is applied to the sub-surface immediately after the parent surface's state is applied. This ensures atomic updates of the parent and all its synchronized sub-surfaces. Applying the cached state will invalidate the cache, so further parent surface commits do not (re-)apply old state. See wl_subsurface for the recursive effect of this mode. Change the commit behaviour of the sub-surface to desynchronized mode, also described as independent or freely running mode. In desynchronized mode, wl_surface.commit on a sub-surface will apply the pending state directly, without caching, as happens normally with a wl_surface. Calling wl_surface.commit on the parent surface has no effect on the sub-surface's wl_surface state. This mode allows a sub-surface to be updated on its own. If cached state exists when wl_surface.commit is called in desynchronized mode, the pending state is added to the cached state, and applied as a whole. This invalidates the cache. Note: even if a sub-surface is set to desynchronized, a parent sub-surface may override it to behave as synchronized. For details, see wl_subsurface. If a surface's parent surface behaves as desynchronized, then the cached state is applied on set_desync. wayland-1.23.1/release.sh000077500000000000000000000036111466237767300152420ustar00rootroot00000000000000#!/bin/sh -eu build_dir=build-release if ! type glab >/dev/null; then echo "glab is needed to create a release" exit 1 fi case "$(git rev-parse --abbrev-ref HEAD)" in main | [0-9]*.[0-9]*) ;; *) echo "Not on the main or a stable branch" exit 1 esac if [ -n "$(git log @{upstream}..)" ]; then echo "The main branch has unpushed commits" exit 1 fi meson_options="" if [ -e "$build_dir" ]; then meson_options="$meson_options --wipe" fi meson setup "$build_dir" $meson_options prev_version="$(git describe --tags --abbrev=0)" version="$(meson introspect "$build_dir" --projectinfo | jq -r .version)" if [ "$version" = "$prev_version" ]; then echo "Version not bumped" exit 1 fi name="$(meson introspect "$build_dir" --projectinfo | jq -r .descriptive_name)" if [ "$name" = "" ]; then echo "Cannot determine project name" exit 1 fi ninja -C "$build_dir" dist archive_name="$name-$version.tar.xz" archive_path="$build_dir/meson-dist/$archive_name" gpg --detach-sig "$archive_path" sha256="$(cd $build_dir/meson-dist && sha256sum $archive_name)" sha512="$(cd $build_dir/meson-dist && sha512sum $archive_name)" archive_url="https://gitlab.freedesktop.org/wayland/$name/-/releases/$version/downloads/$archive_name" announce_path="$build_dir/meson-dist/$name-$version-announce.eml" current_branch=$(git branch --show-current) remote_name=$(git config --get branch.${current_branch}.remote) cat >"$announce_path" < Subject: [ANNOUNCE] $name $version `git shortlog --no-merges "$prev_version.."` git tag: $version $archive_url SHA256: $sha256 SHA512: $sha512 PGP: $archive_url.sig EOF echo "Release announcement written to $announce_path" echo -n "Release $name $version? [y/N] " read answer if [ "$answer" != "y" ]; then exit 1 fi git tag -s -m "$version" "$version" git push "$remote_name" "$version" glab release create "$version" "$archive_path"* --notes "" wayland-1.23.1/releasing.txt000066400000000000000000000045771466237767300160110ustar00rootroot00000000000000To make a release of Wayland, follow these steps. 0. Verify the test suites and codebase checks pass. All of the tests should either pass or skip. $ ninja -C build/ test 1. Update the first stanza of meson.build to the intended version. Then commit your changes: $ export RELEASE_NUMBER="x.y.z" $ export RELEASE_NAME="[alpha|beta|RC1|RC2|official|point]" $ git status $ git commit meson.build -m "build: bump to version $RELEASE_NUMBER for the $RELEASE_NAME release" $ git push 2. Run the release.sh script to generate the tarballs, sign and upload them, and generate a release announcement template. 3. Compose the release announcements. The script will generate a wayland-x.y.z-announce.eml file with a list of changes and tags. Prepend it with a human-readable listing of the most notable changes. For x.y.0 releases, indicate the schedule for the x.y+1.0 release. 4. PGP sign the release announcements and send them to wayland-devel@lists.freedesktop.org 5. Update releases.html in wayland-web with links to tarballs and the release email URL. The wl_register_release script in wayland-web will generate an HTML snippet that can be pasted into releases.html (or e.g. in emacs insert it via "C-u M-! scripts/wl_register_release x.y.z") and customized. Once satisfied: $ git commit ./releases.html -m "releases: Add ${RELEASE_NUMBER} release" $ git push $ ./deploy 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 cherry-pick them back to the stable branch. wayland-1.23.1/src/000077500000000000000000000000001466237767300140515ustar00rootroot00000000000000wayland-1.23.1/src/.gitignore000066400000000000000000000000371466237767300160410ustar00rootroot00000000000000*.dtd.embed /wayland-version.h wayland-1.23.1/src/connection.c000066400000000000000000001102331466237767300163540ustar00rootroot00000000000000/* * Copyright © 2008 Kristian Høgsberg * Copyright © 2013 Jason Ekstrand * * 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wayland-util.h" #include "wayland-private.h" #include "wayland-os.h" static inline uint32_t div_roundup(uint32_t n, size_t a) { /* The cast to uint64_t is necessary to prevent overflow when rounding * values close to UINT32_MAX. After the division it is again safe to * cast back to uint32_t. */ return (uint32_t) (((uint64_t) n + (a - 1)) / a); } struct wl_ring_buffer { char *data; size_t head, tail; uint32_t size_bits; uint32_t max_size_bits; /* 0 for unlimited */ }; #define MAX_FDS_OUT 28 #define CLEN (CMSG_LEN(MAX_FDS_OUT * sizeof(int32_t))) struct wl_connection { struct wl_ring_buffer in, out; struct wl_ring_buffer fds_in, fds_out; int fd; int want_flush; }; static inline size_t size_pot(uint32_t size_bits) { assert(size_bits < 8 * sizeof(size_t)); return ((size_t)1) << size_bits; } static size_t ring_buffer_capacity(const struct wl_ring_buffer *b) { return size_pot(b->size_bits); } static size_t ring_buffer_mask(const struct wl_ring_buffer *b, size_t i) { size_t m = ring_buffer_capacity(b) - 1; return i & m; } static int ring_buffer_put(struct wl_ring_buffer *b, const void *data, size_t count) { size_t head, size; if (count == 0) return 0; head = ring_buffer_mask(b, b->head); if (head + count <= ring_buffer_capacity(b)) { memcpy(b->data + head, data, count); } else { size = ring_buffer_capacity(b) - head; memcpy(b->data + head, data, size); memcpy(b->data, (const char *) data + size, count - size); } b->head += count; return 0; } static void ring_buffer_put_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count) { size_t head, tail; head = ring_buffer_mask(b, b->head); tail = ring_buffer_mask(b, b->tail); if (head < tail) { iov[0].iov_base = b->data + head; iov[0].iov_len = tail - head; *count = 1; } else if (tail == 0) { iov[0].iov_base = b->data + head; iov[0].iov_len = ring_buffer_capacity(b) - head; *count = 1; } else { iov[0].iov_base = b->data + head; iov[0].iov_len = ring_buffer_capacity(b) - head; iov[1].iov_base = b->data; iov[1].iov_len = tail; *count = 2; } } static void ring_buffer_get_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count) { size_t head, tail; head = ring_buffer_mask(b, b->head); tail = ring_buffer_mask(b, b->tail); if (tail < head) { iov[0].iov_base = b->data + tail; iov[0].iov_len = head - tail; *count = 1; } else if (head == 0) { iov[0].iov_base = b->data + tail; iov[0].iov_len = ring_buffer_capacity(b) - tail; *count = 1; } else { iov[0].iov_base = b->data + tail; iov[0].iov_len = ring_buffer_capacity(b) - tail; iov[1].iov_base = b->data; iov[1].iov_len = head; *count = 2; } } static void ring_buffer_copy(struct wl_ring_buffer *b, void *data, size_t count) { size_t tail, size; if (count == 0) return; tail = ring_buffer_mask(b, b->tail); if (tail + count <= ring_buffer_capacity(b)) { memcpy(data, b->data + tail, count); } else { size = ring_buffer_capacity(b) - tail; memcpy(data, b->data + tail, size); memcpy((char *) data + size, b->data, count - size); } } static size_t ring_buffer_size(struct wl_ring_buffer *b) { return b->head - b->tail; } static char * ring_buffer_tail(const struct wl_ring_buffer *b) { return b->data + ring_buffer_mask(b, b->tail); } static uint32_t get_max_size_bits_for_size(size_t buffer_size) { uint32_t max_size_bits = WL_BUFFER_DEFAULT_SIZE_POT; /* buffer_size == 0 means unbound buffer size */ if (buffer_size == 0) return 0; while (max_size_bits < 8 * sizeof(size_t) && size_pot(max_size_bits) < buffer_size) max_size_bits++; return max_size_bits; } static int ring_buffer_allocate(struct wl_ring_buffer *b, size_t size_bits) { char *new_data; new_data = calloc(size_pot(size_bits), 1); if (!new_data) return -1; ring_buffer_copy(b, new_data, ring_buffer_size(b)); free(b->data); b->data = new_data; b->size_bits = size_bits; b->head = ring_buffer_size(b); b->tail = 0; return 0; } static size_t ring_buffer_get_bits_for_size(struct wl_ring_buffer *b, size_t net_size) { size_t max_size_bits = get_max_size_bits_for_size(net_size); if (max_size_bits < WL_BUFFER_DEFAULT_SIZE_POT) max_size_bits = WL_BUFFER_DEFAULT_SIZE_POT; if (b->max_size_bits > 0 && max_size_bits > b->max_size_bits) max_size_bits = b->max_size_bits; return max_size_bits; } static bool ring_buffer_is_max_size_reached(struct wl_ring_buffer *b) { size_t net_size = ring_buffer_size(b) + 1; size_t size_bits = ring_buffer_get_bits_for_size(b, net_size); return net_size >= size_pot(size_bits); } static int ring_buffer_ensure_space(struct wl_ring_buffer *b, size_t count) { size_t net_size = ring_buffer_size(b) + count; size_t size_bits = ring_buffer_get_bits_for_size(b, net_size); /* The 'size_bits' value represents the required size (in POT) to store * 'net_size', which depending whether the buffers are bounded or not * might not be sufficient (i.e. we might have reached the maximum size * allowed). */ if (net_size > size_pot(size_bits)) { wl_log("Data too big for buffer (%d + %zd > %zd).\n", ring_buffer_size(b), count, size_pot(size_bits)); errno = E2BIG; return -1; } /* The following test here is a short-cut to avoid reallocating a buffer * of the same size. */ if (size_bits == b->size_bits) return 0; /* Otherwise, we (re)allocate the buffer to match the required size */ return ring_buffer_allocate(b, size_bits); } static void ring_buffer_close_fds(struct wl_ring_buffer *buffer, int32_t count) { int32_t i, *p; size_t size, tail; size = ring_buffer_capacity(buffer); tail = ring_buffer_mask(buffer, buffer->tail); p = (int32_t *) (buffer->data + tail); for (i = 0; i < count; i++) { if (p >= (int32_t *) (buffer->data + size)) p = (int32_t *) buffer->data; close(*p++); } } void wl_connection_set_max_buffer_size(struct wl_connection *connection, size_t max_buffer_size) { uint32_t max_size_bits; max_size_bits = get_max_size_bits_for_size(max_buffer_size); connection->fds_in.max_size_bits = max_size_bits; ring_buffer_ensure_space(&connection->fds_in, 0); connection->fds_out.max_size_bits = max_size_bits; ring_buffer_ensure_space(&connection->fds_out, 0); connection->in.max_size_bits = max_size_bits; ring_buffer_ensure_space(&connection->in, 0); connection->out.max_size_bits = max_size_bits; ring_buffer_ensure_space(&connection->out, 0); } struct wl_connection * wl_connection_create(int fd, size_t max_buffer_size) { struct wl_connection *connection; connection = zalloc(sizeof *connection); if (connection == NULL) return NULL; wl_connection_set_max_buffer_size(connection, max_buffer_size); connection->fd = fd; return connection; } static void close_fds(struct wl_ring_buffer *buffer, int max) { size_t size; int32_t count; size = ring_buffer_size(buffer); if (size == 0) return; count = size / sizeof(int32_t); if (max > 0 && max < count) count = max; ring_buffer_close_fds(buffer, count); size = count * sizeof(int32_t); buffer->tail += size; } void wl_connection_close_fds_in(struct wl_connection *connection, int max) { close_fds(&connection->fds_in, max); } int wl_connection_destroy(struct wl_connection *connection) { int fd = connection->fd; close_fds(&connection->fds_out, -1); free(connection->fds_out.data); free(connection->out.data); close_fds(&connection->fds_in, -1); free(connection->fds_in.data); free(connection->in.data); free(connection); return fd; } void wl_connection_copy(struct wl_connection *connection, void *data, size_t size) { ring_buffer_copy(&connection->in, data, size); } void wl_connection_consume(struct wl_connection *connection, size_t size) { connection->in.tail += size; } static void build_cmsg(struct wl_ring_buffer *buffer, char *data, size_t *clen) { struct cmsghdr *cmsg; size_t size; size = ring_buffer_size(buffer); if (size > MAX_FDS_OUT * sizeof(int32_t)) size = MAX_FDS_OUT * sizeof(int32_t); if (size > 0) { cmsg = (struct cmsghdr *) data; cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(size); ring_buffer_copy(buffer, CMSG_DATA(cmsg), size); *clen = cmsg->cmsg_len; } else { *clen = 0; } } static int decode_cmsg(struct wl_ring_buffer *buffer, struct msghdr *msg) { struct cmsghdr *cmsg; size_t size, i; int overflow = 0; for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) continue; size = cmsg->cmsg_len - CMSG_LEN(0); if (ring_buffer_ensure_space(buffer, size) < 0 || overflow) { overflow = 1; size /= sizeof(int32_t); for (i = 0; i < size; i++) close(((int*)CMSG_DATA(cmsg))[i]); } else if (ring_buffer_put(buffer, CMSG_DATA(cmsg), size) < 0) { return -1; } } if (overflow) { errno = EOVERFLOW; return -1; } return 0; } int wl_connection_flush(struct wl_connection *connection) { struct iovec iov[2]; struct msghdr msg = {0}; char cmsg[CLEN]; int len = 0, count; size_t clen; size_t tail; if (!connection->want_flush) return 0; tail = connection->out.tail; while (ring_buffer_size(&connection->out) > 0) { build_cmsg(&connection->fds_out, cmsg, &clen); if (clen >= CLEN) { /* UNIX domain sockets allows to send file descriptors * using ancillary data. * * As per the UNIX domain sockets man page (man 7 unix), * "at least one byte of real data should be sent when * sending ancillary data". * * This is why we send only a single byte here, to ensure * all file descriptors are sent before the bytes are * cleared out. * * Otherwise This can fail to clear the file descriptors * first if individual messages are allowed to have 224 * (8 bytes * MAX_FDS_OUT = 224) file descriptors . */ iov[0].iov_base = ring_buffer_tail(&connection->out); iov[0].iov_len = 1; count = 1; } else { ring_buffer_get_iov(&connection->out, iov, &count); } msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = count; msg.msg_control = (clen > 0) ? cmsg : NULL; msg.msg_controllen = clen; do { len = sendmsg(connection->fd, &msg, MSG_NOSIGNAL | MSG_DONTWAIT); } while (len == -1 && errno == EINTR); if (len == -1) return -1; close_fds(&connection->fds_out, MAX_FDS_OUT); connection->out.tail += len; } connection->want_flush = 0; return connection->out.head - tail; } uint32_t wl_connection_pending_input(struct wl_connection *connection) { return ring_buffer_size(&connection->in); } int wl_connection_read(struct wl_connection *connection) { struct iovec iov[2]; struct msghdr msg; char cmsg[CLEN]; int len, count, ret; while (1) { int data_size = ring_buffer_size(&connection->in); /* Stop once we've read the max buffer size. */ if (ring_buffer_is_max_size_reached(&connection->in)) return data_size; if (ring_buffer_ensure_space(&connection->in, 1) < 0) return -1; ring_buffer_put_iov(&connection->in, iov, &count); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = count; msg.msg_control = cmsg; msg.msg_controllen = sizeof cmsg; msg.msg_flags = 0; do { len = wl_os_recvmsg_cloexec(connection->fd, &msg, MSG_DONTWAIT); } while (len < 0 && errno == EINTR); if (len == 0) { /* EOF, return previously read data first */ return data_size; } if (len < 0) { if (errno == EAGAIN && data_size > 0) { /* nothing new read, return previously read data */ return data_size; } return len; } ret = decode_cmsg(&connection->fds_in, &msg); if (ret) return -1; connection->in.head += len; } } int wl_connection_write(struct wl_connection *connection, const void *data, size_t count) { if (wl_connection_queue(connection, data, count) < 0) return -1; connection->want_flush = 1; return 0; } int wl_connection_queue(struct wl_connection *connection, const void *data, size_t count) { /* We want to try to flush when the buffer reaches the default maximum * size even if the buffer has been previously expanded. * * Otherwise the larger buffer will cause us to flush less frequently, * which could increase lag. * * We'd like to flush often and get the buffer size back down if possible. */ if (ring_buffer_size(&connection->out) + count > WL_BUFFER_DEFAULT_MAX_SIZE) { connection->want_flush = 1; if (wl_connection_flush(connection) < 0 && errno != EAGAIN) return -1; } if (ring_buffer_ensure_space(&connection->out, count) < 0) return -1; return ring_buffer_put(&connection->out, data, count); } int wl_message_count_arrays(const struct wl_message *message) { int i, arrays; for (i = 0, arrays = 0; message->signature[i]; i++) { if (message->signature[i] == WL_ARG_ARRAY) arrays++; } return arrays; } int wl_connection_get_fd(struct wl_connection *connection) { return connection->fd; } static int wl_connection_put_fd(struct wl_connection *connection, int32_t fd) { if (ring_buffer_size(&connection->fds_out) >= MAX_FDS_OUT * sizeof fd) { connection->want_flush = 1; if (wl_connection_flush(connection) < 0 && errno != EAGAIN) return -1; } if (ring_buffer_ensure_space(&connection->fds_out, sizeof fd) < 0) return -1; return ring_buffer_put(&connection->fds_out, &fd, sizeof fd); } const char * get_next_argument(const char *signature, struct argument_details *details) { details->nullable = 0; for(; *signature; ++signature) { switch(*signature) { case WL_ARG_INT: case WL_ARG_UINT: case WL_ARG_FIXED: case WL_ARG_STRING: case WL_ARG_OBJECT: case WL_ARG_NEW_ID: case WL_ARG_ARRAY: case WL_ARG_FD: details->type = *signature; return signature + 1; case '?': details->nullable = 1; } } details->type = '\0'; return signature; } int arg_count_for_signature(const char *signature) { int count = 0; for(; *signature; ++signature) { switch(*signature) { case WL_ARG_INT: case WL_ARG_UINT: case WL_ARG_FIXED: case WL_ARG_STRING: case WL_ARG_OBJECT: case WL_ARG_NEW_ID: case WL_ARG_ARRAY: case WL_ARG_FD: ++count; } } return count; } int wl_message_get_since(const struct wl_message *message) { int since; since = atoi(message->signature); if (since == 0) since = 1; return since; } void wl_argument_from_va_list(const char *signature, union wl_argument *args, int count, va_list ap) { int i; const char *sig_iter; struct argument_details arg; sig_iter = signature; for (i = 0; i < count; i++) { sig_iter = get_next_argument(sig_iter, &arg); switch(arg.type) { case WL_ARG_INT: args[i].i = va_arg(ap, int32_t); break; case WL_ARG_UINT: args[i].u = va_arg(ap, uint32_t); break; case WL_ARG_FIXED: args[i].f = va_arg(ap, wl_fixed_t); break; case WL_ARG_STRING: args[i].s = va_arg(ap, const char *); break; case WL_ARG_OBJECT: args[i].o = va_arg(ap, struct wl_object *); break; case WL_ARG_NEW_ID: args[i].o = va_arg(ap, struct wl_object *); break; case WL_ARG_ARRAY: args[i].a = va_arg(ap, struct wl_array *); break; case WL_ARG_FD: args[i].h = va_arg(ap, int32_t); break; } } } static void wl_closure_clear_fds(struct wl_closure *closure) { const char *signature = closure->message->signature; struct argument_details arg; int i; for (i = 0; i < closure->count; i++) { signature = get_next_argument(signature, &arg); if (arg.type == WL_ARG_FD) closure->args[i].h = -1; } } static struct wl_closure * wl_closure_init(const struct wl_message *message, uint32_t size, int *num_arrays, union wl_argument *args) { struct wl_closure *closure; int count; count = arg_count_for_signature(message->signature); if (count > WL_CLOSURE_MAX_ARGS) { wl_log("too many args (%d) for %s (signature %s)\n", count, message->name, message->signature); errno = EINVAL; return NULL; } int size_to_allocate; if (size) { *num_arrays = wl_message_count_arrays(message); size_to_allocate = sizeof *closure + size + *num_arrays * sizeof(struct wl_array); } else { size_to_allocate = sizeof *closure; } closure = zalloc(size_to_allocate); if (!closure) { wl_log("could not allocate closure of size (%d) for " "%s (signature %s)\n", size_to_allocate, message->name, message->signature); errno = ENOMEM; return NULL; } if (args) memcpy(closure->args, args, count * sizeof *args); closure->message = message; closure->count = count; /* Set these all to -1 so we can close any that have been * set to a real value during wl_closure_destroy(). * We may have copied a bunch of fds into the closure with * memcpy previously, but those are undup()d client fds * that we would have replaced anyway. */ wl_closure_clear_fds(closure); return closure; } struct wl_closure * wl_closure_marshal(struct wl_object *sender, uint32_t opcode, union wl_argument *args, const struct wl_message *message) { struct wl_closure *closure; struct wl_object *object; int i, count, fd, dup_fd; const char *signature; struct argument_details arg; closure = wl_closure_init(message, 0, NULL, args); if (closure == NULL) return NULL; count = closure->count; signature = message->signature; for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { case WL_ARG_FIXED: case WL_ARG_UINT: case WL_ARG_INT: break; case WL_ARG_STRING: if (!arg.nullable && args[i].s == NULL) goto err_null; break; case WL_ARG_OBJECT: if (!arg.nullable && args[i].o == NULL) goto err_null; break; case WL_ARG_NEW_ID: object = args[i].o; if (object == NULL) goto err_null; closure->args[i].n = object ? object->id : 0; break; case WL_ARG_ARRAY: if (args[i].a == NULL) goto err_null; break; case WL_ARG_FD: fd = args[i].h; dup_fd = wl_os_dupfd_cloexec(fd, 0); if (dup_fd < 0) { wl_closure_destroy(closure); wl_log("error marshalling arguments for %s: dup failed: %s\n", message->name, strerror(errno)); return NULL; } closure->args[i].h = dup_fd; break; default: wl_abort("unhandled format code: '%c'\n", arg.type); break; } } closure->sender_id = sender->id; closure->opcode = opcode; return closure; err_null: wl_closure_destroy(closure); wl_log("error marshalling arguments for %s (signature %s): " "null value passed for arg %i\n", message->name, message->signature, i); errno = EINVAL; return NULL; } struct wl_closure * wl_closure_vmarshal(struct wl_object *sender, uint32_t opcode, va_list ap, const struct wl_message *message) { union wl_argument args[WL_CLOSURE_MAX_ARGS]; wl_argument_from_va_list(message->signature, args, WL_CLOSURE_MAX_ARGS, ap); return wl_closure_marshal(sender, opcode, args, message); } struct wl_closure * wl_connection_demarshal(struct wl_connection *connection, uint32_t size, struct wl_map *objects, const struct wl_message *message) { uint32_t *p, *next, *end, length, length_in_u32, id; int fd; char *s; int i, count, num_arrays; const char *signature; struct argument_details arg; struct wl_closure *closure; struct wl_array *array_extra; /* Space for sender_id and opcode */ if (size < 2 * sizeof *p) { wl_log("message too short, invalid header\n"); wl_connection_consume(connection, size); errno = EINVAL; return NULL; } closure = wl_closure_init(message, size, &num_arrays, NULL); if (closure == NULL) { wl_connection_consume(connection, size); return NULL; } count = closure->count; array_extra = closure->extra; p = (uint32_t *)(closure->extra + num_arrays); end = p + size / sizeof *p; wl_connection_copy(connection, p, size); closure->sender_id = *p++; closure->opcode = *p++ & 0x0000ffff; signature = message->signature; for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); if (arg.type != WL_ARG_FD && p + 1 > end) { wl_log("message too short, " "object (%d), message %s(%s)\n", closure->sender_id, message->name, message->signature); errno = EINVAL; goto err; } switch (arg.type) { case WL_ARG_UINT: closure->args[i].u = *p++; break; case WL_ARG_INT: closure->args[i].i = *p++; break; case WL_ARG_FIXED: closure->args[i].f = *p++; break; case WL_ARG_STRING: length = *p++; if (length == 0 && !arg.nullable) { wl_log("NULL string received on non-nullable " "type, message %s(%s)\n", message->name, message->signature); errno = EINVAL; goto err; } if (length == 0) { closure->args[i].s = NULL; break; } length_in_u32 = div_roundup(length, sizeof *p); if ((uint32_t) (end - p) < length_in_u32) { wl_log("message too short, " "object (%d), message %s(%s)\n", closure->sender_id, message->name, message->signature); errno = EINVAL; goto err; } next = p + length_in_u32; s = (char *) p; if (length > 0 && s[length - 1] != '\0') { wl_log("string not nul-terminated, " "message %s(%s)\n", message->name, message->signature); errno = EINVAL; goto err; } closure->args[i].s = s; p = next; break; case WL_ARG_OBJECT: id = *p++; closure->args[i].n = id; if (id == 0 && !arg.nullable) { wl_log("NULL object received on non-nullable " "type, message %s(%s)\n", message->name, message->signature); errno = EINVAL; goto err; } break; case WL_ARG_NEW_ID: id = *p++; closure->args[i].n = id; if (id == 0) { wl_log("NULL new ID received on non-nullable " "type, message %s(%s)\n", message->name, message->signature); errno = EINVAL; goto err; } if (wl_map_reserve_new(objects, id) < 0) { if (errno == EINVAL) { wl_log("not a valid new object id (%u), " "message %s(%s)\n", id, message->name, message->signature); } goto err; } break; case WL_ARG_ARRAY: length = *p++; length_in_u32 = div_roundup(length, sizeof *p); if ((uint32_t) (end - p) < length_in_u32) { wl_log("message too short, " "object (%d), message %s(%s)\n", closure->sender_id, message->name, message->signature); errno = EINVAL; goto err; } next = p + length_in_u32; array_extra->size = length; array_extra->alloc = 0; array_extra->data = p; closure->args[i].a = array_extra++; p = next; break; case WL_ARG_FD: if (connection->fds_in.tail == connection->fds_in.head) { wl_log("file descriptor expected, " "object (%d), message %s(%s)\n", closure->sender_id, message->name, message->signature); errno = EINVAL; goto err; } ring_buffer_copy(&connection->fds_in, &fd, sizeof fd); connection->fds_in.tail += sizeof fd; closure->args[i].h = fd; break; default: wl_abort("unknown type\n"); break; } } wl_connection_consume(connection, size); return closure; err: wl_closure_destroy(closure); wl_connection_consume(connection, size); return NULL; } bool wl_object_is_zombie(struct wl_map *map, uint32_t id) { uint32_t flags; /* Zombie objects only exist on the client side. */ if (map->side == WL_MAP_SERVER_SIDE) return false; /* Zombie objects can only have been created by the client. */ if (id >= WL_SERVER_ID_START) return false; flags = wl_map_lookup_flags(map, id); return !!(flags & WL_MAP_ENTRY_ZOMBIE); } int wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects) { struct wl_object *object; const struct wl_message *message; const char *signature; struct argument_details arg; int i, count; uint32_t id; message = closure->message; signature = message->signature; count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); if (arg.type != WL_ARG_OBJECT) continue; id = closure->args[i].n; closure->args[i].o = NULL; object = wl_map_lookup(objects, id); if (wl_object_is_zombie(objects, id)) { /* references object we've already * destroyed client side */ object = NULL; } else if (object == NULL && id != 0) { wl_log("unknown object (%u), message %s(%s)\n", id, message->name, message->signature); errno = EINVAL; return -1; } if (object != NULL && message->types[i] != NULL && !wl_interface_equal((object)->interface, message->types[i])) { wl_log("invalid object (%u), type (%s), " "message %s(%s)\n", id, (object)->interface->name, message->name, message->signature); errno = EINVAL; return -1; } closure->args[i].o = object; } return 0; } static void convert_arguments_to_ffi(const char *signature, uint32_t flags, union wl_argument *args, int count, ffi_type **ffi_types, void** ffi_args) { int i; const char *sig_iter; struct argument_details arg; sig_iter = signature; for (i = 0; i < count; i++) { sig_iter = get_next_argument(sig_iter, &arg); switch(arg.type) { case WL_ARG_INT: ffi_types[i] = &ffi_type_sint32; ffi_args[i] = &args[i].i; break; case WL_ARG_UINT: ffi_types[i] = &ffi_type_uint32; ffi_args[i] = &args[i].u; break; case WL_ARG_FIXED: ffi_types[i] = &ffi_type_sint32; ffi_args[i] = &args[i].f; break; case WL_ARG_STRING: ffi_types[i] = &ffi_type_pointer; ffi_args[i] = &args[i].s; break; case WL_ARG_OBJECT: ffi_types[i] = &ffi_type_pointer; ffi_args[i] = &args[i].o; break; case WL_ARG_NEW_ID: if (flags & WL_CLOSURE_INVOKE_CLIENT) { ffi_types[i] = &ffi_type_pointer; ffi_args[i] = &args[i].o; } else { ffi_types[i] = &ffi_type_uint32; ffi_args[i] = &args[i].n; } break; case WL_ARG_ARRAY: ffi_types[i] = &ffi_type_pointer; ffi_args[i] = &args[i].a; break; case WL_ARG_FD: ffi_types[i] = &ffi_type_sint32; ffi_args[i] = &args[i].h; break; default: wl_abort("unknown type\n"); break; } } } void wl_closure_invoke(struct wl_closure *closure, uint32_t flags, struct wl_object *target, uint32_t opcode, void *data) { int count; ffi_cif cif; ffi_type *ffi_types[WL_CLOSURE_MAX_ARGS + 2]; void * ffi_args[WL_CLOSURE_MAX_ARGS + 2]; void (* const *implementation)(void); count = arg_count_for_signature(closure->message->signature); ffi_types[0] = &ffi_type_pointer; ffi_args[0] = &data; ffi_types[1] = &ffi_type_pointer; ffi_args[1] = ⌖ convert_arguments_to_ffi(closure->message->signature, flags, closure->args, count, ffi_types + 2, ffi_args + 2); ffi_prep_cif(&cif, FFI_DEFAULT_ABI, count + 2, &ffi_type_void, ffi_types); implementation = target->implementation; if (!implementation[opcode]) { wl_abort("listener function for opcode %u of %s is NULL\n", opcode, target->interface->name); } ffi_call(&cif, implementation[opcode], NULL, ffi_args); wl_closure_clear_fds(closure); } void wl_closure_dispatch(struct wl_closure *closure, wl_dispatcher_func_t dispatcher, struct wl_object *target, uint32_t opcode) { dispatcher(target->implementation, target, opcode, closure->message, closure->args); wl_closure_clear_fds(closure); } static int copy_fds_to_connection(struct wl_closure *closure, struct wl_connection *connection) { const struct wl_message *message = closure->message; uint32_t i, count; struct argument_details arg; const char *signature = message->signature; int fd; count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); if (arg.type != WL_ARG_FD) continue; fd = closure->args[i].h; if (wl_connection_put_fd(connection, fd)) { wl_log("request could not be marshaled: " "can't send file descriptor\n"); return -1; } closure->args[i].h = -1; } return 0; } static uint32_t buffer_size_for_closure(struct wl_closure *closure) { const struct wl_message *message = closure->message; int i, count; struct argument_details arg; const char *signature; uint32_t size, buffer_size = 0; signature = message->signature; count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { case WL_ARG_FD: break; case WL_ARG_UINT: case WL_ARG_INT: case WL_ARG_FIXED: case WL_ARG_OBJECT: case WL_ARG_NEW_ID: buffer_size++; break; case WL_ARG_STRING: if (closure->args[i].s == NULL) { buffer_size++; break; } size = strlen(closure->args[i].s) + 1; buffer_size += 1 + div_roundup(size, sizeof(uint32_t)); break; case WL_ARG_ARRAY: if (closure->args[i].a == NULL) { buffer_size++; break; } size = closure->args[i].a->size; buffer_size += (1 + div_roundup(size, sizeof(uint32_t))); break; default: break; } } return buffer_size + 2; } static int serialize_closure(struct wl_closure *closure, uint32_t *buffer, size_t buffer_count) { const struct wl_message *message = closure->message; unsigned int i, count, size; uint32_t *p, *end; struct argument_details arg; const char *signature; if (buffer_count < 2) goto overflow; p = buffer + 2; end = buffer + buffer_count; signature = message->signature; count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); if (arg.type == WL_ARG_FD) continue; if (p + 1 > end) goto overflow; switch (arg.type) { case WL_ARG_UINT: *p++ = closure->args[i].u; break; case WL_ARG_INT: *p++ = closure->args[i].i; break; case WL_ARG_FIXED: *p++ = closure->args[i].f; break; case WL_ARG_OBJECT: *p++ = closure->args[i].o ? closure->args[i].o->id : 0; break; case WL_ARG_NEW_ID: *p++ = closure->args[i].n; break; case WL_ARG_STRING: if (closure->args[i].s == NULL) { *p++ = 0; break; } size = strlen(closure->args[i].s) + 1; *p++ = size; if (p + div_roundup(size, sizeof *p) > end) goto overflow; memcpy(p, closure->args[i].s, size); p += div_roundup(size, sizeof *p); break; case WL_ARG_ARRAY: if (closure->args[i].a == NULL) { *p++ = 0; break; } size = closure->args[i].a->size; *p++ = size; if (p + div_roundup(size, sizeof *p) > end) goto overflow; if (size != 0) memcpy(p, closure->args[i].a->data, size); p += div_roundup(size, sizeof *p); break; case WL_ARG_FD: break; } } size = (p - buffer) * sizeof *p; buffer[0] = closure->sender_id; buffer[1] = size << 16 | (closure->opcode & 0x0000ffff); return size; overflow: wl_log("serialize_closure overflow for %s (signature %s)\n", message->name, message->signature); errno = ERANGE; return -1; } int wl_closure_send(struct wl_closure *closure, struct wl_connection *connection) { int size; uint32_t buffer_size; uint32_t *buffer; int result; if (copy_fds_to_connection(closure, connection)) return -1; buffer_size = buffer_size_for_closure(closure); buffer = zalloc(buffer_size * sizeof buffer[0]); if (buffer == NULL) { wl_log("wl_closure_send error: buffer allocation failure of " "size %d\n for %s (signature %s)", buffer_size * sizeof buffer[0], closure->message->name, closure->message->signature); return -1; } size = serialize_closure(closure, buffer, buffer_size); if (size < 0) { free(buffer); return -1; } result = wl_connection_write(connection, buffer, size); free(buffer); return result; } int wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection) { int size; uint32_t buffer_size; uint32_t *buffer; int result; if (copy_fds_to_connection(closure, connection)) return -1; buffer_size = buffer_size_for_closure(closure); buffer = malloc(buffer_size * sizeof buffer[0]); if (buffer == NULL) { wl_log("wl_closure_queue error: buffer allocation failure of " "size %d\n for %s (signature %s)", buffer_size * sizeof buffer[0], closure->message->name, closure->message->signature); return -1; } size = serialize_closure(closure, buffer, buffer_size); if (size < 0) { free(buffer); return -1; } result = wl_connection_queue(connection, buffer, size); free(buffer); return result; } void wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send, int discarded, uint32_t (*n_parse)(union wl_argument *arg), const char *queue_name) { int i; struct argument_details arg; const char *signature = closure->message->signature; struct timespec tp; unsigned int time; uint32_t nval; FILE *f; char *buffer; size_t buffer_length; f = open_memstream(&buffer, &buffer_length); if (f == NULL) return; clock_gettime(CLOCK_REALTIME, &tp); time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); fprintf(f, "[%7u.%03u] ", time / 1000, time % 1000); if (queue_name) fprintf(f, "{%s} ", queue_name); fprintf(f, "%s%s%s#%u.%s(", discarded ? "discarded " : "", send ? " -> " : "", target->interface->name, target->id, closure->message->name); for (i = 0; i < closure->count; i++) { signature = get_next_argument(signature, &arg); if (i > 0) fprintf(f, ", "); switch (arg.type) { case WL_ARG_UINT: fprintf(f, "%u", closure->args[i].u); break; case WL_ARG_INT: fprintf(f, "%d", closure->args[i].i); break; case WL_ARG_FIXED: /* The magic number 390625 is 1e8 / 256 */ if (closure->args[i].f >= 0) { fprintf(f, "%d.%08d", closure->args[i].f / 256, 390625 * (closure->args[i].f % 256)); } else { fprintf(f, "-%d.%08d", closure->args[i].f / -256, -390625 * (closure->args[i].f % 256)); } break; case WL_ARG_STRING: if (closure->args[i].s) fprintf(f, "\"%s\"", closure->args[i].s); else fprintf(f, "nil"); break; case WL_ARG_OBJECT: if (closure->args[i].o) fprintf(f, "%s#%u", closure->args[i].o->interface->name, closure->args[i].o->id); else fprintf(f, "nil"); break; case WL_ARG_NEW_ID: if (n_parse) nval = n_parse(&closure->args[i]); else nval = closure->args[i].n; fprintf(f, "new id %s#", (closure->message->types[i]) ? closure->message->types[i]->name : "[unknown]"); if (nval != 0) fprintf(f, "%u", nval); else fprintf(f, "nil"); break; case WL_ARG_ARRAY: fprintf(f, "array[%zu]", closure->args[i].a->size); break; case WL_ARG_FD: fprintf(f, "fd %d", closure->args[i].h); break; } } fprintf(f, ")\n"); if (fclose(f) == 0) { fprintf(stderr, "%s", buffer); free(buffer); } } static int wl_closure_close_fds(struct wl_closure *closure) { int i; struct argument_details arg; const char *signature = closure->message->signature; for (i = 0; i < closure->count; i++) { signature = get_next_argument(signature, &arg); if (arg.type == WL_ARG_FD && closure->args[i].h != -1) close(closure->args[i].h); } return 0; } void wl_closure_destroy(struct wl_closure *closure) { /* wl_closure_destroy has free() semantics */ if (!closure) return; wl_closure_close_fds(closure); free(closure); } wayland-1.23.1/src/embed.py000066400000000000000000000027451466237767300155070ustar00rootroot00000000000000#!/usr/bin/env python3 """ Simple C data embedder License: MIT Copyright (c) 2020 Simon Ser Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import sys if len(sys.argv) != 3: print('usage: ' + sys.argv[0] + ' ', file=sys.stderr) sys.exit(1) filename = sys.argv[1] ident = sys.argv[2] with open(filename, 'rb') as f: buf = f.read() print('static const char ' + ident + '[] = {\n\t', end='') for i in range(len(buf)): ch = buf[i:i+1] print('0x' + ch.hex() + ', ', end='') print('\n};') wayland-1.23.1/src/event-loop.c000066400000000000000000000732371466237767300163210ustar00rootroot00000000000000/* * Copyright © 2008 Kristian Høgsberg * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wayland-util.h" #include "wayland-private.h" #include "wayland-server-core.h" #include "wayland-server-private.h" #include "wayland-os.h" /** \cond INTERNAL */ #define TIMER_REMOVED -2 struct wl_event_loop; struct wl_event_source_interface; struct wl_event_source_timer; struct wl_event_source { struct wl_event_source_interface *interface; struct wl_event_loop *loop; struct wl_list link; void *data; int fd; }; struct wl_timer_heap { struct wl_event_source base; /* pointers to the user-visible event sources */ struct wl_event_source_timer **data; int space, active, count; }; struct wl_event_loop { int epoll_fd; struct wl_list check_list; struct wl_list idle_list; struct wl_list destroy_list; struct wl_priv_signal destroy_signal; struct wl_timer_heap timers; }; struct wl_event_source_interface { int (*dispatch)(struct wl_event_source *source, struct epoll_event *ep); }; struct wl_event_source_fd { struct wl_event_source base; wl_event_loop_fd_func_t func; int fd; }; /** \endcond */ static int wl_event_source_fd_dispatch(struct wl_event_source *source, struct epoll_event *ep) { struct wl_event_source_fd *fd_source = (struct wl_event_source_fd *) source; uint32_t mask; mask = 0; if (ep->events & EPOLLIN) mask |= WL_EVENT_READABLE; if (ep->events & EPOLLOUT) mask |= WL_EVENT_WRITABLE; if (ep->events & EPOLLHUP) mask |= WL_EVENT_HANGUP; if (ep->events & EPOLLERR) mask |= WL_EVENT_ERROR; return fd_source->func(fd_source->fd, mask, source->data); } struct wl_event_source_interface fd_source_interface = { wl_event_source_fd_dispatch, }; static struct wl_event_source * add_source(struct wl_event_loop *loop, struct wl_event_source *source, uint32_t mask, void *data) { struct epoll_event ep; if (source->fd < 0) { free(source); return NULL; } source->loop = loop; source->data = data; wl_list_init(&source->link); memset(&ep, 0, sizeof ep); if (mask & WL_EVENT_READABLE) ep.events |= EPOLLIN; if (mask & WL_EVENT_WRITABLE) ep.events |= EPOLLOUT; ep.data.ptr = source; if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) { close(source->fd); free(source); return NULL; } return source; } /** Create a file descriptor event source * * \param loop The event loop that will process the new source. * \param fd The file descriptor to watch. * \param mask A bitwise-or of which events to watch for: \c WL_EVENT_READABLE, * \c WL_EVENT_WRITABLE. * \param func The file descriptor dispatch function. * \param data User data. * \return A new file descriptor event source. * * The given file descriptor is initially watched for the events given in * \c mask. This can be changed as needed with wl_event_source_fd_update(). * * If it is possible that program execution causes the file descriptor to be * read while leaving the data in a buffer without actually processing it, * it may be necessary to register the file descriptor source to be re-checked, * see wl_event_source_check(). This will ensure that the dispatch function * gets called even if the file descriptor is not readable or writable * anymore. This is especially useful with IPC libraries that automatically * buffer incoming data, possibly as a side-effect of other operations. * * \sa wl_event_loop_fd_func_t * \memberof wl_event_source */ WL_EXPORT struct wl_event_source * wl_event_loop_add_fd(struct wl_event_loop *loop, int fd, uint32_t mask, wl_event_loop_fd_func_t func, void *data) { struct wl_event_source_fd *source; source = zalloc(sizeof *source); if (source == NULL) return NULL; source->base.interface = &fd_source_interface; source->base.fd = wl_os_dupfd_cloexec(fd, 0); source->func = func; source->fd = fd; return add_source(loop, &source->base, mask, data); } /** Update a file descriptor source's event mask * * \param source The file descriptor event source to update. * \param mask The new mask, a bitwise-or of: \c WL_EVENT_READABLE, * \c WL_EVENT_WRITABLE. * \return 0 on success, -1 on failure. * * This changes which events, readable and/or writable, cause the dispatch * callback to be called on. * * File descriptors are usually writable to begin with, so they do not need to * be polled for writable until a write actually fails. When a write fails, * the event mask can be changed to poll for readable and writable, delivering * a dispatch callback when it is possible to write more. Once all data has * been written, the mask can be changed to poll only for readable to avoid * busy-looping on dispatch. * * \sa wl_event_loop_add_fd() * \memberof wl_event_source */ WL_EXPORT int wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask) { struct wl_event_loop *loop = source->loop; struct epoll_event ep; memset(&ep, 0, sizeof ep); if (mask & WL_EVENT_READABLE) ep.events |= EPOLLIN; if (mask & WL_EVENT_WRITABLE) ep.events |= EPOLLOUT; ep.data.ptr = source; return epoll_ctl(loop->epoll_fd, EPOLL_CTL_MOD, source->fd, &ep); } /** \cond INTERNAL */ struct wl_event_source_timer { struct wl_event_source base; wl_event_loop_timer_func_t func; struct wl_event_source_timer *next_due; struct timespec deadline; int heap_idx; }; static int noop_dispatch(struct wl_event_source *source, struct epoll_event *ep) { return 0; } struct wl_event_source_interface timer_heap_source_interface = { noop_dispatch, }; static bool time_lt(struct timespec ta, struct timespec tb) { if (ta.tv_sec != tb.tv_sec) { return ta.tv_sec < tb.tv_sec; } return ta.tv_nsec < tb.tv_nsec; } static int set_timer(int timerfd, struct timespec deadline) { struct itimerspec its; its.it_interval.tv_sec = 0; its.it_interval.tv_nsec = 0; its.it_value = deadline; return timerfd_settime(timerfd, TFD_TIMER_ABSTIME, &its, NULL); } static int clear_timer(int timerfd) { struct itimerspec its; its.it_interval.tv_sec = 0; its.it_interval.tv_nsec = 0; its.it_value.tv_sec = 0; its.it_value.tv_nsec = 0; return timerfd_settime(timerfd, 0, &its, NULL); } static void wl_timer_heap_init(struct wl_timer_heap *timers, struct wl_event_loop *loop) { timers->base.fd = -1; timers->base.data = NULL; wl_list_init(&timers->base.link); timers->base.interface = &timer_heap_source_interface; timers->base.loop = loop; loop->timers.data = NULL; loop->timers.active = 0; loop->timers.space = 0; loop->timers.count = 0; } static void wl_timer_heap_release(struct wl_timer_heap *timers) { if (timers->base.fd != -1) { close(timers->base.fd); } free(timers->data); } static int wl_timer_heap_ensure_timerfd(struct wl_timer_heap *timers) { struct epoll_event ep; int timer_fd; if (timers->base.fd != -1) return 0; memset(&ep, 0, sizeof ep); ep.events = EPOLLIN; ep.data.ptr = timers; timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); if (timer_fd < 0) return -1; if (epoll_ctl(timers->base.loop->epoll_fd, EPOLL_CTL_ADD, timer_fd, &ep) < 0) { close(timer_fd); return -1; } timers->base.fd = timer_fd; return 0; } static int wl_timer_heap_reserve(struct wl_timer_heap *timers) { struct wl_event_source_timer **n; int new_space; if (timers->count + 1 > timers->space) { new_space = timers->space >= 8 ? timers->space * 2 : 8; n = realloc(timers->data, (size_t)new_space * sizeof(*n)); if (!n) { wl_log("Allocation failure when expanding timer list\n"); return -1; } timers->data = n; timers->space = new_space; } timers->count++; return 0; } static void wl_timer_heap_unreserve(struct wl_timer_heap *timers) { struct wl_event_source_timer **n; timers->count--; if (timers->space >= 16 && timers->space >= 4 * timers->count) { n = realloc(timers->data, (size_t)timers->space / 2 * sizeof(*n)); if (!n) { wl_log("Reallocation failure when shrinking timer list\n"); return; } timers->data = n; timers->space = timers->space / 2; } } static int heap_set(struct wl_event_source_timer **data, struct wl_event_source_timer *a, int idx) { int tmp; tmp = a->heap_idx; a->heap_idx = idx; data[a->heap_idx] = a; return tmp; } static void heap_sift_down(struct wl_event_source_timer **data, int num_active, struct wl_event_source_timer *source) { struct wl_event_source_timer *child, *other_child; int cursor_idx; struct timespec key; cursor_idx = source->heap_idx; key = source->deadline; while (1) { int lchild_idx = cursor_idx * 2 + 1; if (lchild_idx >= num_active) { break; } child = data[lchild_idx]; if (lchild_idx + 1 < num_active) { other_child = data[lchild_idx + 1]; if (time_lt(other_child->deadline, child->deadline)) child = other_child; } if (time_lt(child->deadline, key)) cursor_idx = heap_set(data, child, cursor_idx); else break; } heap_set(data, source, cursor_idx); } static void heap_sift_up(struct wl_event_source_timer **data, struct wl_event_source_timer *source) { int cursor_idx; struct timespec key; cursor_idx = source->heap_idx; key = source->deadline; while (cursor_idx > 0) { struct wl_event_source_timer *parent = data[(cursor_idx - 1) / 2]; if (time_lt(key, parent->deadline)) cursor_idx = heap_set(data, parent, cursor_idx); else break; } heap_set(data, source, cursor_idx); } /* requires timer be armed */ static void wl_timer_heap_disarm(struct wl_timer_heap *timers, struct wl_event_source_timer *source) { struct wl_event_source_timer *last_end_evt; int old_source_idx; assert(source->heap_idx >= 0); old_source_idx = source->heap_idx; source->heap_idx = -1; source->deadline.tv_sec = 0; source->deadline.tv_nsec = 0; last_end_evt = timers->data[timers->active - 1]; timers->data[timers->active - 1] = NULL; timers->active--; if (old_source_idx == timers->active) return; timers->data[old_source_idx] = last_end_evt; last_end_evt->heap_idx = old_source_idx; /* Move the displaced (active) element to its proper place. * Only one of sift-down and sift-up will have any effect */ heap_sift_down(timers->data, timers->active, last_end_evt); heap_sift_up(timers->data, last_end_evt); } /* requires timer be disarmed */ static void wl_timer_heap_arm(struct wl_timer_heap *timers, struct wl_event_source_timer *source, struct timespec deadline) { assert(source->heap_idx == -1); source->deadline = deadline; timers->data[timers->active] = source; source->heap_idx = timers->active; timers->active++; heap_sift_up(timers->data, source); } static int wl_timer_heap_dispatch(struct wl_timer_heap *timers) { struct timespec now; struct wl_event_source_timer *root; struct wl_event_source_timer *list_cursor = NULL, *list_tail = NULL; clock_gettime(CLOCK_MONOTONIC, &now); while (timers->active > 0) { root = timers->data[0]; if (time_lt(now, root->deadline)) break; wl_timer_heap_disarm(timers, root); if (list_cursor == NULL) list_cursor = root; else list_tail->next_due = root; list_tail = root; } if (list_tail) list_tail->next_due = NULL; if (timers->active > 0) { if (set_timer(timers->base.fd, timers->data[0]->deadline) < 0) return -1; } else { if (clear_timer(timers->base.fd) < 0) return -1; } /* Execute precisely the functions for events before `now`, in order. * Because wl_event_loop_dispatch ignores return codes, do the same * here as well */ for (; list_cursor; list_cursor = list_cursor->next_due) { if (list_cursor->base.fd != TIMER_REMOVED) list_cursor->func(list_cursor->base.data); } return 0; } static int wl_event_source_timer_dispatch(struct wl_event_source *source, struct epoll_event *ep) { struct wl_event_source_timer *timer; timer = wl_container_of(source, timer, base); return timer->func(timer->base.data); } struct wl_event_source_interface timer_source_interface = { wl_event_source_timer_dispatch, }; /** \endcond */ /** Create a timer event source * * \param loop The event loop that will process the new source. * \param func The timer dispatch function. * \param data User data. * \return A new timer event source. * * The timer is initially disarmed. It needs to be armed with a call to * wl_event_source_timer_update() before it can trigger a dispatch call. * * \sa wl_event_loop_timer_func_t * \memberof wl_event_source */ WL_EXPORT struct wl_event_source * wl_event_loop_add_timer(struct wl_event_loop *loop, wl_event_loop_timer_func_t func, void *data) { struct wl_event_source_timer *source; if (wl_timer_heap_ensure_timerfd(&loop->timers) < 0) return NULL; source = zalloc(sizeof *source); if (source == NULL) return NULL; source->base.interface = &timer_source_interface; source->base.fd = -1; source->func = func; source->base.loop = loop; source->base.data = data; wl_list_init(&source->base.link); source->next_due = NULL; source->deadline.tv_sec = 0; source->deadline.tv_nsec = 0; source->heap_idx = -1; if (wl_timer_heap_reserve(&loop->timers) < 0) { free(source); return NULL; } return &source->base; } /** Arm or disarm a timer * * \param source The timer event source to modify. * \param ms_delay The timeout in milliseconds. * \return 0 on success, -1 on failure. * * If the timeout is zero, the timer is disarmed. * * If the timeout is non-zero, the timer is set to expire after the given * timeout in milliseconds. When the timer expires, the dispatch function * set with wl_event_loop_add_timer() is called once from * wl_event_loop_dispatch(). If another dispatch is desired after another * expiry, wl_event_source_timer_update() needs to be called again. * * \memberof wl_event_source */ WL_EXPORT int wl_event_source_timer_update(struct wl_event_source *source, int ms_delay) { struct wl_event_source_timer *tsource = wl_container_of(source, tsource, base); struct wl_timer_heap *timers = &tsource->base.loop->timers; if (ms_delay > 0) { struct timespec deadline; clock_gettime(CLOCK_MONOTONIC, &deadline); deadline.tv_nsec += (ms_delay % 1000) * 1000000L; deadline.tv_sec += ms_delay / 1000; if (deadline.tv_nsec >= 1000000000L) { deadline.tv_nsec -= 1000000000L; deadline.tv_sec += 1; } if (tsource->heap_idx == -1) { wl_timer_heap_arm(timers, tsource, deadline); } else if (time_lt(deadline, tsource->deadline)) { tsource->deadline = deadline; heap_sift_up(timers->data, tsource); } else { tsource->deadline = deadline; heap_sift_down(timers->data, timers->active, tsource); } if (tsource->heap_idx == 0) { /* Only update the timerfd if the new deadline is * the earliest */ if (set_timer(timers->base.fd, deadline) < 0) return -1; } } else { if (tsource->heap_idx == -1) return 0; wl_timer_heap_disarm(timers, tsource); if (timers->active == 0) { /* Only update the timerfd if this was the last * active timer */ if (clear_timer(timers->base.fd) < 0) return -1; } } return 0; } /** \cond INTERNAL */ struct wl_event_source_signal { struct wl_event_source base; int signal_number; wl_event_loop_signal_func_t func; }; /** \endcond */ static int wl_event_source_signal_dispatch(struct wl_event_source *source, struct epoll_event *ep) { struct wl_event_source_signal *signal_source = (struct wl_event_source_signal *) source; struct signalfd_siginfo signal_info; int len; len = read(source->fd, &signal_info, sizeof signal_info); if (!(len == -1 && errno == EAGAIN) && len != sizeof signal_info) /* Is there anything we can do here? Will this ever happen? */ wl_log("signalfd read error: %s\n", strerror(errno)); return signal_source->func(signal_source->signal_number, signal_source->base.data); } struct wl_event_source_interface signal_source_interface = { wl_event_source_signal_dispatch, }; /** Create a POSIX signal event source * * \param loop The event loop that will process the new source. * \param signal_number Number of the signal to watch for. * \param func The signal dispatch function. * \param data User data. * \return A new signal event source. * * This function blocks the normal delivery of the given signal in the calling * thread, and creates a "watch" for it. Signal delivery no longer happens * asynchronously, but by wl_event_loop_dispatch() calling the dispatch * callback function \c func. * * It is the caller's responsibility to ensure that all other threads have * also blocked the signal. * * \sa wl_event_loop_signal_func_t * \memberof wl_event_source */ WL_EXPORT struct wl_event_source * wl_event_loop_add_signal(struct wl_event_loop *loop, int signal_number, wl_event_loop_signal_func_t func, void *data) { struct wl_event_source_signal *source; sigset_t mask; source = zalloc(sizeof *source); if (source == NULL) return NULL; source->base.interface = &signal_source_interface; source->signal_number = signal_number; sigemptyset(&mask); sigaddset(&mask, signal_number); source->base.fd = signalfd(-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK); sigprocmask(SIG_BLOCK, &mask, NULL); source->func = func; return add_source(loop, &source->base, WL_EVENT_READABLE, data); } /** \cond INTERNAL */ struct wl_event_source_idle { struct wl_event_source base; wl_event_loop_idle_func_t func; }; /** \endcond */ struct wl_event_source_interface idle_source_interface = { NULL, }; /** Create an idle task * * \param loop The event loop that will process the new task. * \param func The idle task dispatch function. * \param data User data. * \return A new idle task (an event source). * * Idle tasks are dispatched before wl_event_loop_dispatch() goes to sleep. * See wl_event_loop_dispatch() for more details. * * Idle tasks fire once, and are automatically destroyed right after the * callback function has been called. * * An idle task can be cancelled before the callback has been called by * wl_event_source_remove(). Calling wl_event_source_remove() after or from * within the callback results in undefined behaviour. * * \sa wl_event_loop_idle_func_t * \memberof wl_event_source */ WL_EXPORT struct wl_event_source * wl_event_loop_add_idle(struct wl_event_loop *loop, wl_event_loop_idle_func_t func, void *data) { struct wl_event_source_idle *source; source = zalloc(sizeof *source); if (source == NULL) return NULL; source->base.interface = &idle_source_interface; source->base.loop = loop; source->base.fd = -1; source->func = func; source->base.data = data; wl_list_insert(loop->idle_list.prev, &source->base.link); return &source->base; } /** Mark event source to be re-checked * * \param source The event source to be re-checked. * * This function permanently marks the event source to be re-checked after * the normal dispatch of sources in wl_event_loop_dispatch(). Re-checking * will keep iterating over all such event sources until the dispatch * function for them all returns zero. * * Re-checking is used on sources that may become ready to dispatch as a * side-effect of dispatching themselves or other event sources, including idle * sources. Re-checking ensures all the incoming events have been fully drained * before wl_event_loop_dispatch() returns. * * \memberof wl_event_source */ WL_EXPORT void wl_event_source_check(struct wl_event_source *source) { wl_list_insert(source->loop->check_list.prev, &source->link); } /** Remove an event source from its event loop * * \param source The event source to be removed. * \return Zero. * * The event source is removed from the event loop it was created for, * and is effectively destroyed. This invalidates \c source . * The dispatch function of the source will no longer be called through this * source. * * \memberof wl_event_source */ WL_EXPORT int wl_event_source_remove(struct wl_event_source *source) { struct wl_event_loop *loop = source->loop; /* We need to explicitly remove the fd, since closing the fd * isn't enough in case we've dup'ed the fd. */ if (source->fd >= 0) { epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, source->fd, NULL); close(source->fd); source->fd = -1; } if (source->interface == &timer_source_interface && source->fd != TIMER_REMOVED) { /* Disarm the timer (and the loop's timerfd, if necessary), * before removing its space in the loop timer heap */ wl_event_source_timer_update(source, 0); wl_timer_heap_unreserve(&loop->timers); /* Set the fd field to to indicate that the timer should NOT * be dispatched in `wl_event_loop_dispatch` */ source->fd = TIMER_REMOVED; } wl_list_remove(&source->link); wl_list_insert(&loop->destroy_list, &source->link); return 0; } static void wl_event_loop_process_destroy_list(struct wl_event_loop *loop) { struct wl_event_source *source, *next; wl_list_for_each_safe(source, next, &loop->destroy_list, link) free(source); wl_list_init(&loop->destroy_list); } /** Create a new event loop context * * \return A new event loop context object. * * This creates a new event loop context. Initially this context is empty. * Event sources need to be explicitly added to it. * * Normally the event loop is run by calling wl_event_loop_dispatch() in * a loop until the program terminates. Alternatively, an event loop can be * embedded in another event loop by its file descriptor, see * wl_event_loop_get_fd(). * * \memberof wl_event_loop */ WL_EXPORT struct wl_event_loop * wl_event_loop_create(void) { struct wl_event_loop *loop; loop = zalloc(sizeof *loop); if (loop == NULL) return NULL; loop->epoll_fd = wl_os_epoll_create_cloexec(); if (loop->epoll_fd < 0) { free(loop); return NULL; } wl_list_init(&loop->check_list); wl_list_init(&loop->idle_list); wl_list_init(&loop->destroy_list); wl_priv_signal_init(&loop->destroy_signal); wl_timer_heap_init(&loop->timers, loop); return loop; } /** Destroy an event loop context * * \param loop The event loop to be destroyed. * * This emits the event loop destroy signal, closes the event loop file * descriptor, and frees \c loop. * * If the event loop has existing sources, those cannot be safely removed * afterwards. Therefore one must call wl_event_source_remove() on all * event sources before destroying the event loop context. * * \memberof wl_event_loop */ WL_EXPORT void wl_event_loop_destroy(struct wl_event_loop *loop) { wl_priv_signal_final_emit(&loop->destroy_signal, loop); wl_event_loop_process_destroy_list(loop); wl_timer_heap_release(&loop->timers); close(loop->epoll_fd); free(loop); } static bool post_dispatch_check(struct wl_event_loop *loop) { struct epoll_event ep; struct wl_event_source *source, *next; bool needs_recheck = false; ep.events = 0; wl_list_for_each_safe(source, next, &loop->check_list, link) { int dispatch_result; dispatch_result = source->interface->dispatch(source, &ep); if (dispatch_result < 0) { wl_log("Source dispatch function returned negative value!\n"); wl_log("This would previously accidentally suppress a follow-up dispatch\n"); } needs_recheck |= dispatch_result != 0; } return needs_recheck; } /** Dispatch the idle sources * * \param loop The event loop whose idle sources are dispatched. * * \sa wl_event_loop_add_idle() * \memberof wl_event_loop */ WL_EXPORT void wl_event_loop_dispatch_idle(struct wl_event_loop *loop) { struct wl_event_source_idle *source; while (!wl_list_empty(&loop->idle_list)) { source = wl_container_of(loop->idle_list.next, source, base.link); source->func(source->base.data); wl_event_source_remove(&source->base); } } static int timespec_to_ms(struct timespec value) { return (value.tv_sec * 1000) + (value.tv_nsec / 1000000); } static struct timespec ms_to_timespec(int ms) { struct timespec val; val.tv_sec = ms / 1000; val.tv_nsec = (ms % 1000) * 1000000; return val; } static struct timespec timespec_normalize(struct timespec value) { struct timespec result = value; while (result.tv_nsec >= 1000000000) { result.tv_nsec -= 1000000000; result.tv_sec++; } while (result.tv_nsec < 0) { result.tv_nsec += 1000000000; result.tv_sec--; } return result; } static struct timespec timespec_add(struct timespec a, struct timespec b) { struct timespec result; result.tv_sec = a.tv_sec + b.tv_sec; result.tv_nsec = a.tv_nsec + b.tv_nsec; return timespec_normalize(result); } static struct timespec timespec_sub(struct timespec a, struct timespec b) { struct timespec result; result.tv_sec = a.tv_sec - b.tv_sec; result.tv_nsec = a.tv_nsec - b.tv_nsec; return timespec_normalize(result); } /** Wait for events and dispatch them * * \param loop The event loop whose sources to wait for. * \param timeout The polling timeout in milliseconds. * \return 0 for success, -1 for polling (or timer update) error. * * All the associated event sources are polled. This function blocks until * any event source delivers an event (idle sources excluded), or the timeout * expires. A timeout of -1 disables the timeout, causing the function to block * indefinitely. A timeout of zero causes the poll to always return immediately. * * All idle sources are dispatched before blocking. An idle source is destroyed * when it is dispatched. After blocking, all other ready sources are * dispatched. Then, idle sources are dispatched again, in case the dispatched * events created idle sources. Finally, all sources marked with * wl_event_source_check() are dispatched in a loop until their dispatch * functions all return zero. * * \memberof wl_event_loop */ WL_EXPORT int wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout) { struct epoll_event ep[32]; struct wl_event_source *source; int i, count; bool has_timers = false; bool use_timeout = timeout > 0; struct timespec now, end; wl_event_loop_dispatch_idle(loop); if (use_timeout) { clock_gettime(CLOCK_MONOTONIC, &now); end = timespec_add(now, ms_to_timespec(timeout)); } while (true) { count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout); if (count >= 0) break; /* have events or timeout */ else if (count < 0 && errno != EINTR && errno != EAGAIN) break; /* have error */ if (use_timeout) { clock_gettime(CLOCK_MONOTONIC, &now); timeout = timespec_to_ms(timespec_sub(end, now)); if (timeout <= 0) { /* too late */ count = 0; break; } } } if (count < 0) return -1; for (i = 0; i < count; i++) { source = ep[i].data.ptr; if (source == &loop->timers.base) { has_timers = true; break; } } if (has_timers) { /* Dispatch timer sources before non-timer sources, so that * the non-timer sources can not cancel (by calling * `wl_event_source_timer_update`) the dispatching of the timers * (Note that timer sources also can't cancel pending non-timer * sources, since epoll_wait has already been called) */ if (wl_timer_heap_dispatch(&loop->timers) < 0) return -1; } for (i = 0; i < count; i++) { source = ep[i].data.ptr; if (source->fd != -1) source->interface->dispatch(source, &ep[i]); } wl_event_loop_process_destroy_list(loop); wl_event_loop_dispatch_idle(loop); while (post_dispatch_check(loop)); return 0; } /** Get the event loop file descriptor * * \param loop The event loop context. * \return The aggregate file descriptor. * * This function returns the aggregate file descriptor, that represents all * the event sources (idle sources excluded) associated with the given event * loop context. When any event source makes an event available, it will be * reflected in the aggregate file descriptor. * * When the aggregate file descriptor delivers an event, one can call * wl_event_loop_dispatch() on the event loop context to dispatch all the * available events. * * \memberof wl_event_loop */ WL_EXPORT int wl_event_loop_get_fd(struct wl_event_loop *loop) { return loop->epoll_fd; } /** Register a destroy listener for an event loop context * * \param loop The event loop context whose destruction to listen for. * \param listener The listener with the callback to be called. * * \sa wl_listener * \memberof wl_event_loop */ WL_EXPORT void wl_event_loop_add_destroy_listener(struct wl_event_loop *loop, struct wl_listener *listener) { wl_priv_signal_add(&loop->destroy_signal, listener); } /** Get the listener struct for the specified callback * * \param loop The event loop context to inspect. * \param notify The destroy callback to find. * \return The wl_listener registered to the event loop context with * the given callback pointer. * * \memberof wl_event_loop */ WL_EXPORT struct wl_listener * wl_event_loop_get_destroy_listener(struct wl_event_loop *loop, wl_notify_func_t notify) { return wl_priv_signal_get(&loop->destroy_signal, notify); } wayland-1.23.1/src/meson.build000066400000000000000000000166021466237767300162200ustar00rootroot00000000000000if not (get_option('scanner') or get_option('libraries')) error('Either -Dscanner=true or -Dlibraries=true is required') endif wayland_version_h = configuration_data() wayland_version_h.set('WAYLAND_VERSION', meson.project_version()) wayland_version_h.set('WAYLAND_VERSION_MAJOR', wayland_version[0].to_int()) wayland_version_h.set('WAYLAND_VERSION_MINOR', wayland_version[1].to_int()) wayland_version_h.set('WAYLAND_VERSION_MICRO', wayland_version[2].to_int()) configure_file( input: 'wayland-version.h.in', output: 'wayland-version.h', configuration: wayland_version_h, install: get_option('libraries'), install_dir: join_paths(get_option('prefix'), get_option('includedir')) ) wayland_util = static_library( 'wayland-util', sources: 'wayland-util.c' ) wayland_util_dep = declare_dependency( link_with: wayland_util, include_directories: include_directories('.') ) if get_option('scanner') # wayland-scanner scanner_deps = [ dependency('expat') ] scanner_args = [ '-include', 'config.h' ] if get_option('dtd_validation') scanner_deps += dependency('libxml-2.0') scanner_args += '-DHAVE_LIBXML=1' endif prog_embed = find_program('embed.py', native: true) embed_dtd = custom_target( 'wayland.dtd.h', input: '../protocol/wayland.dtd', output: 'wayland.dtd.h', command: [ prog_embed, '@INPUT@', 'wayland_dtd' ], capture: true ) wayland_scanner_sources = [ 'scanner.c', embed_dtd ] wayland_scanner_includes = [ root_inc, protocol_inc ] wayland_scanner = executable( 'wayland-scanner', wayland_scanner_sources, c_args: scanner_args, include_directories: wayland_scanner_includes, dependencies: [ scanner_deps, wayland_util_dep, ], install: true ) pkgconfig.generate( name: 'Wayland Scanner', description: 'Wayland scanner', version: meson.project_version(), variables: [ 'datarootdir=' + join_paths('${prefix}', get_option('datadir')), 'pkgdatadir=' + join_paths('${pc_sysrootdir}${datarootdir}', meson.project_name()), 'bindir=' + join_paths('${prefix}', get_option('bindir')), 'wayland_scanner=${bindir}/wayland-scanner' ], filebase: 'wayland-scanner' ) if meson.can_run_host_binaries() meson.override_find_program('wayland-scanner', wayland_scanner) meson.override_dependency('wayland-scanner', declare_dependency( variables: { 'wayland_scanner': 'wayland-scanner' }, )) endif endif if meson.is_cross_build() or not get_option('scanner') scanner_dep = dependency('wayland-scanner', native: true, version: meson.project_version()) wayland_scanner_for_build = find_program(scanner_dep.get_variable(pkgconfig: 'wayland_scanner')) else wayland_scanner_for_build = wayland_scanner endif if get_option('libraries') # wayland libraries mathlib_dep = cc.find_library('m', required: false) threads_dep = dependency('threads', required: false) wayland_private = static_library( 'wayland-private', sources: [ 'connection.c', 'wayland-os.c' ], dependencies: [ epoll_dep, ffi_dep, rt_dep ] ) wayland_private_dep = declare_dependency( link_with: wayland_private, include_directories: include_directories('.') ) generated_headers = [ { 'scanner_args': ['server-header'], 'output': 'wayland-server-protocol.h', 'install': true, }, { 'scanner_args': ['server-header', '-c'], 'output': 'wayland-server-protocol-core.h', 'install': false, }, { 'scanner_args': ['client-header'], 'output': 'wayland-client-protocol.h', 'install': true, }, { 'scanner_args': ['client-header', '-c'], 'output': 'wayland-client-protocol-core.h', 'install': false, }, ] foreach gen: generated_headers scanner_args = gen['scanner_args'] output_file = gen['output'] install_file = gen['install'] install_dir = join_paths(get_option('prefix'), get_option('includedir')) target_name = output_file.underscorify() target = custom_target( target_name, command: [ wayland_scanner_for_build, '-s', scanner_args, '@INPUT@', '@OUTPUT@' ], input: wayland_protocol_xml, output: output_file, install: install_file, install_dir: install_dir ) set_variable(target_name, target) endforeach wayland_protocol_c = custom_target( 'protocol source', command: [ wayland_scanner_for_build, '-s', 'public-code', '@INPUT@', '@OUTPUT@' ], input: wayland_protocol_xml, output: 'wayland-protocol.c' ) if wayland_version[0] != '1' # The versioning used for the shared libraries assumes that the major # version of Wayland as a whole will increase to 2 if and only if there # is an ABI break, at which point we should probably bump the SONAME of # all libraries to .so.2. For more details see # https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/177 error('We probably need to bump the SONAME of libwayland-server and -client') endif wayland_server = library( 'wayland-server', sources: [ wayland_server_protocol_core_h, wayland_server_protocol_h, wayland_protocol_c, 'wayland-server.c', 'wayland-shm.c', 'event-loop.c' ], # To avoid an unnecessary SONAME bump, wayland 1.x.y produces # libwayland-server.so.0.x.y. version: '.'.join(['0', wayland_version[1], wayland_version[2]]), dependencies: [ epoll_dep, ffi_dep, wayland_private_dep, wayland_util_dep, mathlib_dep, threads_dep, rt_dep ], include_directories: root_inc, install: true ) wayland_server_dep = declare_dependency( link_with: wayland_server, include_directories: [ root_inc, include_directories('.') ], dependencies: [ epoll_dep, ffi_dep, mathlib_dep, threads_dep ], sources: [ wayland_server_protocol_core_h, wayland_server_protocol_h ] ) pkgconfig.generate( wayland_server, name: 'Wayland Server', description: 'Server side implementation of the Wayland protocol', version: meson.project_version(), filebase: 'wayland-server', variables: [ 'datarootdir=' + join_paths('${prefix}', get_option('datadir')), 'pkgdatadir=' + join_paths('${pc_sysrootdir}${datarootdir}', meson.project_name()) ] ) if meson.version().version_compare('>= 0.54.0') meson.override_dependency('wayland-server', wayland_server_dep) endif wayland_client = library( 'wayland-client', sources: [ wayland_client_protocol_core_h, wayland_client_protocol_h, wayland_protocol_c, 'wayland-client.c' ], # To avoid an unnecessary SONAME bump, wayland 1.x.y produces # libwayland-client.so.0.x.y. version: '.'.join(['0', wayland_version[1], wayland_version[2]]), dependencies: [ epoll_dep, ffi_dep, wayland_private_dep, wayland_util_dep, mathlib_dep, threads_dep ], include_directories: root_inc, install: true ) pkgconfig.generate( wayland_client, name: 'Wayland Client', description: 'Wayland client side library', version: meson.project_version(), filebase: 'wayland-client', variables: [ 'datarootdir=' + join_paths('${prefix}', get_option('datadir')), 'pkgdatadir=' + join_paths('${pc_sysrootdir}${datarootdir}', meson.project_name()) ] ) wayland_client_dep = declare_dependency( link_with: wayland_client, include_directories: [ root_inc, include_directories('.') ], sources: [ wayland_client_protocol_core_h, wayland_client_protocol_h ] ) if meson.version().version_compare('>= 0.54.0') meson.override_dependency('wayland-client', wayland_client_dep) endif install_headers([ 'wayland-util.h', 'wayland-server.h', 'wayland-server-core.h', 'wayland-client.h', 'wayland-client-core.h', ]) endif wayland-1.23.1/src/scanner.c000066400000000000000000001510651466237767300156560ustar00rootroot00000000000000/* * Copyright © 2008-2011 Kristian Høgsberg * Copyright © 2011 Intel Corporation * Copyright © 2015 Red Hat, Inc. * * 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 "wayland-version.h" #include #include #include #include #include #include #include #include #include #include #if HAVE_LIBXML #include /* Embedded wayland.dtd file */ /* static const char wayland_dtd[]; wayland.dtd */ #include "wayland.dtd.h" #endif /* Expat must be included after libxml as both want to declare XMLCALL; see * the Git commit that 'git blame' for this comment points to for more. */ #include #include "wayland-util.h" #define PROGRAM_NAME "wayland-scanner" enum side { CLIENT, SERVER, }; enum visibility { PRIVATE, PUBLIC, }; static int usage(int ret) { fprintf(stderr, "usage: %s [OPTION] [client-header|server-header|enum-header|private-code|public-code]" " [input_file output_file]\n", PROGRAM_NAME); fprintf(stderr, "\n"); fprintf(stderr, "Converts XML protocol descriptions supplied on " "stdin or input file to client\n" "headers, server headers, or protocol marshalling code.\n\n" "Use \"public-code\" only if the marshalling code will be public - " "aka DSO will export it while other components will be using it.\n" "Using \"private-code\" is strongly recommended.\n\n"); fprintf(stderr, "options:\n"); fprintf(stderr, " -h, --help display this help and exit.\n" " -v, --version print the wayland library version that\n" " the scanner was built against.\n" " -c, --include-core-only include the core version of the headers,\n" " that is e.g. wayland-client-core.h instead\n" " of wayland-client.h.\n" " -s, --strict exit immediately with an error if DTD\n" " verification fails.\n"); exit(ret); } static int scanner_version(int ret) { fprintf(stderr, "%s %s\n", PROGRAM_NAME, WAYLAND_VERSION); exit(ret); } static bool is_dtd_valid(FILE *input, const char *filename) { bool rc = true; #if HAVE_LIBXML xmlParserCtxtPtr ctx = NULL; xmlDocPtr doc = NULL; xmlDtdPtr dtd = NULL; xmlValidCtxtPtr dtdctx; xmlParserInputBufferPtr buffer; int fd = fileno(input); dtdctx = xmlNewValidCtxt(); ctx = xmlNewParserCtxt(); if (!ctx || !dtdctx) abort(); buffer = xmlParserInputBufferCreateMem(wayland_dtd, sizeof(wayland_dtd), XML_CHAR_ENCODING_UTF8); if (!buffer) { fprintf(stderr, "Failed to init buffer for DTD.\n"); abort(); } dtd = xmlIOParseDTD(NULL, buffer, XML_CHAR_ENCODING_UTF8); if (!dtd) { fprintf(stderr, "Failed to parse DTD.\n"); abort(); } doc = xmlCtxtReadFd(ctx, fd, filename, NULL, 0); if (!doc) { fprintf(stderr, "Failed to read XML\n"); abort(); } rc = xmlValidateDtd(dtdctx, doc, dtd); xmlFreeDoc(doc); xmlFreeParserCtxt(ctx); xmlFreeDtd(dtd); xmlFreeValidCtxt(dtdctx); /* xmlIOParseDTD consumes buffer */ if (lseek(fd, 0, SEEK_SET) != 0) { fprintf(stderr, "Failed to reset fd, output would be garbage.\n"); abort(); } #endif return rc; } #define XML_BUFFER_SIZE 4096 struct location { const char *filename; int line_number; }; struct description { char *summary; char *text; }; struct protocol { char *name; char *uppercase_name; struct wl_list interface_list; int type_index; int null_run_length; char *copyright; struct description *description; bool core_headers; }; struct interface { struct location loc; char *name; char *uppercase_name; int version; int since, deprecated_since; struct wl_list request_list; struct wl_list event_list; struct wl_list enumeration_list; struct wl_list link; struct description *description; }; struct message { struct location loc; char *name; char *uppercase_name; struct wl_list arg_list; struct wl_list link; int arg_count; int new_id_count; int type_index; int all_null; int destructor; int since, deprecated_since; struct description *description; }; enum arg_type { NEW_ID, INT, UNSIGNED, FIXED, STRING, OBJECT, ARRAY, FD }; struct arg { char *name; enum arg_type type; int nullable; char *interface_name; struct wl_list link; char *summary; char *enumeration_name; }; struct enumeration { char *name; char *uppercase_name; struct wl_list entry_list; struct wl_list link; struct description *description; bool bitfield; int since; }; struct entry { char *name; char *uppercase_name; char *value; char *summary; int since, deprecated_since; struct wl_list link; struct description *description; }; struct parse_context { struct location loc; XML_Parser parser; struct protocol *protocol; struct interface *interface; struct message *message; struct enumeration *enumeration; struct entry *entry; struct description *description; char character_data[8192]; unsigned int character_data_length; }; enum identifier_role { STANDALONE_IDENT, TRAILING_IDENT }; static void * fail_on_null(void *p) { if (p == NULL) { fprintf(stderr, "%s: out of memory\n", PROGRAM_NAME); exit(EXIT_FAILURE); } return p; } static void * zalloc(size_t s) { return calloc(s, 1); } static void * xzalloc(size_t s) { return fail_on_null(zalloc(s)); } static char * xstrdup(const char *s) { return fail_on_null(strdup(s)); } static char * uppercase_dup(const char *src) { char *u; int i; u = xstrdup(src); for (i = 0; u[i]; i++) u[i] = toupper(u[i]); u[i] = '\0'; return u; } static const char *indent(int n) { const char *whitespace[] = { "\t\t\t\t\t\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\t\t\t\t\t ", "\t\t\t\t\t\t\t\t\t\t\t\t ", "\t\t\t\t\t\t\t\t\t\t\t\t ", "\t\t\t\t\t\t\t\t\t\t\t\t ", "\t\t\t\t\t\t\t\t\t\t\t\t ", "\t\t\t\t\t\t\t\t\t\t\t\t ", "\t\t\t\t\t\t\t\t\t\t\t\t " }; return whitespace[n % 8] + 12 - n / 8; } static void desc_dump(char *desc, const char *fmt, ...) WL_PRINTF(2, 3); static void desc_dump(char *desc, const char *fmt, ...) { va_list ap; char buf[128], hang; int col, i, j, k, startcol, newlines; va_start(ap, fmt); vsnprintf(buf, sizeof buf, fmt, ap); va_end(ap); for (i = 0, col = 0; buf[i] != '*'; i++) { if (buf[i] == '\t') col = (col + 8) & ~7; else col++; } printf("%s", buf); if (!desc) { printf("(none)\n"); return; } startcol = col; col += strlen(&buf[i]); if (col - startcol > 2) hang = '\t'; else hang = ' '; for (i = 0; desc[i]; ) { k = i; newlines = 0; while (desc[i] && isspace(desc[i])) { if (desc[i] == '\n') newlines++; i++; } if (!desc[i]) break; j = i; while (desc[i] && !isspace(desc[i])) i++; if (newlines > 1) printf("\n%s*", indent(startcol)); if (newlines > 1 || col + i - j > 72) { printf("\n%s*%c", indent(startcol), hang); col = startcol; } if (col > startcol && k > 0) col += printf(" "); col += printf("%.*s", i - j, &desc[j]); } putchar('\n'); } static void __attribute__ ((noreturn)) fail(struct location *loc, const char *msg, ...) { va_list ap; va_start(ap, msg); fprintf(stderr, "%s:%d: error: ", loc->filename, loc->line_number); vfprintf(stderr, msg, ap); fprintf(stderr, "\n"); va_end(ap); exit(EXIT_FAILURE); } static void warn(struct location *loc, const char *msg, ...) { va_list ap; va_start(ap, msg); fprintf(stderr, "%s:%d: warning: ", loc->filename, loc->line_number); vfprintf(stderr, msg, ap); fprintf(stderr, "\n"); va_end(ap); } static bool is_nullable_type(struct arg *arg) { switch (arg->type) { /* Strings and objects are possibly nullable */ case STRING: case OBJECT: return true; default: return false; } } static struct message * create_message(struct location loc, const char *name) { struct message *message; message = xzalloc(sizeof *message); message->loc = loc; message->name = xstrdup(name); message->uppercase_name = uppercase_dup(name); wl_list_init(&message->arg_list); return message; } static void free_arg(struct arg *arg) { free(arg->name); free(arg->interface_name); free(arg->summary); free(arg->enumeration_name); free(arg); } static struct arg * create_arg(const char *name) { struct arg *arg; arg = xzalloc(sizeof *arg); arg->name = xstrdup(name); return arg; } static bool set_arg_type(struct arg *arg, const char *type) { if (strcmp(type, "int") == 0) arg->type = INT; else if (strcmp(type, "uint") == 0) arg->type = UNSIGNED; else if (strcmp(type, "fixed") == 0) arg->type = FIXED; else if (strcmp(type, "string") == 0) arg->type = STRING; else if (strcmp(type, "array") == 0) arg->type = ARRAY; else if (strcmp(type, "fd") == 0) arg->type = FD; else if (strcmp(type, "new_id") == 0) arg->type = NEW_ID; else if (strcmp(type, "object") == 0) arg->type = OBJECT; else return false; return true; } static void free_description(struct description *desc) { if (!desc) return; free(desc->summary); free(desc->text); free(desc); } static void free_message(struct message *message) { struct arg *a, *a_next; free(message->name); free(message->uppercase_name); free_description(message->description); wl_list_for_each_safe(a, a_next, &message->arg_list, link) free_arg(a); free(message); } static struct enumeration * create_enumeration(const char *name) { struct enumeration *enumeration; enumeration = xzalloc(sizeof *enumeration); enumeration->name = xstrdup(name); enumeration->uppercase_name = uppercase_dup(name); enumeration->since = 1; wl_list_init(&enumeration->entry_list); return enumeration; } static struct entry * create_entry(const char *name, const char *value) { struct entry *entry; entry = xzalloc(sizeof *entry); entry->name = xstrdup(name); entry->uppercase_name = uppercase_dup(name); entry->value = xstrdup(value); return entry; } static void free_entry(struct entry *entry) { free(entry->name); free(entry->uppercase_name); free(entry->value); free(entry->summary); free_description(entry->description); free(entry); } static void free_enumeration(struct enumeration *enumeration) { struct entry *e, *e_next; free(enumeration->name); free(enumeration->uppercase_name); free_description(enumeration->description); wl_list_for_each_safe(e, e_next, &enumeration->entry_list, link) free_entry(e); free(enumeration); } static struct interface * create_interface(struct location loc, const char *name, int version) { struct interface *interface; interface = xzalloc(sizeof *interface); interface->loc = loc; interface->name = xstrdup(name); interface->uppercase_name = uppercase_dup(name); interface->version = version; interface->since = 1; wl_list_init(&interface->request_list); wl_list_init(&interface->event_list); wl_list_init(&interface->enumeration_list); return interface; } static void free_interface(struct interface *interface) { struct message *m, *next_m; struct enumeration *e, *next_e; free(interface->name); free(interface->uppercase_name); free_description(interface->description); wl_list_for_each_safe(m, next_m, &interface->request_list, link) free_message(m); wl_list_for_each_safe(m, next_m, &interface->event_list, link) free_message(m); wl_list_for_each_safe(e, next_e, &interface->enumeration_list, link) free_enumeration(e); free(interface); } /* Convert string to unsigned integer * * Parses a non-negative base-10 number from the given string. If the * specified string is blank, contains non-numerical characters, is out * of range, or results in a negative number, -1 is returned to indicate * an error. * * Upon error, this routine does not modify or set errno. * * Returns -1 on error, or a non-negative integer on success */ static int strtouint(const char *str) { long int ret; char *end; int prev_errno = errno; errno = 0; ret = strtol(str, &end, 10); if (errno != 0 || end == str || *end != '\0') return -1; /* check range */ if (ret < 0 || ret > INT_MAX) { return -1; } errno = prev_errno; return (int)ret; } /* Check that the provided string will produce valid "C" identifiers. * * If the string will form the prefix of an identifier in the * generated C code, then it must match [_a-zA-Z][_0-9a-zA-Z]*. * * If the string will form the suffix of an identifier, then * it must match [_0-9a-zA-Z]+. * * Unicode characters or escape sequences are not permitted, * since not all C compilers support them. * * If the above conditions are not met, then fail() */ static void validate_identifier(struct location *loc, const char *str, enum identifier_role role) { const char *scan; if (!*str) { fail(loc, "element name is empty"); } for (scan = str; *scan; scan++) { char c = *scan; /* we do not use the locale-dependent `isalpha` */ bool is_alpha = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); bool is_digit = c >= '0' && c <= '9'; bool leading_char = (scan == str) && role == STANDALONE_IDENT; if (is_alpha || c == '_' || (!leading_char && is_digit)) continue; if (role == TRAILING_IDENT) fail(loc, "'%s' is not a valid trailing identifier part", str); else fail(loc, "'%s' is not a valid standalone identifier", str); } } static int version_from_since(struct parse_context *ctx, const char *since) { int version; if (since != NULL) { version = strtouint(since); if (version == -1) { fail(&ctx->loc, "invalid integer (%s)\n", since); } else if (version > ctx->interface->version) { fail(&ctx->loc, "since (%u) larger than version (%u)\n", version, ctx->interface->version); } } else { version = 1; } return version; } static int version_from_deprecated_since(struct parse_context *ctx, const char *deprecated_since) { int version; if (deprecated_since == NULL) return 0; version = strtouint(deprecated_since); if (version == -1) { fail(&ctx->loc, "invalid integer (%s)\n", deprecated_since); } else if (version > ctx->interface->version) { fail(&ctx->loc, "deprecated-since (%u) larger than version (%u)\n", version, ctx->interface->version); } return version; } static void start_element(void *data, const char *element_name, const char **atts) { struct parse_context *ctx = data; struct interface *interface; struct message *message; struct arg *arg; struct enumeration *enumeration; struct entry *entry; struct description *description = NULL; const char *name = NULL; const char *type = NULL; const char *interface_name = NULL; const char *value = NULL; const char *summary = NULL; const char *since = NULL; const char *deprecated_since = NULL; const char *allow_null = NULL; const char *enumeration_name = NULL; const char *bitfield = NULL; int i, version = 0; ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser); for (i = 0; atts[i]; i += 2) { if (strcmp(atts[i], "name") == 0) name = atts[i + 1]; if (strcmp(atts[i], "version") == 0) { version = strtouint(atts[i + 1]); if (version == -1) fail(&ctx->loc, "wrong version (%s)", atts[i + 1]); } if (strcmp(atts[i], "type") == 0) type = atts[i + 1]; if (strcmp(atts[i], "value") == 0) value = atts[i + 1]; if (strcmp(atts[i], "interface") == 0) interface_name = atts[i + 1]; if (strcmp(atts[i], "summary") == 0) summary = atts[i + 1]; if (strcmp(atts[i], "since") == 0) since = atts[i + 1]; if (strcmp(atts[i], "deprecated-since") == 0) deprecated_since = atts[i + 1]; if (strcmp(atts[i], "allow-null") == 0) allow_null = atts[i + 1]; if (strcmp(atts[i], "enum") == 0) enumeration_name = atts[i + 1]; if (strcmp(atts[i], "bitfield") == 0) bitfield = atts[i + 1]; } ctx->character_data_length = 0; if (strcmp(element_name, "protocol") == 0) { if (name == NULL) fail(&ctx->loc, "no protocol name given"); validate_identifier(&ctx->loc, name, STANDALONE_IDENT); ctx->protocol->name = xstrdup(name); ctx->protocol->uppercase_name = uppercase_dup(name); } else if (strcmp(element_name, "copyright") == 0) { } else if (strcmp(element_name, "interface") == 0) { if (name == NULL) fail(&ctx->loc, "no interface name given"); if (version == 0) fail(&ctx->loc, "no interface version given"); validate_identifier(&ctx->loc, name, STANDALONE_IDENT); interface = create_interface(ctx->loc, name, version); ctx->interface = interface; wl_list_insert(ctx->protocol->interface_list.prev, &interface->link); } else if (strcmp(element_name, "request") == 0 || strcmp(element_name, "event") == 0) { if (name == NULL) fail(&ctx->loc, "no request name given"); validate_identifier(&ctx->loc, name, STANDALONE_IDENT); message = create_message(ctx->loc, name); if (strcmp(element_name, "request") == 0) wl_list_insert(ctx->interface->request_list.prev, &message->link); else wl_list_insert(ctx->interface->event_list.prev, &message->link); if (type != NULL && strcmp(type, "destructor") == 0) message->destructor = 1; version = version_from_since(ctx, since); if (version < ctx->interface->since) warn(&ctx->loc, "since version not increasing\n"); ctx->interface->since = version; message->since = version; version = version_from_deprecated_since(ctx, deprecated_since); if (version > 0 && version <= message->since) fail(&ctx->loc, "deprecated-since version (%d) smaller " "or equal to since version (%u)\n", version, message->since); message->deprecated_since = version; if (strcmp(name, "destroy") == 0 && !message->destructor) fail(&ctx->loc, "destroy request should be destructor type"); ctx->message = message; } else if (strcmp(element_name, "arg") == 0) { if (name == NULL) fail(&ctx->loc, "no argument name given"); validate_identifier(&ctx->loc, name, STANDALONE_IDENT); arg = create_arg(name); if (!set_arg_type(arg, type)) fail(&ctx->loc, "unknown type (%s)", type); switch (arg->type) { case NEW_ID: ctx->message->new_id_count++; /* fallthrough */ case OBJECT: if (interface_name) { validate_identifier(&ctx->loc, interface_name, STANDALONE_IDENT); arg->interface_name = xstrdup(interface_name); } break; default: if (interface_name != NULL) fail(&ctx->loc, "interface attribute not allowed for type %s", type); break; } if (allow_null) { if (strcmp(allow_null, "true") == 0) arg->nullable = 1; else if (strcmp(allow_null, "false") != 0) fail(&ctx->loc, "invalid value for allow-null attribute (%s)", allow_null); if (!is_nullable_type(arg)) fail(&ctx->loc, "allow-null is only valid for objects, strings, and arrays"); } if (enumeration_name == NULL || strcmp(enumeration_name, "") == 0) arg->enumeration_name = NULL; else arg->enumeration_name = xstrdup(enumeration_name); if (summary) arg->summary = xstrdup(summary); wl_list_insert(ctx->message->arg_list.prev, &arg->link); ctx->message->arg_count++; } else if (strcmp(element_name, "enum") == 0) { if (name == NULL) fail(&ctx->loc, "no enum name given"); validate_identifier(&ctx->loc, name, TRAILING_IDENT); enumeration = create_enumeration(name); if (bitfield == NULL || strcmp(bitfield, "false") == 0) enumeration->bitfield = false; else if (strcmp(bitfield, "true") == 0) enumeration->bitfield = true; else fail(&ctx->loc, "invalid value (%s) for bitfield attribute (only true/false are accepted)", bitfield); wl_list_insert(ctx->interface->enumeration_list.prev, &enumeration->link); ctx->enumeration = enumeration; } else if (strcmp(element_name, "entry") == 0) { if (name == NULL) fail(&ctx->loc, "no entry name given"); validate_identifier(&ctx->loc, name, TRAILING_IDENT); entry = create_entry(name, value); version = version_from_since(ctx, since); if (version < ctx->enumeration->since) warn(&ctx->loc, "since version not increasing\n"); ctx->enumeration->since = version; entry->since = version; version = version_from_deprecated_since(ctx, deprecated_since); if (version > 0 && version <= entry->since) fail(&ctx->loc, "deprecated-since version (%d) smaller " "or equal to since version (%u)\n", version, entry->since); entry->deprecated_since = version; if (summary) entry->summary = xstrdup(summary); else entry->summary = NULL; wl_list_insert(ctx->enumeration->entry_list.prev, &entry->link); ctx->entry = entry; } else if (strcmp(element_name, "description") == 0) { if (summary == NULL) fail(&ctx->loc, "description without summary"); description = xzalloc(sizeof *description); description->summary = xstrdup(summary); if (ctx->message) ctx->message->description = description; else if (ctx->entry) ctx->entry->description = description; else if (ctx->enumeration) ctx->enumeration->description = description; else if (ctx->interface) ctx->interface->description = description; else ctx->protocol->description = description; ctx->description = description; } } static struct enumeration * find_enumeration(struct protocol *protocol, struct interface *interface, char *enum_attribute) { struct interface *i; struct enumeration *e; char *enum_name; uint32_t idx = 0, j; for (j = 0; j + 1 < strlen(enum_attribute); j++) { if (enum_attribute[j] == '.') { idx = j; } } if (idx > 0) { enum_name = enum_attribute + idx + 1; wl_list_for_each(i, &protocol->interface_list, link) if (strncmp(i->name, enum_attribute, idx) == 0) wl_list_for_each(e, &i->enumeration_list, link) if (strcmp(e->name, enum_name) == 0) return e; } else if (interface) { enum_name = enum_attribute; wl_list_for_each(e, &interface->enumeration_list, link) if (strcmp(e->name, enum_name) == 0) return e; } return NULL; } static void verify_arguments(struct parse_context *ctx, struct interface *interface, struct wl_list *messages, struct wl_list *enumerations) { struct message *m; wl_list_for_each(m, messages, link) { struct arg *a; wl_list_for_each(a, &m->arg_list, link) { struct enumeration *e; if (!a->enumeration_name) continue; e = find_enumeration(ctx->protocol, interface, a->enumeration_name); switch (a->type) { case INT: if (e && e->bitfield) fail(&ctx->loc, "bitfield-style enum must only be referenced by uint"); break; case UNSIGNED: break; default: fail(&ctx->loc, "enumeration-style argument has wrong type"); } } } } #ifndef HAVE_STRNDUP char * strndup(const char *s, size_t size) { char *r = malloc(size + 1); strncpy(r, s, size); r[size] = '\0'; return r; } #endif static void end_element(void *data, const XML_Char *name) { struct parse_context *ctx = data; if (strcmp(name, "copyright") == 0) { ctx->protocol->copyright = strndup(ctx->character_data, ctx->character_data_length); } else if (strcmp(name, "description") == 0) { ctx->description->text = strndup(ctx->character_data, ctx->character_data_length); ctx->description = NULL; } else if (strcmp(name, "request") == 0 || strcmp(name, "event") == 0) { ctx->message = NULL; } else if (strcmp(name, "enum") == 0) { if (wl_list_empty(&ctx->enumeration->entry_list)) { fail(&ctx->loc, "enumeration %s was empty", ctx->enumeration->name); } ctx->enumeration = NULL; } else if (strcmp(name, "entry") == 0) { ctx->entry = NULL; } else if (strcmp(name, "protocol") == 0) { struct interface *i; wl_list_for_each(i, &ctx->protocol->interface_list, link) { verify_arguments(ctx, i, &i->request_list, &i->enumeration_list); verify_arguments(ctx, i, &i->event_list, &i->enumeration_list); } } } static void character_data(void *data, const XML_Char *s, int len) { struct parse_context *ctx = data; if (ctx->character_data_length + len > sizeof (ctx->character_data)) { fprintf(stderr, "too much character data"); exit(EXIT_FAILURE); } memcpy(ctx->character_data + ctx->character_data_length, s, len); ctx->character_data_length += len; } static void format_text_to_comment(const char *text, bool standalone_comment) { int bol = 1, start = 0, i, length; bool comment_started = !standalone_comment; length = strlen(text); for (i = 0; i <= length; i++) { if (bol && (text[i] == ' ' || text[i] == '\t')) { continue; } else if (bol) { bol = 0; start = i; } if (text[i] == '\n' || (text[i] == '\0' && !(start == i))) { printf("%s%s%.*s\n", comment_started ? " *" : "/*", i > start ? " " : "", i - start, text + start); bol = 1; comment_started = true; } } if (comment_started && standalone_comment) printf(" */\n\n"); } static void emit_opcodes(struct wl_list *message_list, struct interface *interface) { struct message *m; int opcode; if (wl_list_empty(message_list)) return; opcode = 0; wl_list_for_each(m, message_list, link) printf("#define %s_%s %d\n", interface->uppercase_name, m->uppercase_name, opcode++); printf("\n"); } static void emit_opcode_versions(struct wl_list *message_list, struct interface *interface) { struct message *m; wl_list_for_each(m, message_list, link) { printf("/**\n * @ingroup iface_%s\n */\n", interface->name); printf("#define %s_%s_SINCE_VERSION %d\n", interface->uppercase_name, m->uppercase_name, m->since); } printf("\n"); } static void emit_type(struct arg *a) { switch (a->type) { default: case INT: case FD: printf("int32_t "); break; case NEW_ID: case UNSIGNED: printf("uint32_t "); break; case FIXED: printf("wl_fixed_t "); break; case STRING: printf("const char *"); break; case OBJECT: printf("struct %s *", a->interface_name); break; case ARRAY: printf("struct wl_array *"); break; } } static void emit_stubs(struct wl_list *message_list, struct interface *interface) { struct message *m; struct arg *a, *ret; int has_destructor, has_destroy; printf("/** @ingroup iface_%s */\n", interface->name); printf("static inline void\n" "%s_set_user_data(struct %s *%s, void *user_data)\n" "{\n" "\twl_proxy_set_user_data((struct wl_proxy *) %s, user_data);\n" "}\n\n", interface->name, interface->name, interface->name, interface->name); printf("/** @ingroup iface_%s */\n", interface->name); printf("static inline void *\n" "%s_get_user_data(struct %s *%s)\n" "{\n" "\treturn wl_proxy_get_user_data((struct wl_proxy *) %s);\n" "}\n\n", interface->name, interface->name, interface->name, interface->name); printf("static inline uint32_t\n" "%s_get_version(struct %s *%s)\n" "{\n" "\treturn wl_proxy_get_version((struct wl_proxy *) %s);\n" "}\n\n", interface->name, interface->name, interface->name, interface->name); has_destructor = 0; has_destroy = 0; wl_list_for_each(m, message_list, link) { if (m->destructor) has_destructor = 1; if (strcmp(m->name, "destroy") == 0) has_destroy = 1; } if (!has_destructor && has_destroy) { fail(&interface->loc, "interface '%s' has method named destroy " "but no destructor", interface->name); exit(EXIT_FAILURE); } if (!has_destroy && strcmp(interface->name, "wl_display") != 0) { printf("/** @ingroup iface_%s */\n", interface->name); printf("static inline void\n" "%s_destroy(struct %s *%s)\n" "{\n" "\twl_proxy_destroy(" "(struct wl_proxy *) %s);\n" "}\n\n", interface->name, interface->name, interface->name, interface->name); } if (wl_list_empty(message_list)) return; wl_list_for_each(m, message_list, link) { if (m->new_id_count > 1) { warn(&m->loc, "request '%s::%s' has more than " "one new_id arg, not emitting stub\n", interface->name, m->name); continue; } ret = NULL; wl_list_for_each(a, &m->arg_list, link) { if (a->type == NEW_ID) ret = a; } printf("/**\n" " * @ingroup iface_%s\n", interface->name); if (m->description && m->description->text) format_text_to_comment(m->description->text, false); printf(" */\n"); if (ret && ret->interface_name == NULL) printf("static inline void *\n"); else if (ret) printf("static inline struct %s *\n", ret->interface_name); else printf("static inline void\n"); printf("%s_%s(struct %s *%s", interface->name, m->name, interface->name, interface->name); wl_list_for_each(a, &m->arg_list, link) { if (a->type == NEW_ID && a->interface_name == NULL) { printf(", const struct wl_interface *interface" ", uint32_t version"); continue; } else if (a->type == NEW_ID) continue; printf(", "); emit_type(a); printf("%s", a->name); } printf(")\n" "{\n"); printf("\t"); if (ret) { printf("struct wl_proxy *%s;\n\n" "\t%s = ", ret->name, ret->name); } printf("wl_proxy_marshal_flags(" "(struct wl_proxy *) %s,\n" "\t\t\t %s_%s", interface->name, interface->uppercase_name, m->uppercase_name); if (ret) { if (ret->interface_name) { /* Normal factory case, an arg has type="new_id" and * an interface is provided */ printf(", &%s_interface", ret->interface_name); } else { /* an arg has type ="new_id" but interface is not * provided, such as in wl_registry.bind */ printf(", interface"); } } else { /* No args have type="new_id" */ printf(", NULL"); } if (ret && ret->interface_name == NULL) printf(", version"); else printf(", wl_proxy_get_version((struct wl_proxy *) %s)", interface->name); printf(", %s", m->destructor ? "WL_MARSHAL_FLAG_DESTROY" : "0"); wl_list_for_each(a, &m->arg_list, link) { if (a->type == NEW_ID) { if (a->interface_name == NULL) printf(", interface->name, version"); printf(", NULL"); } else { printf(", %s", a->name); } } printf(");\n"); if (ret && ret->interface_name == NULL) printf("\n\treturn (void *) %s;\n", ret->name); else if (ret) printf("\n\treturn (struct %s *) %s;\n", ret->interface_name, ret->name); printf("}\n\n"); } } static void emit_event_wrappers(struct wl_list *message_list, struct interface *interface) { struct message *m; struct arg *a; /* We provide hand written functions for the display object */ if (strcmp(interface->name, "wl_display") == 0) return; wl_list_for_each(m, message_list, link) { printf("/**\n" " * @ingroup iface_%s\n" " * Sends an %s event to the client owning the resource.\n", interface->name, m->name); printf(" * @param resource_ The client's resource\n"); wl_list_for_each(a, &m->arg_list, link) { if (a->summary) printf(" * @param %s %s\n", a->name, a->summary); } printf(" */\n"); printf("static inline void\n" "%s_send_%s(struct wl_resource *resource_", interface->name, m->name); wl_list_for_each(a, &m->arg_list, link) { printf(", "); switch (a->type) { case NEW_ID: case OBJECT: printf("struct wl_resource *"); break; default: emit_type(a); } printf("%s", a->name); } printf(")\n" "{\n" "\twl_resource_post_event(resource_, %s_%s", interface->uppercase_name, m->uppercase_name); wl_list_for_each(a, &m->arg_list, link) printf(", %s", a->name); printf(");\n"); printf("}\n\n"); } } static void emit_validator(struct interface *interface, struct enumeration *e) { struct entry *entry; printf("/**\n" " * @ingroup iface_%s\n" " * Validate a %s %s value.\n" " *\n" " * @return true on success, false on error.\n" " * @ref %s_%s\n" " */\n" "static inline bool\n" "%s_%s_is_valid(uint32_t value, uint32_t version) {\n", interface->name, interface->name, e->name, interface->name, e->name, interface->name, e->name); if (e->bitfield) { printf(" uint32_t valid = 0;\n"); wl_list_for_each(entry, &e->entry_list, link) { printf(" if (version >= %d)\n" " valid |= %s_%s_%s;\n", entry->since, interface->uppercase_name, e->uppercase_name, entry->uppercase_name); } printf(" return (value & ~valid) == 0;\n"); } else { printf(" switch (value) {\n"); wl_list_for_each(entry, &e->entry_list, link) { printf(" case %s%s_%s_%s:\n" " return version >= %d;\n", entry->value[0] == '-' ? "(uint32_t)" : "", interface->uppercase_name, e->uppercase_name, entry->uppercase_name, entry->since); } printf(" default:\n" " return false;\n" " }\n"); } printf("}\n"); } static void emit_enumerations(struct interface *interface, bool with_validators) { struct enumeration *e; struct entry *entry; wl_list_for_each(e, &interface->enumeration_list, link) { struct description *desc = e->description; printf("#ifndef %s_%s_ENUM\n", interface->uppercase_name, e->uppercase_name); printf("#define %s_%s_ENUM\n", interface->uppercase_name, e->uppercase_name); if (desc) { printf("/**\n"); printf(" * @ingroup iface_%s\n", interface->name); format_text_to_comment(desc->summary, false); if (desc->text) format_text_to_comment(desc->text, false); printf(" */\n"); } printf("enum %s_%s {\n", interface->name, e->name); wl_list_for_each(entry, &e->entry_list, link) { desc = entry->description; if (entry->summary || entry->since > 1 || desc) { printf("\t/**\n"); if (entry->summary) printf("\t * %s\n", entry->summary); if (desc) { printf("\t * %s\n", desc->summary); printf("\t *\n"); if (desc->text) desc_dump(desc->text, "\t * "); } if (entry->since > 1) printf("\t * @since %d\n", entry->since); if (entry->deprecated_since > 0) printf("\t * @deprecated Deprecated since version %d\n", entry->deprecated_since); printf("\t */\n"); } printf("\t%s_%s_%s = %s,\n", interface->uppercase_name, e->uppercase_name, entry->uppercase_name, entry->value); } printf("};\n"); wl_list_for_each(entry, &e->entry_list, link) { if (entry->since == 1) continue; printf("/**\n * @ingroup iface_%s\n */\n", interface->name); printf("#define %s_%s_%s_SINCE_VERSION %d\n", interface->uppercase_name, e->uppercase_name, entry->uppercase_name, entry->since); } if (with_validators) emit_validator(interface, e); printf("#endif /* %s_%s_ENUM */\n\n", interface->uppercase_name, e->uppercase_name); } } static void emit_structs(struct wl_list *message_list, struct interface *interface, enum side side) { struct message *m; struct arg *a; int n; if (wl_list_empty(message_list)) return; printf("/**\n"); printf(" * @ingroup iface_%s\n", interface->name); printf(" * @struct %s_%s\n", interface->name, (side == SERVER) ? "interface" : "listener"); printf(" */\n"); printf("struct %s_%s {\n", interface->name, (side == SERVER) ? "interface" : "listener"); wl_list_for_each(m, message_list, link) { struct description *mdesc = m->description; printf("\t/**\n"); if (mdesc) { if (mdesc->summary) printf("\t * %s\n", mdesc->summary); printf("\t *\n"); desc_dump(mdesc->text, "\t * "); } wl_list_for_each(a, &m->arg_list, link) { if (side == SERVER && a->type == NEW_ID && a->interface_name == NULL) printf("\t * @param interface name of the objects interface\n" "\t * @param version version of the objects interface\n"); if (a->summary) printf("\t * @param %s %s\n", a->name, a->summary); } if (m->since > 1) printf("\t * @since %d\n", m->since); if (m->deprecated_since > 0) printf("\t * @deprecated Deprecated since version %d\n", m->deprecated_since); printf("\t */\n"); printf("\tvoid (*%s)(", m->name); n = strlen(m->name) + 17; if (side == SERVER) { printf("struct wl_client *client,\n" "%sstruct wl_resource *resource", indent(n)); } else { printf("void *data,\n"), printf("%sstruct %s *%s", indent(n), interface->name, interface->name); } wl_list_for_each(a, &m->arg_list, link) { printf(",\n%s", indent(n)); if (side == SERVER && a->type == OBJECT) printf("struct wl_resource *"); else if (side == SERVER && a->type == NEW_ID && a->interface_name == NULL) printf("const char *interface, uint32_t version, uint32_t "); else if (side == CLIENT && a->type == OBJECT && a->interface_name == NULL) printf("void *"); else if (side == CLIENT && a->type == NEW_ID) printf("struct %s *", a->interface_name); else emit_type(a); printf("%s", a->name); } printf(");\n"); } printf("};\n\n"); if (side == CLIENT) { printf("/**\n" " * @ingroup iface_%s\n" " */\n", interface->name); printf("static inline int\n" "%s_add_listener(struct %s *%s,\n" "%sconst struct %s_listener *listener, void *data)\n" "{\n" "\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n" "%s(void (**)(void)) listener, data);\n" "}\n\n", interface->name, interface->name, interface->name, indent(14 + strlen(interface->name)), interface->name, interface->name, indent(37)); } } static void emit_types_forward_declarations(struct protocol *protocol, struct wl_list *message_list, struct wl_array *types) { struct message *m; struct arg *a; int length; char **p; wl_list_for_each(m, message_list, link) { length = 0; m->all_null = 1; wl_list_for_each(a, &m->arg_list, link) { length++; switch (a->type) { case NEW_ID: case OBJECT: if (!a->interface_name) continue; m->all_null = 0; p = fail_on_null(wl_array_add(types, sizeof *p)); *p = a->interface_name; break; default: break; } } if (m->all_null && length > protocol->null_run_length) protocol->null_run_length = length; } } static int cmp_names(const void *p1, const void *p2) { const char * const *s1 = p1, * const *s2 = p2; return strcmp(*s1, *s2); } static const char * get_include_name(bool core, enum side side) { if (side == SERVER) return core ? "wayland-server-core.h" : "wayland-server.h"; else return core ? "wayland-client-core.h" : "wayland-client.h"; } static void emit_mainpage_blurb(const struct protocol *protocol, enum side side) { struct interface *i; printf("/**\n" " * @page page_%s The %s protocol\n", protocol->name, protocol->name); if (protocol->description) { if (protocol->description->summary) { printf(" * %s\n" " *\n", protocol->description->summary); } if (protocol->description->text) { printf(" * @section page_desc_%s Description\n", protocol->name); format_text_to_comment(protocol->description->text, false); printf(" *\n"); } } printf(" * @section page_ifaces_%s Interfaces\n", protocol->name); wl_list_for_each(i, &protocol->interface_list, link) { printf(" * - @subpage page_iface_%s - %s\n", i->name, i->description && i->description->summary ? i->description->summary : ""); } if (protocol->copyright) { printf(" * @section page_copyright_%s Copyright\n", protocol->name); printf(" *
\n");
		format_text_to_comment(protocol->copyright, false);
		printf(" * 
\n"); } printf(" */\n"); } static void emit_header(struct protocol *protocol, enum side side) { struct interface *i, *i_next; struct wl_array types; const char *s = (side == SERVER) ? "SERVER" : "CLIENT"; char **p, *prev; printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION); printf("#ifndef %s_%s_PROTOCOL_H\n" "#define %s_%s_PROTOCOL_H\n" "\n" "#include \n" "#include \n" "#include \"%s\"\n\n" "#ifdef __cplusplus\n" "extern \"C\" {\n" "#endif\n\n", protocol->uppercase_name, s, protocol->uppercase_name, s, get_include_name(protocol->core_headers, side)); if (side == SERVER) printf("struct wl_client;\n" "struct wl_resource;\n\n"); emit_mainpage_blurb(protocol, side); wl_array_init(&types); wl_list_for_each(i, &protocol->interface_list, link) { emit_types_forward_declarations(protocol, &i->request_list, &types); emit_types_forward_declarations(protocol, &i->event_list, &types); } wl_list_for_each(i, &protocol->interface_list, link) { p = fail_on_null(wl_array_add(&types, sizeof *p)); *p = i->name; } if (types.size > 0) qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names); prev = NULL; wl_array_for_each(p, &types) { if (prev && strcmp(*p, prev) == 0) continue; printf("struct %s;\n", *p); prev = *p; } wl_array_release(&types); printf("\n"); wl_list_for_each(i, &protocol->interface_list, link) { printf("#ifndef %s_INTERFACE\n", i->uppercase_name); printf("#define %s_INTERFACE\n", i->uppercase_name); printf("/**\n" " * @page page_iface_%s %s\n", i->name, i->name); if (i->description && i->description->text) { printf(" * @section page_iface_%s_desc Description\n", i->name); format_text_to_comment(i->description->text, false); } printf(" * @section page_iface_%s_api API\n" " * See @ref iface_%s.\n" " */\n", i->name, i->name); printf("/**\n" " * @defgroup iface_%s The %s interface\n", i->name, i->name); if (i->description && i->description->text) format_text_to_comment(i->description->text, false); printf(" */\n"); printf("extern const struct wl_interface " "%s_interface;\n", i->name); printf("#endif\n"); } printf("\n"); wl_list_for_each_safe(i, i_next, &protocol->interface_list, link) { emit_enumerations(i, side == SERVER); if (side == SERVER) { emit_structs(&i->request_list, i, side); emit_opcodes(&i->event_list, i); emit_opcode_versions(&i->event_list, i); emit_opcode_versions(&i->request_list, i); emit_event_wrappers(&i->event_list, i); } else { emit_structs(&i->event_list, i, side); emit_opcodes(&i->request_list, i); emit_opcode_versions(&i->event_list, i); emit_opcode_versions(&i->request_list, i); emit_stubs(&i->request_list, i); } free_interface(i); } printf("#ifdef __cplusplus\n" "}\n" "#endif\n" "\n" "#endif\n"); } static void emit_enum_header(struct protocol *protocol) { struct interface *i, *i_next; printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION); printf("#ifndef %s_ENUM_PROTOCOL_H\n" "#define %s_ENUM_PROTOCOL_H\n" "\n" "#ifdef __cplusplus\n" "extern \"C\" {\n" "#endif\n\n", protocol->uppercase_name, protocol->uppercase_name); wl_list_for_each_safe(i, i_next, &protocol->interface_list, link) { emit_enumerations(i, false); free_interface(i); } printf("#ifdef __cplusplus\n" "}\n" "#endif\n" "\n" "#endif\n"); } static void emit_null_run(struct protocol *protocol) { int i; for (i = 0; i < protocol->null_run_length; i++) printf("\tNULL,\n"); } static void emit_types(struct protocol *protocol, struct wl_list *message_list) { struct message *m; struct arg *a; wl_list_for_each(m, message_list, link) { if (m->all_null) { m->type_index = 0; continue; } m->type_index = protocol->null_run_length + protocol->type_index; protocol->type_index += m->arg_count; wl_list_for_each(a, &m->arg_list, link) { switch (a->type) { case NEW_ID: case OBJECT: if (a->interface_name) printf("\t&%s_interface,\n", a->interface_name); else printf("\tNULL,\n"); break; default: printf("\tNULL,\n"); break; } } } } static void emit_messages(const char *name, struct wl_list *message_list, struct interface *interface, const char *suffix) { struct message *m; struct arg *a; if (wl_list_empty(message_list)) return; printf("static const struct wl_message " "%s_%s[] = {\n", interface->name, suffix); wl_list_for_each(m, message_list, link) { printf("\t{ \"%s\", \"", m->name); if (m->since > 1) printf("%d", m->since); wl_list_for_each(a, &m->arg_list, link) { if (is_nullable_type(a) && a->nullable) printf("?"); switch (a->type) { default: case INT: printf("i"); break; case NEW_ID: if (a->interface_name == NULL) printf("su"); printf("n"); break; case UNSIGNED: printf("u"); break; case FIXED: printf("f"); break; case STRING: printf("s"); break; case OBJECT: printf("o"); break; case ARRAY: printf("a"); break; case FD: printf("h"); break; } } printf("\", %s_types + %d },\n", name, m->type_index); } printf("};\n\n"); } static void emit_code(struct protocol *protocol, enum visibility vis) { const char *symbol_visibility; struct interface *i, *next; struct wl_array types; char **p, *prev; printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION); if (protocol->copyright) format_text_to_comment(protocol->copyright, true); printf("#include \n" "#include \n" "#include \n" "#include \"wayland-util.h\"\n\n"); /* When building a shared library symbols must be exported, otherwise * we want to have the symbols hidden. */ if (vis == PRIVATE) { symbol_visibility = "WL_PRIVATE"; printf("#ifndef __has_attribute\n" "# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */\n" "#endif\n\n"); printf("#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)\n" "#define WL_PRIVATE __attribute__ ((visibility(\"hidden\")))\n" "#else\n" "#define WL_PRIVATE\n" "#endif\n\n"); } else { symbol_visibility = "WL_EXPORT"; } wl_array_init(&types); wl_list_for_each(i, &protocol->interface_list, link) { emit_types_forward_declarations(protocol, &i->request_list, &types); emit_types_forward_declarations(protocol, &i->event_list, &types); } if (types.size > 0) qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names); prev = NULL; wl_array_for_each(p, &types) { if (prev && strcmp(*p, prev) == 0) continue; printf("extern const struct wl_interface %s_interface;\n", *p); prev = *p; } wl_array_release(&types); printf("\n"); printf("static const struct wl_interface *%s_types[] = {\n", protocol->name); emit_null_run(protocol); wl_list_for_each(i, &protocol->interface_list, link) { emit_types(protocol, &i->request_list); emit_types(protocol, &i->event_list); } printf("};\n\n"); wl_list_for_each_safe(i, next, &protocol->interface_list, link) { emit_messages(protocol->name, &i->request_list, i, "requests"); emit_messages(protocol->name, &i->event_list, i, "events"); printf("%s const struct wl_interface " "%s_interface = {\n" "\t\"%s\", %d,\n", symbol_visibility, i->name, i->name, i->version); if (!wl_list_empty(&i->request_list)) printf("\t%d, %s_requests,\n", wl_list_length(&i->request_list), i->name); else printf("\t0, NULL,\n"); if (!wl_list_empty(&i->event_list)) printf("\t%d, %s_events,\n", wl_list_length(&i->event_list), i->name); else printf("\t0, NULL,\n"); printf("};\n\n"); /* we won't need it any further */ free_interface(i); } } static void free_protocol(struct protocol *protocol) { free(protocol->name); free(protocol->uppercase_name); free(protocol->copyright); free_description(protocol->description); } int main(int argc, char *argv[]) { struct parse_context ctx; struct protocol protocol; FILE *input = stdin; char *input_filename = NULL; int len; void *buf; bool help = false; bool core_headers = false; bool version = false; bool strict = false; bool fail = false; int opt; enum { CLIENT_HEADER, SERVER_HEADER, ENUM_HEADER, PRIVATE_CODE, PUBLIC_CODE, CODE, } mode; static const struct option options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { "include-core-only", no_argument, NULL, 'c' }, { "strict", no_argument, NULL, 's' }, { 0, 0, NULL, 0 } }; while (1) { opt = getopt_long(argc, argv, "hvcs", options, NULL); if (opt == -1) break; switch (opt) { case 'h': help = true; break; case 'v': version = true; break; case 'c': core_headers = true; break; case 's': strict = true; break; default: fail = true; break; } } argv += optind; argc -= optind; if (help) usage(EXIT_SUCCESS); else if (version) scanner_version(EXIT_SUCCESS); else if ((argc != 1 && argc != 3) || fail) usage(EXIT_FAILURE); else if (strcmp(argv[0], "help") == 0) usage(EXIT_SUCCESS); else if (strcmp(argv[0], "client-header") == 0) mode = CLIENT_HEADER; else if (strcmp(argv[0], "server-header") == 0) mode = SERVER_HEADER; else if (strcmp(argv[0], "enum-header") == 0) mode = ENUM_HEADER; else if (strcmp(argv[0], "private-code") == 0) mode = PRIVATE_CODE; else if (strcmp(argv[0], "public-code") == 0) mode = PUBLIC_CODE; else if (strcmp(argv[0], "code") == 0) mode = CODE; else usage(EXIT_FAILURE); if (argc == 3) { input_filename = argv[1]; input = fopen(input_filename, "r"); if (input == NULL) { fprintf(stderr, "Could not open input file: %s\n", strerror(errno)); exit(EXIT_FAILURE); } if (freopen(argv[2], "w", stdout) == NULL) { fprintf(stderr, "Could not open output file: %s\n", strerror(errno)); fclose(input); exit(EXIT_FAILURE); } } /* initialize protocol structure */ memset(&protocol, 0, sizeof protocol); wl_list_init(&protocol.interface_list); protocol.core_headers = core_headers; /* initialize context */ memset(&ctx, 0, sizeof ctx); ctx.protocol = &protocol; if (input == stdin) ctx.loc.filename = ""; else ctx.loc.filename = input_filename; if (!is_dtd_valid(input, ctx.loc.filename)) { fprintf(stderr, "*******************************************************\n" "* *\n" "* WARNING: XML failed validation against built-in DTD *\n" "* *\n" "*******************************************************\n"); if (strict) { fclose(input); exit(EXIT_FAILURE); } } /* create XML parser */ ctx.parser = XML_ParserCreate(NULL); XML_SetUserData(ctx.parser, &ctx); if (ctx.parser == NULL) { fprintf(stderr, "failed to create parser\n"); fclose(input); exit(EXIT_FAILURE); } XML_SetElementHandler(ctx.parser, start_element, end_element); XML_SetCharacterDataHandler(ctx.parser, character_data); do { buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE); len = fread(buf, 1, XML_BUFFER_SIZE, input); if (len < 0) { fprintf(stderr, "fread: %s\n", strerror(errno)); fclose(input); exit(EXIT_FAILURE); } if (XML_ParseBuffer(ctx.parser, len, len == 0) == 0) { fprintf(stderr, "Error parsing XML at line %ld col %ld: %s\n", XML_GetCurrentLineNumber(ctx.parser), XML_GetCurrentColumnNumber(ctx.parser), XML_ErrorString(XML_GetErrorCode(ctx.parser))); fclose(input); exit(EXIT_FAILURE); } } while (len > 0); XML_ParserFree(ctx.parser); switch (mode) { case CLIENT_HEADER: emit_header(&protocol, CLIENT); break; case SERVER_HEADER: emit_header(&protocol, SERVER); break; case ENUM_HEADER: emit_enum_header(&protocol); break; case PRIVATE_CODE: emit_code(&protocol, PRIVATE); break; case CODE: fprintf(stderr, "Using \"code\" is deprecated - use " "private-code or public-code.\n" "See the help page for details.\n"); /* fallthrough */ case PUBLIC_CODE: emit_code(&protocol, PUBLIC); break; } free_protocol(&protocol); fclose(input); return 0; } wayland-1.23.1/src/wayland-client-core.h000066400000000000000000000227631466237767300200750ustar00rootroot00000000000000/* * Copyright © 2008 Kristian Høgsberg * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef WAYLAND_CLIENT_CORE_H #define WAYLAND_CLIENT_CORE_H #include #include "wayland-util.h" #include "wayland-version.h" #ifdef __cplusplus extern "C" { #endif /** \class wl_proxy * * \brief Represents a protocol object on the client side. * * A wl_proxy acts as a client side proxy to an object existing in the * compositor. The proxy is responsible for converting requests made by the * clients with \ref wl_proxy_marshal() into Wayland's wire format. Events * coming from the compositor are also handled by the proxy, which will in * turn call the handler set with \ref wl_proxy_add_listener(). * * \note With the exception of function \ref wl_proxy_set_queue(), functions * accessing a wl_proxy are not normally used by client code. Clients * should normally use the higher level interface generated by the scanner to * interact with compositor objects. * */ struct wl_proxy; /** \class wl_display * * \brief Represents a connection to the compositor and acts as a proxy to * the wl_display singleton object. * * A wl_display object represents a client connection to a Wayland * compositor. It is created with either \ref wl_display_connect() or * \ref wl_display_connect_to_fd(). A connection is terminated using * \ref wl_display_disconnect(). * * A wl_display is also used as the \ref wl_proxy for the wl_display * singleton object on the compositor side. * * A wl_display object handles all the data sent from and to the * compositor. When a \ref wl_proxy marshals a request, it will write its wire * representation to the display's write buffer. The data is sent to the * compositor when the client calls \ref wl_display_flush(). * * Incoming data is handled in two steps: queueing and dispatching. In the * queue step, the data coming from the display fd is interpreted and * added to a queue. On the dispatch step, the handler for the incoming * event set by the client on the corresponding \ref wl_proxy is called. * * A wl_display has at least one event queue, called the default * queue. Clients can create additional event queues with \ref * wl_display_create_queue() and assign \ref wl_proxy's to it. Events * occurring in a particular proxy are always queued in its assigned queue. * A client can ensure that a certain assumption, such as holding a lock * or running from a given thread, is true when a proxy event handler is * called by assigning that proxy to an event queue and making sure that * this queue is only dispatched when the assumption holds. * * The default queue is dispatched by calling \ref wl_display_dispatch(). * This will dispatch any events queued on the default queue and attempt * to read from the display fd if it's empty. Events read are then queued * on the appropriate queues according to the proxy assignment. * * A user created queue is dispatched with \ref wl_display_dispatch_queue(). * This function behaves exactly the same as wl_display_dispatch() * but it dispatches given queue instead of the default queue. * * A real world example of event queue usage is Mesa's implementation of * eglSwapBuffers() for the Wayland platform. This function might need * to block until a frame callback is received, but dispatching the default * queue could cause an event handler on the client to start drawing * again. This problem is solved using another event queue, so that only * the events handled by the EGL code are dispatched during the block. * * This creates a problem where a thread dispatches a non-default * queue, reading all the data from the display fd. If the application * would call \em poll(2) after that it would block, even though there * might be events queued on the default queue. Those events should be * dispatched with \ref wl_display_dispatch_pending() or \ref * wl_display_dispatch_queue_pending() before flushing and blocking. */ struct wl_display; /** \class wl_event_queue * * \brief A queue for \ref wl_proxy object events. * * Event queues allows the events on a display to be handled in a thread-safe * manner. See \ref wl_display for details. * */ struct wl_event_queue; /** Destroy proxy after marshalling * \relates wl_proxy */ #define WL_MARSHAL_FLAG_DESTROY (1 << 0) void wl_event_queue_destroy(struct wl_event_queue *queue); struct wl_proxy * wl_proxy_marshal_flags(struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, uint32_t flags, ...); struct wl_proxy * wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, uint32_t flags, union wl_argument *args); void wl_proxy_marshal(struct wl_proxy *p, uint32_t opcode, ...); void wl_proxy_marshal_array(struct wl_proxy *p, uint32_t opcode, union wl_argument *args); struct wl_proxy * wl_proxy_create(struct wl_proxy *factory, const struct wl_interface *interface); void * wl_proxy_create_wrapper(void *proxy); void wl_proxy_wrapper_destroy(void *proxy_wrapper); struct wl_proxy * wl_proxy_marshal_constructor(struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, ...); struct wl_proxy * wl_proxy_marshal_constructor_versioned(struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, ...); struct wl_proxy * wl_proxy_marshal_array_constructor(struct wl_proxy *proxy, uint32_t opcode, union wl_argument *args, const struct wl_interface *interface); struct wl_proxy * wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy, uint32_t opcode, union wl_argument *args, const struct wl_interface *interface, uint32_t version); void wl_proxy_destroy(struct wl_proxy *proxy); int wl_proxy_add_listener(struct wl_proxy *proxy, void (**implementation)(void), void *data); const void * wl_proxy_get_listener(struct wl_proxy *proxy); int wl_proxy_add_dispatcher(struct wl_proxy *proxy, wl_dispatcher_func_t dispatcher_func, const void * dispatcher_data, void *data); void wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data); void * wl_proxy_get_user_data(struct wl_proxy *proxy); uint32_t wl_proxy_get_version(struct wl_proxy *proxy); uint32_t wl_proxy_get_id(struct wl_proxy *proxy); void wl_proxy_set_tag(struct wl_proxy *proxy, const char * const *tag); const char * const * wl_proxy_get_tag(struct wl_proxy *proxy); const char * wl_proxy_get_class(struct wl_proxy *proxy); struct wl_display * wl_proxy_get_display(struct wl_proxy *proxy); void wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue); struct wl_event_queue * wl_proxy_get_queue(const struct wl_proxy *proxy); const char * wl_event_queue_get_name(const struct wl_event_queue *queue); struct wl_display * wl_display_connect(const char *name); struct wl_display * wl_display_connect_to_fd(int fd); void wl_display_disconnect(struct wl_display *display); int wl_display_get_fd(struct wl_display *display); int wl_display_dispatch(struct wl_display *display); int wl_display_dispatch_queue(struct wl_display *display, struct wl_event_queue *queue); int wl_display_dispatch_queue_pending(struct wl_display *display, struct wl_event_queue *queue); int wl_display_dispatch_pending(struct wl_display *display); int wl_display_get_error(struct wl_display *display); uint32_t wl_display_get_protocol_error(struct wl_display *display, const struct wl_interface **interface, uint32_t *id); int wl_display_flush(struct wl_display *display); int wl_display_roundtrip_queue(struct wl_display *display, struct wl_event_queue *queue); int wl_display_roundtrip(struct wl_display *display); struct wl_event_queue * wl_display_create_queue(struct wl_display *display); struct wl_event_queue * wl_display_create_queue_with_name(struct wl_display *display, const char *name); int wl_display_prepare_read_queue(struct wl_display *display, struct wl_event_queue *queue); int wl_display_prepare_read(struct wl_display *display); void wl_display_cancel_read(struct wl_display *display); int wl_display_read_events(struct wl_display *display); void wl_log_set_handler_client(wl_log_func_t handler); void wl_display_set_max_buffer_size(struct wl_display *display, size_t max_buffer_size); #ifdef __cplusplus } #endif #endif wayland-1.23.1/src/wayland-client.c000066400000000000000000002171631466237767300171420ustar00rootroot00000000000000/* * Copyright © 2008-2012 Kristian Høgsberg * Copyright © 2010-2012 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wayland-util.h" #include "wayland-os.h" #include "wayland-client.h" #include "wayland-private.h" /** \cond */ enum wl_proxy_flag { WL_PROXY_FLAG_ID_DELETED = (1 << 0), WL_PROXY_FLAG_DESTROYED = (1 << 1), WL_PROXY_FLAG_WRAPPER = (1 << 2), }; struct wl_zombie { int event_count; int *fd_count; }; struct wl_proxy { struct wl_object object; struct wl_display *display; struct wl_event_queue *queue; uint32_t flags; int refcount; void *user_data; wl_dispatcher_func_t dispatcher; uint32_t version; const char * const *tag; struct wl_list queue_link; /**< in struct wl_event_queue::proxy_list */ }; struct wl_event_queue { struct wl_list event_list; struct wl_list proxy_list; /**< struct wl_proxy::queue_link */ struct wl_display *display; char *name; }; struct wl_display { struct wl_proxy proxy; struct wl_connection *connection; /* errno of the last wl_display error */ int last_error; /* When display gets an error event from some object, it stores * information about it here, so that client can get this * information afterwards */ struct { /* Code of the error. It can be compared to * the interface's errors enumeration. */ uint32_t code; /* interface (protocol) in which the error occurred */ const struct wl_interface *interface; /* id of the proxy that caused the error. There's no warranty * that the proxy is still valid. It's up to client how it will * use it */ uint32_t id; } protocol_error; int fd; struct wl_map objects; struct wl_event_queue display_queue; struct wl_event_queue default_queue; pthread_mutex_t mutex; int reader_count; uint32_t read_serial; pthread_cond_t reader_cond; }; /** \endcond */ static int debug_client = 0; /** * This helper function wakes up all threads that are * waiting for display->reader_cond (i. e. when reading is done, * canceled, or an error occurred) * * NOTE: must be called with display->mutex locked */ static void display_wakeup_threads(struct wl_display *display) { /* Thread can get sleeping only in read_events(). If we're * waking it up, it means that the read completed or was * canceled, so we must increase the read_serial. * This prevents from indefinite sleeping in read_events(). */ ++display->read_serial; pthread_cond_broadcast(&display->reader_cond); } /** * This function is called for local errors (no memory, server hung up) * * \param display * \param error error value (EINVAL, EFAULT, ...) * * \note this function is called with display mutex locked */ static void display_fatal_error(struct wl_display *display, int error) { if (display->last_error) return; if (!error) error = EFAULT; display->last_error = error; display_wakeup_threads(display); } /** * This function is called for error events * and indicates that in some object an error occurred. * The difference between this function and display_fatal_error() * is that this one handles errors that will come by wire, * whereas display_fatal_error() is called for local errors. * * \param display * \param code error code * \param id id of the object that generated the error * \param intf protocol interface */ static void display_protocol_error(struct wl_display *display, uint32_t code, uint32_t id, const struct wl_interface *intf) { int err; if (display->last_error) return; /* set correct errno */ if (intf && wl_interface_equal(intf, &wl_display_interface)) { switch (code) { case WL_DISPLAY_ERROR_INVALID_OBJECT: case WL_DISPLAY_ERROR_INVALID_METHOD: err = EINVAL; break; case WL_DISPLAY_ERROR_NO_MEMORY: err = ENOMEM; break; case WL_DISPLAY_ERROR_IMPLEMENTATION: err = EPROTO; break; default: err = EFAULT; } } else { err = EPROTO; } pthread_mutex_lock(&display->mutex); display->last_error = err; display->protocol_error.code = code; display->protocol_error.id = id; display->protocol_error.interface = intf; /* * here it is not necessary to wake up threads like in * display_fatal_error, because this function is called from * an event handler and that means that read_events() is done * and woke up all threads. Since wl_display_prepare_read() * fails when there are events in the queue, no threads * can sleep in read_events() during dispatching * (and therefore during calling this function), so this is safe. */ pthread_mutex_unlock(&display->mutex); } static void wl_event_queue_init(struct wl_event_queue *queue, struct wl_display *display, const char *name) { wl_list_init(&queue->event_list); wl_list_init(&queue->proxy_list); queue->display = display; if (name) queue->name = strdup(name); } static void wl_proxy_unref(struct wl_proxy *proxy) { assert(proxy->refcount > 0); if (--proxy->refcount > 0) return; /* If we get here, the client must have explicitly requested * deletion. */ assert(proxy->flags & WL_PROXY_FLAG_DESTROYED); free(proxy); } static void validate_closure_objects(struct wl_closure *closure) { const char *signature; struct argument_details arg; int i, count; struct wl_proxy *proxy; signature = closure->message->signature; count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { case WL_ARG_NEW_ID: case WL_ARG_OBJECT: proxy = (struct wl_proxy *) closure->args[i].o; if (proxy && proxy->flags & WL_PROXY_FLAG_DESTROYED) closure->args[i].o = NULL; break; default: break; } } } /* Destroys a closure which was demarshaled for dispatch; unrefs all the * proxies in its arguments, as well as its own proxy, and destroys the * closure itself. */ static void destroy_queued_closure(struct wl_closure *closure) { const char *signature; struct argument_details arg; struct wl_proxy *proxy; int i, count; signature = closure->message->signature; count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { case WL_ARG_NEW_ID: case WL_ARG_OBJECT: proxy = (struct wl_proxy *) closure->args[i].o; if (proxy) wl_proxy_unref(proxy); break; default: break; } } wl_proxy_unref(closure->proxy); wl_closure_destroy(closure); } static void wl_event_queue_release(struct wl_event_queue *queue) { struct wl_closure *closure; if (!wl_list_empty(&queue->proxy_list)) { struct wl_proxy *proxy, *tmp; if (queue != &queue->display->default_queue) { if (queue->name) { wl_log("warning: queue \"%s\" " "%p destroyed while proxies " "still attached:\n", queue->name, queue); } else { wl_log("warning: queue " "%p destroyed while proxies " "still attached:\n", queue); } } wl_list_for_each_safe(proxy, tmp, &queue->proxy_list, queue_link) { if (queue != &queue->display->default_queue) { wl_log(" %s#%u still attached\n", proxy->object.interface->name, proxy->object.id); } proxy->queue = NULL; wl_list_remove(&proxy->queue_link); wl_list_init(&proxy->queue_link); } } while (!wl_list_empty(&queue->event_list)) { closure = wl_container_of(queue->event_list.next, closure, link); wl_list_remove(&closure->link); destroy_queued_closure(closure); } } /** Destroy an event queue * * \param queue The event queue to be destroyed * * Destroy the given event queue. Any pending event on that queue is * discarded. * * The \ref wl_display object used to create the queue should not be * destroyed until all event queues created with it are destroyed with * this function. * * \memberof wl_event_queue */ WL_EXPORT void wl_event_queue_destroy(struct wl_event_queue *queue) { struct wl_display *display = queue->display; pthread_mutex_lock(&display->mutex); wl_event_queue_release(queue); free(queue->name); free(queue); pthread_mutex_unlock(&display->mutex); } /** Create a new event queue for this display * * \param display The display context object * \return A new event queue associated with this display or NULL on * failure. * * \memberof wl_display */ WL_EXPORT struct wl_event_queue * wl_display_create_queue(struct wl_display *display) { struct wl_event_queue *queue; queue = zalloc(sizeof *queue); if (queue == NULL) return NULL; wl_event_queue_init(queue, display, NULL); return queue; } /** Create a new event queue for this display and give it a name * * \param display The display context object * \param name A human readable queue name * \return A new event queue associated with this display or NULL on * failure. * * \memberof wl_display */ WL_EXPORT struct wl_event_queue * wl_display_create_queue_with_name(struct wl_display *display, const char *name) { struct wl_event_queue *queue; queue = zalloc(sizeof *queue); if (queue == NULL) return NULL; wl_event_queue_init(queue, display, name); return queue; } static int message_count_fds(const char *signature) { unsigned int count, i, fds = 0; struct argument_details arg; count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); if (arg.type == WL_ARG_FD) fds++; } return fds; } static struct wl_zombie * prepare_zombie(struct wl_proxy *proxy) { const struct wl_interface *interface = proxy->object.interface; const struct wl_message *message; int i, count; struct wl_zombie *zombie = NULL; /* If we hit an event with an FD, ensure we have a zombie object and * fill the fd_count slot for that event with the number of FDs for * that event. Interfaces with no events containing FDs will not have * zombie objects created. */ for (i = 0; i < interface->event_count; i++) { message = &interface->events[i]; count = message_count_fds(message->signature); if (!count) continue; if (!zombie) { zombie = zalloc(sizeof(*zombie) + (interface->event_count * sizeof(int))); if (!zombie) return NULL; zombie->event_count = interface->event_count; zombie->fd_count = (int *) &zombie[1]; } zombie->fd_count[i] = count; } return zombie; } static enum wl_iterator_result free_zombies(void *element, void *data, uint32_t flags) { if (flags & WL_MAP_ENTRY_ZOMBIE) free(element); return WL_ITERATOR_CONTINUE; } static struct wl_proxy * proxy_create(struct wl_proxy *factory, const struct wl_interface *interface, uint32_t version) { struct wl_proxy *proxy; struct wl_display *display = factory->display; proxy = zalloc(sizeof *proxy); if (proxy == NULL) return NULL; proxy->object.interface = interface; proxy->display = display; proxy->queue = factory->queue; proxy->refcount = 1; proxy->version = version; proxy->object.id = wl_map_insert_new(&display->objects, 0, proxy); if (proxy->object.id == 0) { free(proxy); return NULL; } wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link); return proxy; } /** Create a proxy object with a given interface * * \param factory Factory proxy object * \param interface Interface the proxy object should use * \return A newly allocated proxy object or NULL on failure * * This function creates a new proxy object with the supplied interface. The * proxy object will have an id assigned from the client id space. The id * should be created on the compositor side by sending an appropriate request * with \ref wl_proxy_marshal(). * * The proxy will inherit the display and event queue of the factory object. * * \note This should not normally be used by non-generated code. * * \sa wl_display, wl_event_queue, wl_proxy_marshal() * * \memberof wl_proxy */ WL_EXPORT struct wl_proxy * wl_proxy_create(struct wl_proxy *factory, const struct wl_interface *interface) { struct wl_display *display = factory->display; struct wl_proxy *proxy; pthread_mutex_lock(&display->mutex); proxy = proxy_create(factory, interface, factory->version); pthread_mutex_unlock(&display->mutex); return proxy; } /* The caller should hold the display lock */ static struct wl_proxy * wl_proxy_create_for_id(struct wl_proxy *factory, uint32_t id, const struct wl_interface *interface) { struct wl_proxy *proxy; struct wl_display *display = factory->display; proxy = zalloc(sizeof *proxy); if (proxy == NULL) return NULL; proxy->object.interface = interface; proxy->object.id = id; proxy->display = display; proxy->queue = factory->queue; proxy->refcount = 1; proxy->version = factory->version; if (wl_map_insert_at(&display->objects, 0, id, proxy) == -1) { free(proxy); return NULL; } wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link); return proxy; } static void proxy_destroy(struct wl_proxy *proxy) { if (proxy->flags & WL_PROXY_FLAG_ID_DELETED) { wl_map_remove(&proxy->display->objects, proxy->object.id); } else if (proxy->object.id < WL_SERVER_ID_START) { struct wl_zombie *zombie = prepare_zombie(proxy); /* The map now contains the zombie entry, until the delete_id * event arrives. */ wl_map_insert_at(&proxy->display->objects, WL_MAP_ENTRY_ZOMBIE, proxy->object.id, zombie); } else { wl_map_insert_at(&proxy->display->objects, 0, proxy->object.id, NULL); } proxy->flags |= WL_PROXY_FLAG_DESTROYED; proxy->queue = NULL; wl_list_remove(&proxy->queue_link); wl_list_init(&proxy->queue_link); wl_proxy_unref(proxy); } static void wl_proxy_destroy_caller_locks(struct wl_proxy *proxy) { if (proxy->flags & WL_PROXY_FLAG_WRAPPER) wl_abort("Tried to destroy wrapper with wl_proxy_destroy()\n"); proxy_destroy(proxy); } /** Destroy a proxy object * * \param proxy The proxy to be destroyed * * \c proxy must not be a proxy wrapper. * * \note This function will abort in response to egregious * errors, and will do so with the display lock held. This means * SIGABRT handlers must not perform any actions that would * attempt to take that lock, or a deadlock would occur. * * \memberof wl_proxy */ WL_EXPORT void wl_proxy_destroy(struct wl_proxy *proxy) { struct wl_display *display = proxy->display; pthread_mutex_lock(&display->mutex); wl_proxy_destroy_caller_locks(proxy); pthread_mutex_unlock(&display->mutex); } /** Set a proxy's listener * * \param proxy The proxy object * \param implementation The listener to be added to proxy * \param data User data to be associated with the proxy * \return 0 on success or -1 on failure * * Set proxy's listener to \c implementation and its user data to * \c data. If a listener has already been set, this function * fails and nothing is changed. * * \c implementation is a vector of function pointers. For an opcode * \c n, \c implementation[n] should point to the handler of \c n for * the given object. * * \c proxy must not be a proxy wrapper. * * \memberof wl_proxy */ WL_EXPORT int wl_proxy_add_listener(struct wl_proxy *proxy, void (**implementation)(void), void *data) { if (proxy->flags & WL_PROXY_FLAG_WRAPPER) wl_abort("Proxy %p is a wrapper\n", proxy); if (proxy->object.implementation || proxy->dispatcher) { wl_log("proxy %p already has listener\n", proxy); return -1; } proxy->object.implementation = implementation; proxy->user_data = data; return 0; } /** Get a proxy's listener * * \param proxy The proxy object * \return The address of the proxy's listener or NULL if no listener is set * * Gets the address to the proxy's listener; which is the listener set with * \ref wl_proxy_add_listener. * * This function is useful in clients with multiple listeners on the same * interface to allow the identification of which code to execute. * * \memberof wl_proxy */ WL_EXPORT const void * wl_proxy_get_listener(struct wl_proxy *proxy) { return proxy->object.implementation; } /** Set a proxy's listener (with dispatcher) * * \param proxy The proxy object * \param dispatcher The dispatcher to be used for this proxy * \param implementation The dispatcher-specific listener implementation * \param data User data to be associated with the proxy * \return 0 on success or -1 on failure * * Set proxy's listener to use \c dispatcher_func as its dispatcher and \c * dispatcher_data as its dispatcher-specific implementation and its user data * to \c data. If a listener has already been set, this function * fails and nothing is changed. * * The exact details of dispatcher_data depend on the dispatcher used. This * function is intended to be used by language bindings, not user code. * * \c proxy must not be a proxy wrapper. * * \memberof wl_proxy */ WL_EXPORT int wl_proxy_add_dispatcher(struct wl_proxy *proxy, wl_dispatcher_func_t dispatcher, const void *implementation, void *data) { if (proxy->flags & WL_PROXY_FLAG_WRAPPER) wl_abort("Proxy %p is a wrapper\n", proxy); if (proxy->object.implementation || proxy->dispatcher) { wl_log("proxy %p already has listener\n", proxy); return -1; } proxy->object.implementation = implementation; proxy->dispatcher = dispatcher; proxy->user_data = data; return 0; } static struct wl_proxy * create_outgoing_proxy(struct wl_proxy *proxy, const struct wl_message *message, union wl_argument *args, const struct wl_interface *interface, uint32_t version) { int i, count; const char *signature; struct argument_details arg; struct wl_proxy *new_proxy = NULL; signature = message->signature; count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); if (arg.type != WL_ARG_NEW_ID) continue; new_proxy = proxy_create(proxy, interface, version); if (new_proxy == NULL) return NULL; args[i].o = &new_proxy->object; } return new_proxy; } /** Prepare a request to be sent to the compositor * * \param proxy The proxy object * \param opcode Opcode of the request to be sent * \param args Extra arguments for the given request * \param interface The interface to use for the new proxy * * This function translates a request given an opcode, an interface and a * wl_argument array to the wire format and writes it to the connection * buffer. * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned * on success or NULL on error with errno set accordingly. The newly * created proxy will inherit their version from their parent. * * \note This is intended to be used by language bindings and not in * non-generated code. * * \sa wl_proxy_marshal() * * \memberof wl_proxy */ WL_EXPORT struct wl_proxy * wl_proxy_marshal_array_constructor(struct wl_proxy *proxy, uint32_t opcode, union wl_argument *args, const struct wl_interface *interface) { return wl_proxy_marshal_array_constructor_versioned(proxy, opcode, args, interface, proxy->version); } /** Prepare a request to be sent to the compositor * * \param proxy The proxy object * \param opcode Opcode of the request to be sent * \param args Extra arguments for the given request * \param interface The interface to use for the new proxy * \param version The protocol object version for the new proxy * * Translates the request given by opcode and the extra arguments into the * wire format and write it to the connection buffer. This version takes an * array of the union type wl_argument. * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned * on success or NULL on error with errno set accordingly. The newly * created proxy will have the version specified. * * \note This is intended to be used by language bindings and not in * non-generated code. * * \sa wl_proxy_marshal() * * \memberof wl_proxy */ WL_EXPORT struct wl_proxy * wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy, uint32_t opcode, union wl_argument *args, const struct wl_interface *interface, uint32_t version) { return wl_proxy_marshal_array_flags(proxy, opcode, interface, version, 0, args); } /** Prepare a request to be sent to the compositor * * \param proxy The proxy object * \param opcode Opcode of the request to be sent * \param interface The interface to use for the new proxy * \param version The protocol object version of the new proxy * \param flags Flags that modify marshalling behaviour * \param ... Extra arguments for the given request * \return A new wl_proxy for the new_id argument or NULL on error * * Translates the request given by opcode and the extra arguments into the * wire format and write it to the connection buffer. * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned * on success or NULL on error with errno set accordingly. The newly * created proxy will have the version specified. * * The flag WL_MARSHAL_FLAG_DESTROY may be passed to ensure the proxy * is destroyed atomically with the marshalling in order to prevent * races that can occur if the display lock is dropped between the * marshal and destroy operations. * * \note This should not normally be used by non-generated code. * * \memberof wl_proxy */ WL_EXPORT struct wl_proxy * wl_proxy_marshal_flags(struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, uint32_t flags, ...) { union wl_argument args[WL_CLOSURE_MAX_ARGS]; va_list ap; va_start(ap, flags); wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature, args, WL_CLOSURE_MAX_ARGS, ap); va_end(ap); return wl_proxy_marshal_array_flags(proxy, opcode, interface, version, flags, args); } /** Prepare a request to be sent to the compositor * * \param proxy The proxy object * \param opcode Opcode of the request to be sent * \param interface The interface to use for the new proxy * \param version The protocol object version for the new proxy * \param flags Flags that modify marshalling behaviour * \param args Extra arguments for the given request * * Translates the request given by opcode and the extra arguments into the * wire format and write it to the connection buffer. This version takes an * array of the union type wl_argument. * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned * on success or NULL on error with errno set accordingly. The newly * created proxy will have the version specified. * * The flag WL_MARSHAL_FLAG_DESTROY may be passed to ensure the proxy * is destroyed atomically with the marshalling in order to prevent * races that can occur if the display lock is dropped between the * marshal and destroy operations. * * \note This is intended to be used by language bindings and not in * non-generated code. * * \sa wl_proxy_marshal_flags() * * \memberof wl_proxy */ WL_EXPORT struct wl_proxy * wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, uint32_t flags, union wl_argument *args) { struct wl_closure *closure; struct wl_proxy *new_proxy = NULL; const struct wl_message *message; struct wl_display *disp = proxy->display; pthread_mutex_lock(&disp->mutex); message = &proxy->object.interface->methods[opcode]; if (interface) { new_proxy = create_outgoing_proxy(proxy, message, args, interface, version); if (new_proxy == NULL) goto err_unlock; } if (proxy->display->last_error) { goto err_unlock; } closure = wl_closure_marshal(&proxy->object, opcode, args, message); if (closure == NULL) { wl_log("Error marshalling request: %s\n", strerror(errno)); display_fatal_error(proxy->display, errno); goto err_unlock; } if (debug_client) { struct wl_event_queue *queue; const char *queue_name = NULL; queue = wl_proxy_get_queue(proxy); if (queue) queue_name = wl_event_queue_get_name(queue); wl_closure_print(closure, &proxy->object, true, false, NULL, queue_name); } if (wl_closure_send(closure, proxy->display->connection)) { wl_log("Error sending request: %s\n", strerror(errno)); display_fatal_error(proxy->display, errno); } wl_closure_destroy(closure); err_unlock: if (flags & WL_MARSHAL_FLAG_DESTROY) wl_proxy_destroy_caller_locks(proxy); pthread_mutex_unlock(&disp->mutex); return new_proxy; } /** Prepare a request to be sent to the compositor * * \param proxy The proxy object * \param opcode Opcode of the request to be sent * \param ... Extra arguments for the given request * * This function is similar to wl_proxy_marshal_constructor(), except * it doesn't create proxies for new-id arguments. * * \note This should not normally be used by non-generated code. * * \sa wl_proxy_create() * * \memberof wl_proxy */ WL_EXPORT void wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...) { union wl_argument args[WL_CLOSURE_MAX_ARGS]; va_list ap; va_start(ap, opcode); wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature, args, WL_CLOSURE_MAX_ARGS, ap); va_end(ap); wl_proxy_marshal_array_constructor(proxy, opcode, args, NULL); } /** Prepare a request to be sent to the compositor * * \param proxy The proxy object * \param opcode Opcode of the request to be sent * \param interface The interface to use for the new proxy * \param ... Extra arguments for the given request * \return A new wl_proxy for the new_id argument or NULL on error * * This function translates a request given an opcode, an interface and extra * arguments to the wire format and writes it to the connection buffer. The * types of the extra arguments must correspond to the argument types of the * method associated with the opcode in the interface. * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned * on success or NULL on error with errno set accordingly. The newly * created proxy will inherit their version from their parent. * * \note This should not normally be used by non-generated code. * * \memberof wl_proxy */ WL_EXPORT struct wl_proxy * wl_proxy_marshal_constructor(struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, ...) { union wl_argument args[WL_CLOSURE_MAX_ARGS]; va_list ap; va_start(ap, interface); wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature, args, WL_CLOSURE_MAX_ARGS, ap); va_end(ap); return wl_proxy_marshal_array_constructor(proxy, opcode, args, interface); } /** Prepare a request to be sent to the compositor * * \param proxy The proxy object * \param opcode Opcode of the request to be sent * \param interface The interface to use for the new proxy * \param version The protocol object version of the new proxy * \param ... Extra arguments for the given request * \return A new wl_proxy for the new_id argument or NULL on error * * Translates the request given by opcode and the extra arguments into the * wire format and write it to the connection buffer. * * For new-id arguments, this function will allocate a new wl_proxy * and send the ID to the server. The new wl_proxy will be returned * on success or NULL on error with errno set accordingly. The newly * created proxy will have the version specified. * * \note This should not normally be used by non-generated code. * * \memberof wl_proxy */ WL_EXPORT struct wl_proxy * wl_proxy_marshal_constructor_versioned(struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, ...) { union wl_argument args[WL_CLOSURE_MAX_ARGS]; va_list ap; va_start(ap, version); wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature, args, WL_CLOSURE_MAX_ARGS, ap); va_end(ap); return wl_proxy_marshal_array_constructor_versioned(proxy, opcode, args, interface, version); } /** Prepare a request to be sent to the compositor * * \param proxy The proxy object * \param opcode Opcode of the request to be sent * \param args Extra arguments for the given request * * This function is similar to wl_proxy_marshal_array_constructor(), except * it doesn't create proxies for new-id arguments. * * \note This is intended to be used by language bindings and not in * non-generated code. * * \sa wl_proxy_marshal() * * \memberof wl_proxy */ WL_EXPORT void wl_proxy_marshal_array(struct wl_proxy *proxy, uint32_t opcode, union wl_argument *args) { wl_proxy_marshal_array_constructor(proxy, opcode, args, NULL); } static void display_handle_error(void *data, struct wl_display *display, void *object, uint32_t code, const char *message) { struct wl_proxy *proxy = object; uint32_t object_id; const struct wl_interface *interface; if (proxy) { wl_log("%s#%u: error %d: %s\n", proxy->object.interface->name, proxy->object.id, code, message); object_id = proxy->object.id; interface = proxy->object.interface; } else { wl_log("[destroyed object]: error %d: %s\n", code, message); object_id = 0; interface = NULL; } display_protocol_error(display, code, object_id, interface); } static void display_handle_delete_id(void *data, struct wl_display *display, uint32_t id) { struct wl_proxy *proxy; pthread_mutex_lock(&display->mutex); proxy = wl_map_lookup(&display->objects, id); if (wl_object_is_zombie(&display->objects, id)) { /* For zombie objects, the 'proxy' is actually the zombie * event-information structure, which we can free. */ free(proxy); wl_map_remove(&display->objects, id); } else if (proxy) { proxy->flags |= WL_PROXY_FLAG_ID_DELETED; } else { wl_log("error: received delete_id for unknown id (%u)\n", id); } pthread_mutex_unlock(&display->mutex); } static const struct wl_display_listener display_listener = { display_handle_error, display_handle_delete_id }; static int connect_to_socket(const char *name) { struct sockaddr_un addr; socklen_t size; const char *runtime_dir; int name_size, fd; bool path_is_absolute; if (name == NULL) name = getenv("WAYLAND_DISPLAY"); if (name == NULL) name = "wayland-0"; path_is_absolute = name[0] == '/'; runtime_dir = getenv("XDG_RUNTIME_DIR"); if (((!runtime_dir || runtime_dir[0] != '/') && !path_is_absolute)) { wl_log("error: XDG_RUNTIME_DIR is invalid or not set in the environment.\n"); /* to prevent programs reporting * "failed to create display: Success" */ errno = ENOENT; return -1; } fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0); if (fd < 0) return -1; memset(&addr, 0, sizeof addr); addr.sun_family = AF_LOCAL; if (!path_is_absolute) { name_size = snprintf(addr.sun_path, sizeof addr.sun_path, "%s/%s", runtime_dir, name) + 1; } else { /* absolute path */ name_size = snprintf(addr.sun_path, sizeof addr.sun_path, "%s", name) + 1; } assert(name_size > 0); if (name_size > (int)sizeof addr.sun_path) { if (!path_is_absolute) { wl_log("error: socket path \"%s/%s\" plus null terminator" " exceeds %i bytes\n", runtime_dir, name, (int) sizeof(addr.sun_path)); } else { wl_log("error: socket path \"%s\" plus null terminator" " exceeds %i bytes\n", name, (int) sizeof(addr.sun_path)); } close(fd); /* to prevent programs reporting * "failed to add socket: Success" */ errno = ENAMETOOLONG; return -1; }; size = offsetof (struct sockaddr_un, sun_path) + name_size; if (connect(fd, (struct sockaddr *) &addr, size) < 0) { close(fd); return -1; } return fd; } /** Connect to Wayland display on an already open fd * * \param fd The fd to use for the connection * \return A \ref wl_display object or \c NULL on failure * * The wl_display takes ownership of the fd and will close it when the * display is destroyed. The fd will also be closed in case of * failure. * * \memberof wl_display */ WL_EXPORT struct wl_display * wl_display_connect_to_fd(int fd) { struct wl_display *display; const char *debug; debug = getenv("WAYLAND_DEBUG"); if (debug && (strstr(debug, "client") || strstr(debug, "1"))) debug_client = 1; display = zalloc(sizeof *display); if (display == NULL) { close(fd); return NULL; } display->fd = fd; wl_map_init(&display->objects, WL_MAP_CLIENT_SIDE); wl_event_queue_init(&display->default_queue, display, "Default Queue"); wl_event_queue_init(&display->display_queue, display, "Display Queue"); pthread_mutex_init(&display->mutex, NULL); pthread_cond_init(&display->reader_cond, NULL); display->reader_count = 0; if (wl_map_insert_at(&display->objects, 0, 0, NULL) == -1) goto err_connection; display->proxy.object.id = wl_map_insert_new(&display->objects, 0, display); if (display->proxy.object.id == 0) goto err_connection; display->proxy.object.interface = &wl_display_interface; display->proxy.display = display; display->proxy.object.implementation = (void(**)(void)) &display_listener; display->proxy.user_data = display; display->proxy.queue = &display->default_queue; display->proxy.flags = 0; display->proxy.refcount = 1; /* We set this version to 0 for backwards compatibility. * * If a client is using old versions of protocol headers, * it will use unversioned API to create proxies. Those * proxies will inherit this 0. * * A client could be passing these proxies into library * code newer than the headers that checks proxy * versions. When the proxy version is reported as 0 * the library will know that it can't reliably determine * the proxy version, and should do whatever fallback is * required. * * This trick forces wl_display to always report 0, but * since it's a special object that we can't bind * specific versions of anyway, this should be fine. */ display->proxy.version = 0; display->connection = wl_connection_create(display->fd, 0); if (display->connection == NULL) goto err_connection; return display; err_connection: pthread_mutex_destroy(&display->mutex); pthread_cond_destroy(&display->reader_cond); wl_map_release(&display->objects); close(display->fd); free(display); return NULL; } /** Connect to a Wayland display * * \param name Name of the Wayland display to connect to * \return A \ref wl_display object or \c NULL on failure * * Connect to the Wayland display named \c name. If \c name is \c NULL, * its value will be replaced with the WAYLAND_DISPLAY environment * variable if it is set, otherwise display "wayland-0" will be used. * * If WAYLAND_SOCKET is set, it's interpreted as a file descriptor number * referring to an already opened socket. In this case, the socket is used * as-is and \c name is ignored. * * If \c name is a relative path, then the socket is opened relative to * the XDG_RUNTIME_DIR directory. * * If \c name is an absolute path, then that path is used as-is for * the location of the socket at which the Wayland server is listening; * no qualification inside XDG_RUNTIME_DIR is attempted. * * If \c name is \c NULL and the WAYLAND_DISPLAY environment variable * is set to an absolute pathname, then that pathname is used as-is * for the socket in the same manner as if \c name held an absolute * path. Support for absolute paths in \c name and WAYLAND_DISPLAY * is present since Wayland version 1.15. * * \memberof wl_display */ WL_EXPORT struct wl_display * wl_display_connect(const char *name) { char *connection, *end; int flags, fd; connection = getenv("WAYLAND_SOCKET"); if (connection) { int prev_errno = errno; errno = 0; fd = strtol(connection, &end, 10); if (errno != 0 || connection == end || *end != '\0') return NULL; errno = prev_errno; flags = fcntl(fd, F_GETFD); if (flags == -1 && errno == EBADF) return NULL; else if (flags != -1) fcntl(fd, F_SETFD, flags | FD_CLOEXEC); unsetenv("WAYLAND_SOCKET"); } else { fd = connect_to_socket(name); if (fd < 0) return NULL; } return wl_display_connect_to_fd(fd); } /** Close a connection to a Wayland display * * \param display The display context object * * Close the connection to \c display. The \ref wl_proxy and * \ref wl_event_queue objects need to be manually destroyed by the caller * before disconnecting. * * \memberof wl_display */ WL_EXPORT void wl_display_disconnect(struct wl_display *display) { wl_connection_destroy(display->connection); wl_map_for_each(&display->objects, free_zombies, NULL); wl_map_release(&display->objects); wl_event_queue_release(&display->default_queue); free(display->default_queue.name); wl_event_queue_release(&display->display_queue); free(display->display_queue.name); pthread_mutex_destroy(&display->mutex); pthread_cond_destroy(&display->reader_cond); close(display->fd); free(display); } /** Get a display context's file descriptor * * \param display The display context object * \return Display object file descriptor * * Return the file descriptor associated with a display so it can be * integrated into the client's main loop. * * \memberof wl_display */ WL_EXPORT int wl_display_get_fd(struct wl_display *display) { return display->fd; } static void sync_callback(void *data, struct wl_callback *callback, uint32_t serial) { int *done = data; *done = 1; wl_callback_destroy(callback); } static const struct wl_callback_listener sync_listener = { sync_callback }; /** Block until all pending request are processed by the server * * \param display The display context object * \param queue The queue on which to run the roundtrip * \return The number of dispatched events on success or -1 on failure * * This function blocks until the server has processed all currently issued * requests by sending a request to the display server and waiting for a * reply before returning. * * This function uses wl_display_dispatch_queue() internally. It is not allowed * to call this function while the thread is being prepared for reading events, * and doing so will cause a dead lock. * * \note This function may dispatch other events being received on the given * queue. * * \sa wl_display_roundtrip() * \memberof wl_display */ WL_EXPORT int wl_display_roundtrip_queue(struct wl_display *display, struct wl_event_queue *queue) { struct wl_display *display_wrapper; struct wl_callback *callback; int done, ret = 0; done = 0; display_wrapper = wl_proxy_create_wrapper(display); if (!display_wrapper) return -1; wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue); callback = wl_display_sync(display_wrapper); wl_proxy_wrapper_destroy(display_wrapper); if (callback == NULL) return -1; wl_callback_add_listener(callback, &sync_listener, &done); while (!done && ret >= 0) ret = wl_display_dispatch_queue(display, queue); if (ret == -1 && !done) wl_callback_destroy(callback); return ret; } /** Block until all pending request are processed by the server * * \param display The display context object * \return The number of dispatched events on success or -1 on failure * * This function blocks until the server has processed all currently issued * requests by sending a request to the display server and waiting for a reply * before returning. * * This function uses wl_display_dispatch_queue() internally. It is not allowed * to call this function while the thread is being prepared for reading events, * and doing so will cause a dead lock. * * \note This function may dispatch other events being received on the default * queue. * * \memberof wl_display */ WL_EXPORT int wl_display_roundtrip(struct wl_display *display) { return wl_display_roundtrip_queue(display, &display->default_queue); } static int create_proxies(struct wl_proxy *sender, struct wl_closure *closure) { struct wl_proxy *proxy; const char *signature; struct argument_details arg; uint32_t id; int i; int count; signature = closure->message->signature; count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); if (arg.type != WL_ARG_NEW_ID) continue; id = closure->args[i].n; if (id == 0) { closure->args[i].o = NULL; continue; } proxy = wl_proxy_create_for_id(sender, id, closure->message->types[i]); if (proxy == NULL) return -1; closure->args[i].o = (struct wl_object *)proxy; } return 0; } static void increase_closure_args_refcount(struct wl_closure *closure) { const char *signature; struct argument_details arg; int i, count; struct wl_proxy *proxy; signature = closure->message->signature; count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { case WL_ARG_NEW_ID: case WL_ARG_OBJECT: proxy = (struct wl_proxy *) closure->args[i].o; if (proxy) proxy->refcount++; break; default: break; } } closure->proxy->refcount++; } static int queue_event(struct wl_display *display, int len) { uint32_t p[2], id; int opcode, size; struct wl_proxy *proxy; struct wl_closure *closure; const struct wl_message *message; struct wl_event_queue *queue; struct timespec tp; unsigned int time; int num_zombie_fds; wl_connection_copy(display->connection, p, sizeof p); id = p[0]; opcode = p[1] & 0xffff; size = p[1] >> 16; if (len < size) return 0; /* If our proxy is gone or a zombie, just eat the event (and any FDs, * if applicable). */ proxy = wl_map_lookup(&display->objects, id); if (!proxy || wl_object_is_zombie(&display->objects, id)) { struct wl_zombie *zombie = wl_map_lookup(&display->objects, id); num_zombie_fds = (zombie && opcode < zombie->event_count) ? zombie->fd_count[opcode] : 0; if (debug_client) { clock_gettime(CLOCK_REALTIME, &tp); time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); fprintf(stderr, "[%7u.%03u] discarded [%s]#%d.[event %d]" "(%d fd, %d byte)\n", time / 1000, time % 1000, zombie ? "zombie" : "unknown", id, opcode, num_zombie_fds, size); } if (num_zombie_fds > 0) wl_connection_close_fds_in(display->connection, num_zombie_fds); wl_connection_consume(display->connection, size); return size; } if (opcode >= proxy->object.interface->event_count) { wl_log("interface '%s' has no event %u\n", proxy->object.interface->name, opcode); return -1; } message = &proxy->object.interface->events[opcode]; closure = wl_connection_demarshal(display->connection, size, &display->objects, message); if (!closure) return -1; if (create_proxies(proxy, closure) < 0) { wl_closure_destroy(closure); return -1; } if (wl_closure_lookup_objects(closure, &display->objects) != 0) { wl_closure_destroy(closure); return -1; } closure->proxy = proxy; increase_closure_args_refcount(closure); if (proxy == &display->proxy) queue = &display->display_queue; else queue = proxy->queue; if (!queue) wl_abort("Tried to add event to destroyed queue\n"); wl_list_insert(queue->event_list.prev, &closure->link); return size; } static uint32_t id_from_object(union wl_argument *arg) { struct wl_proxy *proxy; if (arg->o) { proxy = (struct wl_proxy *)arg->o; return proxy->object.id; } return 0; } static void dispatch_event(struct wl_display *display, struct wl_event_queue *queue) { struct wl_closure *closure; struct wl_proxy *proxy; int opcode; bool proxy_destroyed; closure = wl_container_of(queue->event_list.next, closure, link); wl_list_remove(&closure->link); opcode = closure->opcode; /* Verify that the receiving object is still valid by checking if has * been destroyed by the application. */ validate_closure_objects(closure); proxy = closure->proxy; proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED); if (debug_client) { bool discarded = proxy_destroyed || !(proxy->dispatcher || proxy->object.implementation); wl_closure_print(closure, &proxy->object, false, discarded, id_from_object, queue->name); } if (proxy_destroyed) { destroy_queued_closure(closure); return; } pthread_mutex_unlock(&display->mutex); if (proxy->dispatcher) { wl_closure_dispatch(closure, proxy->dispatcher, &proxy->object, opcode); } else if (proxy->object.implementation) { wl_closure_invoke(closure, WL_CLOSURE_INVOKE_CLIENT, &proxy->object, opcode, proxy->user_data); } pthread_mutex_lock(&display->mutex); destroy_queued_closure(closure); } static int read_events(struct wl_display *display) { int total, rem, size; uint32_t serial; display->reader_count--; if (display->reader_count == 0) { total = wl_connection_read(display->connection); if (total == -1) { if (errno == EAGAIN) { /* we must wake up threads whenever * the reader_count dropped to 0 */ display_wakeup_threads(display); return 0; } display_fatal_error(display, errno); return -1; } else if (total == 0) { /* The compositor has closed the socket. This * should be considered an error so we'll fake * an errno */ errno = EPIPE; display_fatal_error(display, errno); return -1; } for (rem = total; rem >= 8; rem -= size) { size = queue_event(display, rem); if (size == -1) { display_fatal_error(display, errno); return -1; } else if (size == 0) { break; } } display_wakeup_threads(display); } else { serial = display->read_serial; while (display->read_serial == serial) pthread_cond_wait(&display->reader_cond, &display->mutex); if (display->last_error) { errno = display->last_error; return -1; } } return 0; } static void cancel_read(struct wl_display *display) { display->reader_count--; if (display->reader_count == 0) display_wakeup_threads(display); } /** Read events from display file descriptor * * \param display The display context object * \return 0 on success or -1 on error. In case of error errno will * be set accordingly * * Calling this function will result in data available on the display file * descriptor being read and read events will be queued on their corresponding * event queues. * * Before calling this function, depending on what thread it is to be called * from, wl_display_prepare_read_queue() or wl_display_prepare_read() needs to * be called. See wl_display_prepare_read_queue() for more details. * * When being called at a point where other threads have been prepared to read * (using wl_display_prepare_read_queue() or wl_display_prepare_read()) this * function will sleep until all other prepared threads have either been * cancelled (using wl_display_cancel_read()) or them self entered this * function. The last thread that calls this function will then read and queue * events on their corresponding event queues, and finally wake up all other * wl_display_read_events() calls causing them to return. * * If a thread cancels a read preparation when all other threads that have * prepared to read has either called wl_display_cancel_read() or * wl_display_read_events(), all reader threads will return without having read * any data. * * To dispatch events that may have been queued, call * wl_display_dispatch_pending() or wl_display_dispatch_queue_pending(). * * \sa wl_display_prepare_read(), wl_display_cancel_read(), * wl_display_dispatch_pending(), wl_display_dispatch() * * \memberof wl_display */ WL_EXPORT int wl_display_read_events(struct wl_display *display) { int ret; pthread_mutex_lock(&display->mutex); if (display->last_error) { cancel_read(display); pthread_mutex_unlock(&display->mutex); errno = display->last_error; return -1; } ret = read_events(display); pthread_mutex_unlock(&display->mutex); return ret; } static int dispatch_queue(struct wl_display *display, struct wl_event_queue *queue) { int count; if (display->last_error) goto err; count = 0; while (!wl_list_empty(&display->display_queue.event_list)) { dispatch_event(display, &display->display_queue); if (display->last_error) goto err; count++; } while (!wl_list_empty(&queue->event_list)) { dispatch_event(display, queue); if (display->last_error) goto err; count++; } return count; err: errno = display->last_error; return -1; } /** Prepare to read events from the display's file descriptor to a queue * * \param display The display context object * \param queue The event queue to use * \return 0 on success or -1 if event queue was not empty * * This function (or wl_display_prepare_read()) must be called before reading * from the file descriptor using wl_display_read_events(). Calling * wl_display_prepare_read_queue() announces the calling thread's intention to * read and ensures that until the thread is ready to read and calls * wl_display_read_events(), no other thread will read from the file descriptor. * This only succeeds if the event queue is empty, and if not -1 is returned and * errno set to EAGAIN. * * If a thread successfully calls wl_display_prepare_read_queue(), it must * either call wl_display_read_events() when it's ready or cancel the read * intention by calling wl_display_cancel_read(). * * Use this function before polling on the display fd or integrate the fd into a * toolkit event loop in a race-free way. A correct usage would be (with most * error checking left out): * * \code * while (wl_display_prepare_read_queue(display, queue) != 0) * wl_display_dispatch_queue_pending(display, queue); * wl_display_flush(display); * * ret = poll(fds, nfds, -1); * if (has_error(ret)) * wl_display_cancel_read(display); * else * wl_display_read_events(display); * * wl_display_dispatch_queue_pending(display, queue); * \endcode * * Here we call wl_display_prepare_read_queue(), which ensures that between * returning from that call and eventually calling wl_display_read_events(), no * other thread will read from the fd and queue events in our queue. If the call * to wl_display_prepare_read_queue() fails, we dispatch the pending events and * try again until we're successful. * * The wl_display_prepare_read_queue() function doesn't acquire exclusive access * to the display's fd. It only registers that the thread calling this function * has intention to read from fd. When all registered readers call * wl_display_read_events(), only one (at random) eventually reads and queues * the events and the others are sleeping meanwhile. This way we avoid races and * still can read from more threads. * * \sa wl_display_cancel_read(), wl_display_read_events(), * wl_display_prepare_read() * * \memberof wl_display */ WL_EXPORT int wl_display_prepare_read_queue(struct wl_display *display, struct wl_event_queue *queue) { int ret; pthread_mutex_lock(&display->mutex); if (!wl_list_empty(&queue->event_list)) { errno = EAGAIN; ret = -1; } else { display->reader_count++; ret = 0; } pthread_mutex_unlock(&display->mutex); return ret; } /** Prepare to read events from the display's file descriptor * * \param display The display context object * \return 0 on success or -1 if event queue was not empty * * This function does the same thing as wl_display_prepare_read_queue() * with the default queue passed as the queue. * * \sa wl_display_prepare_read_queue * \memberof wl_display */ WL_EXPORT int wl_display_prepare_read(struct wl_display *display) { return wl_display_prepare_read_queue(display, &display->default_queue); } /** Cancel read intention on display's fd * * \param display The display context object * * After a thread successfully called wl_display_prepare_read() it must * either call wl_display_read_events() or wl_display_cancel_read(). * If the threads do not follow this rule it will lead to deadlock. * * \sa wl_display_prepare_read(), wl_display_read_events() * * \memberof wl_display */ WL_EXPORT void wl_display_cancel_read(struct wl_display *display) { pthread_mutex_lock(&display->mutex); cancel_read(display); pthread_mutex_unlock(&display->mutex); } static int wl_display_poll(struct wl_display *display, short int events) { int ret; struct pollfd pfd[1]; pfd[0].fd = display->fd; pfd[0].events = events; do { ret = poll(pfd, 1, -1); } while (ret == -1 && errno == EINTR); return ret; } /** Dispatch events in an event queue * * \param display The display context object * \param queue The event queue to dispatch * \return The number of dispatched events on success or -1 on failure * * Dispatch events on the given event queue. * * If the given event queue is empty, this function blocks until there are * events to be read from the display fd. Events are read and queued on * the appropriate event queues. Finally, events on given event queue are * dispatched. On failure -1 is returned and errno set appropriately. * * In a multi threaded environment, do not manually wait using poll() (or * equivalent) before calling this function, as doing so might cause a dead * lock. If external reliance on poll() (or equivalent) is required, see * wl_display_prepare_read_queue() of how to do so. * * This function is thread safe as long as it dispatches the right queue on the * right thread. It is also compatible with the multi thread event reading * preparation API (see wl_display_prepare_read_queue()), and uses the * equivalent functionality internally. It is not allowed to call this function * while the thread is being prepared for reading events, and doing so will * cause a dead lock. * * It can be used as a helper function to ease the procedure of reading and * dispatching events. * * \note Since Wayland 1.5 the display has an extra queue * for its own events (i. e. delete_id). This queue is dispatched always, * no matter what queue we passed as an argument to this function. * That means that this function can return non-0 value even when it * haven't dispatched any event for the given queue. * * \sa wl_display_dispatch(), wl_display_dispatch_pending(), * wl_display_dispatch_queue_pending(), wl_display_prepare_read_queue() * * \memberof wl_display */ WL_EXPORT int wl_display_dispatch_queue(struct wl_display *display, struct wl_event_queue *queue) { int ret; if (wl_display_prepare_read_queue(display, queue) == -1) return wl_display_dispatch_queue_pending(display, queue); while (true) { ret = wl_display_flush(display); if (ret != -1 || errno != EAGAIN) break; if (wl_display_poll(display, POLLOUT) == -1) { wl_display_cancel_read(display); return -1; } } /* Don't stop if flushing hits an EPIPE; continue so we can read any * protocol error that may have triggered it. */ if (ret < 0 && errno != EPIPE) { wl_display_cancel_read(display); return -1; } if (wl_display_poll(display, POLLIN) == -1) { wl_display_cancel_read(display); return -1; } if (wl_display_read_events(display) == -1) return -1; return wl_display_dispatch_queue_pending(display, queue); } /** Dispatch pending events in an event queue * * \param display The display context object * \param queue The event queue to dispatch * \return The number of dispatched events on success or -1 on failure * * Dispatch all incoming events for objects assigned to the given * event queue. On failure -1 is returned and errno set appropriately. * If there are no events queued, this function returns immediately. * * \memberof wl_display * \since 1.0.2 */ WL_EXPORT int wl_display_dispatch_queue_pending(struct wl_display *display, struct wl_event_queue *queue) { int ret; pthread_mutex_lock(&display->mutex); ret = dispatch_queue(display, queue); pthread_mutex_unlock(&display->mutex); return ret; } /** Process incoming events * * \param display The display context object * \return The number of dispatched events on success or -1 on failure * * Dispatch events on the default event queue. * * If the default event queue is empty, this function blocks until there are * events to be read from the display fd. Events are read and queued on * the appropriate event queues. Finally, events on the default event queue * are dispatched. On failure -1 is returned and errno set appropriately. * * In a multi threaded environment, do not manually wait using poll() (or * equivalent) before calling this function, as doing so might cause a dead * lock. If external reliance on poll() (or equivalent) is required, see * wl_display_prepare_read_queue() of how to do so. * * This function is thread safe as long as it dispatches the right queue on the * right thread. It is also compatible with the multi thread event reading * preparation API (see wl_display_prepare_read_queue()), and uses the * equivalent functionality internally. It is not allowed to call this function * while the thread is being prepared for reading events, and doing so will * cause a dead lock. * * \note It is not possible to check if there are events on the queue * or not. For dispatching default queue events without blocking, see \ref * wl_display_dispatch_pending(). * * \sa wl_display_dispatch_pending(), wl_display_dispatch_queue(), * wl_display_read_events() * * \memberof wl_display */ WL_EXPORT int wl_display_dispatch(struct wl_display *display) { return wl_display_dispatch_queue(display, &display->default_queue); } /** Dispatch default queue events without reading from the display fd * * \param display The display context object * \return The number of dispatched events or -1 on failure * * This function dispatches events on the main event queue. It does not * attempt to read the display fd and simply returns zero if the main * queue is empty, i.e., it doesn't block. * * \sa wl_display_dispatch(), wl_display_dispatch_queue(), * wl_display_flush() * * \memberof wl_display */ WL_EXPORT int wl_display_dispatch_pending(struct wl_display *display) { return wl_display_dispatch_queue_pending(display, &display->default_queue); } /** Retrieve the last error that occurred on a display * * \param display The display context object * \return The last error that occurred on \c display or 0 if no error occurred * * Return the last error that occurred on the display. This may be an error sent * by the server or caused by the local client. * * \note Errors are \b fatal. If this function returns non-zero the display * can no longer be used. * * \memberof wl_display */ WL_EXPORT int wl_display_get_error(struct wl_display *display) { int ret; pthread_mutex_lock(&display->mutex); ret = display->last_error; pthread_mutex_unlock(&display->mutex); return ret; } /** Retrieves the information about a protocol error: * * \param display The Wayland display * \param interface if not NULL, stores the interface where the error occurred, * or NULL, if unknown. * \param id if not NULL, stores the object id that generated * the error, or 0, if the object id is unknown. There's no * guarantee the object is still valid; the client must know * if it deleted the object. * \return The error code as defined in the interface specification. * * \code * int err = wl_display_get_error(display); * * if (err == EPROTO) { * code = wl_display_get_protocol_error(display, &interface, &id); * handle_error(code, interface, id); * } * * ... * \endcode * \memberof wl_display */ WL_EXPORT uint32_t wl_display_get_protocol_error(struct wl_display *display, const struct wl_interface **interface, uint32_t *id) { uint32_t ret; pthread_mutex_lock(&display->mutex); ret = display->protocol_error.code; if (interface) *interface = display->protocol_error.interface; if (id) *id = display->protocol_error.id; pthread_mutex_unlock(&display->mutex); return ret; } /** Send all buffered requests on the display to the server * * \param display The display context object * \return The number of bytes sent on success or -1 on failure * * Send all buffered data on the client side to the server. Clients should * always call this function before blocking on input from the display fd. * On success, the number of bytes sent to the server is returned. On * failure, this function returns -1 and errno is set appropriately. * * wl_display_flush() never blocks. It will write as much data as * possible, but if all data could not be written, errno will be set * to EAGAIN and -1 returned. In that case, use poll on the display * file descriptor to wait for it to become writable again. * * \memberof wl_display */ WL_EXPORT int wl_display_flush(struct wl_display *display) { int ret; pthread_mutex_lock(&display->mutex); if (display->last_error) { errno = display->last_error; ret = -1; } else { /* We don't make EPIPE a fatal error here, so that we may try to * read events after the failed flush. When the compositor sends * an error it will close the socket, and if we make EPIPE fatal * here we don't get a chance to process the error. */ ret = wl_connection_flush(display->connection); if (ret < 0 && errno != EAGAIN && errno != EPIPE) display_fatal_error(display, errno); } pthread_mutex_unlock(&display->mutex); return ret; } /** Adjust the maximum size of the client connection buffers * * \param display The display context object * \param max_buffer_size The maximum size of the connection buffers * * Client buffers are unbounded by default. This function sets a limit to the * size of the connection buffers. * * A value of 0 for \a max_buffer_size requests the buffers to be unbounded. * * The actual size of the connection buffers is a power of two, the requested * \a max_buffer_size is therefore rounded up to the nearest power of two value. * * Lowering the maximum size may not take effect immediately if the current * content of the buffer does not fit within the new size limit. * * \memberof wl_display * \since 1.22.90 */ WL_EXPORT void wl_display_set_max_buffer_size(struct wl_display *display, size_t max_buffer_size) { wl_connection_set_max_buffer_size(display->connection, max_buffer_size); } /** Set the user data associated with a proxy * * \param proxy The proxy object * \param user_data The data to be associated with proxy * * Set the user data associated with \c proxy. When events for this * proxy are received, \c user_data will be supplied to its listener. * * \memberof wl_proxy */ WL_EXPORT void wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data) { proxy->user_data = user_data; } /** Get the user data associated with a proxy * * \param proxy The proxy object * \return The user data associated with proxy * * \memberof wl_proxy */ WL_EXPORT void * wl_proxy_get_user_data(struct wl_proxy *proxy) { return proxy->user_data; } /** Get the protocol object version of a proxy object * * \param proxy The proxy object * \return The protocol object version of the proxy or 0 * * Gets the protocol object version of a proxy object, or 0 * if the proxy was created with unversioned API. * * A returned value of 0 means that no version information is * available, so the caller must make safe assumptions about * the object's real version. * * wl_display's version will always return 0. * * \memberof wl_proxy */ WL_EXPORT uint32_t wl_proxy_get_version(struct wl_proxy *proxy) { return proxy->version; } /** Get the id of a proxy object * * \param proxy The proxy object * \return The id the object associated with the proxy * * \memberof wl_proxy */ WL_EXPORT uint32_t wl_proxy_get_id(struct wl_proxy *proxy) { return proxy->object.id; } /** Set the tag of a proxy object * * A toolkit or application can set a unique tag on a proxy in order to * identify whether an object is managed by itself or some external part. * * To create a tag, the recommended way is to define a statically allocated * constant char array containing some descriptive string. The tag will be the * pointer to the non-const pointer to the beginning of the array. * * For example, to define and set a tag on a surface managed by a certain * subsystem: * * static const char *my_tag = "my tag"; * * wl_proxy_set_tag((struct wl_proxy *) surface, &my_tag); * * Then, in a callback with wl_surface as an argument, in order to check * whether it's a surface managed by the same subsystem. * * const char * const *tag; * * tag = wl_proxy_get_tag((struct wl_proxy *) surface); * if (tag != &my_tag) * return; * * ... * * For debugging purposes, a tag should be suitable to be included in a debug * log entry, e.g. * * const char * const *tag; * * tag = wl_proxy_get_tag((struct wl_proxy *) surface); * printf("Got a surface with the tag %p (%s)\n", * tag, (tag && *tag) ? *tag : ""); * * \param proxy The proxy object * \param tag The tag * * \memberof wl_proxy * \since 1.17.90 */ WL_EXPORT void wl_proxy_set_tag(struct wl_proxy *proxy, const char * const *tag) { proxy->tag = tag; } /** Get the tag of a proxy object * * See wl_proxy_set_tag for details. * * \param proxy The proxy object * * \memberof wl_proxy * \since 1.17.90 */ WL_EXPORT const char * const * wl_proxy_get_tag(struct wl_proxy *proxy) { return proxy->tag; } /** Get the interface name (class) of a proxy object * * \param proxy The proxy object * \return The interface name of the object associated with the proxy * * \memberof wl_proxy */ WL_EXPORT const char * wl_proxy_get_class(struct wl_proxy *proxy) { return proxy->object.interface->name; } /** Get the display of a proxy object * * \param proxy The proxy object * \return The wl_display the proxy is associated with * * \memberof wl_proxy * \since 1.23 */ WL_EXPORT struct wl_display * wl_proxy_get_display(struct wl_proxy *proxy) { return proxy->display; } /** Assign a proxy to an event queue * * \param proxy The proxy object * \param queue The event queue that will handle this proxy or NULL * * Assign proxy to event queue. Events coming from \c proxy will be * queued in \c queue from now. If queue is NULL, then the display's * default queue is set to the proxy. * * In order to guarantee proper handing of all events which were queued * before the queue change takes effect, it is required to dispatch the * proxy's old event queue after setting a new event queue. * * This is particularly important for multi-threaded setups, where it is * possible for events to be queued to the proxy's old queue from a * different thread during the invocation of this function. * * To ensure that all events for a newly created proxy are dispatched * on a particular queue, it is necessary to use a proxy wrapper if * events are read and dispatched on more than one thread. See * wl_proxy_create_wrapper() for more details. * * \note By default, the queue set in proxy is the one inherited from parent. * * \sa wl_display_dispatch_queue() * * \memberof wl_proxy */ WL_EXPORT void wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue) { pthread_mutex_lock(&proxy->display->mutex); wl_list_remove(&proxy->queue_link); if (queue) { assert(proxy->display == queue->display); proxy->queue = queue; } else { proxy->queue = &proxy->display->default_queue; } wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link); pthread_mutex_unlock(&proxy->display->mutex); } /** Get a proxy's event queue * * \param proxy The proxy to query * * Return the event queue */ WL_EXPORT struct wl_event_queue * wl_proxy_get_queue(const struct wl_proxy *proxy) { return proxy->queue; } /** Get the name of an event queue * * \param queue The queue to query * * Return the human readable name for the event queue * * This may be NULL if no name has been set. * * \memberof wl_proxy */ WL_EXPORT const char * wl_event_queue_get_name(const struct wl_event_queue *queue) { return queue->name; } /** Create a proxy wrapper for making queue assignments thread-safe * * \param proxy The proxy object to be wrapped * \return A proxy wrapper for the given proxy or NULL on failure * * A proxy wrapper is type of 'struct wl_proxy' instance that can be used when * sending requests instead of using the original proxy. A proxy wrapper does * not have an implementation or dispatcher, and events received on the * object is still emitted on the original proxy. Trying to set an * implementation or dispatcher will have no effect but result in a warning * being logged. * * Setting the proxy queue of the proxy wrapper will make new objects created * using the proxy wrapper use the set proxy queue. * Even though there is no implementation nor dispatcher, the proxy queue can * be changed. This will affect the default queue of new objects created by * requests sent via the proxy wrapper. * * A proxy wrapper can only be destroyed using wl_proxy_wrapper_destroy(). * * A proxy wrapper must be destroyed before the proxy it was created from. * * If a user reads and dispatches events on more than one thread, it is * necessary to use a proxy wrapper when sending requests on objects when the * intention is that a newly created proxy is to use a proxy queue different * from the proxy the request was sent on, as creating the new proxy and then * setting the queue is not thread safe. * * For example, a module that runs using its own proxy queue that needs to * do display roundtrip must wrap the wl_display proxy object before sending * the wl_display.sync request. For example: * * \code * * struct wl_event_queue *queue = ...; * struct wl_display *wrapped_display; * struct wl_callback *callback; * * wrapped_display = wl_proxy_create_wrapper(display); * wl_proxy_set_queue((struct wl_proxy *) wrapped_display, queue); * callback = wl_display_sync(wrapped_display); * wl_proxy_wrapper_destroy(wrapped_display); * wl_callback_add_listener(callback, ...); * * \endcode * * \memberof wl_proxy */ WL_EXPORT void * wl_proxy_create_wrapper(void *proxy) { struct wl_proxy *wrapped_proxy = proxy; struct wl_proxy *wrapper; wrapper = zalloc(sizeof *wrapper); if (!wrapper) return NULL; pthread_mutex_lock(&wrapped_proxy->display->mutex); wrapper->object.interface = wrapped_proxy->object.interface; wrapper->object.id = wrapped_proxy->object.id; wrapper->version = wrapped_proxy->version; wrapper->display = wrapped_proxy->display; wrapper->queue = wrapped_proxy->queue; wrapper->flags = WL_PROXY_FLAG_WRAPPER; wrapper->refcount = 1; wl_list_insert(&wrapper->queue->proxy_list, &wrapper->queue_link); pthread_mutex_unlock(&wrapped_proxy->display->mutex); return wrapper; } /** Destroy a proxy wrapper * \param proxy_wrapper The proxy wrapper to be destroyed * * \memberof wl_proxy */ WL_EXPORT void wl_proxy_wrapper_destroy(void *proxy_wrapper) { struct wl_proxy *wrapper = proxy_wrapper; if (!(wrapper->flags & WL_PROXY_FLAG_WRAPPER)) wl_abort("Tried to destroy non-wrapper proxy with " "wl_proxy_wrapper_destroy\n"); assert(wrapper->refcount == 1); pthread_mutex_lock(&wrapper->display->mutex); wl_list_remove(&wrapper->queue_link); pthread_mutex_unlock(&wrapper->display->mutex); free(wrapper); } WL_EXPORT void wl_log_set_handler_client(wl_log_func_t handler) { wl_log_handler = handler; } wayland-1.23.1/src/wayland-client.h000066400000000000000000000030451466237767300171370ustar00rootroot00000000000000/* * Copyright © 2008 Kristian Høgsberg * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** \file * * \brief Include the client API and protocol C API. * * \warning Use of this header file is discouraged. Prefer including * wayland-client-core.h instead, which does not include the * client protocol header and as such only defines the library * API. */ #ifndef WAYLAND_CLIENT_H #define WAYLAND_CLIENT_H #include "wayland-client-core.h" #include "wayland-client-protocol.h" #endif wayland-1.23.1/src/wayland-os.c000066400000000000000000000137511466237767300163020ustar00rootroot00000000000000/* * Copyright © 2012 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. */ #define _GNU_SOURCE #include "../config.h" #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_UCRED_H #include #endif #include "wayland-os.h" /* used by tests */ int (*wl_fcntl)(int fildes, int cmd, ...) = fcntl; int (*wl_socket)(int domain, int type, int protocol) = socket; ssize_t (*wl_recvmsg)(int socket, struct msghdr *message, int flags) = recvmsg; int (*wl_epoll_create1)(int flags) = epoll_create1; static int set_cloexec_or_close(int fd) { long flags; if (fd == -1) return -1; flags = wl_fcntl(fd, F_GETFD); if (flags == -1) goto err; if (wl_fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) goto err; return fd; err: close(fd); return -1; } int wl_os_socket_cloexec(int domain, int type, int protocol) { int fd; fd = wl_socket(domain, type | SOCK_CLOEXEC, protocol); if (fd >= 0) return fd; if (errno != EINVAL) return -1; fd = wl_socket(domain, type, protocol); return set_cloexec_or_close(fd); } #if defined(__FreeBSD__) int wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid) { socklen_t len; struct xucred ucred; len = sizeof(ucred); if (getsockopt(sockfd, SOL_LOCAL, LOCAL_PEERCRED, &ucred, &len) < 0 || ucred.cr_version != XUCRED_VERSION) return -1; *uid = ucred.cr_uid; *gid = ucred.cr_gid; #if HAVE_XUCRED_CR_PID /* Since https://cgit.freebsd.org/src/commit/?id=c5afec6e895a */ *pid = ucred.cr_pid; #else *pid = 0; #endif return 0; } #elif defined(SO_PEERCRED) int wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid) { socklen_t len; #if defined(__OpenBSD__) struct sockpeercred ucred; #else struct ucred ucred; #endif len = sizeof(ucred); if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) return -1; *uid = ucred.uid; *gid = ucred.gid; *pid = ucred.pid; return 0; } #else #error "Don't know how to read ucred on this platform" #endif int wl_os_dupfd_cloexec(int fd, int minfd) { int newfd; newfd = wl_fcntl(fd, F_DUPFD_CLOEXEC, minfd); if (newfd >= 0) return newfd; if (errno != EINVAL) return -1; newfd = wl_fcntl(fd, F_DUPFD, minfd); return set_cloexec_or_close(newfd); } static ssize_t recvmsg_cloexec_fallback(int sockfd, struct msghdr *msg, int flags) { ssize_t len; struct cmsghdr *cmsg; unsigned char *data; int *fd; int *end; len = wl_recvmsg(sockfd, msg, flags); if (len == -1) return -1; if (!msg->msg_control || msg->msg_controllen == 0) return len; cmsg = CMSG_FIRSTHDR(msg); for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) continue; data = CMSG_DATA(cmsg); end = (int *)(data + cmsg->cmsg_len - CMSG_LEN(0)); for (fd = (int *)data; fd < end; ++fd) *fd = set_cloexec_or_close(*fd); } return len; } ssize_t wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags) { #if HAVE_BROKEN_MSG_CMSG_CLOEXEC /* * FreeBSD had a broken implementation of MSG_CMSG_CLOEXEC between 2015 * and 2021, so we have to use the non-MSG_CMSG_CLOEXEC fallback * directly when compiling against a version that does not include the * fix (https://cgit.freebsd.org/src/commit/?id=6ceacebdf52211). */ #pragma message("Using fallback directly since MSG_CMSG_CLOEXEC is broken.") #else ssize_t len; len = wl_recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC); if (len >= 0) return len; if (errno != EINVAL) return -1; #endif return recvmsg_cloexec_fallback(sockfd, msg, flags); } int wl_os_epoll_create_cloexec(void) { int fd; #ifdef EPOLL_CLOEXEC fd = wl_epoll_create1(EPOLL_CLOEXEC); if (fd >= 0) return fd; if (errno != EINVAL) return -1; #endif fd = epoll_create(1); return set_cloexec_or_close(fd); } int wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { int fd; #ifdef HAVE_ACCEPT4 fd = accept4(sockfd, addr, addrlen, SOCK_CLOEXEC); if (fd >= 0) return fd; if (errno != ENOSYS) return -1; #endif fd = accept(sockfd, addr, addrlen); return set_cloexec_or_close(fd); } /* * Fallback function for operating systems that don't implement * mremap(MREMAP_MAYMOVE). */ void * wl_os_mremap_maymove(int fd, void *old_data, ssize_t *old_size, ssize_t new_size, int prot, int flags) { void *result; /* Make sure any pending write is flushed. */ if (msync(old_data, *old_size, MS_SYNC) != 0) return MAP_FAILED; /* We could try mapping a new block immediately after the current one * with MAP_FIXED, however that is not guaranteed to work and breaks * on CHERI-enabled architectures since the data pointer will still * have the bounds of the previous allocation. */ result = mmap(NULL, new_size, prot, flags, fd, 0); if (result == MAP_FAILED) return MAP_FAILED; if (munmap(old_data, *old_size) == 0) *old_size = 0; return result; } wayland-1.23.1/src/wayland-os.h000066400000000000000000000040461466237767300163040ustar00rootroot00000000000000/* * Copyright © 2012 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. */ #ifndef WAYLAND_OS_H #define WAYLAND_OS_H #include #include int wl_os_socket_cloexec(int domain, int type, int protocol); int wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid); int wl_os_dupfd_cloexec(int fd, int minfd); ssize_t wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags); int wl_os_epoll_create_cloexec(void); int wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen); void * wl_os_mremap_maymove(int fd, void *old_data, ssize_t *old_size, ssize_t new_size, int prot, int flags); /* * The following are for wayland-os.c and the unit tests. * Do not use them elsewhere. */ #ifdef __linux__ #ifndef SOCK_CLOEXEC #define SOCK_CLOEXEC 02000000 #endif #ifndef F_DUPFD_CLOEXEC #define F_DUPFD_CLOEXEC 1030 #endif #ifndef MSG_CMSG_CLOEXEC #define MSG_CMSG_CLOEXEC 0x40000000 #endif #endif /* __linux__ */ #endif wayland-1.23.1/src/wayland-private.h000066400000000000000000000151721466237767300173370ustar00rootroot00000000000000/* * Copyright © 2008-2011 Kristian Høgsberg * Copyright © 2011 Intel Corporation * Copyright © 2013 Jason Ekstrand * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef WAYLAND_PRIVATE_H #define WAYLAND_PRIVATE_H #include #include #include #include #define WL_HIDE_DEPRECATED 1 #include "wayland-util.h" /* Invalid memory address */ #define WL_ARRAY_POISON_PTR (void *) 4 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) #define WL_MAP_SERVER_SIDE 0 #define WL_MAP_CLIENT_SIDE 1 #define WL_SERVER_ID_START 0xff000000 #define WL_MAP_MAX_OBJECTS 0x00f00000 #define WL_CLOSURE_MAX_ARGS 20 #define WL_BUFFER_DEFAULT_SIZE_POT 12 #define WL_BUFFER_DEFAULT_MAX_SIZE (1 << WL_BUFFER_DEFAULT_SIZE_POT) /** * Argument types used in signatures. */ enum wl_arg_type { WL_ARG_INT = 'i', WL_ARG_UINT = 'u', WL_ARG_FIXED = 'f', WL_ARG_STRING = 's', WL_ARG_OBJECT = 'o', WL_ARG_NEW_ID = 'n', WL_ARG_ARRAY = 'a', WL_ARG_FD = 'h', }; struct wl_object { const struct wl_interface *interface; const void *implementation; uint32_t id; }; int wl_interface_equal(const struct wl_interface *iface1, const struct wl_interface *iface2); /* Flags for wl_map_insert_new and wl_map_insert_at. Flags can be queried with * wl_map_lookup_flags. The current implementation has room for 1 bit worth of * flags. If more flags are ever added, the implementation of wl_map will have * to change to allow for new flags */ enum wl_map_entry_flags { WL_MAP_ENTRY_LEGACY = (1 << 0), /* Server side only */ WL_MAP_ENTRY_ZOMBIE = (1 << 0) /* Client side only */ }; struct wl_map { struct wl_array client_entries; struct wl_array server_entries; uint32_t side; uint32_t free_list; }; typedef enum wl_iterator_result (*wl_iterator_func_t)(void *element, void *data, uint32_t flags); void wl_map_init(struct wl_map *map, uint32_t side); void wl_map_release(struct wl_map *map); uint32_t wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data); int wl_map_insert_at(struct wl_map *map, uint32_t flags, uint32_t i, void *data); int wl_map_reserve_new(struct wl_map *map, uint32_t i); void wl_map_remove(struct wl_map *map, uint32_t i); void * wl_map_lookup(struct wl_map *map, uint32_t i); uint32_t wl_map_lookup_flags(struct wl_map *map, uint32_t i); void wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data); struct wl_connection * wl_connection_create(int fd, size_t max_buffer_size); int wl_connection_destroy(struct wl_connection *connection); void wl_connection_copy(struct wl_connection *connection, void *data, size_t size); void wl_connection_consume(struct wl_connection *connection, size_t size); int wl_connection_flush(struct wl_connection *connection); uint32_t wl_connection_pending_input(struct wl_connection *connection); int wl_connection_read(struct wl_connection *connection); int wl_connection_write(struct wl_connection *connection, const void *data, size_t count); int wl_connection_queue(struct wl_connection *connection, const void *data, size_t count); int wl_connection_get_fd(struct wl_connection *connection); struct wl_closure { int count; const struct wl_message *message; uint32_t opcode; uint32_t sender_id; union wl_argument args[WL_CLOSURE_MAX_ARGS]; struct wl_list link; struct wl_proxy *proxy; struct wl_array extra[0]; }; struct argument_details { enum wl_arg_type type; int nullable; }; const char * get_next_argument(const char *signature, struct argument_details *details); int arg_count_for_signature(const char *signature); int wl_message_count_arrays(const struct wl_message *message); int wl_message_get_since(const struct wl_message *message); void wl_argument_from_va_list(const char *signature, union wl_argument *args, int count, va_list ap); struct wl_closure * wl_closure_marshal(struct wl_object *sender, uint32_t opcode, union wl_argument *args, const struct wl_message *message); struct wl_closure * wl_closure_vmarshal(struct wl_object *sender, uint32_t opcode, va_list ap, const struct wl_message *message); struct wl_closure * wl_connection_demarshal(struct wl_connection *connection, uint32_t size, struct wl_map *objects, const struct wl_message *message); bool wl_object_is_zombie(struct wl_map *map, uint32_t id); int wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects); enum wl_closure_invoke_flag { WL_CLOSURE_INVOKE_CLIENT = (1 << 0), WL_CLOSURE_INVOKE_SERVER = (1 << 1) }; void wl_closure_invoke(struct wl_closure *closure, uint32_t flags, struct wl_object *target, uint32_t opcode, void *data); void wl_closure_dispatch(struct wl_closure *closure, wl_dispatcher_func_t dispatcher, struct wl_object *target, uint32_t opcode); int wl_closure_send(struct wl_closure *closure, struct wl_connection *connection); int wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection); void wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send, int discarded, uint32_t (*n_parse)(union wl_argument *arg), const char *queue_name); void wl_closure_destroy(struct wl_closure *closure); extern wl_log_func_t wl_log_handler; void wl_log(const char *fmt, ...); void wl_abort(const char *fmt, ...); struct wl_display; struct wl_array * wl_display_get_additional_shm_formats(struct wl_display *display); static inline void * zalloc(size_t s) { return calloc(1, s); } void wl_connection_close_fds_in(struct wl_connection *connection, int max); void wl_connection_set_max_buffer_size(struct wl_connection *connection, size_t max_buffer_size); #endif wayland-1.23.1/src/wayland-server-core.h000066400000000000000000000470301466237767300201170ustar00rootroot00000000000000/* * Copyright © 2008 Kristian Høgsberg * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef WAYLAND_SERVER_CORE_H #define WAYLAND_SERVER_CORE_H #include #include #include #include "wayland-util.h" #include "wayland-version.h" #ifdef __cplusplus extern "C" { #endif enum { WL_EVENT_READABLE = 0x01, WL_EVENT_WRITABLE = 0x02, WL_EVENT_HANGUP = 0x04, WL_EVENT_ERROR = 0x08 }; /** File descriptor dispatch function type * * Functions of this type are used as callbacks for file descriptor events. * * \param fd The file descriptor delivering the event. * \param mask Describes the kind of the event as a bitwise-or of: * \c WL_EVENT_READABLE, \c WL_EVENT_WRITABLE, \c WL_EVENT_HANGUP, * \c WL_EVENT_ERROR. * \param data The user data argument of the related wl_event_loop_add_fd() * call. * \return If the event source is registered for re-check with * wl_event_source_check(): 0 for all done, 1 for needing a re-check. * If not registered, the return value is ignored and should be zero. * * \sa wl_event_loop_add_fd() * \memberof wl_event_source */ typedef int (*wl_event_loop_fd_func_t)(int fd, uint32_t mask, void *data); /** Timer dispatch function type * * Functions of this type are used as callbacks for timer expiry. * * \param data The user data argument of the related wl_event_loop_add_timer() * call. * \return If the event source is registered for re-check with * wl_event_source_check(): 0 for all done, 1 for needing a re-check. * If not registered, the return value is ignored and should be zero. * * \sa wl_event_loop_add_timer() * \memberof wl_event_source */ typedef int (*wl_event_loop_timer_func_t)(void *data); /** Signal dispatch function type * * Functions of this type are used as callbacks for (POSIX) signals. * * \param signal_number * \param data The user data argument of the related wl_event_loop_add_signal() * call. * \return If the event source is registered for re-check with * wl_event_source_check(): 0 for all done, 1 for needing a re-check. * If not registered, the return value is ignored and should be zero. * * \sa wl_event_loop_add_signal() * \memberof wl_event_source */ typedef int (*wl_event_loop_signal_func_t)(int signal_number, void *data); /** Idle task function type * * Functions of this type are used as callbacks before blocking in * wl_event_loop_dispatch(). * * \param data The user data argument of the related wl_event_loop_add_idle() * call. * * \sa wl_event_loop_add_idle() wl_event_loop_dispatch() * \memberof wl_event_source */ typedef void (*wl_event_loop_idle_func_t)(void *data); /** \struct wl_event_loop * * \brief An event loop context * * Usually you create an event loop context, add sources to it, and call * wl_event_loop_dispatch() in a loop to process events. * * \sa wl_event_source */ /** \struct wl_event_source * * \brief An abstract event source * * This is the generic type for fd, timer, signal, and idle sources. * Functions that operate on specific source types must not be used with * a different type, even if the function signature allows it. */ struct wl_event_loop * wl_event_loop_create(void); void wl_event_loop_destroy(struct wl_event_loop *loop); struct wl_event_source * wl_event_loop_add_fd(struct wl_event_loop *loop, int fd, uint32_t mask, wl_event_loop_fd_func_t func, void *data); int wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask); struct wl_event_source * wl_event_loop_add_timer(struct wl_event_loop *loop, wl_event_loop_timer_func_t func, void *data); struct wl_event_source * wl_event_loop_add_signal(struct wl_event_loop *loop, int signal_number, wl_event_loop_signal_func_t func, void *data); int wl_event_source_timer_update(struct wl_event_source *source, int ms_delay); int wl_event_source_remove(struct wl_event_source *source); void wl_event_source_check(struct wl_event_source *source); int wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout); void wl_event_loop_dispatch_idle(struct wl_event_loop *loop); struct wl_event_source * wl_event_loop_add_idle(struct wl_event_loop *loop, wl_event_loop_idle_func_t func, void *data); int wl_event_loop_get_fd(struct wl_event_loop *loop); struct wl_listener; typedef void (*wl_notify_func_t)(struct wl_listener *listener, void *data); void wl_event_loop_add_destroy_listener(struct wl_event_loop *loop, struct wl_listener *listener); struct wl_listener * wl_event_loop_get_destroy_listener(struct wl_event_loop *loop, wl_notify_func_t notify); struct wl_display * wl_display_create(void); void wl_display_destroy(struct wl_display *display); struct wl_event_loop * wl_display_get_event_loop(struct wl_display *display); int wl_display_add_socket(struct wl_display *display, const char *name); const char * wl_display_add_socket_auto(struct wl_display *display); int wl_display_add_socket_fd(struct wl_display *display, int sock_fd); void wl_display_terminate(struct wl_display *display); void wl_display_run(struct wl_display *display); void wl_display_flush_clients(struct wl_display *display); void wl_display_destroy_clients(struct wl_display *display); void wl_display_set_default_max_buffer_size(struct wl_display *display, size_t max_buffer_size); struct wl_client; typedef void (*wl_global_bind_func_t)(struct wl_client *client, void *data, uint32_t version, uint32_t id); uint32_t wl_display_get_serial(struct wl_display *display); uint32_t wl_display_next_serial(struct wl_display *display); void wl_display_add_destroy_listener(struct wl_display *display, struct wl_listener *listener); void wl_display_add_client_created_listener(struct wl_display *display, struct wl_listener *listener); struct wl_listener * wl_display_get_destroy_listener(struct wl_display *display, wl_notify_func_t notify); struct wl_global * wl_global_create(struct wl_display *display, const struct wl_interface *interface, int version, void *data, wl_global_bind_func_t bind); void wl_global_remove(struct wl_global *global); void wl_global_destroy(struct wl_global *global); /** A filter function for wl_global objects * * \param client The client object * \param global The global object to show or hide * \param data The user data pointer * * A filter function enables the server to decide which globals to * advertise to each client. * * When a wl_global filter is set, the given callback function will be * called during wl_global advertisement and binding. * * This function should return true if the global object should be made * visible to the client or false otherwise. */ typedef bool (*wl_display_global_filter_func_t)(const struct wl_client *client, const struct wl_global *global, void *data); void wl_display_set_global_filter(struct wl_display *display, wl_display_global_filter_func_t filter, void *data); const struct wl_interface * wl_global_get_interface(const struct wl_global *global); uint32_t wl_global_get_name(const struct wl_global *global, const struct wl_client *client); uint32_t wl_global_get_version(const struct wl_global *global); struct wl_display * wl_global_get_display(const struct wl_global *global); void * wl_global_get_user_data(const struct wl_global *global); void wl_global_set_user_data(struct wl_global *global, void *data); struct wl_client * wl_client_create(struct wl_display *display, int fd); struct wl_list * wl_display_get_client_list(struct wl_display *display); struct wl_list * wl_client_get_link(struct wl_client *client); struct wl_client * wl_client_from_link(struct wl_list *link); /** Iterate over a list of clients. */ #define wl_client_for_each(client, list) \ for (client = wl_client_from_link((list)->next); \ wl_client_get_link(client) != (list); \ client = wl_client_from_link(wl_client_get_link(client)->next)) void wl_client_destroy(struct wl_client *client); void wl_client_flush(struct wl_client *client); void wl_client_get_credentials(struct wl_client *client, pid_t *pid, uid_t *uid, gid_t *gid); int wl_client_get_fd(struct wl_client *client); void wl_client_add_destroy_listener(struct wl_client *client, struct wl_listener *listener); struct wl_listener * wl_client_get_destroy_listener(struct wl_client *client, wl_notify_func_t notify); void wl_client_add_destroy_late_listener(struct wl_client *client, struct wl_listener *listener); struct wl_listener * wl_client_get_destroy_late_listener(struct wl_client *client, wl_notify_func_t notify); struct wl_resource * wl_client_get_object(struct wl_client *client, uint32_t id); void wl_client_post_no_memory(struct wl_client *client); void wl_client_post_implementation_error(struct wl_client *client, const char* msg, ...) WL_PRINTF(2,3); void wl_client_add_resource_created_listener(struct wl_client *client, struct wl_listener *listener); typedef enum wl_iterator_result (*wl_client_for_each_resource_iterator_func_t)( struct wl_resource *resource, void *user_data); void wl_client_for_each_resource(struct wl_client *client, wl_client_for_each_resource_iterator_func_t iterator, void *user_data); typedef void (*wl_user_data_destroy_func_t)(void *data); void wl_client_set_user_data(struct wl_client *client, void *data, wl_user_data_destroy_func_t dtor); void * wl_client_get_user_data(struct wl_client *client); void wl_client_set_max_buffer_size(struct wl_client *client, size_t max_buffer_size); /** \class wl_listener * * \brief A single listener for Wayland signals * * wl_listener provides the means to listen for wl_signal notifications. Many * Wayland objects use wl_listener for notification of significant events like * object destruction. * * Clients should create wl_listener objects manually and can register them as * listeners to signals using #wl_signal_add, assuming the signal is * directly accessible. For opaque structs like wl_event_loop, adding a * listener should be done through provided accessor methods. A listener can * only listen to one signal at a time. * * \code * struct wl_listener your_listener; * * your_listener.notify = your_callback_method; * * // Direct access * wl_signal_add(&some_object->destroy_signal, &your_listener); * * // Accessor access * wl_event_loop *loop = ...; * wl_event_loop_add_destroy_listener(loop, &your_listener); * \endcode * * If the listener is part of a larger struct, #wl_container_of can be used * to retrieve a pointer to it: * * \code * void your_listener(struct wl_listener *listener, void *data) * { * struct your_data *data; * * your_data = wl_container_of(listener, data, your_member_name); * } * \endcode * * If you need to remove a listener from a signal, use wl_list_remove(). * * \code * wl_list_remove(&your_listener.link); * \endcode * * \sa wl_signal */ struct wl_listener { struct wl_list link; wl_notify_func_t notify; }; /** \class wl_signal * * \brief A source of a type of observable event * * Signals are recognized points where significant events can be observed. * Compositors as well as the server can provide signals. Observers are * wl_listener's that are added through #wl_signal_add. Signals are emitted * using #wl_signal_emit, which will invoke all listeners until that * listener is removed by wl_list_remove() (or whenever the signal is * destroyed). * * \sa wl_listener for more information on using wl_signal */ struct wl_signal { struct wl_list listener_list; }; /** Initialize a new \ref wl_signal for use. * * \param signal The signal that will be initialized * * \memberof wl_signal */ static inline void wl_signal_init(struct wl_signal *signal) { wl_list_init(&signal->listener_list); } /** Add the specified listener to this signal. * * \param signal The signal that will emit events to the listener * \param listener The listener to add * * \memberof wl_signal */ static inline void wl_signal_add(struct wl_signal *signal, struct wl_listener *listener) { wl_list_insert(signal->listener_list.prev, &listener->link); } /** Gets the listener struct for the specified callback. * * \param signal The signal that contains the specified listener * \param notify The listener that is the target of this search * \return the list item that corresponds to the specified listener, or NULL * if none was found * * \memberof wl_signal */ static inline struct wl_listener * wl_signal_get(struct wl_signal *signal, wl_notify_func_t notify) { struct wl_listener *l; wl_list_for_each(l, &signal->listener_list, link) if (l->notify == notify) return l; return NULL; } /** Emits this signal, notifying all registered listeners. * * \param signal The signal object that will emit the signal * \param data The data that will be emitted with the signal * * \memberof wl_signal */ static inline void wl_signal_emit(struct wl_signal *signal, void *data) { struct wl_listener *l, *next; wl_list_for_each_safe(l, next, &signal->listener_list, link) l->notify(l, data); } void wl_signal_emit_mutable(struct wl_signal *signal, void *data); typedef void (*wl_resource_destroy_func_t)(struct wl_resource *resource); /* * Post an event to the client's object referred to by 'resource'. * 'opcode' is the event number generated from the protocol XML * description (the event name). The variable arguments are the event * parameters, in the order they appear in the protocol XML specification. * * The variable arguments' types are: * - type=uint: uint32_t * - type=int: int32_t * - type=fixed: wl_fixed_t * - type=string: (const char *) to a nil-terminated string * - type=array: (struct wl_array *) * - type=fd: int, that is an open file descriptor * - type=new_id: (struct wl_object *) or (struct wl_resource *) * - type=object: (struct wl_object *) or (struct wl_resource *) */ void wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...); void wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode, union wl_argument *args); void wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...); void wl_resource_queue_event_array(struct wl_resource *resource, uint32_t opcode, union wl_argument *args); /* msg is a printf format string, variable args are its args. */ void wl_resource_post_error(struct wl_resource *resource, uint32_t code, const char *msg, ...) WL_PRINTF(3, 4); void wl_resource_post_no_memory(struct wl_resource *resource); struct wl_display * wl_client_get_display(struct wl_client *client); struct wl_resource * wl_resource_create(struct wl_client *client, const struct wl_interface *interface, int version, uint32_t id); void wl_resource_set_implementation(struct wl_resource *resource, const void *implementation, void *data, wl_resource_destroy_func_t destroy); void wl_resource_set_dispatcher(struct wl_resource *resource, wl_dispatcher_func_t dispatcher, const void *implementation, void *data, wl_resource_destroy_func_t destroy); void wl_resource_destroy(struct wl_resource *resource); uint32_t wl_resource_get_id(struct wl_resource *resource); struct wl_list * wl_resource_get_link(struct wl_resource *resource); struct wl_resource * wl_resource_from_link(struct wl_list *resource); struct wl_resource * wl_resource_find_for_client(struct wl_list *list, struct wl_client *client); struct wl_client * wl_resource_get_client(struct wl_resource *resource); void wl_resource_set_user_data(struct wl_resource *resource, void *data); void * wl_resource_get_user_data(struct wl_resource *resource); int wl_resource_get_version(struct wl_resource *resource); void wl_resource_set_destructor(struct wl_resource *resource, wl_resource_destroy_func_t destroy); int wl_resource_instance_of(struct wl_resource *resource, const struct wl_interface *interface, const void *implementation); const char * wl_resource_get_class(struct wl_resource *resource); void wl_resource_add_destroy_listener(struct wl_resource *resource, struct wl_listener *listener); struct wl_listener * wl_resource_get_destroy_listener(struct wl_resource *resource, wl_notify_func_t notify); #define wl_resource_for_each(resource, list) \ for (resource = 0, resource = wl_resource_from_link((list)->next); \ wl_resource_get_link(resource) != (list); \ resource = wl_resource_from_link(wl_resource_get_link(resource)->next)) #define wl_resource_for_each_safe(resource, tmp, list) \ for (resource = 0, tmp = 0, \ resource = wl_resource_from_link((list)->next), \ tmp = wl_resource_from_link((list)->next->next); \ wl_resource_get_link(resource) != (list); \ resource = tmp, \ tmp = wl_resource_from_link(wl_resource_get_link(resource)->next)) struct wl_shm_buffer * wl_shm_buffer_get(struct wl_resource *resource); void wl_shm_buffer_begin_access(struct wl_shm_buffer *buffer); void wl_shm_buffer_end_access(struct wl_shm_buffer *buffer); void * wl_shm_buffer_get_data(struct wl_shm_buffer *buffer); int32_t wl_shm_buffer_get_stride(struct wl_shm_buffer *buffer); uint32_t wl_shm_buffer_get_format(struct wl_shm_buffer *buffer); int32_t wl_shm_buffer_get_width(struct wl_shm_buffer *buffer); int32_t wl_shm_buffer_get_height(struct wl_shm_buffer *buffer); struct wl_shm_pool * wl_shm_buffer_ref_pool(struct wl_shm_buffer *buffer); void wl_shm_pool_unref(struct wl_shm_pool *pool); int wl_display_init_shm(struct wl_display *display); uint32_t * wl_display_add_shm_format(struct wl_display *display, uint32_t format); WL_DEPRECATED struct wl_shm_buffer * wl_shm_buffer_create(struct wl_client *client, uint32_t id, int32_t width, int32_t height, int32_t stride, uint32_t format); void wl_log_set_handler_server(wl_log_func_t handler); enum wl_protocol_logger_type { WL_PROTOCOL_LOGGER_REQUEST, WL_PROTOCOL_LOGGER_EVENT, }; struct wl_protocol_logger_message { struct wl_resource *resource; int message_opcode; const struct wl_message *message; int arguments_count; const union wl_argument *arguments; }; typedef void (*wl_protocol_logger_func_t)(void *user_data, enum wl_protocol_logger_type direction, const struct wl_protocol_logger_message *message); struct wl_protocol_logger * wl_display_add_protocol_logger(struct wl_display *display, wl_protocol_logger_func_t, void *user_data); void wl_protocol_logger_destroy(struct wl_protocol_logger *logger); #ifdef __cplusplus } #endif #endif wayland-1.23.1/src/wayland-server-private.h000066400000000000000000000034431466237767300206410ustar00rootroot00000000000000/* * Copyright © 2008-2011 Kristian Høgsberg * Copyright © 2011 Intel Corporation * Copyright © 2013 Jason Ekstrand * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef WAYLAND_SERVER_PRIVATE_H #define WAYLAND_SERVER_PRIVATE_H #include "wayland-server-core.h" struct wl_priv_signal { struct wl_list listener_list; struct wl_list emit_list; }; void wl_priv_signal_init(struct wl_priv_signal *signal); void wl_priv_signal_add(struct wl_priv_signal *signal, struct wl_listener *listener); struct wl_listener * wl_priv_signal_get(struct wl_priv_signal *signal, wl_notify_func_t notify); void wl_priv_signal_emit(struct wl_priv_signal *signal, void *data); void wl_priv_signal_final_emit(struct wl_priv_signal *signal, void *data); #endif wayland-1.23.1/src/wayland-server.c000066400000000000000000002150621466237767300171660ustar00rootroot00000000000000/* * Copyright © 2008 Kristian Høgsberg * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wayland-util.h" #include "wayland-private.h" #include "wayland-server-private.h" #include "wayland-server.h" #include "wayland-os.h" /* This is the size of the char array in struct sock_addr_un. * No Wayland socket can be created with a path longer than this, * including the null terminator. */ #ifndef UNIX_PATH_MAX #define UNIX_PATH_MAX 108 #endif #define LOCK_SUFFIX ".lock" #define LOCK_SUFFIXLEN 5 struct wl_socket { int fd; int fd_lock; struct sockaddr_un addr; char lock_addr[UNIX_PATH_MAX + LOCK_SUFFIXLEN]; struct wl_list link; struct wl_event_source *source; char *display_name; }; struct wl_client { struct wl_connection *connection; struct wl_event_source *source; struct wl_display *display; struct wl_resource *display_resource; struct wl_list link; struct wl_map objects; struct wl_priv_signal destroy_signal; struct wl_priv_signal destroy_late_signal; pid_t pid; uid_t uid; gid_t gid; bool error; struct wl_priv_signal resource_created_signal; void *data; wl_user_data_destroy_func_t data_dtor; }; struct wl_display { struct wl_event_loop *loop; bool run; uint32_t next_global_name; uint32_t serial; struct wl_list registry_resource_list; struct wl_list global_list; struct wl_list socket_list; struct wl_list client_list; struct wl_list protocol_loggers; struct wl_priv_signal destroy_signal; struct wl_priv_signal create_client_signal; struct wl_array additional_shm_formats; wl_display_global_filter_func_t global_filter; void *global_filter_data; int terminate_efd; struct wl_event_source *term_source; size_t max_buffer_size; }; struct wl_global { struct wl_display *display; const struct wl_interface *interface; uint32_t name; uint32_t version; void *data; wl_global_bind_func_t bind; struct wl_list link; bool removed; }; struct wl_resource { struct wl_object object; wl_resource_destroy_func_t destroy; struct wl_list link; /* Unfortunately some users of libwayland (e.g. mesa) still use the * deprecated wl_resource struct, even if creating it with the new * wl_resource_create(). So we cannot change the layout of the struct * unless after the data field. */ struct wl_signal deprecated_destroy_signal; struct wl_client *client; void *data; int version; wl_dispatcher_func_t dispatcher; struct wl_priv_signal destroy_signal; }; struct wl_protocol_logger { struct wl_list link; wl_protocol_logger_func_t func; void *user_data; }; static int debug_server = 0; static void log_closure(struct wl_resource *resource, struct wl_closure *closure, int send) { struct wl_object *object = &resource->object; struct wl_display *display = resource->client->display; struct wl_protocol_logger *protocol_logger; struct wl_protocol_logger_message message; if (debug_server) wl_closure_print(closure, object, send, false, NULL, NULL); if (!wl_list_empty(&display->protocol_loggers)) { message.resource = resource; message.message_opcode = closure->opcode; message.message = closure->message; message.arguments_count = closure->count; message.arguments = closure->args; wl_list_for_each(protocol_logger, &display->protocol_loggers, link) { protocol_logger->func(protocol_logger->user_data, send ? WL_PROTOCOL_LOGGER_EVENT : WL_PROTOCOL_LOGGER_REQUEST, &message); } } } static bool verify_objects(struct wl_resource *resource, uint32_t opcode, union wl_argument *args) { struct wl_object *object = &resource->object; const char *signature = object->interface->events[opcode].signature; struct argument_details arg; struct wl_resource *res; int count, i; count = arg_count_for_signature(signature); for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { case WL_ARG_NEW_ID: case WL_ARG_OBJECT: res = (struct wl_resource *) (args[i].o); if (res && res->client != resource->client) { wl_log("compositor bug: The compositor " "tried to use an object from one " "client in a '%s.%s' for a different " "client.\n", object->interface->name, object->interface->events[opcode].name); return false; } default: break; } } return true; } static void handle_array(struct wl_resource *resource, uint32_t opcode, union wl_argument *args, int (*send_func)(struct wl_closure *, struct wl_connection *)) { struct wl_closure *closure; struct wl_object *object = &resource->object; if (resource->client->error) return; if (!verify_objects(resource, opcode, args)) { resource->client->error = true; return; } closure = wl_closure_marshal(object, opcode, args, &object->interface->events[opcode]); if (closure == NULL) { resource->client->error = true; return; } log_closure(resource, closure, true); if (send_func(closure, resource->client->connection)) resource->client->error = true; wl_closure_destroy(closure); } WL_EXPORT void wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode, union wl_argument *args) { handle_array(resource, opcode, args, wl_closure_send); } WL_EXPORT void wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...) { union wl_argument args[WL_CLOSURE_MAX_ARGS]; struct wl_object *object = &resource->object; va_list ap; va_start(ap, opcode); wl_argument_from_va_list(object->interface->events[opcode].signature, args, WL_CLOSURE_MAX_ARGS, ap); va_end(ap); wl_resource_post_event_array(resource, opcode, args); } WL_EXPORT void wl_resource_queue_event_array(struct wl_resource *resource, uint32_t opcode, union wl_argument *args) { handle_array(resource, opcode, args, wl_closure_queue); } WL_EXPORT void wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...) { union wl_argument args[WL_CLOSURE_MAX_ARGS]; struct wl_object *object = &resource->object; va_list ap; va_start(ap, opcode); wl_argument_from_va_list(object->interface->events[opcode].signature, args, WL_CLOSURE_MAX_ARGS, ap); va_end(ap); wl_resource_queue_event_array(resource, opcode, args); } static void wl_resource_post_error_vargs(struct wl_resource *resource, uint32_t code, const char *msg, va_list argp) { struct wl_client *client = resource->client; char buffer[128]; vsnprintf(buffer, sizeof buffer, msg, argp); /* * When a client aborts, its resources are destroyed in id order, * which means the display resource is destroyed first. If destruction * of any later resources results in a protocol error, we end up here * with a NULL display_resource. Do not try to send errors to an * already dead client. */ if (client->error || !client->display_resource) return; wl_resource_post_event(client->display_resource, WL_DISPLAY_ERROR, resource, code, buffer); client->error = true; } WL_EXPORT void wl_resource_post_error(struct wl_resource *resource, uint32_t code, const char *msg, ...) { va_list ap; va_start(ap, msg); wl_resource_post_error_vargs(resource, code, msg, ap); va_end(ap); } static void destroy_client_with_error(struct wl_client *client, const char *reason) { wl_log("%s (pid %u)\n", reason, client->pid); wl_client_destroy(client); } static int wl_client_connection_data(int fd, uint32_t mask, void *data) { struct wl_client *client = data; struct wl_connection *connection = client->connection; struct wl_resource *resource; struct wl_object *object; struct wl_closure *closure; const struct wl_message *message; uint32_t p[2]; uint32_t resource_flags; int opcode, size, since; int len; if (mask & WL_EVENT_HANGUP) { wl_client_destroy(client); return 1; } if (mask & WL_EVENT_ERROR) { destroy_client_with_error(client, "socket error"); return 1; } if (mask & WL_EVENT_WRITABLE) { len = wl_connection_flush(connection); if (len < 0 && errno != EAGAIN) { destroy_client_with_error( client, "failed to flush client connection"); return 1; } else if (len >= 0) { wl_event_source_fd_update(client->source, WL_EVENT_READABLE); } } len = 0; if (mask & WL_EVENT_READABLE) { len = wl_connection_read(connection); if (len == 0 || (len < 0 && errno != EAGAIN)) { destroy_client_with_error( client, "failed to read client connection"); return 1; } } while (len >= 0 && (size_t) len >= sizeof p) { wl_connection_copy(connection, p, sizeof p); opcode = p[1] & 0xffff; size = p[1] >> 16; if (len < size) break; resource = wl_map_lookup(&client->objects, p[0]); resource_flags = wl_map_lookup_flags(&client->objects, p[0]); if (resource == NULL) { wl_resource_post_error(client->display_resource, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid object %u", p[0]); break; } object = &resource->object; if (opcode >= object->interface->method_count) { wl_resource_post_error(client->display_resource, WL_DISPLAY_ERROR_INVALID_METHOD, "invalid method %d, object %s#%u", opcode, object->interface->name, object->id); break; } message = &object->interface->methods[opcode]; since = wl_message_get_since(message); if (!(resource_flags & WL_MAP_ENTRY_LEGACY) && resource->version > 0 && resource->version < since) { wl_resource_post_error(client->display_resource, WL_DISPLAY_ERROR_INVALID_METHOD, "invalid method %d (since %d < %d)" ", object %s#%u", opcode, resource->version, since, object->interface->name, object->id); break; } closure = wl_connection_demarshal(client->connection, size, &client->objects, message); if (closure == NULL && errno == ENOMEM) { wl_resource_post_no_memory(resource); break; } else if (closure == NULL || wl_closure_lookup_objects(closure, &client->objects) < 0) { wl_resource_post_error(client->display_resource, WL_DISPLAY_ERROR_INVALID_METHOD, "invalid arguments for %s#%u.%s", object->interface->name, object->id, message->name); wl_closure_destroy(closure); break; } log_closure(resource, closure, false); if ((resource_flags & WL_MAP_ENTRY_LEGACY) || resource->dispatcher == NULL) { wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, object, opcode, client); } else { wl_closure_dispatch(closure, resource->dispatcher, object, opcode); } wl_closure_destroy(closure); if (client->error) break; len = wl_connection_pending_input(connection); } if (client->error) { destroy_client_with_error(client, "error in client communication"); } return 1; } /** Flush pending events to the client * * \param client The client object * * Events sent to clients are queued in a buffer and written to the * socket later - typically when the compositor has handled all * requests and goes back to block in the event loop. This function * flushes all queued up events for a client immediately. * * \memberof wl_client */ WL_EXPORT void wl_client_flush(struct wl_client *client) { wl_connection_flush(client->connection); } /** Get the display object for the given client * * \param client The client object * \return The display object the client is associated with. * * \memberof wl_client */ WL_EXPORT struct wl_display * wl_client_get_display(struct wl_client *client) { return client->display; } static int bind_display(struct wl_client *client, struct wl_display *display); /** Create a client for the given file descriptor * * \param display The display object * \param fd The file descriptor for the socket to the client * \return The new client object or NULL on failure. * * Given a file descriptor corresponding to one end of a socket, this * function will create a wl_client struct and add the new client to * the compositors client list. At that point, the client is * initialized and ready to run, as if the client had connected to the * servers listening socket. When the client eventually sends * requests to the compositor, the wl_client argument to the request * handler will be the wl_client returned from this function. * * The other end of the socket can be passed to * wl_display_connect_to_fd() on the client side or used with the * WAYLAND_SOCKET environment variable on the client side. * * Listeners added with wl_display_add_client_created_listener() will * be notified by this function after the client is fully constructed. * * On failure this function sets errno accordingly and returns NULL. * * On success, the new client object takes the ownership of the file * descriptor. On failure, the ownership of the socket endpoint file * descriptor is unchanged, it is the responsibility of the caller to * perform cleanup, e.g. call close(). * * \memberof wl_display */ WL_EXPORT struct wl_client * wl_client_create(struct wl_display *display, int fd) { struct wl_client *client; client = zalloc(sizeof *client); if (client == NULL) return NULL; wl_priv_signal_init(&client->resource_created_signal); client->display = display; client->source = wl_event_loop_add_fd(display->loop, fd, WL_EVENT_READABLE, wl_client_connection_data, client); if (!client->source) goto err_client; if (wl_os_socket_peercred(fd, &client->uid, &client->gid, &client->pid) != 0) goto err_source; client->connection = wl_connection_create(fd, display->max_buffer_size); if (client->connection == NULL) goto err_source; wl_map_init(&client->objects, WL_MAP_SERVER_SIDE); if (wl_map_insert_at(&client->objects, 0, 0, NULL) < 0) goto err_map; wl_priv_signal_init(&client->destroy_signal); wl_priv_signal_init(&client->destroy_late_signal); if (bind_display(client, display) < 0) goto err_map; wl_list_insert(display->client_list.prev, &client->link); wl_priv_signal_emit(&display->create_client_signal, client); return client; err_map: wl_map_release(&client->objects); wl_connection_destroy(client->connection); err_source: wl_event_source_remove(client->source); err_client: free(client); return NULL; } /** Return Unix credentials for the client * * \param client The display object * \param pid Returns the process ID * \param uid Returns the user ID * \param gid Returns the group ID * * This function returns the process ID, the user ID and the group ID * for the given client. The credentials come from getsockopt() with * SO_PEERCRED, on the client socket fd. All the pointers can be * NULL, if the caller is not interested in a particular ID. * * Note, process IDs are subject to race conditions and are not a reliable way * to identify a client. * * Be aware that for clients that a compositor forks and execs and * then connects using socketpair(), this function will return the * credentials for the compositor. The credentials for the socketpair * are set at creation time in the compositor. * * \memberof wl_client */ WL_EXPORT void wl_client_get_credentials(struct wl_client *client, pid_t *pid, uid_t *uid, gid_t *gid) { if (pid) *pid = client->pid; if (uid) *uid = client->uid; if (gid) *gid = client->gid; } /** Get the file descriptor for the client * * \param client The display object * \return The file descriptor to use for the connection * * This function returns the file descriptor for the given client. * * Be sure to use the file descriptor from the client for inspection only. * If the caller does anything to the file descriptor that changes its state, * it will likely cause problems. * * See also wl_client_get_credentials(). * It is recommended that you evaluate whether wl_client_get_credentials() * can be applied to your use case instead of this function. * * If you would like to distinguish just between the client and the compositor * itself from the client's request, it can be done by getting the client * credentials and by checking the PID of the client and the compositor's PID. * Regarding the case in which the socketpair() is being used, you need to be * careful. Please note the documentation for wl_client_get_credentials(). * * This function can be used for a compositor to validate a request from * a client if there are additional information provided from the client's * file descriptor. For instance, suppose you can get the security contexts * from the client's file descriptor. The compositor can validate the client's * request with the contexts and make a decision whether it permits or deny it. * * \memberof wl_client */ WL_EXPORT int wl_client_get_fd(struct wl_client *client) { return wl_connection_get_fd(client->connection); } /** Look up an object in the client name space * * \param client The client object * \param id The object id * \return The object or NULL if there is not object for the given ID * * This looks up an object in the client object name space by its * object ID. * * \memberof wl_client */ WL_EXPORT struct wl_resource * wl_client_get_object(struct wl_client *client, uint32_t id) { return wl_map_lookup(&client->objects, id); } WL_EXPORT void wl_client_post_no_memory(struct wl_client *client) { wl_resource_post_error(client->display_resource, WL_DISPLAY_ERROR_NO_MEMORY, "no memory"); } /** Report an internal server error * * \param client The client object * \param msg A printf-style format string * \param ... Format string arguments * * Report an unspecified internal implementation error and disconnect * the client. * * \memberof wl_client */ WL_EXPORT void wl_client_post_implementation_error(struct wl_client *client, char const *msg, ...) { va_list ap; va_start(ap, msg); wl_resource_post_error_vargs(client->display_resource, WL_DISPLAY_ERROR_IMPLEMENTATION, msg, ap); va_end(ap); } WL_EXPORT void wl_resource_post_no_memory(struct wl_resource *resource) { wl_resource_post_error(resource->client->display_resource, WL_DISPLAY_ERROR_NO_MEMORY, "no memory"); } /** Detect if a wl_resource uses the deprecated public definition. * * Before Wayland 1.2.0, the definition of struct wl_resource was public. * It was made opaque just before 1.2.0, and later new fields were added. * The new fields cannot be accessed if a program is using the deprecated * definition, as there would not be memory allocated for them. * * The creation pattern for the deprecated definition was wl_resource_init() * followed by wl_client_add_resource(). wl_resource_init() was an inline * function and no longer exists, but binaries might still carry it. * wl_client_add_resource() still exists for ABI compatibility. */ static bool resource_is_deprecated(struct wl_resource *resource) { struct wl_map *map = &resource->client->objects; int id = resource->object.id; /* wl_client_add_resource() marks deprecated resources with the flag. */ if (wl_map_lookup_flags(map, id) & WL_MAP_ENTRY_LEGACY) return true; return false; } /** Removes the wl_resource from the client's object map and deletes it. * * Triggers the destroy signal and destructor for the resource before * removing it from the client's object map and releasing the resource's * memory. * * This order is important to ensure listeners and destruction code can * find the resource before it has been destroyed whilst ensuring the * resource is not accessible via the object map after memory has been * freed. */ static enum wl_iterator_result remove_and_destroy_resource(void *element, void *data, uint32_t flags) { struct wl_resource *resource = element; struct wl_client *client = resource->client; uint32_t id = resource->object.id;; wl_signal_emit(&resource->deprecated_destroy_signal, resource); /* Don't emit the new signal for deprecated resources, as that would * access memory outside the bounds of the deprecated struct */ if (!resource_is_deprecated(resource)) wl_priv_signal_final_emit(&resource->destroy_signal, resource); if (resource->destroy) resource->destroy(resource); /* The resource should be cleared from the map before memory is freed. */ if (id < WL_SERVER_ID_START) { if (client->display_resource) { wl_resource_queue_event(client->display_resource, WL_DISPLAY_DELETE_ID, id); } wl_map_insert_at(&client->objects, 0, id, NULL); } else { wl_map_remove(&client->objects, id); } if (!(flags & WL_MAP_ENTRY_LEGACY)) free(resource); return WL_ITERATOR_CONTINUE; } WL_EXPORT void wl_resource_destroy(struct wl_resource *resource) { struct wl_client *client = resource->client; uint32_t flags = wl_map_lookup_flags(&client->objects, resource->object.id); remove_and_destroy_resource(resource, NULL, flags); } WL_EXPORT uint32_t wl_resource_get_id(struct wl_resource *resource) { return resource->object.id; } WL_EXPORT struct wl_list * wl_resource_get_link(struct wl_resource *resource) { return &resource->link; } WL_EXPORT struct wl_resource * wl_resource_from_link(struct wl_list *link) { struct wl_resource *resource; return wl_container_of(link, resource, link); } WL_EXPORT struct wl_resource * wl_resource_find_for_client(struct wl_list *list, struct wl_client *client) { struct wl_resource *resource; if (client == NULL) return NULL; wl_list_for_each(resource, list, link) { if (resource->client == client) return resource; } return NULL; } WL_EXPORT struct wl_client * wl_resource_get_client(struct wl_resource *resource) { return resource->client; } WL_EXPORT void wl_resource_set_user_data(struct wl_resource *resource, void *data) { resource->data = data; } WL_EXPORT void * wl_resource_get_user_data(struct wl_resource *resource) { return resource->data; } WL_EXPORT int wl_resource_get_version(struct wl_resource *resource) { return resource->version; } WL_EXPORT void wl_resource_set_destructor(struct wl_resource *resource, wl_resource_destroy_func_t destroy) { resource->destroy = destroy; } WL_EXPORT int wl_resource_instance_of(struct wl_resource *resource, const struct wl_interface *interface, const void *implementation) { return wl_interface_equal(resource->object.interface, interface) && resource->object.implementation == implementation; } WL_EXPORT void wl_resource_add_destroy_listener(struct wl_resource *resource, struct wl_listener * listener) { if (resource_is_deprecated(resource)) wl_signal_add(&resource->deprecated_destroy_signal, listener); else wl_priv_signal_add(&resource->destroy_signal, listener); } WL_EXPORT struct wl_listener * wl_resource_get_destroy_listener(struct wl_resource *resource, wl_notify_func_t notify) { if (resource_is_deprecated(resource)) return wl_signal_get(&resource->deprecated_destroy_signal, notify); return wl_priv_signal_get(&resource->destroy_signal, notify); } /** Retrieve the interface name (class) of a resource object. * * \param resource The resource object * * \memberof wl_resource */ WL_EXPORT const char * wl_resource_get_class(struct wl_resource *resource) { return resource->object.interface->name; } /** * Add a listener to be called at the beginning of wl_client destruction * * The listener provided will be called when wl_client destroy has begun, * before any of that client's resources have been destroyed. * * There is no requirement to remove the link of the wl_listener when the * signal is emitted. * * \memberof wl_client */ WL_EXPORT void wl_client_add_destroy_listener(struct wl_client *client, struct wl_listener *listener) { wl_priv_signal_add(&client->destroy_signal, listener); } WL_EXPORT struct wl_listener * wl_client_get_destroy_listener(struct wl_client *client, wl_notify_func_t notify) { return wl_priv_signal_get(&client->destroy_signal, notify); } /** * Add a listener to be called at the end of wl_client destruction * * The listener provided will be called when wl_client destroy is nearly * complete, after all of that client's resources have been destroyed. * * There is no requirement to remove the link of the wl_listener when the * signal is emitted. * * \memberof wl_client * \since 1.22.0 */ WL_EXPORT void wl_client_add_destroy_late_listener(struct wl_client *client, struct wl_listener *listener) { wl_priv_signal_add(&client->destroy_late_signal, listener); } WL_EXPORT struct wl_listener * wl_client_get_destroy_late_listener(struct wl_client *client, wl_notify_func_t notify) { return wl_priv_signal_get(&client->destroy_late_signal, notify); } WL_EXPORT void wl_client_destroy(struct wl_client *client) { /* wl_client_destroy() should not be called twice for the same client. */ if (wl_list_empty(&client->link)) { client->error = 1; wl_log("wl_client_destroy: encountered re-entrant client destruction.\n"); return; } wl_list_remove(&client->link); /* Keep the client link safe to inspect. */ wl_list_init(&client->link); wl_priv_signal_final_emit(&client->destroy_signal, client); wl_client_flush(client); wl_map_for_each(&client->objects, remove_and_destroy_resource, NULL); wl_map_release(&client->objects); wl_event_source_remove(client->source); close(wl_connection_destroy(client->connection)); wl_priv_signal_final_emit(&client->destroy_late_signal, client); wl_list_remove(&client->resource_created_signal.listener_list); if (client->data_dtor) client->data_dtor(client->data); free(client); } /* Check if a global filter is registered and use it if any. * * If no wl_global filter has been registered, this function will * return true, allowing the wl_global to be visible to the wl_client */ static bool wl_global_is_visible(const struct wl_client *client, const struct wl_global *global) { struct wl_display *display = client->display; return (display->global_filter == NULL || display->global_filter(client, global, display->global_filter_data)); } static void registry_bind(struct wl_client *client, struct wl_resource *resource, uint32_t name, const char *interface, uint32_t version, uint32_t id) { struct wl_global *global; struct wl_display *display = resource->data; wl_list_for_each(global, &display->global_list, link) if (global->name == name) break; if (&global->link == &display->global_list) wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid global %s (%d)", interface, name); else if (strcmp(global->interface->name, interface) != 0) wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid interface for global %u: " "have %s, wanted %s", name, interface, global->interface->name); else if (version == 0) wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid version for global %s (%d): 0 is not a valid version", interface, name); else if (global->version < version) wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid version for global %s (%d): have %d, wanted %d", interface, name, global->version, version); else if (!wl_global_is_visible(client, global)) wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid global %s (%d)", interface, name); else global->bind(client, global->data, version, id); } static const struct wl_registry_interface registry_interface = { registry_bind }; static void display_sync(struct wl_client *client, struct wl_resource *resource, uint32_t id) { struct wl_resource *callback; uint32_t serial; callback = wl_resource_create(client, &wl_callback_interface, 1, id); if (callback == NULL) { wl_client_post_no_memory(client); return; } serial = wl_display_get_serial(client->display); wl_callback_send_done(callback, serial); wl_resource_destroy(callback); } static void unbind_resource(struct wl_resource *resource) { wl_list_remove(&resource->link); } static void display_get_registry(struct wl_client *client, struct wl_resource *resource, uint32_t id) { struct wl_display *display = resource->data; struct wl_resource *registry_resource; struct wl_global *global; registry_resource = wl_resource_create(client, &wl_registry_interface, 1, id); if (registry_resource == NULL) { wl_client_post_no_memory(client); return; } wl_resource_set_implementation(registry_resource, ®istry_interface, display, unbind_resource); wl_list_insert(&display->registry_resource_list, ®istry_resource->link); wl_list_for_each(global, &display->global_list, link) if (wl_global_is_visible(client, global) && !global->removed) wl_resource_post_event(registry_resource, WL_REGISTRY_GLOBAL, global->name, global->interface->name, global->version); } static const struct wl_display_interface display_interface = { display_sync, display_get_registry }; static void destroy_client_display_resource(struct wl_resource *resource) { resource->client->display_resource = NULL; } static int bind_display(struct wl_client *client, struct wl_display *display) { client->display_resource = wl_resource_create(client, &wl_display_interface, 1, 1); if (client->display_resource == NULL) { /* DON'T send no-memory error to client - it has no * resource to which it could post the event */ return -1; } wl_resource_set_implementation(client->display_resource, &display_interface, display, destroy_client_display_resource); return 0; } static int handle_display_terminate(int fd, uint32_t mask, void *data) { uint64_t term_event; if (read(fd, &term_event, sizeof(term_event)) < 0 && errno != EAGAIN) return -1; return 0; } /** Create Wayland display object. * * \return The Wayland display object. Null if failed to create * * This creates the wl_display object. * * \memberof wl_display */ WL_EXPORT struct wl_display * wl_display_create(void) { struct wl_display *display; const char *debug; debug = getenv("WAYLAND_DEBUG"); if (debug && (strstr(debug, "server") || strstr(debug, "1"))) debug_server = 1; display = zalloc(sizeof *display); if (display == NULL) return NULL; display->loop = wl_event_loop_create(); if (display->loop == NULL) { free(display); return NULL; } display->terminate_efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); if (display->terminate_efd < 0) goto err_eventfd; display->term_source = wl_event_loop_add_fd(display->loop, display->terminate_efd, WL_EVENT_READABLE, handle_display_terminate, NULL); if (display->term_source == NULL) goto err_term_source; wl_list_init(&display->global_list); wl_list_init(&display->socket_list); wl_list_init(&display->client_list); wl_list_init(&display->registry_resource_list); wl_list_init(&display->protocol_loggers); wl_priv_signal_init(&display->destroy_signal); wl_priv_signal_init(&display->create_client_signal); display->next_global_name = 1; display->serial = 0; display->global_filter = NULL; display->global_filter_data = NULL; display->max_buffer_size = WL_BUFFER_DEFAULT_MAX_SIZE; wl_array_init(&display->additional_shm_formats); return display; err_term_source: close(display->terminate_efd); err_eventfd: wl_event_loop_destroy(display->loop); free(display); return NULL; } static void wl_socket_destroy(struct wl_socket *s) { if (s->source) wl_event_source_remove(s->source); if (s->addr.sun_path[0]) unlink(s->addr.sun_path); if (s->fd >= 0) close(s->fd); if (s->lock_addr[0]) unlink(s->lock_addr); if (s->fd_lock >= 0) close(s->fd_lock); free(s); } static struct wl_socket * wl_socket_alloc(void) { struct wl_socket *s; s = zalloc(sizeof *s); if (!s) return NULL; s->fd = -1; s->fd_lock = -1; return s; } /** Destroy Wayland display object. * * \param display The Wayland display object which should be destroyed. * * This function emits the wl_display destroy signal, releases * all the sockets added to this display, free's all the globals associated * with this display, free's memory of additional shared memory formats and * destroy the display object. * * \sa wl_display_add_destroy_listener * * \memberof wl_display */ WL_EXPORT void wl_display_destroy(struct wl_display *display) { struct wl_socket *s, *next; struct wl_global *global, *gnext; wl_priv_signal_final_emit(&display->destroy_signal, display); wl_list_for_each_safe(s, next, &display->socket_list, link) { wl_socket_destroy(s); } close(display->terminate_efd); wl_event_source_remove(display->term_source); wl_event_loop_destroy(display->loop); wl_list_for_each_safe(global, gnext, &display->global_list, link) free(global); wl_array_release(&display->additional_shm_formats); wl_list_remove(&display->protocol_loggers); free(display); } /** Set a filter function for global objects * * \param display The Wayland display object. * \param filter The global filter function. * \param data User data to be associated with the global filter. * * Set a filter for the wl_display to advertise or hide global objects * to clients. * The set filter will be used during wl_global advertisement to * determine whether a global object should be advertised to a * given client, and during wl_global binding to determine whether * a given client should be allowed to bind to a global. * * Clients that try to bind to a global that was filtered out will * have an error raised. * * Setting the filter NULL will result in all globals being * advertised to all clients. The default is no filter. * * The filter should be installed before any client connects and should always * take the same decision given a client and a global. Not doing so will result * in inconsistent filtering and broken wl_registry event sequences. * * \memberof wl_display */ WL_EXPORT void wl_display_set_global_filter(struct wl_display *display, wl_display_global_filter_func_t filter, void *data) { display->global_filter = filter; display->global_filter_data = data; } WL_EXPORT struct wl_global * wl_global_create(struct wl_display *display, const struct wl_interface *interface, int version, void *data, wl_global_bind_func_t bind) { struct wl_global *global; struct wl_resource *resource; if (version < 1) { wl_log("wl_global_create: failing to create interface " "'%s' with version %d because it is less than 1\n", interface->name, version); return NULL; } if (version > interface->version) { wl_log("wl_global_create: implemented version for '%s' " "higher than interface version (%d > %d)\n", interface->name, version, interface->version); return NULL; } if (display->next_global_name >= UINT32_MAX) { wl_log("wl_global_create: ran out of global names\n"); return NULL; } global = zalloc(sizeof *global); if (global == NULL) return NULL; global->display = display; global->name = display->next_global_name++; global->interface = interface; global->version = version; global->data = data; global->bind = bind; global->removed = false; wl_list_insert(display->global_list.prev, &global->link); wl_list_for_each(resource, &display->registry_resource_list, link) if (wl_global_is_visible(resource->client, global)) wl_resource_post_event(resource, WL_REGISTRY_GLOBAL, global->name, global->interface->name, global->version); return global; } /** Remove the global * * \param global The Wayland global. * * Broadcast a global remove event to all clients without destroying the * global. This function can only be called once per global. * * wl_global_destroy() removes the global and immediately destroys it. On * the other end, this function only removes the global, allowing clients * that have not yet received the global remove event to continue to bind to * it. * * This can be used by compositors to mitigate clients being disconnected * because a global has been added and removed too quickly. Compositors can call * wl_global_remove(), then wait an implementation-defined amount of time, then * call wl_global_destroy(). Note that the destruction of a global is still * racy, since clients have no way to acknowledge that they received the remove * event. * * \since 1.17.90 */ WL_EXPORT void wl_global_remove(struct wl_global *global) { struct wl_display *display = global->display; struct wl_resource *resource; if (global->removed) wl_abort("wl_global_remove: called twice on the same " "global '%s#%"PRIu32"'", global->interface->name, global->name); wl_list_for_each(resource, &display->registry_resource_list, link) if (wl_global_is_visible(resource->client, global)) wl_resource_post_event(resource, WL_REGISTRY_GLOBAL_REMOVE, global->name); global->removed = true; } WL_EXPORT void wl_global_destroy(struct wl_global *global) { if (!global->removed) wl_global_remove(global); wl_list_remove(&global->link); free(global); } WL_EXPORT const struct wl_interface * wl_global_get_interface(const struct wl_global *global) { return global->interface; } /** Get the name of the global. * * \param global The global object. * \param client Client for which to look up the global. * \return The name of the global, or 0 if the global is not visible to the * client. * * \memberof wl_global * \since 1.22 */ WL_EXPORT uint32_t wl_global_get_name(const struct wl_global *global, const struct wl_client *client) { return wl_global_is_visible(client, global) ? global->name : 0; } /** Get the version of the given global. * * \param global The global object. * \return The version advertised by the global. * * \memberof wl_global * \since 1.21 */ WL_EXPORT uint32_t wl_global_get_version(const struct wl_global *global) { return global->version; } /** Get the display object for the given global * * \param global The global object * \return The display object the global is associated with. * * \memberof wl_global * \since 1.20 */ WL_EXPORT struct wl_display * wl_global_get_display(const struct wl_global *global) { return global->display; } WL_EXPORT void * wl_global_get_user_data(const struct wl_global *global) { return global->data; } /** Set the global's user data * * \param global The global object * \param data The user data pointer * * \since 1.17.90 */ WL_EXPORT void wl_global_set_user_data(struct wl_global *global, void *data) { global->data = data; } /** Get the current serial number * * \param display The display object * * This function returns the most recent serial number, but does not * increment it. * * \memberof wl_display */ WL_EXPORT uint32_t wl_display_get_serial(struct wl_display *display) { return display->serial; } /** Get the next serial number * * \param display The display object * * This function increments the display serial number and returns the * new value. * * \memberof wl_display */ WL_EXPORT uint32_t wl_display_next_serial(struct wl_display *display) { display->serial++; return display->serial; } WL_EXPORT struct wl_event_loop * wl_display_get_event_loop(struct wl_display *display) { return display->loop; } WL_EXPORT void wl_display_terminate(struct wl_display *display) { int ret; uint64_t terminate = 1; display->run = false; ret = write(display->terminate_efd, &terminate, sizeof(terminate)); assert (ret >= 0 || errno == EAGAIN); } WL_EXPORT void wl_display_run(struct wl_display *display) { display->run = true; while (display->run) { wl_display_flush_clients(display); if (wl_event_loop_dispatch(display->loop, -1) < 0) { break; } } } WL_EXPORT void wl_display_flush_clients(struct wl_display *display) { struct wl_client *client, *next; int ret; wl_list_for_each_safe(client, next, &display->client_list, link) { ret = wl_connection_flush(client->connection); if (ret < 0 && errno == EAGAIN) { wl_event_source_fd_update(client->source, WL_EVENT_WRITABLE | WL_EVENT_READABLE); } else if (ret < 0) { wl_client_destroy(client); } } } /** Destroy all clients connected to the display * * \param display The display object * * This function should be called right before wl_display_destroy() to ensure * all client resources are closed properly. Destroying a client from within * wl_display_destroy_clients() is safe, but creating one will leak resources * and raise a warning. * * \memberof wl_display */ WL_EXPORT void wl_display_destroy_clients(struct wl_display *display) { struct wl_list tmp_client_list, *pos; struct wl_client *client; /* Move the whole client list to a temporary head because some new clients * might be added to the original head. */ wl_list_init(&tmp_client_list); wl_list_insert_list(&tmp_client_list, &display->client_list); wl_list_init(&display->client_list); /* wl_list_for_each_safe isn't enough here: it fails if the next client is * destroyed by the destroy handler of the current one. */ while (!wl_list_empty(&tmp_client_list)) { pos = tmp_client_list.next; client = wl_container_of(pos, client, link); wl_client_destroy(client); } if (!wl_list_empty(&display->client_list)) { wl_log("wl_display_destroy_clients: cannot destroy all clients because " "new ones were created by destroy callbacks\n"); } } /** Sets the default maximum size for connection buffers of new clients * * \param display The display object * \param max_buffer_size The default maximum size of the connection buffers * * This function sets the default size of the internal connection buffers for * new clients. It doesn't change the buffer size for existing wl_client. * * The connection buffer size of an existing wl_client can be adjusted using * wl_client_set_max_buffer_size(). * * The actual size of the connection buffers is a power of two, the requested * \a max_buffer_size is therefore rounded up to the nearest power of two value. * * The minimum buffer size is 4096. * * \sa wl_client_set_max_buffer_size * * \memberof wl_display * \since 1.22.90 */ WL_EXPORT void wl_display_set_default_max_buffer_size(struct wl_display *display, size_t max_buffer_size) { if (max_buffer_size < WL_BUFFER_DEFAULT_MAX_SIZE) max_buffer_size = WL_BUFFER_DEFAULT_MAX_SIZE; display->max_buffer_size = max_buffer_size; } static int socket_data(int fd, uint32_t mask, void *data) { struct wl_display *display = data; struct sockaddr_un name; socklen_t length; int client_fd; length = sizeof name; client_fd = wl_os_accept_cloexec(fd, (struct sockaddr *) &name, &length); if (client_fd < 0) wl_log("failed to accept: %s\n", strerror(errno)); else if (!wl_client_create(display, client_fd)) close(client_fd); return 1; } static int wl_socket_lock(struct wl_socket *socket) { struct stat socket_stat; snprintf(socket->lock_addr, sizeof socket->lock_addr, "%s%s", socket->addr.sun_path, LOCK_SUFFIX); socket->fd_lock = open(socket->lock_addr, O_CREAT | O_CLOEXEC | O_RDWR, (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)); if (socket->fd_lock < 0) { wl_log("unable to open lockfile %s check permissions\n", socket->lock_addr); goto err; } if (flock(socket->fd_lock, LOCK_EX | LOCK_NB) < 0) { wl_log("unable to lock lockfile %s, maybe another compositor is running\n", socket->lock_addr); goto err_fd; } if (lstat(socket->addr.sun_path, &socket_stat) < 0 ) { if (errno != ENOENT) { wl_log("did not manage to stat file %s\n", socket->addr.sun_path); goto err_fd; } } else if (socket_stat.st_mode & S_IWUSR || socket_stat.st_mode & S_IWGRP) { unlink(socket->addr.sun_path); } return 0; err_fd: close(socket->fd_lock); socket->fd_lock = -1; err: *socket->lock_addr = 0; /* we did not set this value here, but without lock the * socket won't be created anyway. This prevents the * wl_socket_destroy from unlinking already existing socket * created by other compositor */ *socket->addr.sun_path = 0; return -1; } static int wl_socket_init_for_display_name(struct wl_socket *s, const char *name) { int name_size; const char *runtime_dir = ""; const char *separator = ""; if (name[0] != '/') { runtime_dir = getenv("XDG_RUNTIME_DIR"); if (!runtime_dir || runtime_dir[0] != '/') { wl_log("error: XDG_RUNTIME_DIR is invalid or not set in" " the environment\n"); /* to prevent programs reporting * "failed to add socket: Success" */ errno = ENOENT; return -1; } separator = "/"; } s->addr.sun_family = AF_LOCAL; name_size = snprintf(s->addr.sun_path, sizeof s->addr.sun_path, "%s%s%s", runtime_dir, separator, name) + 1; assert(name_size > 0); if (name_size > (int)sizeof s->addr.sun_path) { wl_log("error: socket path \"%s%s%s\" plus null terminator" " exceeds 108 bytes\n", runtime_dir, separator, name); *s->addr.sun_path = 0; /* to prevent programs reporting * "failed to add socket: Success" */ errno = ENAMETOOLONG; return -1; } s->display_name = (s->addr.sun_path + name_size - 1) - strlen(name); return 0; } static int _wl_display_add_socket(struct wl_display *display, struct wl_socket *s) { socklen_t size; s->fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0); if (s->fd < 0) { return -1; } size = offsetof (struct sockaddr_un, sun_path) + strlen(s->addr.sun_path); if (bind(s->fd, (struct sockaddr *) &s->addr, size) < 0) { wl_log("bind() failed with error: %s\n", strerror(errno)); return -1; } if (listen(s->fd, 128) < 0) { wl_log("listen() failed with error: %s\n", strerror(errno)); return -1; } s->source = wl_event_loop_add_fd(display->loop, s->fd, WL_EVENT_READABLE, socket_data, display); if (s->source == NULL) { return -1; } wl_list_insert(display->socket_list.prev, &s->link); return 0; } WL_EXPORT const char * wl_display_add_socket_auto(struct wl_display *display) { struct wl_socket *s; int displayno = 0; char display_name[20] = ""; /* A reasonable number of maximum default sockets. If * you need more than this, use the explicit add_socket API. */ const int MAX_DISPLAYNO = 32; s = wl_socket_alloc(); if (s == NULL) return NULL; do { snprintf(display_name, sizeof display_name, "wayland-%d", displayno); if (wl_socket_init_for_display_name(s, display_name) < 0) { wl_socket_destroy(s); return NULL; } if (wl_socket_lock(s) < 0) continue; if (_wl_display_add_socket(display, s) < 0) { wl_socket_destroy(s); return NULL; } return s->display_name; } while (displayno++ < MAX_DISPLAYNO); /* Ran out of display names. */ wl_socket_destroy(s); errno = EINVAL; return NULL; } /** Add a socket with an existing fd to Wayland display for the clients to connect. * * \param display Wayland display to which the socket should be added. * \param sock_fd The existing socket file descriptor to be used * \return 0 if success. -1 if failed. * * The existing socket fd must already be created, opened, and locked. * The fd must be properly set to CLOEXEC and bound to a socket file * with both bind() and listen() already called. * * On success, the socket fd ownership is transferred to libwayland: * libwayland will close the socket when the display is destroyed. * * \memberof wl_display */ WL_EXPORT int wl_display_add_socket_fd(struct wl_display *display, int sock_fd) { struct wl_socket *s; struct stat buf; /* Require a valid fd or fail */ if (sock_fd < 0 || fstat(sock_fd, &buf) < 0 || !S_ISSOCK(buf.st_mode)) { return -1; } s = wl_socket_alloc(); if (s == NULL) return -1; s->source = wl_event_loop_add_fd(display->loop, sock_fd, WL_EVENT_READABLE, socket_data, display); if (s->source == NULL) { wl_log("failed to establish event source\n"); wl_socket_destroy(s); return -1; } /* Reuse the existing fd */ s->fd = sock_fd; wl_list_insert(display->socket_list.prev, &s->link); return 0; } /** Add a socket to Wayland display for the clients to connect. * * \param display Wayland display to which the socket should be added. * \param name Name of the Unix socket. * \return 0 if success. -1 if failed. * * This adds a Unix socket to Wayland display which can be used by clients to * connect to Wayland display. * * If NULL is passed as name, then it would look for WAYLAND_DISPLAY env * variable for the socket name. If WAYLAND_DISPLAY is not set, then default * wayland-0 is used. * * If the socket name is a relative path, the Unix socket will be created in * the directory pointed to by environment variable XDG_RUNTIME_DIR. If * XDG_RUNTIME_DIR is invalid or not set, then this function fails and returns -1. * * If the socket name is an absolute path, then it is used as-is for the * the Unix socket. * * The length of the computed socket path must not exceed the maximum length * of a Unix socket path. * The function also fails if the user does not have write permission in the * directory or if the path is already in use. * * \memberof wl_display */ WL_EXPORT int wl_display_add_socket(struct wl_display *display, const char *name) { struct wl_socket *s; s = wl_socket_alloc(); if (s == NULL) return -1; if (name == NULL) name = getenv("WAYLAND_DISPLAY"); if (name == NULL) name = "wayland-0"; if (wl_socket_init_for_display_name(s, name) < 0) { wl_socket_destroy(s); return -1; } if (wl_socket_lock(s) < 0) { wl_socket_destroy(s); return -1; } if (_wl_display_add_socket(display, s) < 0) { wl_socket_destroy(s); return -1; } return 0; } WL_EXPORT void wl_display_add_destroy_listener(struct wl_display *display, struct wl_listener *listener) { wl_priv_signal_add(&display->destroy_signal, listener); } /** Registers a listener for the client connection signal. * When a new client object is created, \a listener will be notified, carrying * a pointer to the new wl_client object. * * \ref wl_client_create * \ref wl_display * \ref wl_listener * * \param display The display object * \param listener Signal handler object */ WL_EXPORT void wl_display_add_client_created_listener(struct wl_display *display, struct wl_listener *listener) { wl_priv_signal_add(&display->create_client_signal, listener); } WL_EXPORT struct wl_listener * wl_display_get_destroy_listener(struct wl_display *display, wl_notify_func_t notify) { return wl_priv_signal_get(&display->destroy_signal, notify); } WL_EXPORT void wl_resource_set_implementation(struct wl_resource *resource, const void *implementation, void *data, wl_resource_destroy_func_t destroy) { resource->object.implementation = implementation; resource->data = data; resource->destroy = destroy; resource->dispatcher = NULL; } WL_EXPORT void wl_resource_set_dispatcher(struct wl_resource *resource, wl_dispatcher_func_t dispatcher, const void *implementation, void *data, wl_resource_destroy_func_t destroy) { resource->dispatcher = dispatcher; resource->object.implementation = implementation; resource->data = data; resource->destroy = destroy; } /** Create a new resource object * * \param client The client owner of the new resource. * \param interface The interface of the new resource. * \param version The version of the new resource. * \param id The id of the new resource. If 0, an available id will be used. * * Listeners added with \a wl_client_add_resource_created_listener will be * notified at the end of this function. * * \memberof wl_resource */ WL_EXPORT struct wl_resource * wl_resource_create(struct wl_client *client, const struct wl_interface *interface, int version, uint32_t id) { struct wl_resource *resource; resource = zalloc(sizeof *resource); if (resource == NULL) return NULL; if (id == 0) { id = wl_map_insert_new(&client->objects, 0, NULL); if (id == 0) { free(resource); return NULL; } } resource->object.id = id; resource->object.interface = interface; resource->object.implementation = NULL; wl_signal_init(&resource->deprecated_destroy_signal); wl_priv_signal_init(&resource->destroy_signal); resource->destroy = NULL; resource->client = client; resource->data = NULL; resource->version = version; resource->dispatcher = NULL; if (wl_map_insert_at(&client->objects, 0, id, resource) < 0) { if (errno == EINVAL) { wl_resource_post_error(client->display_resource, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid new id %d", id); } free(resource); return NULL; } wl_priv_signal_emit(&client->resource_created_signal, resource); return resource; } WL_EXPORT void wl_log_set_handler_server(wl_log_func_t handler) { wl_log_handler = handler; } /** Adds a new protocol logger. * * When a new protocol message arrives or is sent from the server * all the protocol logger functions will be called, carrying the * \a user_data pointer, the type of the message (request or * event) and the actual message. * The lifetime of the messages passed to the logger function ends * when they return so the messages cannot be stored and accessed * later. * * \a errno is set on error. * * \param display The display object * \param func The function to call to log a new protocol message * \param user_data The user data pointer to pass to \a func * * \return The protol logger object on success, NULL on failure. * * \sa wl_protocol_logger_destroy * * \memberof wl_display */ WL_EXPORT struct wl_protocol_logger * wl_display_add_protocol_logger(struct wl_display *display, wl_protocol_logger_func_t func, void *user_data) { struct wl_protocol_logger *logger; logger = zalloc(sizeof *logger); if (!logger) return NULL; logger->func = func; logger->user_data = user_data; wl_list_insert(&display->protocol_loggers, &logger->link); return logger; } /** Destroys a protocol logger. * * This function destroys a protocol logger and removes it from the display * it was added to with \a wl_display_add_protocol_logger. * The \a logger object becomes invalid after calling this function. * * \sa wl_display_add_protocol_logger * * \memberof wl_protocol_logger */ WL_EXPORT void wl_protocol_logger_destroy(struct wl_protocol_logger *logger) { wl_list_remove(&logger->link); free(logger); } /** Add support for a wl_shm pixel format * * \param display The display object * \param format The wl_shm pixel format to advertise * \return A pointer to the wl_shm format that was added to the list * or NULL if adding it to the list failed. * * Add the specified wl_shm format to the list of formats the wl_shm * object advertises when a client binds to it. Adding a format to * the list means that clients will know that the compositor supports * this format and may use it for creating wl_shm buffers. The * compositor must be able to handle the pixel format when a client * requests it. * * The compositor by default supports WL_SHM_FORMAT_ARGB8888 and * WL_SHM_FORMAT_XRGB8888. * * \memberof wl_display */ WL_EXPORT uint32_t * wl_display_add_shm_format(struct wl_display *display, uint32_t format) { uint32_t *p = NULL; p = wl_array_add(&display->additional_shm_formats, sizeof *p); if (p != NULL) *p = format; return p; } /** * Get list of additional wl_shm pixel formats * * \param display The display object * * This function returns the list of addition wl_shm pixel formats * that the compositor supports. WL_SHM_FORMAT_ARGB8888 and * WL_SHM_FORMAT_XRGB8888 are always supported and not included in the * array, but all formats added through wl_display_add_shm_format() * will be in the array. * * \sa wl_display_add_shm_format() * * \private * * \memberof wl_display */ struct wl_array * wl_display_get_additional_shm_formats(struct wl_display *display) { return &display->additional_shm_formats; } /** Get the list of currently connected clients * * \param display The display object * * This function returns a pointer to the list of clients currently * connected to the display. You can iterate on the list by using * the \a wl_client_for_each macro. * The returned value is valid for the lifetime of the \a display. * You must not modify the returned list, but only access it. * * \sa wl_client_for_each() * \sa wl_client_get_link() * \sa wl_client_from_link() * * \memberof wl_display */ WL_EXPORT struct wl_list * wl_display_get_client_list(struct wl_display *display) { return &display->client_list; } /** Get the link by which a client is inserted in the client list * * \param client The client object * * \sa wl_client_for_each() * \sa wl_display_get_client_list() * \sa wl_client_from_link() * * \memberof wl_client */ WL_EXPORT struct wl_list * wl_client_get_link(struct wl_client *client) { return &client->link; } /** Get a wl_client by its link * * \param link The link of a wl_client * * \sa wl_client_for_each() * \sa wl_display_get_client_list() * \sa wl_client_get_link() * * \memberof wl_client */ WL_EXPORT struct wl_client * wl_client_from_link(struct wl_list *link) { struct wl_client *client; return wl_container_of(link, client, link); } /** Add a listener for the client's resource creation signal * * \param client The client object * \param listener The listener to be added * * When a new resource is created for this client the listener * will be notified, carrying the new resource as the data argument. * * \memberof wl_client */ WL_EXPORT void wl_client_add_resource_created_listener(struct wl_client *client, struct wl_listener *listener) { wl_priv_signal_add(&client->resource_created_signal, listener); } struct wl_resource_iterator_context { void *user_data; wl_client_for_each_resource_iterator_func_t it; }; static enum wl_iterator_result resource_iterator_helper(void *res, void *user_data, uint32_t flags) { struct wl_resource_iterator_context *context = user_data; struct wl_resource *resource = res; return context->it(resource, context->user_data); } /** Iterate over all the resources of a client * * \param client The client object * \param iterator The iterator function * \param user_data The user data pointer * * The function pointed by \a iterator will be called for each * resource owned by the client. The \a user_data will be passed * as the second argument of the iterator function. * If the \a iterator function returns \a WL_ITERATOR_CONTINUE the iteration * will continue, if it returns \a WL_ITERATOR_STOP it will stop. * * Creating and destroying resources while iterating is safe, but new * resources may or may not be picked up by the iterator. * * \sa wl_iterator_result * * \memberof wl_client */ WL_EXPORT void wl_client_for_each_resource(struct wl_client *client, wl_client_for_each_resource_iterator_func_t iterator, void *user_data) { struct wl_resource_iterator_context context = { .user_data = user_data, .it = iterator, }; wl_map_for_each(&client->objects, resource_iterator_helper, &context); } static void handle_noop(struct wl_listener *listener, void *data) { /* Do nothing */ } /** Emits this signal, notifying all registered listeners. * * A safer version of wl_signal_emit() which can gracefully handle additions * and deletions of any signal listener from within listener notification * callbacks. * * Listeners deleted during a signal emission and which have not already been * notified at the time of deletion are not notified by that emission. * * Listeners added (or readded) during signal emission are ignored by that * emission. * * Note that repurposing a listener without explicitly removing it and readding * it is not supported and can lead to unexpected behavior. * * \param signal The signal object that will emit the signal * \param data The data that will be emitted with the signal * * \memberof wl_signal * \since 1.20.90 */ WL_EXPORT void wl_signal_emit_mutable(struct wl_signal *signal, void *data) { struct wl_listener cursor; struct wl_listener end; /* Add two special markers: one cursor and one end marker. This way, we * know that we've already called listeners on the left of the cursor * and that we don't want to call listeners on the right of the end * marker. The 'it' function can remove any element it wants from the * list without troubles. * * There was a previous attempt that used to steal the whole list of * listeners but then that broke wl_signal_get(). * * wl_list_for_each_safe tries to be safe but it fails: it works fine * if the current item is removed, but not if the next one is. */ wl_list_insert(&signal->listener_list, &cursor.link); cursor.notify = handle_noop; wl_list_insert(signal->listener_list.prev, &end.link); end.notify = handle_noop; while (cursor.link.next != &end.link) { struct wl_list *pos = cursor.link.next; struct wl_listener *l = wl_container_of(pos, l, link); wl_list_remove(&cursor.link); wl_list_insert(pos, &cursor.link); l->notify(l, data); } wl_list_remove(&cursor.link); wl_list_remove(&end.link); } /** Adjust the maximum size of the client connection buffers * * \param client The client object * \param max_buffer_size The maximum size of the connection buffers * * The actual size of the connection buffers is a power of two, the requested * \a max_buffer_size is therefore rounded up to the nearest power of two value. * * Lowering the maximum size may not take effect immediately if the current content * of the buffer does not fit within the new size limit. * * The minimum buffer size is 4096. The default buffers size can be set using * wl_display_set_default_max_buffer_size(). * * \sa wl_display_set_default_max_buffer_size() * * \memberof wl_client * \since 1.22.90 */ WL_EXPORT void wl_client_set_max_buffer_size(struct wl_client *client, size_t max_buffer_size) { if (max_buffer_size < WL_BUFFER_DEFAULT_MAX_SIZE) max_buffer_size = WL_BUFFER_DEFAULT_MAX_SIZE; wl_connection_set_max_buffer_size(client->connection, max_buffer_size); } /** \cond INTERNAL */ /** Initialize a wl_priv_signal object * * wl_priv_signal is a safer implementation of a signal type, with the same API * as wl_signal, but kept as a private utility of libwayland-server. * It is safer because listeners can be removed from within wl_priv_signal_emit() * without corrupting the signal's list. * * Before passing a wl_priv_signal object to any other function it must be * initialized by using wl_priv_signal_init(). * * \memberof wl_priv_signal */ void wl_priv_signal_init(struct wl_priv_signal *signal) { wl_list_init(&signal->listener_list); wl_list_init(&signal->emit_list); } /** Add a listener to a signal * * The new listener will be called when calling wl_signal_emit(). If a listener is * added to the signal while wl_signal_emit() is running it will be called from * the next time wl_priv_signal_emit() is called. * To remove a listener call wl_list_remove() on its link member. * * \memberof wl_priv_signal */ void wl_priv_signal_add(struct wl_priv_signal *signal, struct wl_listener *listener) { wl_list_insert(signal->listener_list.prev, &listener->link); } /** Get a listener added to a signal * * Returns the listener added to the given \a signal and with the given * \a notify function, or NULL if there isn't any. * Calling this function from within wl_priv_signal_emit() is safe and will * return the correct value. * * \memberof wl_priv_signal */ struct wl_listener * wl_priv_signal_get(struct wl_priv_signal *signal, wl_notify_func_t notify) { struct wl_listener *l; wl_list_for_each(l, &signal->listener_list, link) if (l->notify == notify) return l; wl_list_for_each(l, &signal->emit_list, link) if (l->notify == notify) return l; return NULL; } /** Emit the signal, calling all the installed listeners * * Iterate over all the listeners added to this \a signal and call * their \a notify function pointer, passing on the given \a data. * Removing or adding a listener from within wl_priv_signal_emit() * is safe. */ void wl_priv_signal_emit(struct wl_priv_signal *signal, void *data) { struct wl_listener *l; struct wl_list *pos; wl_list_insert_list(&signal->emit_list, &signal->listener_list); wl_list_init(&signal->listener_list); /* Take every element out of the list and put them in a temporary list. * This way, the 'it' func can remove any element it wants from the list * without troubles, because we always get the first element, not the * one after the current, which may be invalid. * wl_list_for_each_safe tries to be safe but it fails: it works fine * if the current item is removed, but not if the next one is. */ while (!wl_list_empty(&signal->emit_list)) { pos = signal->emit_list.next; l = wl_container_of(pos, l, link); wl_list_remove(pos); wl_list_insert(&signal->listener_list, pos); l->notify(l, data); } } /** Emit the signal for the last time, calling all the installed listeners * * Iterate over all the listeners added to this \a signal and call * their \a notify function pointer, passing on the given \a data. * Removing or adding a listener from within wl_priv_signal_emit() * is safe, as is freeing the structure containing the listener. * * A large body of external code assumes it's ok to free a destruction * listener without removing that listener from the list. Mixing code * that acts like this and code that doesn't will result in list * corruption. * * We resolve this by removing each item from the list and isolating it * in another list. We discard it completely after firing the notifier. * This should allow interoperability between code that unlinks its * destruction listeners and code that just frees structures they're in. * */ void wl_priv_signal_final_emit(struct wl_priv_signal *signal, void *data) { struct wl_listener *l; struct wl_list *pos; /* During a destructor notifier isolate every list item before * notifying. This renders harmless the long standing misuse * of freeing listeners without removing them, but allows * callers that do choose to remove them to interoperate with * ones that don't. */ while (!wl_list_empty(&signal->listener_list)) { pos = signal->listener_list.next; l = wl_container_of(pos, l, link); wl_list_remove(pos); wl_list_init(pos); l->notify(l, data); } } /** \endcond INTERNAL */ /** \cond */ /* Deprecated functions below. */ WL_DEPRECATED uint32_t wl_client_add_resource(struct wl_client *client, struct wl_resource *resource); WL_EXPORT uint32_t wl_client_add_resource(struct wl_client *client, struct wl_resource *resource) { if (resource->object.id == 0) { resource->object.id = wl_map_insert_new(&client->objects, WL_MAP_ENTRY_LEGACY, resource); if (resource->object.id == 0) return 0; } else if (wl_map_insert_at(&client->objects, WL_MAP_ENTRY_LEGACY, resource->object.id, resource) < 0) { if (errno == EINVAL) { wl_resource_post_error(client->display_resource, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid new id %d", resource->object.id); } return 0; } resource->client = client; wl_signal_init(&resource->deprecated_destroy_signal); return resource->object.id; } WL_DEPRECATED struct wl_resource * wl_client_add_object(struct wl_client *client, const struct wl_interface *interface, const void *implementation, uint32_t id, void *data); WL_EXPORT struct wl_resource * wl_client_add_object(struct wl_client *client, const struct wl_interface *interface, const void *implementation, uint32_t id, void *data) { struct wl_resource *resource; resource = wl_resource_create(client, interface, -1, id); if (resource == NULL) wl_client_post_no_memory(client); else wl_resource_set_implementation(resource, implementation, data, NULL); return resource; } WL_DEPRECATED struct wl_resource * wl_client_new_object(struct wl_client *client, const struct wl_interface *interface, const void *implementation, void *data); WL_EXPORT struct wl_resource * wl_client_new_object(struct wl_client *client, const struct wl_interface *interface, const void *implementation, void *data) { struct wl_resource *resource; resource = wl_resource_create(client, interface, -1, 0); if (resource == NULL) wl_client_post_no_memory(client); else wl_resource_set_implementation(resource, implementation, data, NULL); return resource; } /** Set the client's user data * * User data is whatever the caller wants to store. Use dtor if * the user data needs freeing as the very last step of destroying * the client. * * \param client The client object * \param data The user data pointer * \param dtor Destroy function to be called after all resources have been * destroyed and all destroy listeners have been called. Can be NULL. * * The argument to the destroy function is the user data pointer. If the * destroy function is not NULL, it will be called even if user data is NULL. * * \since 1.22.90 * \sa wl_client_get_user_data */ WL_EXPORT void wl_client_set_user_data(struct wl_client *client, void *data, wl_user_data_destroy_func_t dtor) { client->data = data; client->data_dtor = dtor; } /** Get the client's user data * * \param client The client object * \return The user data pointer * * \since 1.22.90 * \sa wl_client_set_user_data */ WL_EXPORT void * wl_client_get_user_data(struct wl_client *client) { return client->data; } WL_DEPRECATED struct wl_global * wl_display_add_global(struct wl_display *display, const struct wl_interface *interface, void *data, wl_global_bind_func_t bind); WL_EXPORT struct wl_global * wl_display_add_global(struct wl_display *display, const struct wl_interface *interface, void *data, wl_global_bind_func_t bind) { return wl_global_create(display, interface, interface->version, data, bind); } WL_DEPRECATED void wl_display_remove_global(struct wl_display *display, struct wl_global *global); WL_EXPORT void wl_display_remove_global(struct wl_display *display, struct wl_global *global) { wl_global_destroy(global); } /** \endcond */ /* Functions at the end of this file are deprecated. Instead of adding new * code here, add it before the comment above that states: * Deprecated functions below. */ wayland-1.23.1/src/wayland-server.h000066400000000000000000000062451466237767300171740ustar00rootroot00000000000000/* * Copyright © 2008 Kristian Høgsberg * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** \file * * \brief Include the server API, deprecations and protocol C API. * * \warning Use of this header file is discouraged. Prefer including * wayland-server-core.h instead, which does not include the * server protocol header and as such only defines the library * API, excluding the deprecated API below. */ #ifndef WAYLAND_SERVER_H #define WAYLAND_SERVER_H #include #include "wayland-server-core.h" #ifdef __cplusplus extern "C" { #endif /* * The user can set this macro to hide the wl_object, wl_resource and wl_buffer * objects alongside the associated API. * * The structs were meant to be opaque, although we missed that in the early days. * * NOTE: the list of structs, functions, etc in this section MUST NEVER GROW. * Otherwise we will break forward compatibility and applications that used to * build fine will no longer be able to do so. */ #ifndef WL_HIDE_DEPRECATED struct wl_object { const struct wl_interface *interface; const void *implementation; uint32_t id; }; struct wl_resource { struct wl_object object; wl_resource_destroy_func_t destroy; struct wl_list link; struct wl_signal destroy_signal; struct wl_client *client; void *data; }; WL_DEPRECATED uint32_t wl_client_add_resource(struct wl_client *client, struct wl_resource *resource); WL_DEPRECATED struct wl_resource * wl_client_add_object(struct wl_client *client, const struct wl_interface *interface, const void *implementation, uint32_t id, void *data); WL_DEPRECATED struct wl_resource * wl_client_new_object(struct wl_client *client, const struct wl_interface *interface, const void *implementation, void *data); WL_DEPRECATED struct wl_global * wl_display_add_global(struct wl_display *display, const struct wl_interface *interface, void *data, wl_global_bind_func_t bind); WL_DEPRECATED void wl_display_remove_global(struct wl_display *display, struct wl_global *global); #endif #ifdef __cplusplus } #endif #include "wayland-server-protocol.h" #endif wayland-1.23.1/src/wayland-shm.c000066400000000000000000000442721466237767300164520ustar00rootroot00000000000000/* * Copyright © 2008 Kristian Høgsberg * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Kristian Høgsberg * Benjamin Franzke * */ #define _GNU_SOURCE #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wayland-os.h" #include "wayland-util.h" #include "wayland-private.h" #include "wayland-server.h" /* This once_t is used to synchronize installing the SIGBUS handler * and creating the TLS key. This will be done in the first call * wl_shm_buffer_begin_access which can happen from any thread */ static pthread_once_t wl_shm_sigbus_once = PTHREAD_ONCE_INIT; static pthread_key_t wl_shm_sigbus_data_key; static struct sigaction wl_shm_old_sigbus_action; struct wl_shm_pool { struct wl_resource *resource; int internal_refcount; int external_refcount; char *data; ssize_t size; ssize_t new_size; #ifndef MREMAP_MAYMOVE /* The following three fields are needed for mremap() emulation. */ int mmap_fd; int mmap_flags; int mmap_prot; #endif bool sigbus_is_impossible; }; /** \class wl_shm_buffer * * \brief A SHM buffer * * wl_shm_buffer provides a helper for accessing the contents of a wl_buffer * resource created via the wl_shm interface. * * A wl_shm_buffer becomes invalid as soon as its #wl_resource is destroyed. */ struct wl_shm_buffer { struct wl_resource *resource; int32_t width, height; int32_t stride; uint32_t format; int offset; struct wl_shm_pool *pool; }; struct wl_shm_sigbus_data { struct wl_shm_pool *current_pool; int access_count; int fallback_mapping_used; }; static void * shm_pool_grow_mapping(struct wl_shm_pool *pool) { void *data; #ifdef MREMAP_MAYMOVE data = mremap(pool->data, pool->size, pool->new_size, MREMAP_MAYMOVE); #else data = wl_os_mremap_maymove(pool->mmap_fd, pool->data, &pool->size, pool->new_size, pool->mmap_prot, pool->mmap_flags); if (pool->size != 0 && pool->resource != NULL) { wl_resource_post_error(pool->resource, WL_SHM_ERROR_INVALID_FD, "leaked old mapping"); } #endif return data; } static void shm_pool_finish_resize(struct wl_shm_pool *pool) { void *data; if (pool->size == pool->new_size) return; data = shm_pool_grow_mapping(pool); if (data == MAP_FAILED) { if (pool->resource != NULL) wl_resource_post_error(pool->resource, WL_SHM_ERROR_INVALID_FD, "failed mremap"); return; } pool->data = data; pool->size = pool->new_size; } static void shm_pool_unref(struct wl_shm_pool *pool, bool external) { if (external) { pool->external_refcount--; assert(pool->external_refcount >= 0); if (pool->external_refcount == 0) shm_pool_finish_resize(pool); } else { pool->internal_refcount--; assert(pool->internal_refcount >= 0); } if (pool->internal_refcount + pool->external_refcount > 0) return; munmap(pool->data, pool->size); #ifndef MREMAP_MAYMOVE close(pool->mmap_fd); #endif free(pool); } static void destroy_buffer(struct wl_resource *resource) { struct wl_shm_buffer *buffer = wl_resource_get_user_data(resource); shm_pool_unref(buffer->pool, false); free(buffer); } static void shm_buffer_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); } static const struct wl_buffer_interface shm_buffer_interface = { shm_buffer_destroy }; static bool format_is_supported(struct wl_client *client, uint32_t format) { struct wl_display *display = wl_client_get_display(client); struct wl_array *formats; uint32_t *p; switch (format) { case WL_SHM_FORMAT_ARGB8888: case WL_SHM_FORMAT_XRGB8888: return true; default: formats = wl_display_get_additional_shm_formats(display); wl_array_for_each(p, formats) if (*p == format) return true; } return false; } static void shm_pool_create_buffer(struct wl_client *client, struct wl_resource *resource, uint32_t id, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) { struct wl_shm_pool *pool = wl_resource_get_user_data(resource); struct wl_shm_buffer *buffer; if (!format_is_supported(client, format)) { wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FORMAT, "invalid format 0x%x", format); return; } if (offset < 0 || width <= 0 || height <= 0 || stride < width || INT32_MAX / stride < height || offset > pool->size - stride * height) { wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_STRIDE, "invalid width, height or stride (%dx%d, %u)", width, height, stride); return; } buffer = zalloc(sizeof *buffer); if (buffer == NULL) { wl_client_post_no_memory(client); return; } buffer->width = width; buffer->height = height; buffer->format = format; buffer->stride = stride; buffer->offset = offset; buffer->pool = pool; pool->internal_refcount++; buffer->resource = wl_resource_create(client, &wl_buffer_interface, 1, id); if (buffer->resource == NULL) { wl_client_post_no_memory(client); shm_pool_unref(pool, false); free(buffer); return; } wl_resource_set_implementation(buffer->resource, &shm_buffer_interface, buffer, destroy_buffer); } static void destroy_pool(struct wl_resource *resource) { struct wl_shm_pool *pool = wl_resource_get_user_data(resource); pool->resource = NULL; shm_pool_unref(pool, false); } static void shm_pool_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); } static void shm_pool_resize(struct wl_client *client, struct wl_resource *resource, int32_t size) { struct wl_shm_pool *pool = wl_resource_get_user_data(resource); if (size < pool->size) { wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FD, "shrinking pool invalid"); return; } pool->new_size = size; /* If the compositor has taken references on this pool it * may be caching pointers into it. In that case we * defer the resize (which may move the entire mapping) * until the compositor finishes dereferencing the pool. */ if (pool->external_refcount == 0) shm_pool_finish_resize(pool); } static const struct wl_shm_pool_interface shm_pool_interface = { shm_pool_create_buffer, shm_pool_destroy, shm_pool_resize }; static void shm_create_pool(struct wl_client *client, struct wl_resource *resource, uint32_t id, int fd, int32_t size) { struct wl_shm_pool *pool; struct stat statbuf; int seals; int prot; int flags; uint32_t version; if (size <= 0) { wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_STRIDE, "invalid size (%d)", size); goto err_close; } pool = zalloc(sizeof *pool); if (pool == NULL) { wl_client_post_no_memory(client); goto err_close; } #ifdef HAVE_MEMFD_CREATE seals = fcntl(fd, F_GET_SEALS); if (seals == -1) seals = 0; if ((seals & F_SEAL_SHRINK) && fstat(fd, &statbuf) >= 0) pool->sigbus_is_impossible = statbuf.st_size >= size; else pool->sigbus_is_impossible = false; #else pool->sigbus_is_impossible = false; #endif pool->internal_refcount = 1; pool->external_refcount = 0; pool->size = size; pool->new_size = size; prot = PROT_READ | PROT_WRITE; flags = MAP_SHARED; pool->data = mmap(NULL, size, prot, flags, fd, 0); if (pool->data == MAP_FAILED) { wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FD, "failed mmap fd %d: %s", fd, strerror(errno)); goto err_free; } #ifndef MREMAP_MAYMOVE /* We may need to keep the fd, prot and flags to emulate mremap(). */ pool->mmap_fd = fd; pool->mmap_prot = prot; pool->mmap_flags = flags; #else close(fd); #endif version = wl_resource_get_version(resource); pool->resource = wl_resource_create(client, &wl_shm_pool_interface, version, id); if (!pool->resource) { wl_client_post_no_memory(client); munmap(pool->data, pool->size); free(pool); return; } wl_resource_set_implementation(pool->resource, &shm_pool_interface, pool, destroy_pool); return; err_free: free(pool); err_close: close(fd); } static void shm_release(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); } static const struct wl_shm_interface shm_interface = { shm_create_pool, shm_release, }; static void bind_shm(struct wl_client *client, void *data, uint32_t version, uint32_t id) { struct wl_resource *resource; struct wl_display *display = wl_client_get_display(client); struct wl_array *additional_formats; uint32_t *p; resource = wl_resource_create(client, &wl_shm_interface, version, id); if (!resource) { wl_client_post_no_memory(client); return; } wl_resource_set_implementation(resource, &shm_interface, data, NULL); wl_shm_send_format(resource, WL_SHM_FORMAT_ARGB8888); wl_shm_send_format(resource, WL_SHM_FORMAT_XRGB8888); additional_formats = wl_display_get_additional_shm_formats(display); wl_array_for_each(p, additional_formats) wl_shm_send_format(resource, *p); } WL_EXPORT int wl_display_init_shm(struct wl_display *display) { if (!wl_global_create(display, &wl_shm_interface, 2, NULL, bind_shm)) return -1; return 0; } WL_EXPORT struct wl_shm_buffer * wl_shm_buffer_get(struct wl_resource *resource) { if (resource == NULL) return NULL; if (wl_resource_instance_of(resource, &wl_buffer_interface, &shm_buffer_interface)) return wl_resource_get_user_data(resource); else return NULL; } WL_EXPORT int32_t wl_shm_buffer_get_stride(struct wl_shm_buffer *buffer) { return buffer->stride; } /** Get a pointer to the memory for the SHM buffer * * \param buffer The buffer object * * Returns a pointer which can be used to read the data contained in * the given SHM buffer. * * As this buffer is memory-mapped, reading from it may generate * SIGBUS signals. This can happen if the client claims that the * buffer is larger than it is or if something truncates the * underlying file. To prevent this signal from causing the compositor * to crash you should call wl_shm_buffer_begin_access and * wl_shm_buffer_end_access around code that reads from the memory. * * \memberof wl_shm_buffer */ WL_EXPORT void * wl_shm_buffer_get_data(struct wl_shm_buffer *buffer) { if (buffer->pool->external_refcount && (buffer->pool->size != buffer->pool->new_size)) wl_log("Buffer address requested when its parent pool " "has an external reference and a deferred resize " "pending.\n"); return buffer->pool->data + buffer->offset; } WL_EXPORT uint32_t wl_shm_buffer_get_format(struct wl_shm_buffer *buffer) { return buffer->format; } WL_EXPORT int32_t wl_shm_buffer_get_width(struct wl_shm_buffer *buffer) { return buffer->width; } WL_EXPORT int32_t wl_shm_buffer_get_height(struct wl_shm_buffer *buffer) { return buffer->height; } /** Get a reference to a shm_buffer's shm_pool * * \param buffer The buffer object * * Returns a pointer to a buffer's shm_pool and increases the * shm_pool refcount. * * The compositor must remember to call wl_shm_pool_unref when * it no longer needs the reference to ensure proper destruction * of the pool. * * \memberof wl_shm_buffer * \sa wl_shm_pool_unref */ WL_EXPORT struct wl_shm_pool * wl_shm_buffer_ref_pool(struct wl_shm_buffer *buffer) { assert(buffer->pool->internal_refcount + buffer->pool->external_refcount); buffer->pool->external_refcount++; return buffer->pool; } /** Unreference a shm_pool * * \param pool The pool object * * Drops a reference to a wl_shm_pool object. * * This is only necessary if the compositor has explicitly * taken a reference with wl_shm_buffer_ref_pool(), otherwise * the pool will be automatically destroyed when appropriate. * * \memberof wl_shm_pool * \sa wl_shm_buffer_ref_pool */ WL_EXPORT void wl_shm_pool_unref(struct wl_shm_pool *pool) { shm_pool_unref(pool, true); } static void reraise_sigbus(void) { /* If SIGBUS is raised for some other reason than accessing * the pool then we'll uninstall the signal handler so we can * reraise it. This would presumably kill the process */ sigaction(SIGBUS, &wl_shm_old_sigbus_action, NULL); raise(SIGBUS); } static void sigbus_handler(int signum, siginfo_t *info, void *context) { struct wl_shm_sigbus_data *sigbus_data = pthread_getspecific(wl_shm_sigbus_data_key); struct wl_shm_pool *pool; if (sigbus_data == NULL) { reraise_sigbus(); return; } pool = sigbus_data->current_pool; /* If the offending address is outside the mapped space for * the pool then the error is a real problem so we'll reraise * the signal */ if (pool == NULL || (char *) info->si_addr < pool->data || (char *) info->si_addr >= pool->data + pool->size) { reraise_sigbus(); return; } sigbus_data->fallback_mapping_used = 1; /* This should replace the previous mapping */ if (mmap(pool->data, pool->size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0, 0) == MAP_FAILED) { reraise_sigbus(); return; } } static void destroy_sigbus_data(void *data) { struct wl_shm_sigbus_data *sigbus_data = data; free(sigbus_data); } static void init_sigbus_data_key(void) { struct sigaction new_action = { .sa_sigaction = sigbus_handler, .sa_flags = SA_SIGINFO | SA_NODEFER }; sigemptyset(&new_action.sa_mask); sigaction(SIGBUS, &new_action, &wl_shm_old_sigbus_action); pthread_key_create(&wl_shm_sigbus_data_key, destroy_sigbus_data); } /** Mark that the given SHM buffer is about to be accessed * * \param buffer The SHM buffer * * An SHM buffer is a memory-mapped file given by the client. * According to POSIX, reading from a memory-mapped region that * extends off the end of the file will cause a SIGBUS signal to be * generated. Normally this would cause the compositor to terminate. * In order to make the compositor robust against clients that change * the size of the underlying file or lie about its size, you should * protect access to the buffer by calling this function before * reading from the memory and call wl_shm_buffer_end_access * afterwards. This will install a signal handler for SIGBUS which * will prevent the compositor from crashing. * * After calling this function the signal handler will remain * installed for the lifetime of the compositor process. Note that * this function will not work properly if the compositor is also * installing its own handler for SIGBUS. * * If a SIGBUS signal is received for an address within the range of * the SHM pool of the given buffer then the client will be sent an * error event when wl_shm_buffer_end_access is called. If the signal * is for an address outside that range then the signal handler will * reraise the signal which would will likely cause the compositor to * terminate. * * It is safe to nest calls to these functions as long as the nested * calls are all accessing the same buffer. The number of calls to * wl_shm_buffer_end_access must match the number of calls to * wl_shm_buffer_begin_access. These functions are thread-safe and it * is allowed to simultaneously access different buffers or the same * buffer from multiple threads. * * \memberof wl_shm_buffer */ WL_EXPORT void wl_shm_buffer_begin_access(struct wl_shm_buffer *buffer) { struct wl_shm_pool *pool = buffer->pool; struct wl_shm_sigbus_data *sigbus_data; if (pool->sigbus_is_impossible) return; pthread_once(&wl_shm_sigbus_once, init_sigbus_data_key); sigbus_data = pthread_getspecific(wl_shm_sigbus_data_key); if (sigbus_data == NULL) { sigbus_data = zalloc(sizeof *sigbus_data); if (sigbus_data == NULL) return; pthread_setspecific(wl_shm_sigbus_data_key, sigbus_data); } assert(sigbus_data->current_pool == NULL || sigbus_data->current_pool == pool); sigbus_data->current_pool = pool; sigbus_data->access_count++; } /** Ends the access to a buffer started by wl_shm_buffer_begin_access * * \param buffer The SHM buffer * * This should be called after wl_shm_buffer_begin_access once the * buffer is no longer being accessed. If a SIGBUS signal was * generated in-between these two calls then the resource for the * given buffer will be sent an error. * * \memberof wl_shm_buffer */ WL_EXPORT void wl_shm_buffer_end_access(struct wl_shm_buffer *buffer) { struct wl_shm_pool *pool = buffer->pool; struct wl_shm_sigbus_data *sigbus_data; if (pool->sigbus_is_impossible) return; sigbus_data = pthread_getspecific(wl_shm_sigbus_data_key); assert(sigbus_data && sigbus_data->access_count >= 1); if (--sigbus_data->access_count == 0) { if (sigbus_data->fallback_mapping_used) { wl_resource_post_error(buffer->resource, WL_SHM_ERROR_INVALID_FD, "error accessing SHM buffer"); sigbus_data->fallback_mapping_used = 0; } sigbus_data->current_pool = NULL; } } /** \cond */ /* Deprecated functions below. */ WL_EXPORT struct wl_shm_buffer * wl_shm_buffer_create(struct wl_client *client, uint32_t id, int32_t width, int32_t height, int32_t stride, uint32_t format) { return NULL; } /** \endcond */ /* Functions at the end of this file are deprecated. Instead of adding new * code here, add it before the comment above that states: * Deprecated functions below. */ wayland-1.23.1/src/wayland-util.c000066400000000000000000000227741466237767300166430ustar00rootroot00000000000000/* * Copyright © 2008-2011 Kristian Høgsberg * Copyright © 2011 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 #include #include #include #include #include #include "wayland-util.h" #include "wayland-private.h" WL_EXPORT void wl_list_init(struct wl_list *list) { list->prev = list; list->next = list; } WL_EXPORT void wl_list_insert(struct wl_list *list, struct wl_list *elm) { elm->prev = list; elm->next = list->next; list->next = elm; elm->next->prev = elm; } WL_EXPORT void wl_list_remove(struct wl_list *elm) { elm->prev->next = elm->next; elm->next->prev = elm->prev; elm->next = NULL; elm->prev = NULL; } WL_EXPORT int wl_list_length(const struct wl_list *list) { struct wl_list *e; int count; count = 0; e = list->next; while (e != list) { e = e->next; count++; } return count; } WL_EXPORT int wl_list_empty(const struct wl_list *list) { return list->next == list; } WL_EXPORT void wl_list_insert_list(struct wl_list *list, struct wl_list *other) { if (wl_list_empty(other)) return; other->next->prev = list; other->prev->next = list->next; list->next->prev = other->prev; list->next = other->next; } WL_EXPORT void wl_array_init(struct wl_array *array) { memset(array, 0, sizeof *array); } WL_EXPORT void wl_array_release(struct wl_array *array) { free(array->data); array->data = WL_ARRAY_POISON_PTR; } WL_EXPORT void * wl_array_add(struct wl_array *array, size_t size) { size_t alloc; void *data, *p; if (array->alloc > 0) alloc = array->alloc; else alloc = 16; while (alloc < array->size + size) alloc *= 2; if (array->alloc < alloc) { if (array->alloc > 0) data = realloc(array->data, alloc); else data = malloc(alloc); if (data == NULL) return NULL; array->data = data; array->alloc = alloc; } p = (char *)array->data + array->size; array->size += size; return p; } WL_EXPORT int wl_array_copy(struct wl_array *array, struct wl_array *source) { if (array->size < source->size) { if (!wl_array_add(array, source->size - array->size)) return -1; } else { array->size = source->size; } if (source->size > 0) memcpy(array->data, source->data, source->size); return 0; } /** \cond */ int wl_interface_equal(const struct wl_interface *a, const struct wl_interface *b) { /* In most cases the pointer equality test is sufficient. * However, in some cases, depending on how things are split * across shared objects, we can end up with multiple * instances of the interface metadata constants. So if the * pointers match, the interfaces are equal, if they don't * match we have to compare the interface names. */ return a == b || strcmp(a->name, b->name) == 0; } union map_entry { uintptr_t next; void *data; }; static inline bool map_entry_is_free(union map_entry entry) { return entry.next & 0x1; } static inline void * map_entry_get_data(union map_entry entry) { return (void *)(entry.next & ~(uintptr_t)0x3); } static inline uint32_t map_entry_get_flags(union map_entry entry) { return (entry.next >> 1) & 0x1; } void wl_map_init(struct wl_map *map, uint32_t side) { memset(map, 0, sizeof *map); map->side = side; } void wl_map_release(struct wl_map *map) { wl_array_release(&map->client_entries); wl_array_release(&map->server_entries); } uint32_t wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data) { union map_entry *start, *entry; struct wl_array *entries; uint32_t base; uint32_t count; if (map->side == WL_MAP_CLIENT_SIDE) { entries = &map->client_entries; base = 0; } else { entries = &map->server_entries; base = WL_SERVER_ID_START; } if (map->free_list) { start = entries->data; entry = &start[map->free_list >> 1]; map->free_list = entry->next; } else { entry = wl_array_add(entries, sizeof *entry); if (!entry) return 0; start = entries->data; } /* wl_array only grows, so if we have too many objects at * this point there's no way to clean up. We could be more * pro-active about trying to avoid this allocation, but * it doesn't really matter because at this point there is * nothing to be done but disconnect the client and delete * the whole array either way. */ count = entry - start; if (count > WL_MAP_MAX_OBJECTS) { /* entry->data is freshly malloced garbage, so we'd * better make it a NULL so wl_map_for_each doesn't * dereference it later. */ entry->data = NULL; errno = ENOSPC; return 0; } entry->data = data; entry->next |= (flags & 0x1) << 1; return count + base; } int wl_map_insert_at(struct wl_map *map, uint32_t flags, uint32_t i, void *data) { union map_entry *start; uint32_t count; struct wl_array *entries; if (i < WL_SERVER_ID_START) { entries = &map->client_entries; } else { entries = &map->server_entries; i -= WL_SERVER_ID_START; } if (i > WL_MAP_MAX_OBJECTS) { errno = ENOSPC; return -1; } count = entries->size / sizeof *start; if (count < i) { errno = EINVAL; return -1; } if (count == i) { if (!wl_array_add(entries, sizeof *start)) return -1; } start = entries->data; start[i].data = data; start[i].next |= (flags & 0x1) << 1; return 0; } int wl_map_reserve_new(struct wl_map *map, uint32_t i) { union map_entry *start; uint32_t count; struct wl_array *entries; if (i < WL_SERVER_ID_START) { if (map->side == WL_MAP_CLIENT_SIDE) { errno = EINVAL; return -1; } entries = &map->client_entries; } else { if (map->side == WL_MAP_SERVER_SIDE) { errno = EINVAL; return -1; } entries = &map->server_entries; i -= WL_SERVER_ID_START; } if (i > WL_MAP_MAX_OBJECTS) { errno = ENOSPC; return -1; } count = entries->size / sizeof *start; if (count < i) { errno = EINVAL; return -1; } if (count == i) { if (!wl_array_add(entries, sizeof *start)) return -1; start = entries->data; start[i].data = NULL; } else { start = entries->data; if (start[i].data != NULL) { errno = EINVAL; return -1; } } return 0; } void wl_map_remove(struct wl_map *map, uint32_t i) { union map_entry *start; struct wl_array *entries; if (i < WL_SERVER_ID_START) { if (map->side == WL_MAP_SERVER_SIDE) return; entries = &map->client_entries; } else { if (map->side == WL_MAP_CLIENT_SIDE) return; entries = &map->server_entries; i -= WL_SERVER_ID_START; } start = entries->data; start[i].next = map->free_list; map->free_list = (i << 1) | 1; } void * wl_map_lookup(struct wl_map *map, uint32_t i) { union map_entry *start; uint32_t count; struct wl_array *entries; if (i < WL_SERVER_ID_START) { entries = &map->client_entries; } else { entries = &map->server_entries; i -= WL_SERVER_ID_START; } start = entries->data; count = entries->size / sizeof *start; if (i < count && !map_entry_is_free(start[i])) return map_entry_get_data(start[i]); return NULL; } uint32_t wl_map_lookup_flags(struct wl_map *map, uint32_t i) { union map_entry *start; uint32_t count; struct wl_array *entries; if (i < WL_SERVER_ID_START) { entries = &map->client_entries; } else { entries = &map->server_entries; i -= WL_SERVER_ID_START; } start = entries->data; count = entries->size / sizeof *start; if (i < count && !map_entry_is_free(start[i])) return map_entry_get_flags(start[i]); return 0; } static enum wl_iterator_result for_each_helper(struct wl_array *entries, wl_iterator_func_t func, void *data) { enum wl_iterator_result ret = WL_ITERATOR_CONTINUE; union map_entry entry, *start; size_t count; start = (union map_entry *) entries->data; count = entries->size / sizeof(union map_entry); for (size_t idx = 0; idx < count; idx++) { entry = start[idx]; if (entry.data && !map_entry_is_free(entry)) { ret = func(map_entry_get_data(entry), data, map_entry_get_flags(entry)); if (ret != WL_ITERATOR_CONTINUE) break; } } return ret; } void wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data) { enum wl_iterator_result ret; ret = for_each_helper(&map->client_entries, func, data); if (ret == WL_ITERATOR_CONTINUE) for_each_helper(&map->server_entries, func, data); } static void wl_log_stderr_handler(const char *fmt, va_list arg) { vfprintf(stderr, fmt, arg); } wl_log_func_t wl_log_handler = wl_log_stderr_handler; void wl_log(const char *fmt, ...) { va_list argp; va_start(argp, fmt); wl_log_handler(fmt, argp); va_end(argp); } void wl_abort(const char *fmt, ...) { va_list argp; va_start(argp, fmt); wl_log_handler(fmt, argp); va_end(argp); abort(); } /** \endcond */ wayland-1.23.1/src/wayland-util.h000066400000000000000000000571551466237767300166510ustar00rootroot00000000000000/* * Copyright © 2008 Kristian Høgsberg * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** \file wayland-util.h * * \brief Utility classes, functions, and macros. */ #ifndef WAYLAND_UTIL_H #define WAYLAND_UTIL_H #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** Visibility attribute */ #if defined(__GNUC__) && __GNUC__ >= 4 #define WL_EXPORT __attribute__ ((visibility("default"))) #else #define WL_EXPORT #endif /** Deprecated attribute */ #if __STDC_VERSION__ >= 202311L #define WL_DEPRECATED [[deprecated]] #elif defined(__GNUC__) && __GNUC__ >= 4 #define WL_DEPRECATED __attribute__ ((deprecated)) #else #define WL_DEPRECATED #endif /** * Printf-style argument attribute * * \param x Ordinality of the format string argument * \param y Ordinality of the argument to check against the format string * * \sa https://gcc.gnu.org/onlinedocs/gcc-3.2.1/gcc/Function-Attributes.html */ #if defined(__GNUC__) && __GNUC__ >= 4 #define WL_PRINTF(x, y) __attribute__((__format__(__printf__, x, y))) #else #define WL_PRINTF(x, y) #endif #if __STDC_VERSION__ >= 202311L #define WL_TYPEOF(expr) typeof(expr) #else #define WL_TYPEOF(expr) __typeof__(expr) #endif /** \class wl_object * * \brief A protocol object. * * A `wl_object` is an opaque struct identifying the protocol object * underlying a `wl_proxy` or `wl_resource`. * * \note Functions accessing a `wl_object` are not normally used by client code. * Clients should normally use the higher level interface generated by the * scanner to interact with compositor objects. * */ struct wl_object; /** * Protocol message signature * * A wl_message describes the signature of an actual protocol message, such as a * request or event, that adheres to the Wayland protocol wire format. The * protocol implementation uses a wl_message within its demarshal machinery for * decoding messages between a compositor and its clients. In a sense, a * wl_message is to a protocol message like a class is to an object. * * The `name` of a wl_message is the name of the corresponding protocol message. * * The `signature` is an ordered list of symbols representing the data types * of message arguments and, optionally, a protocol version and indicators for * nullability. A leading integer in the `signature` indicates the _since_ * version of the protocol message. A `?` preceding a data type symbol indicates * that the following argument type is nullable. While it is a protocol violation * to send messages with non-nullable arguments set to `NULL`, event handlers in * clients might still get called with non-nullable object arguments set to * `NULL`. This can happen when the client destroyed the object being used as * argument on its side and an event referencing that object was sent before the * server knew about its destruction. As this race cannot be prevented, clients * should - as a general rule - program their event handlers such that they can * handle object arguments declared non-nullable being `NULL` gracefully. * * When no arguments accompany a message, `signature` is an empty string. * * Symbols: * * * `i`: int * * `u`: uint * * `f`: fixed * * `s`: string * * `o`: object * * `n`: new_id * * `a`: array * * `h`: fd * * `?`: following argument (`o` or `s`) is nullable * * While demarshaling primitive arguments is straightforward, when demarshaling * messages containing `object` or `new_id` arguments, the protocol * implementation often must determine the type of the object. The `types` of a * wl_message is an array of wl_interface references that correspond to `o` and * `n` arguments in `signature`, with `NULL` placeholders for arguments with * non-object types. * * Consider the protocol event wl_display `delete_id` that has a single `uint` * argument. The wl_message is: * * \code * { "delete_id", "u", [NULL] } * \endcode * * Here, the message `name` is `"delete_id"`, the `signature` is `"u"`, and the * argument `types` is `[NULL]`, indicating that the `uint` argument has no * corresponding wl_interface since it is a primitive argument. * * In contrast, consider a `wl_foo` interface supporting protocol request `bar` * that has existed since version 2, and has two arguments: a `uint` and an * object of type `wl_baz_interface` that may be `NULL`. Such a `wl_message` * might be: * * \code * { "bar", "2u?o", [NULL, &wl_baz_interface] } * \endcode * * Here, the message `name` is `"bar"`, and the `signature` is `"2u?o"`. Notice * how the `2` indicates the protocol version, the `u` indicates the first * argument type is `uint`, and the `?o` indicates that the second argument * is an object that may be `NULL`. Lastly, the argument `types` array indicates * that no wl_interface corresponds to the first argument, while the type * `wl_baz_interface` corresponds to the second argument. * * \sa wl_argument * \sa wl_interface * \sa Wire Format */ struct wl_message { /** Message name */ const char *name; /** Message signature */ const char *signature; /** Object argument interfaces */ const struct wl_interface **types; }; /** * Protocol object interface * * A wl_interface describes the API of a protocol object defined in the Wayland * protocol specification. The protocol implementation uses a wl_interface * within its marshalling machinery for encoding client requests. * * The `name` of a wl_interface is the name of the corresponding protocol * interface, and `version` represents the version of the interface. The members * `method_count` and `event_count` represent the number of `methods` (requests) * and `events` in the respective wl_message members. * * For example, consider a protocol interface `foo`, marked as version `1`, with * two requests and one event. * * \code{.xml} * * * * * * \endcode * * Given two wl_message arrays `foo_requests` and `foo_events`, a wl_interface * for `foo` might be: * * \code * struct wl_interface foo_interface = { * "foo", 1, * 2, foo_requests, * 1, foo_events * }; * \endcode * * \note The server side of the protocol may define interface implementation * types that incorporate the term `interface` in their name. Take * care to not confuse these server-side `struct`s with a wl_interface * variable whose name also ends in `interface`. For example, while the * server may define a type `struct wl_foo_interface`, the client may * define a `struct wl_interface wl_foo_interface`. * * \sa wl_message * \sa wl_proxy * \sa Interfaces * \sa Versioning */ struct wl_interface { /** Interface name */ const char *name; /** Interface version */ int version; /** Number of methods (requests) */ int method_count; /** Method (request) signatures */ const struct wl_message *methods; /** Number of events */ int event_count; /** Event signatures */ const struct wl_message *events; }; /** \class wl_list * * \brief Doubly-linked list * * On its own, an instance of `struct wl_list` represents the sentinel head of * a doubly-linked list, and must be initialized using wl_list_init(). * When empty, the list head's `next` and `prev` members point to the list head * itself, otherwise `next` references the first element in the list, and `prev` * refers to the last element in the list. * * Use the `struct wl_list` type to represent both the list head and the links * between elements within the list. Use wl_list_empty() to determine if the * list is empty in O(1). * * All elements in the list must be of the same type. The element type must have * a `struct wl_list` member, often named `link` by convention. Prior to * insertion, there is no need to initialize an element's `link` - invoking * wl_list_init() on an individual list element's `struct wl_list` member is * unnecessary if the very next operation is wl_list_insert(). However, a * common idiom is to initialize an element's `link` prior to removal - ensure * safety by invoking wl_list_init() before wl_list_remove(). * * Consider a list reference `struct wl_list foo_list`, an element type as * `struct element`, and an element's link member as `struct wl_list link`. * * The following code initializes a list and adds three elements to it. * * \code * struct wl_list foo_list; * * struct element { * int foo; * struct wl_list link; * }; * struct element e1, e2, e3; * * wl_list_init(&foo_list); * wl_list_insert(&foo_list, &e1.link); // e1 is the first element * wl_list_insert(&foo_list, &e2.link); // e2 is now the first element * wl_list_insert(&e2.link, &e3.link); // insert e3 after e2 * \endcode * * The list now looks like [e2, e3, e1]. * * The `wl_list` API provides some iterator macros. For example, to iterate * a list in ascending order: * * \code * struct element *e; * wl_list_for_each(e, foo_list, link) { * do_something_with_element(e); * } * \endcode * * See the documentation of each iterator for details. * \sa http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/linux/list.h */ struct wl_list { /** Previous list element */ struct wl_list *prev; /** Next list element */ struct wl_list *next; }; /** * Initializes the list. * * \param list List to initialize * * \memberof wl_list */ void wl_list_init(struct wl_list *list); /** * Inserts an element into the list, after the element represented by \p list. * When \p list is a reference to the list itself (the head), set the containing * struct of \p elm as the first element in the list. * * \note If \p elm is already part of a list, inserting it again will lead to * list corruption. * * \param list List element after which the new element is inserted * \param elm Link of the containing struct to insert into the list * * \memberof wl_list */ void wl_list_insert(struct wl_list *list, struct wl_list *elm); /** * Removes an element from the list. * * \note This operation leaves \p elm in an invalid state. * * \param elm Link of the containing struct to remove from the list * * \memberof wl_list */ void wl_list_remove(struct wl_list *elm); /** * Determines the length of the list. * * \note This is an O(n) operation. * * \param list List whose length is to be determined * * \return Number of elements in the list * * \memberof wl_list */ int wl_list_length(const struct wl_list *list); /** * Determines if the list is empty. * * \param list List whose emptiness is to be determined * * \return 1 if empty, or 0 if not empty * * \memberof wl_list */ int wl_list_empty(const struct wl_list *list); /** * Inserts all of the elements of one list into another, after the element * represented by \p list. * * \note This leaves \p other in an invalid state. * * \param list List element after which the other list elements will be inserted * \param other List of elements to insert * * \memberof wl_list */ void wl_list_insert_list(struct wl_list *list, struct wl_list *other); /** * Retrieves a pointer to a containing struct, given a member name. * * This macro allows "conversion" from a pointer to a member to its containing * struct. This is useful if you have a contained item like a wl_list, * wl_listener, or wl_signal, provided via a callback or other means, and would * like to retrieve the struct that contains it. * * To demonstrate, the following example retrieves a pointer to * `example_container` given only its `destroy_listener` member: * * \code * struct example_container { * struct wl_listener destroy_listener; * // other members... * }; * * void example_container_destroy(struct wl_listener *listener, void *data) * { * struct example_container *ctr; * * ctr = wl_container_of(listener, ctr, destroy_listener); * // destroy ctr... * } * \endcode * * \note `sample` need not be a valid pointer. A null or uninitialised pointer * is sufficient. * * \param ptr Valid pointer to the contained member * \param sample Pointer to a struct whose type contains \p ptr * \param member Named location of \p ptr within the \p sample type * * \return The container for the specified pointer */ #define wl_container_of(ptr, sample, member) \ (WL_TYPEOF(sample))((char *)(ptr) - \ offsetof(WL_TYPEOF(*sample), member)) /** * Iterates over a list. * * This macro expresses a for-each iterator for wl_list. Given a list and * wl_list link member name (often named `link` by convention), this macro * assigns each element in the list to \p pos, which can then be referenced in * a trailing code block. For example, given a wl_list of `struct message` * elements: * * \code * struct message { * char *contents; * wl_list link; * }; * * struct wl_list *message_list; * // Assume message_list now "contains" many messages * * struct message *m; * wl_list_for_each(m, message_list, link) { * do_something_with_message(m); * } * \endcode * * \param pos Cursor that each list element will be assigned to * \param head Head of the list to iterate over * \param member Name of the link member within the element struct * * \relates wl_list */ #define wl_list_for_each(pos, head, member) \ for (pos = wl_container_of((head)->next, pos, member); \ &pos->member != (head); \ pos = wl_container_of(pos->member.next, pos, member)) /** * Iterates over a list, safe against removal of the list element. * * \note Only removal of the current element, \p pos, is safe. Removing * any other element during traversal may lead to a loop malfunction. * * \sa wl_list_for_each() * * \param pos Cursor that each list element will be assigned to * \param tmp Temporary pointer of the same type as \p pos * \param head Head of the list to iterate over * \param member Name of the link member within the element struct * * \relates wl_list */ #define wl_list_for_each_safe(pos, tmp, head, member) \ for (pos = wl_container_of((head)->next, pos, member), \ tmp = wl_container_of((pos)->member.next, tmp, member); \ &pos->member != (head); \ pos = tmp, \ tmp = wl_container_of(pos->member.next, tmp, member)) /** * Iterates backwards over a list. * * \sa wl_list_for_each() * * \param pos Cursor that each list element will be assigned to * \param head Head of the list to iterate over * \param member Name of the link member within the element struct * * \relates wl_list */ #define wl_list_for_each_reverse(pos, head, member) \ for (pos = wl_container_of((head)->prev, pos, member); \ &pos->member != (head); \ pos = wl_container_of(pos->member.prev, pos, member)) /** * Iterates backwards over a list, safe against removal of the list element. * * \note Only removal of the current element, \p pos, is safe. Removing * any other element during traversal may lead to a loop malfunction. * * \sa wl_list_for_each() * * \param pos Cursor that each list element will be assigned to * \param tmp Temporary pointer of the same type as \p pos * \param head Head of the list to iterate over * \param member Name of the link member within the element struct * * \relates wl_list */ #define wl_list_for_each_reverse_safe(pos, tmp, head, member) \ for (pos = wl_container_of((head)->prev, pos, member), \ tmp = wl_container_of((pos)->member.prev, tmp, member); \ &pos->member != (head); \ pos = tmp, \ tmp = wl_container_of(pos->member.prev, tmp, member)) /** * \class wl_array * * Dynamic array * * A wl_array is a dynamic array that can only grow until released. It is * intended for relatively small allocations whose size is variable or not known * in advance. While construction of a wl_array does not require all elements to * be of the same size, wl_array_for_each() does require all elements to have * the same type and size. * */ struct wl_array { /** Array size */ size_t size; /** Allocated space */ size_t alloc; /** Array data */ void *data; }; /** * Initializes the array. * * \param array Array to initialize * * \memberof wl_array */ void wl_array_init(struct wl_array *array); /** * Releases the array data. * * \note Leaves the array in an invalid state. * * \param array Array whose data is to be released * * \memberof wl_array */ void wl_array_release(struct wl_array *array); /** * Increases the size of the array by \p size bytes. * * \param array Array whose size is to be increased * \param size Number of bytes to increase the size of the array by * * \return A pointer to the beginning of the newly appended space, or NULL when * resizing fails. * * \memberof wl_array */ void * wl_array_add(struct wl_array *array, size_t size); /** * Copies the contents of \p source to \p array. * * \param array Destination array to copy to * \param source Source array to copy from * * \return 0 on success, or -1 on failure * * \memberof wl_array */ int wl_array_copy(struct wl_array *array, struct wl_array *source); /** * Iterates over an array. * * This macro expresses a for-each iterator for wl_array. It assigns each * element in the array to \p pos, which can then be referenced in a trailing * code block. \p pos must be a pointer to the array element type, and all * array elements must be of the same type and size. * * \param pos Cursor that each array element will be assigned to * \param array Array to iterate over * * \relates wl_array * \sa wl_list_for_each() */ #define wl_array_for_each(pos, array) \ for (pos = (array)->data; \ (array)->size != 0 && \ (const char *) pos < ((const char *) (array)->data + (array)->size); \ (pos)++) /** * Fixed-point number * * A `wl_fixed_t` is a 24.8 signed fixed-point number with a sign bit, 23 bits * of integer precision and 8 bits of decimal precision. Consider `wl_fixed_t` * as an opaque struct with methods that facilitate conversion to and from * `double` and `int` types. */ typedef int32_t wl_fixed_t; /** * Converts a fixed-point number to a floating-point number. * * \param f Fixed-point number to convert * * \return Floating-point representation of the fixed-point argument */ static inline double wl_fixed_to_double(wl_fixed_t f) { return f / 256.0; } /** * Converts a floating-point number to a fixed-point number. * * \param d Floating-point number to convert * * \return Fixed-point representation of the floating-point argument */ static inline wl_fixed_t wl_fixed_from_double(double d) { return (wl_fixed_t) (d * 256.0); } /** * Converts a fixed-point number to an integer. * * \param f Fixed-point number to convert * * \return Integer component of the fixed-point argument */ static inline int wl_fixed_to_int(wl_fixed_t f) { return f / 256; } /** * Converts an integer to a fixed-point number. * * \param i Integer to convert * * \return Fixed-point representation of the integer argument */ static inline wl_fixed_t wl_fixed_from_int(int i) { return i * 256; } /** * Protocol message argument data types * * This union represents all of the argument types in the Wayland protocol wire * format. The protocol implementation uses wl_argument within its marshalling * machinery for dispatching messages between a client and a compositor. * * \sa wl_message * \sa wl_interface * \sa Wire Format */ union wl_argument { int32_t i; /**< `int` */ uint32_t u; /**< `uint` */ wl_fixed_t f; /**< `fixed` */ const char *s; /**< `string` */ struct wl_object *o; /**< `object` */ uint32_t n; /**< `new_id` */ struct wl_array *a; /**< `array` */ int32_t h; /**< `fd` */ }; /** * Dispatcher function type alias * * A dispatcher is a function that handles the emitting of callbacks in client * code. For programs directly using the C library, this is done by using * libffi to call function pointers. When binding to languages other than C, * dispatchers provide a way to abstract the function calling process to be * friendlier to other function calling systems. * * A dispatcher takes five arguments: The first is the dispatcher-specific * implementation associated with the target object. The second is the object * upon which the callback is being invoked (either wl_proxy or wl_resource). * The third and fourth arguments are the opcode and the wl_message * corresponding to the callback. The final argument is an array of arguments * received from the other process via the wire protocol. * * \param user_data Dispatcher-specific implementation data * \param target Callback invocation target (wl_proxy or `wl_resource`) * \param opcode Callback opcode * \param msg Callback message signature * \param args Array of received arguments * * \return 0 on success, or -1 on failure */ typedef int (*wl_dispatcher_func_t)(const void *user_data, void *target, uint32_t opcode, const struct wl_message *msg, union wl_argument *args); /** * Log function type alias * * The C implementation of the Wayland protocol abstracts the details of * logging. Users may customize the logging behavior, with a function conforming * to the `wl_log_func_t` type, via `wl_log_set_handler_client` and * `wl_log_set_handler_server`. * * A `wl_log_func_t` must conform to the expectations of `vprintf`, and * expects two arguments: a string to write and a corresponding variable * argument list. While the string to write may contain format specifiers and * use values in the variable argument list, the behavior of any `wl_log_func_t` * depends on the implementation. * * \note Take care to not confuse this with `wl_protocol_logger_func_t`, which * is a specific server-side logger for requests and events. * * \param fmt String to write to the log, containing optional format * specifiers * \param args Variable argument list * * \sa wl_log_set_handler_client * \sa wl_log_set_handler_server */ typedef void (*wl_log_func_t)(const char *fmt, va_list args) WL_PRINTF(1, 0); /** * Return value of an iterator function * * \sa wl_client_for_each_resource_iterator_func_t * \sa wl_client_for_each_resource */ enum wl_iterator_result { /** Stop the iteration */ WL_ITERATOR_STOP, /** Continue the iteration */ WL_ITERATOR_CONTINUE }; #ifdef __cplusplus } #endif #endif wayland-1.23.1/src/wayland-version.h.in000066400000000000000000000026261466237767300177570ustar00rootroot00000000000000/* * Copyright © 2012 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. */ #ifndef WAYLAND_VERSION_H #define WAYLAND_VERSION_H #define WAYLAND_VERSION_MAJOR @WAYLAND_VERSION_MAJOR@ #define WAYLAND_VERSION_MINOR @WAYLAND_VERSION_MINOR@ #define WAYLAND_VERSION_MICRO @WAYLAND_VERSION_MICRO@ #define WAYLAND_VERSION "@WAYLAND_VERSION@" #endif wayland-1.23.1/tests/000077500000000000000000000000001466237767300144245ustar00rootroot00000000000000wayland-1.23.1/tests/array-test.c000066400000000000000000000072121466237767300166650ustar00rootroot00000000000000/* * Copyright © 2012 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 #include #include #include "wayland-util.h" #include "wayland-private.h" #include "test-runner.h" TEST(array_init) { struct wl_array array; /* fill with garbage to emulate uninitialized memory */ memset(&array, 0x57, sizeof array); wl_array_init(&array); assert(array.size == 0); assert(array.alloc == 0); assert(array.data == 0); } TEST(array_release) { struct wl_array array; void *ptr; wl_array_init(&array); ptr = wl_array_add(&array, 1); assert(ptr != NULL); assert(array.data != NULL); wl_array_release(&array); assert(array.data == WL_ARRAY_POISON_PTR); } TEST(array_add) { struct mydata { unsigned int a; unsigned int b; double c; double d; }; const unsigned int iterations = 1321; /* this is arbitrary */ const int datasize = sizeof(struct mydata); struct wl_array array; size_t i; wl_array_init(&array); /* add some data */ for (i = 0; i < iterations; i++) { struct mydata* ptr = wl_array_add(&array, datasize); assert(ptr); assert((i + 1) * datasize == array.size); ptr->a = i * 3; ptr->b = 20000 - i; ptr->c = (double)(i); ptr->d = (double)(i / 2.); } /* verify the data */ for (i = 0; i < iterations; ++i) { struct mydata* check = (struct mydata*)array.data + i; assert(check->a == i * 3); assert(check->b == 20000 - i); assert(check->c == (double)(i)); assert(check->d == (double)(i/2.)); } wl_array_release(&array); } TEST(array_copy) { const int iterations = 1529; /* this is arbitrary */ struct wl_array source; struct wl_array copy; int i; wl_array_init(&source); /* add some data */ for (i = 0; i < iterations; i++) { int *p = wl_array_add(&source, sizeof(int)); assert(p); *p = i * 2 + i; } /* copy the array */ wl_array_init(©); wl_array_copy(©, &source); /* check the copy */ for (i = 0; i < iterations; i++) { int *s = (int *)source.data + i; int *c = (int *)copy.data + i; assert(*s == *c); /* verify the values are the same */ assert(s != c); /* ensure the addresses aren't the same */ assert(*s == i * 2 + i); /* sanity check */ } wl_array_release(&source); wl_array_release(©); } TEST(array_for_each) { static const int elements[] = { 77, 12, 45192, 53280, 334455 }; struct wl_array array; int *p; int i; wl_array_init(&array); for (i = 0; i < 5; i++) { p = wl_array_add(&array, sizeof *p); assert(p); *p = elements[i]; } i = 0; wl_array_for_each(p, &array) { assert(*p == elements[i]); i++; } assert(i == 5); wl_array_release(&array); } wayland-1.23.1/tests/client-test.c000066400000000000000000000136541466237767300170340ustar00rootroot00000000000000/* * Copyright © 2012 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 #include #include #include #include #include #include #include #include #include #include "wayland-private.h" #include "wayland-server.h" #include "test-runner.h" struct client_destroy_listener { struct wl_listener listener; bool done; struct wl_listener late_listener; bool late_done; struct wl_listener resource_listener; bool resource_done; }; static void client_destroy_notify(struct wl_listener *l, void *data) { struct client_destroy_listener *listener = wl_container_of(l, listener, listener); listener->done = true; assert(!listener->resource_done); assert(!listener->late_done); } static void client_resource_destroy_notify(struct wl_listener *l, void *data) { struct client_destroy_listener *listener = wl_container_of(l, listener, resource_listener); assert(listener->done); listener->resource_done = true; assert(!listener->late_done); } static void client_late_destroy_notify(struct wl_listener *l, void *data) { struct client_destroy_listener *listener = wl_container_of(l, listener, late_listener); assert(listener->done); assert(listener->resource_done); listener->late_done = true; } static void client_user_data_destroy(void *data) { bool *user_data_destroyed = data; *user_data_destroyed = true; } TEST(client_destroy_listener) { struct wl_display *display; struct wl_client *client; struct wl_resource *resource; struct client_destroy_listener a, b; bool user_data_destroyed = false; int s[2]; assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); display = wl_display_create(); assert(display); client = wl_client_create(display, s[0]); assert(client); wl_client_set_user_data(client, &user_data_destroyed, client_user_data_destroy); assert(wl_client_get_user_data(client) == &user_data_destroyed); resource = wl_resource_create(client, &wl_callback_interface, 1, 0); assert(resource); a.listener.notify = client_destroy_notify; a.done = false; a.resource_listener.notify = client_resource_destroy_notify; a.resource_done = false; a.late_listener.notify = client_late_destroy_notify; a.late_done = false; wl_client_add_destroy_listener(client, &a.listener); wl_resource_add_destroy_listener(resource, &a.resource_listener); wl_client_add_destroy_late_listener(client, &a.late_listener); assert(wl_client_get_destroy_listener(client, client_destroy_notify) == &a.listener); assert(wl_resource_get_destroy_listener(resource, client_resource_destroy_notify) == &a.resource_listener); assert(wl_client_get_destroy_late_listener(client, client_late_destroy_notify) == &a.late_listener); b.listener.notify = client_destroy_notify; b.done = false; b.resource_listener.notify = client_resource_destroy_notify; b.resource_done = false; b.late_listener.notify = client_late_destroy_notify; b.late_done = false; wl_client_add_destroy_listener(client, &b.listener); wl_resource_add_destroy_listener(resource, &b.resource_listener); wl_client_add_destroy_late_listener(client, &b.late_listener); wl_list_remove(&a.listener.link); wl_list_remove(&a.resource_listener.link); wl_list_remove(&a.late_listener.link); assert(!user_data_destroyed); wl_client_destroy(client); assert(!a.done); assert(!a.resource_done); assert(!a.late_done); assert(b.done); assert(b.resource_done); assert(b.late_done); assert(user_data_destroyed); close(s[0]); close(s[1]); wl_display_destroy(display); } static void client_destroy_remove_link_notify(struct wl_listener *l, void *data) { struct wl_client *client = data; struct client_destroy_listener *listener = wl_container_of(l, listener, listener); /* The client destruction signal should not be emitted more than once. */ assert(!listener->done); listener->done = true; /* The client should have been removed from the display's list. */ assert(wl_list_empty(wl_client_get_link(client))); } /* * Tests that wl_client_destroy() will remove the client from the display's * client list to prevent client access during destruction. */ TEST(client_destroy_removes_link) { struct wl_display *display; struct wl_client *client; struct client_destroy_listener destroy_listener; int s[2]; assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); display = wl_display_create(); assert(display); client = wl_client_create(display, s[0]); assert(client); destroy_listener.listener.notify = client_destroy_remove_link_notify; destroy_listener.done = false; wl_client_add_destroy_listener(client, &destroy_listener.listener); assert(wl_client_get_destroy_listener(client, client_destroy_remove_link_notify) == &destroy_listener.listener); wl_client_destroy(client); assert(destroy_listener.done); close(s[0]); close(s[1]); wl_display_destroy(display); } wayland-1.23.1/tests/compositor-introspection-test.c000066400000000000000000000113361466237767300226450ustar00rootroot00000000000000/* * Copyright © 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com * * 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 #include #include #include #include #include #include #include "wayland-client.h" #include "wayland-server.h" #include "test-runner.h" /* Ensure the connection doesn't fail due to lack of XDG_RUNTIME_DIR. */ static const char * require_xdg_runtime_dir(void) { char *val = getenv("XDG_RUNTIME_DIR"); assert(val && val[0] == '/' && "set $XDG_RUNTIME_DIR to run this test"); return val; } struct compositor { struct wl_display *display; struct wl_listener listener; struct wl_client *client; }; static void client_created(struct wl_listener *listener, void *data) { struct compositor *c = wl_container_of(listener, c, listener); c->client = data; } static void check_client_list(struct compositor *compositor) { struct wl_list *client_list; struct wl_client *client, *client_it; int num_clients = 0; client_list = wl_display_get_client_list(compositor->display); wl_client_for_each(client_it, client_list) { num_clients++; client = client_it; } assert(num_clients == 1); /* 'client_it' is not valid here, so we took a copy of the client in the loop. * We could also do this assert in the loop directly, but in case it fails it is * easier to understand the problem when we know that the previous assert passed, * so that there is only one client but the wrong one. */ assert(compositor->client == client); } static const char * setup_compositor(struct compositor *compositor) { const char *socket; require_xdg_runtime_dir(); compositor->display = wl_display_create(); socket = wl_display_add_socket_auto(compositor->display); compositor->listener.notify = client_created; wl_display_add_client_created_listener(compositor->display, &compositor->listener); return socket; } static void cleanup_compositor(struct compositor *compositor) { wl_client_destroy(compositor->client); wl_display_destroy(compositor->display); } TEST(new_client_connect) { const char *socket; struct compositor compositor = { 0 }; struct { struct wl_display *display; } client; socket = setup_compositor(&compositor); client.display = wl_display_connect(socket); wl_event_loop_dispatch(wl_display_get_event_loop(compositor.display), 100); assert(compositor.client != NULL); check_client_list(&compositor); wl_display_disconnect(client.display); cleanup_compositor(&compositor); } struct resource_listener { struct wl_listener listener; int count; }; static void resource_created(struct wl_listener *listener, void *data) { struct resource_listener *l; l = wl_container_of(listener, l, listener); l->count++; } TEST(new_resource) { const char *socket; struct compositor compositor = { 0 }; struct { struct wl_display *display; struct wl_callback *cb; } client; struct resource_listener resource_listener; socket = setup_compositor(&compositor); client.display = wl_display_connect(socket); wl_event_loop_dispatch(wl_display_get_event_loop(compositor.display), 100); resource_listener.count = 0; resource_listener.listener.notify = resource_created; wl_client_add_resource_created_listener(compositor.client, &resource_listener.listener); client.cb = wl_display_sync(client.display); wl_display_flush(client.display); wl_event_loop_dispatch(wl_display_get_event_loop(compositor.display), 100); assert(resource_listener.count == 1); wl_callback_destroy(client.cb); wl_display_disconnect(client.display); cleanup_compositor(&compositor); /* This is defined to be safe also after client destruction */ wl_list_remove(&resource_listener.listener.link); } wayland-1.23.1/tests/connection-test.c000066400000000000000000000562001466237767300177070ustar00rootroot00000000000000/* * Copyright © 2012 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "wayland-private.h" #include "test-runner.h" #include "test-compositor.h" static const char message[] = "Hello, world"; static struct wl_connection * setup(int *s) { struct wl_connection *connection; assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); connection = wl_connection_create(s[0], WL_BUFFER_DEFAULT_MAX_SIZE); assert(connection); return connection; } TEST(connection_create) { struct wl_connection *connection; int s[2]; connection = setup(s); wl_connection_destroy(connection); close(s[0]); close(s[1]); } TEST(connection_write) { struct wl_connection *connection; int s[2]; char buffer[64]; connection = setup(s); assert(wl_connection_write(connection, message, sizeof message) == 0); assert(wl_connection_flush(connection) == sizeof message); assert(read(s[1], buffer, sizeof buffer) == sizeof message); assert(memcmp(message, buffer, sizeof message) == 0); wl_connection_destroy(connection); close(s[0]); close(s[1]); } TEST(connection_data) { struct wl_connection *connection; int s[2]; char buffer[64]; connection = setup(s); assert(write(s[1], message, sizeof message) == sizeof message); assert(wl_connection_read(connection) == sizeof message); wl_connection_copy(connection, buffer, sizeof message); assert(memcmp(message, buffer, sizeof message) == 0); wl_connection_consume(connection, sizeof message); wl_connection_destroy(connection); close(s[0]); close(s[1]); } TEST(connection_queue) { struct wl_connection *connection; int s[2]; char buffer[64]; connection = setup(s); /* Test that wl_connection_queue() puts data in the output * buffer without flush it. Verify that the data did get in * the buffer by writing another message and making sure that * we receive the two messages on the other fd. */ assert(wl_connection_queue(connection, message, sizeof message) == 0); assert(wl_connection_flush(connection) == 0); assert(wl_connection_write(connection, message, sizeof message) == 0); assert(wl_connection_flush(connection) == 2 * sizeof message); assert(read(s[1], buffer, sizeof buffer) == 2 * sizeof message); assert(memcmp(message, buffer, sizeof message) == 0); assert(memcmp(message, buffer + sizeof message, sizeof message) == 0); wl_connection_destroy(connection); close(s[0]); close(s[1]); } static void va_list_wrapper(const char *signature, union wl_argument *args, int count, ...) { va_list ap; va_start(ap, count); wl_argument_from_va_list(signature, args, count, ap); va_end(ap); } TEST(argument_from_va_list) { union wl_argument args[WL_CLOSURE_MAX_ARGS]; struct wl_object fake_object, fake_new_object; struct wl_array fake_array; va_list_wrapper("i", args, 1, 100); assert(args[0].i == 100); va_list_wrapper("is", args, 2, 101, "value"); assert(args[0].i == 101); assert(strcmp(args[1].s, "value") == 0); va_list_wrapper("?iuf?sonah", args, 8, 102, 103, wl_fixed_from_int(104), "value", &fake_object, &fake_new_object, &fake_array, 106); assert(args[0].i == 102); assert(args[1].u == 103); assert(args[2].f == wl_fixed_from_int(104)); assert(strcmp(args[3].s, "value") == 0); assert(args[4].o == &fake_object); assert(args[5].o == &fake_new_object); assert(args[6].a == &fake_array); assert(args[7].h == 106); } struct marshal_data { struct wl_connection *read_connection; struct wl_connection *write_connection; int s[2]; uint32_t buffer[10]; union { uint32_t u; int32_t i; const char *s; int h; } value; }; static void setup_marshal_data(struct marshal_data *data) { assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, data->s) == 0); data->read_connection = wl_connection_create(data->s[0], WL_BUFFER_DEFAULT_MAX_SIZE); assert(data->read_connection); data->write_connection = wl_connection_create(data->s[1], WL_BUFFER_DEFAULT_MAX_SIZE); assert(data->write_connection); } static void release_marshal_data(struct marshal_data *data) { close(wl_connection_destroy(data->read_connection)); close(wl_connection_destroy(data->write_connection)); } static void marshal(struct marshal_data *data, const char *format, int size, ...) { struct wl_closure *closure; static const uint32_t opcode = 4444; static struct wl_object sender = { NULL, NULL, 1234 }; struct wl_message message = { "test", format, NULL }; va_list ap; va_start(ap, size); closure = wl_closure_vmarshal(&sender, opcode, ap, &message); va_end(ap); assert(closure); assert(wl_closure_send(closure, data->write_connection) == 0); wl_closure_destroy(closure); assert(wl_connection_flush(data->write_connection) == size); assert(read(data->s[0], data->buffer, sizeof data->buffer) == size); assert(data->buffer[0] == sender.id); assert(data->buffer[1] == (opcode | (size << 16))); } TEST(connection_marshal) { struct marshal_data data; struct wl_object object; struct wl_array array; static const char text[] = "curry"; setup_marshal_data(&data); marshal(&data, "i", 12, 42); assert(data.buffer[2] == 42); marshal(&data, "u", 12, 55); assert(data.buffer[2] == 55); marshal(&data, "s", 20, "frappo"); assert(data.buffer[2] == 7); assert(strcmp((char *) &data.buffer[3], "frappo") == 0); object.id = 557799; marshal(&data, "o", 12, &object); assert(data.buffer[2] == object.id); marshal(&data, "n", 12, &object); assert(data.buffer[2] == object.id); array.data = (void *) text; array.size = sizeof text; marshal(&data, "a", 20, &array); assert(data.buffer[2] == array.size); assert(memcmp(&data.buffer[3], text, array.size) == 0); release_marshal_data(&data); } static void expected_fail_marshal(int expected_error, const char *format, ...) { struct wl_closure *closure; static const uint32_t opcode = 4444; static const struct wl_interface test_interface = { .name = "test_object" }; static struct wl_object sender = { 0 }; struct wl_message message = { "test", format, NULL }; sender.interface = &test_interface; sender.id = 1234; va_list ap; va_start(ap, format); closure = wl_closure_vmarshal(&sender, opcode, ap, &message); va_end(ap); assert(closure == NULL); assert(errno == expected_error); } static void marshal_send(struct marshal_data *data, const char *format, ...) { struct wl_closure *closure; static const uint32_t opcode = 4444; static struct wl_object sender = { NULL, NULL, 1234 }; struct wl_message message = { "test", format, NULL }; va_list ap; va_start(ap, format); closure = wl_closure_vmarshal(&sender, opcode, ap, &message); va_end(ap); assert(closure); assert(wl_closure_send(closure, data->write_connection) == 0); wl_closure_destroy(closure); } static void expected_fail_marshal_send(struct marshal_data *data, int expected_error, const char *format, ...) { struct wl_closure *closure; static const uint32_t opcode = 4444; static struct wl_object sender = { NULL, NULL, 1234 }; struct wl_message message = { "test", format, NULL }; va_list ap; va_start(ap, format); closure = wl_closure_vmarshal(&sender, opcode, ap, &message); va_end(ap); assert(closure); assert(wl_closure_send(closure, data->write_connection) < 0); assert(errno == expected_error); wl_closure_destroy(closure); } TEST(connection_marshal_nullables) { struct marshal_data data; struct wl_object object; const char text[] = "curry"; setup_marshal_data(&data); expected_fail_marshal(EINVAL, "o", NULL); expected_fail_marshal(EINVAL, "s", NULL); expected_fail_marshal(EINVAL, "a", NULL); marshal(&data, "?o", 12, NULL); assert(data.buffer[2] == 0); marshal(&data, "?s", 12, NULL); assert(data.buffer[2] == 0); object.id = 55293; marshal(&data, "?o", 12, &object); assert(data.buffer[2] == object.id); marshal(&data, "?s", 20, text); assert(data.buffer[2] == sizeof text); assert(strcmp((char *) &data.buffer[3], text) == 0); release_marshal_data(&data); } static void validate_demarshal_u(struct marshal_data *data, struct wl_object *object, uint32_t u) { assert(data->value.u == u); } static void validate_demarshal_i(struct marshal_data *data, struct wl_object *object, int32_t i) { assert(data->value.i == i); } static void validate_demarshal_s(struct marshal_data *data, struct wl_object *object, const char *s) { if (data->value.s != NULL) assert(strcmp(data->value.s, s) == 0); else assert(s == NULL); } static void validate_demarshal_h(struct marshal_data *data, struct wl_object *object, int fd) { struct stat buf1, buf2; assert(fd != data->value.h); fstat(fd, &buf1); fstat(data->value.h, &buf2); assert(buf1.st_dev == buf2.st_dev); assert(buf1.st_ino == buf2.st_ino); close(fd); close(data->value.h); } static void validate_demarshal_f(struct marshal_data *data, struct wl_object *object, wl_fixed_t f) { assert(data->value.i == f); } static void demarshal(struct marshal_data *data, const char *format, uint32_t *msg, void (*func)(void)) { struct wl_message message = { "test", format, NULL }; struct wl_closure *closure; struct wl_map objects; struct wl_object object = { NULL, &func, 0 }; int size = msg[1] >> 16; assert(write(data->s[1], msg, size) == size); assert(wl_connection_read(data->read_connection) == size); wl_map_init(&objects, WL_MAP_SERVER_SIDE); object.id = msg[0]; closure = wl_connection_demarshal(data->read_connection, size, &objects, &message); assert(closure); wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, data); wl_closure_destroy(closure); } TEST(connection_demarshal) { struct marshal_data data; uint32_t msg[10]; setup_marshal_data(&data); data.value.u = 8000; msg[0] = 400200; /* object id */ msg[1] = 12 << 16; /* size = 12, opcode = 0 */ msg[2] = data.value.u; demarshal(&data, "u", msg, (void *) validate_demarshal_u); data.value.i = -557799; msg[0] = 400200; msg[1] = 12 << 16; msg[2] = data.value.i; demarshal(&data, "i", msg, (void *) validate_demarshal_i); data.value.s = "superdude"; msg[0] = 400200; msg[1] = 24 << 16; msg[2] = 10; msg[3 + msg[2]/4] = 0; memcpy(&msg[3], data.value.s, msg[2]); demarshal(&data, "s", msg, (void *) validate_demarshal_s); data.value.s = "superdude"; msg[0] = 400200; msg[1] = 24 << 16; msg[2] = 10; msg[3 + msg[2]/4] = 0; memcpy(&msg[3], data.value.s, msg[2]); demarshal(&data, "?s", msg, (void *) validate_demarshal_s); data.value.i = wl_fixed_from_double(-90000.2390); msg[0] = 400200; msg[1] = 12 << 16; msg[2] = data.value.i; demarshal(&data, "f", msg, (void *) validate_demarshal_f); data.value.s = NULL; msg[0] = 400200; msg[1] = 12 << 16; msg[2] = 0; demarshal(&data, "?s", msg, (void *) validate_demarshal_s); release_marshal_data(&data); } static void marshal_demarshal(struct marshal_data *data, void (*func)(void), int size, const char *format, ...) { struct wl_closure *closure; static const int opcode = 4444; static struct wl_object sender = { NULL, NULL, 1234 }; struct wl_message message = { "test", format, NULL }; struct wl_map objects; struct wl_object object = { NULL, &func, 0 }; va_list ap; uint32_t msg[1] = { 1234 }; va_start(ap, format); closure = wl_closure_vmarshal(&sender, opcode, ap, &message); va_end(ap); assert(closure); assert(wl_closure_send(closure, data->write_connection) == 0); wl_closure_destroy(closure); assert(wl_connection_flush(data->write_connection) == size); assert(wl_connection_read(data->read_connection) == size); wl_map_init(&objects, WL_MAP_SERVER_SIDE); object.id = msg[0]; closure = wl_connection_demarshal(data->read_connection, size, &objects, &message); assert(closure); wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, data); wl_closure_destroy(closure); } TEST(connection_marshal_demarshal) { struct marshal_data data; char f[] = "/tmp/wayland-tests-XXXXXX"; setup_marshal_data(&data); data.value.u = 889911; marshal_demarshal(&data, (void *) validate_demarshal_u, 12, "u", data.value.u); data.value.i = -13; marshal_demarshal(&data, (void *) validate_demarshal_i, 12, "i", data.value.i); data.value.s = "cookie robots"; marshal_demarshal(&data, (void *) validate_demarshal_s, 28, "s", data.value.s); data.value.s = "cookie robots"; marshal_demarshal(&data, (void *) validate_demarshal_s, 28, "?s", data.value.s); data.value.h = mkstemp(f); assert(data.value.h >= 0); unlink(f); marshal_demarshal(&data, (void *) validate_demarshal_h, 8, "h", data.value.h); data.value.i = wl_fixed_from_double(1234.5678); marshal_demarshal(&data, (void *) validate_demarshal_f, 12, "f", data.value.i); data.value.i = wl_fixed_from_double(-90000.2390); marshal_demarshal(&data, (void *) validate_demarshal_f, 12, "f", data.value.i); data.value.i = wl_fixed_from_double((1 << 23) - 1 + 0.0941); marshal_demarshal(&data, (void *) validate_demarshal_f, 12, "f", data.value.i); release_marshal_data(&data); } static void expected_fail_demarshal(struct marshal_data *data, const char *format, const uint32_t *msg, int expected_error) { struct wl_message message = { "test", format, NULL }; struct wl_closure *closure; struct wl_map objects; int size = (msg[1] >> 16); assert(write(data->s[1], msg, size) == size); assert(wl_connection_read(data->read_connection) == size); wl_map_init(&objects, WL_MAP_SERVER_SIDE); closure = wl_connection_demarshal(data->read_connection, size, &objects, &message); assert(closure == NULL); assert(errno == expected_error); } TEST(connection_demarshal_null_strings) { struct marshal_data data; uint32_t msg[3]; setup_marshal_data(&data); data.value.s = NULL; msg[0] = 400200; /* object id */ msg[1] = 12 << 16; /* size = 12, opcode = 0 */ msg[2] = 0; /* string length = 0 */ demarshal(&data, "?s", msg, (void *) validate_demarshal_s); expected_fail_demarshal(&data, "s", msg, EINVAL); release_marshal_data(&data); } /* These tests are verifying that the demarshaling code will gracefully handle * clients lying about string and array lengths and giving values near * UINT32_MAX. Before fixes f7fdface and f5b9e3b9 this test would crash on * 32bit systems. */ TEST(connection_demarshal_failures) { struct marshal_data data; unsigned int i; uint32_t msg[3]; const uint32_t overflowing_values[] = { /* Values very close to UINT32_MAX. Before f5b9e3b9 these * would cause integer overflow in DIV_ROUNDUP. */ 0xffffffff, 0xfffffffe, 0xfffffffd, 0xfffffffc, /* Values at various offsets from UINT32_MAX. Before f7fdface * these would overflow the "p" pointer on 32bit systems, * effectively subtracting the offset from it. It had good * chance to cause crash depending on what was stored at that * offset before "p". */ 0xfffff000, 0xffffd000, 0xffffc000, 0xffffb000 }; setup_marshal_data(&data); /* sender_id, does not matter */ msg[0] = 0; /* (size << 16 | opcode), opcode is 0, does not matter */ msg[1] = sizeof(msg) << 16; for (i = 0; i < ARRAY_LENGTH(overflowing_values); i++) { /* length of the string or array */ msg[2] = overflowing_values[i]; expected_fail_demarshal(&data, "s", msg, EINVAL); expected_fail_demarshal(&data, "a", msg, EINVAL); } release_marshal_data(&data); } TEST(connection_marshal_alot) { struct marshal_data data; char f[64]; int i; setup_marshal_data(&data); /* We iterate enough to make sure we wrap the circular buffers * for both regular data an fds. */ for (i = 0; i < 2000; i++) { strcpy(f, "/tmp/wayland-tests-XXXXXX"); data.value.h = mkstemp(f); assert(data.value.h >= 0); unlink(f); marshal_demarshal(&data, (void *) validate_demarshal_h, 8, "h", data.value.h); } release_marshal_data(&data); } TEST(connection_marshal_too_big) { struct marshal_data data; char *big_string = malloc(5000); assert(big_string); memset(big_string, ' ', 4999); big_string[4999] = '\0'; setup_marshal_data(&data); expected_fail_marshal_send(&data, E2BIG, "s", big_string); release_marshal_data(&data); free(big_string); } TEST(connection_marshal_big_enough) { struct marshal_data data; char *big_string = malloc(5000); assert(big_string); memset(big_string, ' ', 4999); big_string[4999] = '\0'; setup_marshal_data(&data); wl_connection_set_max_buffer_size(data.write_connection, 5120); marshal_send(&data, "s", big_string); release_marshal_data(&data); free(big_string); } TEST(connection_marshal_unbounded_boundary_size) { /* A string of lenth 8178 requires a buffer size of exactly 2^13. */ struct marshal_data data; char *big_string = malloc(8178); assert(big_string); memset(big_string, ' ', 8177); big_string[8177] = '\0'; setup_marshal_data(&data); /* Set the max size to 0 (unbounded). */ wl_connection_set_max_buffer_size(data.write_connection, 0); marshal_send(&data, "s", big_string); release_marshal_data(&data); free(big_string); } static void marshal_helper(const char *format, void *handler, ...) { struct wl_closure *closure; static struct wl_object sender = { NULL, NULL, 1234 }; struct wl_object object = { NULL, &handler, 0 }; static const int opcode = 4444; struct wl_message message = { "test", format, NULL }; va_list ap; int done; va_start(ap, handler); closure = wl_closure_vmarshal(&sender, opcode, ap, &message); va_end(ap); assert(closure); done = 0; wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, &done); wl_closure_destroy(closure); assert(done); } static void suu_handler(void *data, struct wl_object *object, const char *s, uint32_t u1, uint32_t u2) { int *done = data; assert(strcmp(s, "foo") == 0); assert(u1 == 500); assert(u2 == 404040); *done = 1; } TEST(invoke_closure) { marshal_helper("suu", suu_handler, "foo", 500, 404040); } static void leak_closure(void) { struct wl_callback *cb; struct pollfd pfd; struct client *c = client_connect(); cb = wl_display_sync(c->wl_display); assert(cb); assert(wl_display_flush(c->wl_display) > 0); /* we don't need it, it is referenced */ wl_callback_destroy(cb); pfd.fd = wl_display_get_fd(c->wl_display); pfd.events = POLLIN; test_set_timeout(2); assert(poll(&pfd, 1, -1) == 1); /* read events, but do not dispatch them */ assert(wl_display_prepare_read(c->wl_display) == 0); assert(wl_display_read_events(c->wl_display) == 0); /* * now we have wl_callback.done and wl_display.delete_id queued; * if we now release the queue (in wl_display_disconnect()) * we should not leak memory */ client_disconnect(c); } TEST(closure_leaks) { struct display *d = display_create(); client_create_noarg(d, leak_closure); display_run(d); display_destroy(d); } static void leak_after_error(void) { struct client *c = client_connect(); /* this should return -1, because we'll send error * from server. */ assert(stop_display(c, 1) == -1); assert(wl_display_dispatch_pending(c->wl_display) == -1); assert(wl_display_get_error(c->wl_display) == ENOMEM); /* after we got error, we have display_resume event * in the queue. It should be freed in wl_display_disconnect(). * Let's see! */ wl_proxy_destroy((struct wl_proxy *) c->tc); wl_display_disconnect(c->wl_display); free(c); } TEST(closure_leaks_after_error) { struct display *d = display_create(); struct client_info *cl; cl = client_create_noarg(d, leak_after_error); display_run(d); wl_client_post_no_memory(cl->wl_client); display_resume(d); display_destroy(d); } /** Raw read from socket expecting wl_display.error * * \param sockfd The socket to read from. * \param expected_error The expected wl_display error code. * * Reads the socket and manually parses one message, expecting it to be a * wl_display.error with the wl_display as the originating object. * Asserts that the received error code is expected_error. */ static void expect_error_recv(int sockfd, uint32_t expected_error) { uint32_t buf[1024]; ssize_t slen; uint32_t opcode; int str_len; slen = recv(sockfd, buf, sizeof buf, 0); assert(slen >= 2 * (ssize_t)sizeof (uint32_t)); opcode = buf[1] & 0xffff; fprintf(stderr, "Received %zd bytes, object %u, opcode %u\n", slen, buf[0], opcode); /* check error event */ assert(buf[0] == 1); assert(opcode == WL_DISPLAY_ERROR); str_len = buf[4]; assert(str_len > 0); assert(str_len <= slen - 5 * (ssize_t)sizeof (uint32_t)); fprintf(stderr, "Error event on object %u, code %u, message \"%*s\"\n", buf[2], buf[3], str_len, (const char *)&buf[5]); assert(buf[3] == expected_error); } /* A test for https://gitlab.freedesktop.org/wayland/wayland/issues/52 * trying to provoke a read from uninitialized memory in * wl_connection_demarshal() for sender_id and opcode. * * This test might not fail as is even with #52 unfixed, since there is no way * to detect what happens and the crash with zero size depends on stack content. * However, running under Valgrind would point out invalid reads and use of * uninitialized values. */ TEST(request_bogus_size) { struct wl_display *display; struct wl_client *client; int s[2]; uint32_t msg[3]; int bogus_size; test_set_timeout(1); /* * The manufactured message has real size 12. Test all bogus sizes * smaller than that, and zero as the last one since wl_closure_init * handles zero specially and having garbage in the stack makes it more * likely to crash in wl_connection_demarshal. */ for (bogus_size = 11; bogus_size >= 0; bogus_size--) { fprintf(stderr, "* bogus size %d\n", bogus_size); assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); display = wl_display_create(); assert(display); client = wl_client_create(display, s[0]); assert(client); /* manufacture a request that lies about its size */ msg[0] = 1; /* sender id: wl_display */ msg[1] = (bogus_size << 16) | WL_DISPLAY_SYNC; /* size and opcode */ msg[2] = 2; /* sync argument: new_id for wl_callback */ assert(send(s[1], msg, sizeof msg, 0) == sizeof msg); wl_event_loop_dispatch(wl_display_get_event_loop(display), 0); expect_error_recv(s[1], WL_DISPLAY_ERROR_INVALID_METHOD); /* Do not wl_client_destroy, the error already caused it. */ close(s[1]); wl_display_destroy(display); } } wayland-1.23.1/tests/cpp-compile-test.cpp000066400000000000000000000001701466237767300203130ustar00rootroot00000000000000/* This source should compile fine with C++ compiler */ #include "wayland-server-protocol.h" int main() { return 0; } wayland-1.23.1/tests/data/000077500000000000000000000000001466237767300153355ustar00rootroot00000000000000wayland-1.23.1/tests/data/README.md000066400000000000000000000001111466237767300166050ustar00rootroot00000000000000To re-generate the test data, run: ninja -C build/ gen-scanner-test wayland-1.23.1/tests/data/bad-identifier-arg.xml000066400000000000000000000004341466237767300214750ustar00rootroot00000000000000 wayland-1.23.1/tests/data/bad-identifier-entry.xml000066400000000000000000000006041466237767300220640ustar00rootroot00000000000000 wayland-1.23.1/tests/data/bad-identifier-enum.xml000066400000000000000000000004641466237767300216730ustar00rootroot00000000000000 wayland-1.23.1/tests/data/bad-identifier-event.xml000066400000000000000000000003521466237767300220440ustar00rootroot00000000000000 wayland-1.23.1/tests/data/bad-identifier-interface.xml000066400000000000000000000003461466237767300226660ustar00rootroot00000000000000 wayland-1.23.1/tests/data/bad-identifier-protocol.xml000066400000000000000000000003701466237767300225640ustar00rootroot00000000000000 wayland-1.23.1/tests/data/bad-identifier-request.xml000066400000000000000000000004401466237767300224110ustar00rootroot00000000000000 wayland-1.23.1/tests/data/empty-client.h000066400000000000000000000027631466237767300201300ustar00rootroot00000000000000/* SCANNER TEST */ #ifndef EMPTY_CLIENT_PROTOCOL_H #define EMPTY_CLIENT_PROTOCOL_H #include #include #include "wayland-client.h" #ifdef __cplusplus extern "C" { #endif /** * @page page_empty The empty protocol * @section page_ifaces_empty Interfaces * - @subpage page_iface_empty - */ struct empty; #ifndef EMPTY_INTERFACE #define EMPTY_INTERFACE /** * @page page_iface_empty empty * @section page_iface_empty_api API * See @ref iface_empty. */ /** * @defgroup iface_empty The empty interface */ extern const struct wl_interface empty_interface; #endif #define EMPTY_EMPTY 0 /** * @ingroup iface_empty */ #define EMPTY_EMPTY_SINCE_VERSION 1 /** @ingroup iface_empty */ static inline void empty_set_user_data(struct empty *empty, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) empty, user_data); } /** @ingroup iface_empty */ static inline void * empty_get_user_data(struct empty *empty) { return wl_proxy_get_user_data((struct wl_proxy *) empty); } static inline uint32_t empty_get_version(struct empty *empty) { return wl_proxy_get_version((struct wl_proxy *) empty); } /** @ingroup iface_empty */ static inline void empty_destroy(struct empty *empty) { wl_proxy_destroy((struct wl_proxy *) empty); } /** * @ingroup iface_empty */ static inline void empty_empty(struct empty *empty) { wl_proxy_marshal_flags((struct wl_proxy *) empty, EMPTY_EMPTY, NULL, wl_proxy_get_version((struct wl_proxy *) empty), 0); } #ifdef __cplusplus } #endif #endif wayland-1.23.1/tests/data/empty-code.c000066400000000000000000000005471466237767300175550ustar00rootroot00000000000000/* SCANNER TEST */ #include #include #include #include "wayland-util.h" static const struct wl_interface *empty_types[] = { }; static const struct wl_message empty_requests[] = { { "empty", "", empty_types + 0 }, }; WL_EXPORT const struct wl_interface empty_interface = { "empty", 1, 1, empty_requests, 0, NULL, }; wayland-1.23.1/tests/data/empty-server.h000066400000000000000000000016251466237767300201540ustar00rootroot00000000000000/* SCANNER TEST */ #ifndef EMPTY_SERVER_PROTOCOL_H #define EMPTY_SERVER_PROTOCOL_H #include #include #include "wayland-server.h" #ifdef __cplusplus extern "C" { #endif struct wl_client; struct wl_resource; /** * @page page_empty The empty protocol * @section page_ifaces_empty Interfaces * - @subpage page_iface_empty - */ struct empty; #ifndef EMPTY_INTERFACE #define EMPTY_INTERFACE /** * @page page_iface_empty empty * @section page_iface_empty_api API * See @ref iface_empty. */ /** * @defgroup iface_empty The empty interface */ extern const struct wl_interface empty_interface; #endif /** * @ingroup iface_empty * @struct empty_interface */ struct empty_interface { /** */ void (*empty)(struct wl_client *client, struct wl_resource *resource); }; /** * @ingroup iface_empty */ #define EMPTY_EMPTY_SINCE_VERSION 1 #ifdef __cplusplus } #endif #endif wayland-1.23.1/tests/data/empty.xml000066400000000000000000000002531466237767300172150ustar00rootroot00000000000000 wayland-1.23.1/tests/data/example-client.h000066400000000000000000005447271466237767300204400ustar00rootroot00000000000000/* SCANNER TEST */ #ifndef WAYLAND_CLIENT_PROTOCOL_H #define WAYLAND_CLIENT_PROTOCOL_H #include #include #include "wayland-client.h" #ifdef __cplusplus extern "C" { #endif /** * @page page_wayland The wayland protocol * @section page_ifaces_wayland Interfaces * - @subpage page_iface_wl_display - core global object * - @subpage page_iface_wl_registry - global registry object * - @subpage page_iface_wl_callback - callback object * - @subpage page_iface_wl_compositor - the compositor singleton * - @subpage page_iface_wl_shm_pool - a shared memory pool * - @subpage page_iface_wl_shm - shared memory support * - @subpage page_iface_wl_buffer - content for a wl_surface * - @subpage page_iface_wl_data_offer - offer to transfer data * - @subpage page_iface_wl_data_source - offer to transfer data * - @subpage page_iface_wl_data_device - data transfer device * - @subpage page_iface_wl_data_device_manager - data transfer interface * - @subpage page_iface_wl_shell - create desktop-style surfaces * - @subpage page_iface_wl_shell_surface - desktop-style metadata interface * - @subpage page_iface_wl_surface - an onscreen surface * - @subpage page_iface_wl_seat - group of input devices * - @subpage page_iface_wl_pointer - pointer input device * - @subpage page_iface_wl_keyboard - keyboard input device * - @subpage page_iface_wl_touch - touchscreen input device * - @subpage page_iface_wl_output - compositor output region * - @subpage page_iface_wl_region - region interface * - @subpage page_iface_wl_subcompositor - sub-surface compositing * - @subpage page_iface_wl_subsurface - sub-surface interface to a wl_surface * @section page_copyright_wayland Copyright *
 *
 * Copyright © 2008-2011 Kristian Høgsberg
 * Copyright © 2010-2011 Intel Corporation
 * Copyright © 2012-2013 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.
 * 
*/ struct wl_buffer; struct wl_callback; struct wl_compositor; struct wl_data_device; struct wl_data_device_manager; struct wl_data_offer; struct wl_data_source; struct wl_display; struct wl_keyboard; struct wl_output; struct wl_pointer; struct wl_region; struct wl_registry; struct wl_seat; struct wl_shell; struct wl_shell_surface; struct wl_shm; struct wl_shm_pool; struct wl_subcompositor; struct wl_subsurface; struct wl_surface; struct wl_touch; #ifndef WL_DISPLAY_INTERFACE #define WL_DISPLAY_INTERFACE /** * @page page_iface_wl_display wl_display * @section page_iface_wl_display_desc Description * * The core global object. This is a special singleton object. It * is used for internal Wayland protocol features. * @section page_iface_wl_display_api API * See @ref iface_wl_display. */ /** * @defgroup iface_wl_display The wl_display interface * * The core global object. This is a special singleton object. It * is used for internal Wayland protocol features. */ extern const struct wl_interface wl_display_interface; #endif #ifndef WL_REGISTRY_INTERFACE #define WL_REGISTRY_INTERFACE /** * @page page_iface_wl_registry wl_registry * @section page_iface_wl_registry_desc Description * * The singleton global registry object. The server has a number of * global objects that are available to all clients. These objects * typically represent an actual object in the server (for example, * an input device) or they are singleton objects that provide * extension functionality. * * When a client creates a registry object, the registry object * will emit a global event for each global currently in the * registry. Globals come and go as a result of device or * monitor hotplugs, reconfiguration or other events, and the * registry will send out global and global_remove events to * keep the client up to date with the changes. To mark the end * of the initial burst of events, the client can use the * wl_display.sync request immediately after calling * wl_display.get_registry. * * A client can bind to a global object by using the bind * request. This creates a client-side handle that lets the object * emit events to the client and lets the client invoke requests on * the object. * @section page_iface_wl_registry_api API * See @ref iface_wl_registry. */ /** * @defgroup iface_wl_registry The wl_registry interface * * The singleton global registry object. The server has a number of * global objects that are available to all clients. These objects * typically represent an actual object in the server (for example, * an input device) or they are singleton objects that provide * extension functionality. * * When a client creates a registry object, the registry object * will emit a global event for each global currently in the * registry. Globals come and go as a result of device or * monitor hotplugs, reconfiguration or other events, and the * registry will send out global and global_remove events to * keep the client up to date with the changes. To mark the end * of the initial burst of events, the client can use the * wl_display.sync request immediately after calling * wl_display.get_registry. * * A client can bind to a global object by using the bind * request. This creates a client-side handle that lets the object * emit events to the client and lets the client invoke requests on * the object. */ extern const struct wl_interface wl_registry_interface; #endif #ifndef WL_CALLBACK_INTERFACE #define WL_CALLBACK_INTERFACE /** * @page page_iface_wl_callback wl_callback * @section page_iface_wl_callback_desc Description * * Clients can handle the 'done' event to get notified when * the related request is done. * @section page_iface_wl_callback_api API * See @ref iface_wl_callback. */ /** * @defgroup iface_wl_callback The wl_callback interface * * Clients can handle the 'done' event to get notified when * the related request is done. */ extern const struct wl_interface wl_callback_interface; #endif #ifndef WL_COMPOSITOR_INTERFACE #define WL_COMPOSITOR_INTERFACE /** * @page page_iface_wl_compositor wl_compositor * @section page_iface_wl_compositor_desc Description * * A compositor. This object is a singleton global. The * compositor is in charge of combining the contents of multiple * surfaces into one displayable output. * @section page_iface_wl_compositor_api API * See @ref iface_wl_compositor. */ /** * @defgroup iface_wl_compositor The wl_compositor interface * * A compositor. This object is a singleton global. The * compositor is in charge of combining the contents of multiple * surfaces into one displayable output. */ extern const struct wl_interface wl_compositor_interface; #endif #ifndef WL_SHM_POOL_INTERFACE #define WL_SHM_POOL_INTERFACE /** * @page page_iface_wl_shm_pool wl_shm_pool * @section page_iface_wl_shm_pool_desc Description * * The wl_shm_pool object encapsulates a piece of memory shared * between the compositor and client. Through the wl_shm_pool * object, the client can allocate shared memory wl_buffer objects. * All objects created through the same pool share the same * underlying mapped memory. Reusing the mapped memory avoids the * setup/teardown overhead and is useful when interactively resizing * a surface or for many small buffers. * @section page_iface_wl_shm_pool_api API * See @ref iface_wl_shm_pool. */ /** * @defgroup iface_wl_shm_pool The wl_shm_pool interface * * The wl_shm_pool object encapsulates a piece of memory shared * between the compositor and client. Through the wl_shm_pool * object, the client can allocate shared memory wl_buffer objects. * All objects created through the same pool share the same * underlying mapped memory. Reusing the mapped memory avoids the * setup/teardown overhead and is useful when interactively resizing * a surface or for many small buffers. */ extern const struct wl_interface wl_shm_pool_interface; #endif #ifndef WL_SHM_INTERFACE #define WL_SHM_INTERFACE /** * @page page_iface_wl_shm wl_shm * @section page_iface_wl_shm_desc Description * * A singleton global object that provides support for shared * memory. * * Clients can create wl_shm_pool objects using the create_pool * request. * * At connection setup time, the wl_shm object emits one or more * format events to inform clients about the valid pixel formats * that can be used for buffers. * @section page_iface_wl_shm_api API * See @ref iface_wl_shm. */ /** * @defgroup iface_wl_shm The wl_shm interface * * A singleton global object that provides support for shared * memory. * * Clients can create wl_shm_pool objects using the create_pool * request. * * At connection setup time, the wl_shm object emits one or more * format events to inform clients about the valid pixel formats * that can be used for buffers. */ extern const struct wl_interface wl_shm_interface; #endif #ifndef WL_BUFFER_INTERFACE #define WL_BUFFER_INTERFACE /** * @page page_iface_wl_buffer wl_buffer * @section page_iface_wl_buffer_desc Description * * A buffer provides the content for a wl_surface. Buffers are * created through factory interfaces such as wl_drm, wl_shm or * similar. It has a width and a height and can be attached to a * wl_surface, but the mechanism by which a client provides and * updates the contents is defined by the buffer factory interface. * @section page_iface_wl_buffer_api API * See @ref iface_wl_buffer. */ /** * @defgroup iface_wl_buffer The wl_buffer interface * * A buffer provides the content for a wl_surface. Buffers are * created through factory interfaces such as wl_drm, wl_shm or * similar. It has a width and a height and can be attached to a * wl_surface, but the mechanism by which a client provides and * updates the contents is defined by the buffer factory interface. */ extern const struct wl_interface wl_buffer_interface; #endif #ifndef WL_DATA_OFFER_INTERFACE #define WL_DATA_OFFER_INTERFACE /** * @page page_iface_wl_data_offer wl_data_offer * @section page_iface_wl_data_offer_desc Description * * A wl_data_offer represents a piece of data offered for transfer * by another client (the source client). It is used by the * copy-and-paste and drag-and-drop mechanisms. The offer * describes the different mime types that the data can be * converted to and provides the mechanism for transferring the * data directly from the source client. * @section page_iface_wl_data_offer_api API * See @ref iface_wl_data_offer. */ /** * @defgroup iface_wl_data_offer The wl_data_offer interface * * A wl_data_offer represents a piece of data offered for transfer * by another client (the source client). It is used by the * copy-and-paste and drag-and-drop mechanisms. The offer * describes the different mime types that the data can be * converted to and provides the mechanism for transferring the * data directly from the source client. */ extern const struct wl_interface wl_data_offer_interface; #endif #ifndef WL_DATA_SOURCE_INTERFACE #define WL_DATA_SOURCE_INTERFACE /** * @page page_iface_wl_data_source wl_data_source * @section page_iface_wl_data_source_desc Description * * The wl_data_source object is the source side of a wl_data_offer. * It is created by the source client in a data transfer and * provides a way to describe the offered data and a way to respond * to requests to transfer the data. * @section page_iface_wl_data_source_api API * See @ref iface_wl_data_source. */ /** * @defgroup iface_wl_data_source The wl_data_source interface * * The wl_data_source object is the source side of a wl_data_offer. * It is created by the source client in a data transfer and * provides a way to describe the offered data and a way to respond * to requests to transfer the data. */ extern const struct wl_interface wl_data_source_interface; #endif #ifndef WL_DATA_DEVICE_INTERFACE #define WL_DATA_DEVICE_INTERFACE /** * @page page_iface_wl_data_device wl_data_device * @section page_iface_wl_data_device_desc Description * * There is one wl_data_device per seat which can be obtained * from the global wl_data_device_manager singleton. * * A wl_data_device provides access to inter-client data transfer * mechanisms such as copy-and-paste and drag-and-drop. * @section page_iface_wl_data_device_api API * See @ref iface_wl_data_device. */ /** * @defgroup iface_wl_data_device The wl_data_device interface * * There is one wl_data_device per seat which can be obtained * from the global wl_data_device_manager singleton. * * A wl_data_device provides access to inter-client data transfer * mechanisms such as copy-and-paste and drag-and-drop. */ extern const struct wl_interface wl_data_device_interface; #endif #ifndef WL_DATA_DEVICE_MANAGER_INTERFACE #define WL_DATA_DEVICE_MANAGER_INTERFACE /** * @page page_iface_wl_data_device_manager wl_data_device_manager * @section page_iface_wl_data_device_manager_desc Description * * The wl_data_device_manager is a singleton global object that * provides access to inter-client data transfer mechanisms such as * copy-and-paste and drag-and-drop. These mechanisms are tied to * a wl_seat and this interface lets a client get a wl_data_device * corresponding to a wl_seat. * * Depending on the version bound, the objects created from the bound * wl_data_device_manager object will have different requirements for * functioning properly. See wl_data_source.set_actions, * wl_data_offer.accept and wl_data_offer.finish for details. * @section page_iface_wl_data_device_manager_api API * See @ref iface_wl_data_device_manager. */ /** * @defgroup iface_wl_data_device_manager The wl_data_device_manager interface * * The wl_data_device_manager is a singleton global object that * provides access to inter-client data transfer mechanisms such as * copy-and-paste and drag-and-drop. These mechanisms are tied to * a wl_seat and this interface lets a client get a wl_data_device * corresponding to a wl_seat. * * Depending on the version bound, the objects created from the bound * wl_data_device_manager object will have different requirements for * functioning properly. See wl_data_source.set_actions, * wl_data_offer.accept and wl_data_offer.finish for details. */ extern const struct wl_interface wl_data_device_manager_interface; #endif #ifndef WL_SHELL_INTERFACE #define WL_SHELL_INTERFACE /** * @page page_iface_wl_shell wl_shell * @section page_iface_wl_shell_desc Description * * This interface is implemented by servers that provide * desktop-style user interfaces. * * It allows clients to associate a wl_shell_surface with * a basic surface. * @section page_iface_wl_shell_api API * See @ref iface_wl_shell. */ /** * @defgroup iface_wl_shell The wl_shell interface * * This interface is implemented by servers that provide * desktop-style user interfaces. * * It allows clients to associate a wl_shell_surface with * a basic surface. */ extern const struct wl_interface wl_shell_interface; #endif #ifndef WL_SHELL_SURFACE_INTERFACE #define WL_SHELL_SURFACE_INTERFACE /** * @page page_iface_wl_shell_surface wl_shell_surface * @section page_iface_wl_shell_surface_desc Description * * An interface that may be implemented by a wl_surface, for * implementations that provide a desktop-style user interface. * * It provides requests to treat surfaces like toplevel, fullscreen * or popup windows, move, resize or maximize them, associate * metadata like title and class, etc. * * On the server side the object is automatically destroyed when * the related wl_surface is destroyed. On the client side, * wl_shell_surface_destroy() must be called before destroying * the wl_surface object. * @section page_iface_wl_shell_surface_api API * See @ref iface_wl_shell_surface. */ /** * @defgroup iface_wl_shell_surface The wl_shell_surface interface * * An interface that may be implemented by a wl_surface, for * implementations that provide a desktop-style user interface. * * It provides requests to treat surfaces like toplevel, fullscreen * or popup windows, move, resize or maximize them, associate * metadata like title and class, etc. * * On the server side the object is automatically destroyed when * the related wl_surface is destroyed. On the client side, * wl_shell_surface_destroy() must be called before destroying * the wl_surface object. */ extern const struct wl_interface wl_shell_surface_interface; #endif #ifndef WL_SURFACE_INTERFACE #define WL_SURFACE_INTERFACE /** * @page page_iface_wl_surface wl_surface * @section page_iface_wl_surface_desc Description * * A surface is a rectangular area that is displayed on the screen. * It has a location, size and pixel contents. * * The size of a surface (and relative positions on it) is described * in surface-local coordinates, which may differ from the buffer * coordinates of the pixel content, in case a buffer_transform * or a buffer_scale is used. * * A surface without a "role" is fairly useless: a compositor does * not know where, when or how to present it. The role is the * purpose of a wl_surface. Examples of roles are a cursor for a * pointer (as set by wl_pointer.set_cursor), a drag icon * (wl_data_device.start_drag), a sub-surface * (wl_subcompositor.get_subsurface), and a window as defined by a * shell protocol (e.g. wl_shell.get_shell_surface). * * A surface can have only one role at a time. Initially a * wl_surface does not have a role. Once a wl_surface is given a * role, it is set permanently for the whole lifetime of the * wl_surface object. Giving the current role again is allowed, * unless explicitly forbidden by the relevant interface * specification. * * Surface roles are given by requests in other interfaces such as * wl_pointer.set_cursor. The request should explicitly mention * that this request gives a role to a wl_surface. Often, this * request also creates a new protocol object that represents the * role and adds additional functionality to wl_surface. When a * client wants to destroy a wl_surface, they must destroy this 'role * object' before the wl_surface. * * Destroying the role object does not remove the role from the * wl_surface, but it may stop the wl_surface from "playing the role". * For instance, if a wl_subsurface object is destroyed, the wl_surface * it was created for will be unmapped and forget its position and * z-order. It is allowed to create a wl_subsurface for the same * wl_surface again, but it is not allowed to use the wl_surface as * a cursor (cursor is a different role than sub-surface, and role * switching is not allowed). * @section page_iface_wl_surface_api API * See @ref iface_wl_surface. */ /** * @defgroup iface_wl_surface The wl_surface interface * * A surface is a rectangular area that is displayed on the screen. * It has a location, size and pixel contents. * * The size of a surface (and relative positions on it) is described * in surface-local coordinates, which may differ from the buffer * coordinates of the pixel content, in case a buffer_transform * or a buffer_scale is used. * * A surface without a "role" is fairly useless: a compositor does * not know where, when or how to present it. The role is the * purpose of a wl_surface. Examples of roles are a cursor for a * pointer (as set by wl_pointer.set_cursor), a drag icon * (wl_data_device.start_drag), a sub-surface * (wl_subcompositor.get_subsurface), and a window as defined by a * shell protocol (e.g. wl_shell.get_shell_surface). * * A surface can have only one role at a time. Initially a * wl_surface does not have a role. Once a wl_surface is given a * role, it is set permanently for the whole lifetime of the * wl_surface object. Giving the current role again is allowed, * unless explicitly forbidden by the relevant interface * specification. * * Surface roles are given by requests in other interfaces such as * wl_pointer.set_cursor. The request should explicitly mention * that this request gives a role to a wl_surface. Often, this * request also creates a new protocol object that represents the * role and adds additional functionality to wl_surface. When a * client wants to destroy a wl_surface, they must destroy this 'role * object' before the wl_surface. * * Destroying the role object does not remove the role from the * wl_surface, but it may stop the wl_surface from "playing the role". * For instance, if a wl_subsurface object is destroyed, the wl_surface * it was created for will be unmapped and forget its position and * z-order. It is allowed to create a wl_subsurface for the same * wl_surface again, but it is not allowed to use the wl_surface as * a cursor (cursor is a different role than sub-surface, and role * switching is not allowed). */ extern const struct wl_interface wl_surface_interface; #endif #ifndef WL_SEAT_INTERFACE #define WL_SEAT_INTERFACE /** * @page page_iface_wl_seat wl_seat * @section page_iface_wl_seat_desc Description * * A seat is a group of keyboards, pointer and touch devices. This * object is published as a global during start up, or when such a * device is hot plugged. A seat typically has a pointer and * maintains a keyboard focus and a pointer focus. * @section page_iface_wl_seat_api API * See @ref iface_wl_seat. */ /** * @defgroup iface_wl_seat The wl_seat interface * * A seat is a group of keyboards, pointer and touch devices. This * object is published as a global during start up, or when such a * device is hot plugged. A seat typically has a pointer and * maintains a keyboard focus and a pointer focus. */ extern const struct wl_interface wl_seat_interface; #endif #ifndef WL_POINTER_INTERFACE #define WL_POINTER_INTERFACE /** * @page page_iface_wl_pointer wl_pointer * @section page_iface_wl_pointer_desc Description * * The wl_pointer interface represents one or more input devices, * such as mice, which control the pointer location and pointer_focus * of a seat. * * The wl_pointer interface generates motion, enter and leave * events for the surfaces that the pointer is located over, * and button and axis events for button presses, button releases * and scrolling. * @section page_iface_wl_pointer_api API * See @ref iface_wl_pointer. */ /** * @defgroup iface_wl_pointer The wl_pointer interface * * The wl_pointer interface represents one or more input devices, * such as mice, which control the pointer location and pointer_focus * of a seat. * * The wl_pointer interface generates motion, enter and leave * events for the surfaces that the pointer is located over, * and button and axis events for button presses, button releases * and scrolling. */ extern const struct wl_interface wl_pointer_interface; #endif #ifndef WL_KEYBOARD_INTERFACE #define WL_KEYBOARD_INTERFACE /** * @page page_iface_wl_keyboard wl_keyboard * @section page_iface_wl_keyboard_desc Description * * The wl_keyboard interface represents one or more keyboards * associated with a seat. * @section page_iface_wl_keyboard_api API * See @ref iface_wl_keyboard. */ /** * @defgroup iface_wl_keyboard The wl_keyboard interface * * The wl_keyboard interface represents one or more keyboards * associated with a seat. */ extern const struct wl_interface wl_keyboard_interface; #endif #ifndef WL_TOUCH_INTERFACE #define WL_TOUCH_INTERFACE /** * @page page_iface_wl_touch wl_touch * @section page_iface_wl_touch_desc Description * * The wl_touch interface represents a touchscreen * associated with a seat. * * Touch interactions can consist of one or more contacts. * For each contact, a series of events is generated, starting * with a down event, followed by zero or more motion events, * and ending with an up event. Events relating to the same * contact point can be identified by the ID of the sequence. * @section page_iface_wl_touch_api API * See @ref iface_wl_touch. */ /** * @defgroup iface_wl_touch The wl_touch interface * * The wl_touch interface represents a touchscreen * associated with a seat. * * Touch interactions can consist of one or more contacts. * For each contact, a series of events is generated, starting * with a down event, followed by zero or more motion events, * and ending with an up event. Events relating to the same * contact point can be identified by the ID of the sequence. */ extern const struct wl_interface wl_touch_interface; #endif #ifndef WL_OUTPUT_INTERFACE #define WL_OUTPUT_INTERFACE /** * @page page_iface_wl_output wl_output * @section page_iface_wl_output_desc Description * * An output describes part of the compositor geometry. The * compositor works in the 'compositor coordinate system' and an * output corresponds to a rectangular area in that space that is * actually visible. This typically corresponds to a monitor that * displays part of the compositor space. This object is published * as global during start up, or when a monitor is hotplugged. * @section page_iface_wl_output_api API * See @ref iface_wl_output. */ /** * @defgroup iface_wl_output The wl_output interface * * An output describes part of the compositor geometry. The * compositor works in the 'compositor coordinate system' and an * output corresponds to a rectangular area in that space that is * actually visible. This typically corresponds to a monitor that * displays part of the compositor space. This object is published * as global during start up, or when a monitor is hotplugged. */ extern const struct wl_interface wl_output_interface; #endif #ifndef WL_REGION_INTERFACE #define WL_REGION_INTERFACE /** * @page page_iface_wl_region wl_region * @section page_iface_wl_region_desc Description * * A region object describes an area. * * Region objects are used to describe the opaque and input * regions of a surface. * @section page_iface_wl_region_api API * See @ref iface_wl_region. */ /** * @defgroup iface_wl_region The wl_region interface * * A region object describes an area. * * Region objects are used to describe the opaque and input * regions of a surface. */ extern const struct wl_interface wl_region_interface; #endif #ifndef WL_SUBCOMPOSITOR_INTERFACE #define WL_SUBCOMPOSITOR_INTERFACE /** * @page page_iface_wl_subcompositor wl_subcompositor * @section page_iface_wl_subcompositor_desc Description * * The global interface exposing sub-surface compositing capabilities. * A wl_surface, that has sub-surfaces associated, is called the * parent surface. Sub-surfaces can be arbitrarily nested and create * a tree of sub-surfaces. * * The root surface in a tree of sub-surfaces is the main * surface. The main surface cannot be a sub-surface, because * sub-surfaces must always have a parent. * * A main surface with its sub-surfaces forms a (compound) window. * For window management purposes, this set of wl_surface objects is * to be considered as a single window, and it should also behave as * such. * * The aim of sub-surfaces is to offload some of the compositing work * within a window from clients to the compositor. A prime example is * a video player with decorations and video in separate wl_surface * objects. This should allow the compositor to pass YUV video buffer * processing to dedicated overlay hardware when possible. * @section page_iface_wl_subcompositor_api API * See @ref iface_wl_subcompositor. */ /** * @defgroup iface_wl_subcompositor The wl_subcompositor interface * * The global interface exposing sub-surface compositing capabilities. * A wl_surface, that has sub-surfaces associated, is called the * parent surface. Sub-surfaces can be arbitrarily nested and create * a tree of sub-surfaces. * * The root surface in a tree of sub-surfaces is the main * surface. The main surface cannot be a sub-surface, because * sub-surfaces must always have a parent. * * A main surface with its sub-surfaces forms a (compound) window. * For window management purposes, this set of wl_surface objects is * to be considered as a single window, and it should also behave as * such. * * The aim of sub-surfaces is to offload some of the compositing work * within a window from clients to the compositor. A prime example is * a video player with decorations and video in separate wl_surface * objects. This should allow the compositor to pass YUV video buffer * processing to dedicated overlay hardware when possible. */ extern const struct wl_interface wl_subcompositor_interface; #endif #ifndef WL_SUBSURFACE_INTERFACE #define WL_SUBSURFACE_INTERFACE /** * @page page_iface_wl_subsurface wl_subsurface * @section page_iface_wl_subsurface_desc Description * * An additional interface to a wl_surface object, which has been * made a sub-surface. A sub-surface has one parent surface. A * sub-surface's size and position are not limited to that of the parent. * Particularly, a sub-surface is not automatically clipped to its * parent's area. * * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied * and the parent surface is mapped. The order of which one happens * first is irrelevant. A sub-surface is hidden if the parent becomes * hidden, or if a NULL wl_buffer is applied. These rules apply * recursively through the tree of surfaces. * * The behaviour of a wl_surface.commit request on a sub-surface * depends on the sub-surface's mode. The possible modes are * synchronized and desynchronized, see methods * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized * mode caches the wl_surface state to be applied when the parent's * state gets applied, and desynchronized mode applies the pending * wl_surface state directly. A sub-surface is initially in the * synchronized mode. * * Sub-surfaces have also other kind of state, which is managed by * wl_subsurface requests, as opposed to wl_surface requests. This * state includes the sub-surface position relative to the parent * surface (wl_subsurface.set_position), and the stacking order of * the parent and its sub-surfaces (wl_subsurface.place_above and * .place_below). This state is applied when the parent surface's * wl_surface state is applied, regardless of the sub-surface's mode. * As the exception, set_sync and set_desync are effective immediately. * * The main surface can be thought to be always in desynchronized mode, * since it does not have a parent in the sub-surfaces sense. * * Even if a sub-surface is in desynchronized mode, it will behave as * in synchronized mode, if its parent surface behaves as in * synchronized mode. This rule is applied recursively throughout the * tree of surfaces. This means, that one can set a sub-surface into * synchronized mode, and then assume that all its child and grand-child * sub-surfaces are synchronized, too, without explicitly setting them. * * If the wl_surface associated with the wl_subsurface is destroyed, the * wl_subsurface object becomes inert. Note, that destroying either object * takes effect immediately. If you need to synchronize the removal * of a sub-surface to the parent surface update, unmap the sub-surface * first by attaching a NULL wl_buffer, update parent, and then destroy * the sub-surface. * * If the parent wl_surface object is destroyed, the sub-surface is * unmapped. * @section page_iface_wl_subsurface_api API * See @ref iface_wl_subsurface. */ /** * @defgroup iface_wl_subsurface The wl_subsurface interface * * An additional interface to a wl_surface object, which has been * made a sub-surface. A sub-surface has one parent surface. A * sub-surface's size and position are not limited to that of the parent. * Particularly, a sub-surface is not automatically clipped to its * parent's area. * * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied * and the parent surface is mapped. The order of which one happens * first is irrelevant. A sub-surface is hidden if the parent becomes * hidden, or if a NULL wl_buffer is applied. These rules apply * recursively through the tree of surfaces. * * The behaviour of a wl_surface.commit request on a sub-surface * depends on the sub-surface's mode. The possible modes are * synchronized and desynchronized, see methods * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized * mode caches the wl_surface state to be applied when the parent's * state gets applied, and desynchronized mode applies the pending * wl_surface state directly. A sub-surface is initially in the * synchronized mode. * * Sub-surfaces have also other kind of state, which is managed by * wl_subsurface requests, as opposed to wl_surface requests. This * state includes the sub-surface position relative to the parent * surface (wl_subsurface.set_position), and the stacking order of * the parent and its sub-surfaces (wl_subsurface.place_above and * .place_below). This state is applied when the parent surface's * wl_surface state is applied, regardless of the sub-surface's mode. * As the exception, set_sync and set_desync are effective immediately. * * The main surface can be thought to be always in desynchronized mode, * since it does not have a parent in the sub-surfaces sense. * * Even if a sub-surface is in desynchronized mode, it will behave as * in synchronized mode, if its parent surface behaves as in * synchronized mode. This rule is applied recursively throughout the * tree of surfaces. This means, that one can set a sub-surface into * synchronized mode, and then assume that all its child and grand-child * sub-surfaces are synchronized, too, without explicitly setting them. * * If the wl_surface associated with the wl_subsurface is destroyed, the * wl_subsurface object becomes inert. Note, that destroying either object * takes effect immediately. If you need to synchronize the removal * of a sub-surface to the parent surface update, unmap the sub-surface * first by attaching a NULL wl_buffer, update parent, and then destroy * the sub-surface. * * If the parent wl_surface object is destroyed, the sub-surface is * unmapped. */ extern const struct wl_interface wl_subsurface_interface; #endif #ifndef WL_DISPLAY_ERROR_ENUM #define WL_DISPLAY_ERROR_ENUM /** * @ingroup iface_wl_display * global error values * * These errors are global and can be emitted in response to any * server request. */ enum wl_display_error { /** * server couldn't find object */ WL_DISPLAY_ERROR_INVALID_OBJECT = 0, /** * method doesn't exist on the specified interface */ WL_DISPLAY_ERROR_INVALID_METHOD = 1, /** * server is out of memory */ WL_DISPLAY_ERROR_NO_MEMORY = 2, }; #endif /* WL_DISPLAY_ERROR_ENUM */ /** * @ingroup iface_wl_display * @struct wl_display_listener */ struct wl_display_listener { /** * fatal error event * * The error event is sent out when a fatal (non-recoverable) * error has occurred. The object_id argument is the object where * the error occurred, most often in response to a request to that * object. The code identifies the error and is defined by the * object interface. As such, each interface defines its own set of * error codes. The message is a brief description of the error, * for (debugging) convenience. * @param object_id object where the error occurred * @param code error code * @param message error description */ void (*error)(void *data, struct wl_display *wl_display, void *object_id, uint32_t code, const char *message); /** * acknowledge object ID deletion * * This event is used internally by the object ID management * logic. When a client deletes an object, the server will send * this event to acknowledge that it has seen the delete request. * When the client receives this event, it will know that it can * safely reuse the object ID. * @param id deleted object ID */ void (*delete_id)(void *data, struct wl_display *wl_display, uint32_t id); }; /** * @ingroup iface_wl_display */ static inline int wl_display_add_listener(struct wl_display *wl_display, const struct wl_display_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) wl_display, (void (**)(void)) listener, data); } #define WL_DISPLAY_SYNC 0 #define WL_DISPLAY_GET_REGISTRY 1 /** * @ingroup iface_wl_display */ #define WL_DISPLAY_ERROR_SINCE_VERSION 1 /** * @ingroup iface_wl_display */ #define WL_DISPLAY_DELETE_ID_SINCE_VERSION 1 /** * @ingroup iface_wl_display */ #define WL_DISPLAY_SYNC_SINCE_VERSION 1 /** * @ingroup iface_wl_display */ #define WL_DISPLAY_GET_REGISTRY_SINCE_VERSION 1 /** @ingroup iface_wl_display */ static inline void wl_display_set_user_data(struct wl_display *wl_display, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_display, user_data); } /** @ingroup iface_wl_display */ static inline void * wl_display_get_user_data(struct wl_display *wl_display) { return wl_proxy_get_user_data((struct wl_proxy *) wl_display); } static inline uint32_t wl_display_get_version(struct wl_display *wl_display) { return wl_proxy_get_version((struct wl_proxy *) wl_display); } /** * @ingroup iface_wl_display * * The sync request asks the server to emit the 'done' event * on the returned wl_callback object. Since requests are * handled in-order and events are delivered in-order, this can * be used as a barrier to ensure all previous requests and the * resulting events have been handled. * * The object returned by this request will be destroyed by the * compositor after the callback is fired and as such the client must not * attempt to use it after that point. * * The callback_data passed in the callback is the event serial. */ static inline struct wl_callback * wl_display_sync(struct wl_display *wl_display) { struct wl_proxy *callback; callback = wl_proxy_marshal_flags((struct wl_proxy *) wl_display, WL_DISPLAY_SYNC, &wl_callback_interface, wl_proxy_get_version((struct wl_proxy *) wl_display), 0, NULL); return (struct wl_callback *) callback; } /** * @ingroup iface_wl_display * * This request creates a registry object that allows the client * to list and bind the global objects available from the * compositor. */ static inline struct wl_registry * wl_display_get_registry(struct wl_display *wl_display) { struct wl_proxy *registry; registry = wl_proxy_marshal_flags((struct wl_proxy *) wl_display, WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, wl_proxy_get_version((struct wl_proxy *) wl_display), 0, NULL); return (struct wl_registry *) registry; } /** * @ingroup iface_wl_registry * @struct wl_registry_listener */ struct wl_registry_listener { /** * announce global object * * Notify the client of global objects. * * The event notifies the client that a global object with the * given name is now available, and it implements the given version * of the given interface. * @param name numeric name of the global object * @param interface interface implemented by the object * @param version interface version */ void (*global)(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, uint32_t version); /** * announce removal of global object * * Notify the client of removed global objects. * * This event notifies the client that the global identified by * name is no longer available. If the client bound to the global * using the bind request, the client should now destroy that * object. * * The object remains valid and requests to the object will be * ignored until the client destroys it, to avoid races between the * global going away and a client sending a request to it. * @param name numeric name of the global object */ void (*global_remove)(void *data, struct wl_registry *wl_registry, uint32_t name); }; /** * @ingroup iface_wl_registry */ static inline int wl_registry_add_listener(struct wl_registry *wl_registry, const struct wl_registry_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) wl_registry, (void (**)(void)) listener, data); } #define WL_REGISTRY_BIND 0 /** * @ingroup iface_wl_registry */ #define WL_REGISTRY_GLOBAL_SINCE_VERSION 1 /** * @ingroup iface_wl_registry */ #define WL_REGISTRY_GLOBAL_REMOVE_SINCE_VERSION 1 /** * @ingroup iface_wl_registry */ #define WL_REGISTRY_BIND_SINCE_VERSION 1 /** @ingroup iface_wl_registry */ static inline void wl_registry_set_user_data(struct wl_registry *wl_registry, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_registry, user_data); } /** @ingroup iface_wl_registry */ static inline void * wl_registry_get_user_data(struct wl_registry *wl_registry) { return wl_proxy_get_user_data((struct wl_proxy *) wl_registry); } static inline uint32_t wl_registry_get_version(struct wl_registry *wl_registry) { return wl_proxy_get_version((struct wl_proxy *) wl_registry); } /** @ingroup iface_wl_registry */ static inline void wl_registry_destroy(struct wl_registry *wl_registry) { wl_proxy_destroy((struct wl_proxy *) wl_registry); } /** * @ingroup iface_wl_registry * * Binds a new, client-created object to the server using the * specified name as the identifier. */ static inline void * wl_registry_bind(struct wl_registry *wl_registry, uint32_t name, const struct wl_interface *interface, uint32_t version) { struct wl_proxy *id; id = wl_proxy_marshal_flags((struct wl_proxy *) wl_registry, WL_REGISTRY_BIND, interface, version, 0, name, interface->name, version, NULL); return (void *) id; } /** * @ingroup iface_wl_callback * @struct wl_callback_listener */ struct wl_callback_listener { /** * done event * * Notify the client when the related request is done. * @param callback_data request-specific data for the callback */ void (*done)(void *data, struct wl_callback *wl_callback, uint32_t callback_data); }; /** * @ingroup iface_wl_callback */ static inline int wl_callback_add_listener(struct wl_callback *wl_callback, const struct wl_callback_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) wl_callback, (void (**)(void)) listener, data); } /** * @ingroup iface_wl_callback */ #define WL_CALLBACK_DONE_SINCE_VERSION 1 /** @ingroup iface_wl_callback */ static inline void wl_callback_set_user_data(struct wl_callback *wl_callback, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_callback, user_data); } /** @ingroup iface_wl_callback */ static inline void * wl_callback_get_user_data(struct wl_callback *wl_callback) { return wl_proxy_get_user_data((struct wl_proxy *) wl_callback); } static inline uint32_t wl_callback_get_version(struct wl_callback *wl_callback) { return wl_proxy_get_version((struct wl_proxy *) wl_callback); } /** @ingroup iface_wl_callback */ static inline void wl_callback_destroy(struct wl_callback *wl_callback) { wl_proxy_destroy((struct wl_proxy *) wl_callback); } #define WL_COMPOSITOR_CREATE_SURFACE 0 #define WL_COMPOSITOR_CREATE_REGION 1 /** * @ingroup iface_wl_compositor */ #define WL_COMPOSITOR_CREATE_SURFACE_SINCE_VERSION 1 /** * @ingroup iface_wl_compositor */ #define WL_COMPOSITOR_CREATE_REGION_SINCE_VERSION 1 /** @ingroup iface_wl_compositor */ static inline void wl_compositor_set_user_data(struct wl_compositor *wl_compositor, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_compositor, user_data); } /** @ingroup iface_wl_compositor */ static inline void * wl_compositor_get_user_data(struct wl_compositor *wl_compositor) { return wl_proxy_get_user_data((struct wl_proxy *) wl_compositor); } static inline uint32_t wl_compositor_get_version(struct wl_compositor *wl_compositor) { return wl_proxy_get_version((struct wl_proxy *) wl_compositor); } /** @ingroup iface_wl_compositor */ static inline void wl_compositor_destroy(struct wl_compositor *wl_compositor) { wl_proxy_destroy((struct wl_proxy *) wl_compositor); } /** * @ingroup iface_wl_compositor * * Ask the compositor to create a new surface. */ static inline struct wl_surface * wl_compositor_create_surface(struct wl_compositor *wl_compositor) { struct wl_proxy *id; id = wl_proxy_marshal_flags((struct wl_proxy *) wl_compositor, WL_COMPOSITOR_CREATE_SURFACE, &wl_surface_interface, wl_proxy_get_version((struct wl_proxy *) wl_compositor), 0, NULL); return (struct wl_surface *) id; } /** * @ingroup iface_wl_compositor * * Ask the compositor to create a new region. */ static inline struct wl_region * wl_compositor_create_region(struct wl_compositor *wl_compositor) { struct wl_proxy *id; id = wl_proxy_marshal_flags((struct wl_proxy *) wl_compositor, WL_COMPOSITOR_CREATE_REGION, &wl_region_interface, wl_proxy_get_version((struct wl_proxy *) wl_compositor), 0, NULL); return (struct wl_region *) id; } #define WL_SHM_POOL_CREATE_BUFFER 0 #define WL_SHM_POOL_DESTROY 1 #define WL_SHM_POOL_RESIZE 2 /** * @ingroup iface_wl_shm_pool */ #define WL_SHM_POOL_CREATE_BUFFER_SINCE_VERSION 1 /** * @ingroup iface_wl_shm_pool */ #define WL_SHM_POOL_DESTROY_SINCE_VERSION 1 /** * @ingroup iface_wl_shm_pool */ #define WL_SHM_POOL_RESIZE_SINCE_VERSION 1 /** @ingroup iface_wl_shm_pool */ static inline void wl_shm_pool_set_user_data(struct wl_shm_pool *wl_shm_pool, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_shm_pool, user_data); } /** @ingroup iface_wl_shm_pool */ static inline void * wl_shm_pool_get_user_data(struct wl_shm_pool *wl_shm_pool) { return wl_proxy_get_user_data((struct wl_proxy *) wl_shm_pool); } static inline uint32_t wl_shm_pool_get_version(struct wl_shm_pool *wl_shm_pool) { return wl_proxy_get_version((struct wl_proxy *) wl_shm_pool); } /** * @ingroup iface_wl_shm_pool * * Create a wl_buffer object from the pool. * * The buffer is created offset bytes into the pool and has * width and height as specified. The stride argument specifies * the number of bytes from the beginning of one row to the beginning * of the next. The format is the pixel format of the buffer and * must be one of those advertised through the wl_shm.format event. * * A buffer will keep a reference to the pool it was created from * so it is valid to destroy the pool immediately after creating * a buffer from it. */ static inline struct wl_buffer * wl_shm_pool_create_buffer(struct wl_shm_pool *wl_shm_pool, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) { struct wl_proxy *id; id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool, WL_SHM_POOL_CREATE_BUFFER, &wl_buffer_interface, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), 0, NULL, offset, width, height, stride, format); return (struct wl_buffer *) id; } /** * @ingroup iface_wl_shm_pool * * Destroy the shared memory pool. * * The mmapped memory will be released when all * buffers that have been created from this pool * are gone. */ static inline void wl_shm_pool_destroy(struct wl_shm_pool *wl_shm_pool) { wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool, WL_SHM_POOL_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), WL_MARSHAL_FLAG_DESTROY); } /** * @ingroup iface_wl_shm_pool * * This request will cause the server to remap the backing memory * for the pool from the file descriptor passed when the pool was * created, but using the new size. This request can only be * used to make the pool bigger. */ static inline void wl_shm_pool_resize(struct wl_shm_pool *wl_shm_pool, int32_t size) { wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool, WL_SHM_POOL_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), 0, size); } #ifndef WL_SHM_ERROR_ENUM #define WL_SHM_ERROR_ENUM /** * @ingroup iface_wl_shm * wl_shm error values * * These errors can be emitted in response to wl_shm requests. */ enum wl_shm_error { /** * buffer format is not known */ WL_SHM_ERROR_INVALID_FORMAT = 0, /** * invalid size or stride during pool or buffer creation */ WL_SHM_ERROR_INVALID_STRIDE = 1, /** * mmapping the file descriptor failed */ WL_SHM_ERROR_INVALID_FD = 2, }; #endif /* WL_SHM_ERROR_ENUM */ #ifndef WL_SHM_FORMAT_ENUM #define WL_SHM_FORMAT_ENUM /** * @ingroup iface_wl_shm * pixel formats * * This describes the memory layout of an individual pixel. * * All renderers should support argb8888 and xrgb8888 but any other * formats are optional and may not be supported by the particular * renderer in use. * * The drm format codes match the macros defined in drm_fourcc.h. * The formats actually supported by the compositor will be * reported by the format event. */ enum wl_shm_format { /** * 32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian */ WL_SHM_FORMAT_ARGB8888 = 0, /** * 32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian */ WL_SHM_FORMAT_XRGB8888 = 1, /** * 8-bit color index format, [7:0] C */ WL_SHM_FORMAT_C8 = 0x20203843, /** * 8-bit RGB format, [7:0] R:G:B 3:3:2 */ WL_SHM_FORMAT_RGB332 = 0x38424752, /** * 8-bit BGR format, [7:0] B:G:R 2:3:3 */ WL_SHM_FORMAT_BGR233 = 0x38524742, /** * 16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian */ WL_SHM_FORMAT_XRGB4444 = 0x32315258, /** * 16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian */ WL_SHM_FORMAT_XBGR4444 = 0x32314258, /** * 16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian */ WL_SHM_FORMAT_RGBX4444 = 0x32315852, /** * 16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian */ WL_SHM_FORMAT_BGRX4444 = 0x32315842, /** * 16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian */ WL_SHM_FORMAT_ARGB4444 = 0x32315241, /** * 16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian */ WL_SHM_FORMAT_ABGR4444 = 0x32314241, /** * 16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian */ WL_SHM_FORMAT_RGBA4444 = 0x32314152, /** * 16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian */ WL_SHM_FORMAT_BGRA4444 = 0x32314142, /** * 16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian */ WL_SHM_FORMAT_XRGB1555 = 0x35315258, /** * 16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian */ WL_SHM_FORMAT_XBGR1555 = 0x35314258, /** * 16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian */ WL_SHM_FORMAT_RGBX5551 = 0x35315852, /** * 16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian */ WL_SHM_FORMAT_BGRX5551 = 0x35315842, /** * 16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian */ WL_SHM_FORMAT_ARGB1555 = 0x35315241, /** * 16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian */ WL_SHM_FORMAT_ABGR1555 = 0x35314241, /** * 16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian */ WL_SHM_FORMAT_RGBA5551 = 0x35314152, /** * 16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian */ WL_SHM_FORMAT_BGRA5551 = 0x35314142, /** * 16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian */ WL_SHM_FORMAT_RGB565 = 0x36314752, /** * 16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian */ WL_SHM_FORMAT_BGR565 = 0x36314742, /** * 24-bit RGB format, [23:0] R:G:B little endian */ WL_SHM_FORMAT_RGB888 = 0x34324752, /** * 24-bit BGR format, [23:0] B:G:R little endian */ WL_SHM_FORMAT_BGR888 = 0x34324742, /** * 32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian */ WL_SHM_FORMAT_XBGR8888 = 0x34324258, /** * 32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian */ WL_SHM_FORMAT_RGBX8888 = 0x34325852, /** * 32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian */ WL_SHM_FORMAT_BGRX8888 = 0x34325842, /** * 32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian */ WL_SHM_FORMAT_ABGR8888 = 0x34324241, /** * 32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian */ WL_SHM_FORMAT_RGBA8888 = 0x34324152, /** * 32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian */ WL_SHM_FORMAT_BGRA8888 = 0x34324142, /** * 32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian */ WL_SHM_FORMAT_XRGB2101010 = 0x30335258, /** * 32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian */ WL_SHM_FORMAT_XBGR2101010 = 0x30334258, /** * 32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian */ WL_SHM_FORMAT_RGBX1010102 = 0x30335852, /** * 32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian */ WL_SHM_FORMAT_BGRX1010102 = 0x30335842, /** * 32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian */ WL_SHM_FORMAT_ARGB2101010 = 0x30335241, /** * 32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian */ WL_SHM_FORMAT_ABGR2101010 = 0x30334241, /** * 32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian */ WL_SHM_FORMAT_RGBA1010102 = 0x30334152, /** * 32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian */ WL_SHM_FORMAT_BGRA1010102 = 0x30334142, /** * packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */ WL_SHM_FORMAT_YUYV = 0x56595559, /** * packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian */ WL_SHM_FORMAT_YVYU = 0x55595659, /** * packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian */ WL_SHM_FORMAT_UYVY = 0x59565955, /** * packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian */ WL_SHM_FORMAT_VYUY = 0x59555956, /** * packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */ WL_SHM_FORMAT_AYUV = 0x56555941, /** * 2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane */ WL_SHM_FORMAT_NV12 = 0x3231564e, /** * 2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane */ WL_SHM_FORMAT_NV21 = 0x3132564e, /** * 2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane */ WL_SHM_FORMAT_NV16 = 0x3631564e, /** * 2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane */ WL_SHM_FORMAT_NV61 = 0x3136564e, /** * 3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes */ WL_SHM_FORMAT_YUV410 = 0x39565559, /** * 3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes */ WL_SHM_FORMAT_YVU410 = 0x39555659, /** * 3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes */ WL_SHM_FORMAT_YUV411 = 0x31315559, /** * 3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes */ WL_SHM_FORMAT_YVU411 = 0x31315659, /** * 3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes */ WL_SHM_FORMAT_YUV420 = 0x32315559, /** * 3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes */ WL_SHM_FORMAT_YVU420 = 0x32315659, /** * 3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes */ WL_SHM_FORMAT_YUV422 = 0x36315559, /** * 3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes */ WL_SHM_FORMAT_YVU422 = 0x36315659, /** * 3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes */ WL_SHM_FORMAT_YUV444 = 0x34325559, /** * 3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes */ WL_SHM_FORMAT_YVU444 = 0x34325659, }; #endif /* WL_SHM_FORMAT_ENUM */ /** * @ingroup iface_wl_shm * @struct wl_shm_listener */ struct wl_shm_listener { /** * pixel format description * * Informs the client about a valid pixel format that can be used * for buffers. Known formats include argb8888 and xrgb8888. * @param format buffer pixel format */ void (*format)(void *data, struct wl_shm *wl_shm, uint32_t format); }; /** * @ingroup iface_wl_shm */ static inline int wl_shm_add_listener(struct wl_shm *wl_shm, const struct wl_shm_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) wl_shm, (void (**)(void)) listener, data); } #define WL_SHM_CREATE_POOL 0 /** * @ingroup iface_wl_shm */ #define WL_SHM_FORMAT_SINCE_VERSION 1 /** * @ingroup iface_wl_shm */ #define WL_SHM_CREATE_POOL_SINCE_VERSION 1 /** @ingroup iface_wl_shm */ static inline void wl_shm_set_user_data(struct wl_shm *wl_shm, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_shm, user_data); } /** @ingroup iface_wl_shm */ static inline void * wl_shm_get_user_data(struct wl_shm *wl_shm) { return wl_proxy_get_user_data((struct wl_proxy *) wl_shm); } static inline uint32_t wl_shm_get_version(struct wl_shm *wl_shm) { return wl_proxy_get_version((struct wl_proxy *) wl_shm); } /** @ingroup iface_wl_shm */ static inline void wl_shm_destroy(struct wl_shm *wl_shm) { wl_proxy_destroy((struct wl_proxy *) wl_shm); } /** * @ingroup iface_wl_shm * * Create a new wl_shm_pool object. * * The pool can be used to create shared memory based buffer * objects. The server will mmap size bytes of the passed file * descriptor, to use as backing memory for the pool. */ static inline struct wl_shm_pool * wl_shm_create_pool(struct wl_shm *wl_shm, int32_t fd, int32_t size) { struct wl_proxy *id; id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shm, WL_SHM_CREATE_POOL, &wl_shm_pool_interface, wl_proxy_get_version((struct wl_proxy *) wl_shm), 0, NULL, fd, size); return (struct wl_shm_pool *) id; } /** * @ingroup iface_wl_buffer * @struct wl_buffer_listener */ struct wl_buffer_listener { /** * compositor releases buffer * * Sent when this wl_buffer is no longer used by the compositor. * The client is now free to reuse or destroy this buffer and its * backing storage. * * If a client receives a release event before the frame callback * requested in the same wl_surface.commit that attaches this * wl_buffer to a surface, then the client is immediately free to * reuse the buffer and its backing storage, and does not need a * second buffer for the next surface content update. Typically * this is possible, when the compositor maintains a copy of the * wl_surface contents, e.g. as a GL texture. This is an important * optimization for GL(ES) compositors with wl_shm clients. */ void (*release)(void *data, struct wl_buffer *wl_buffer); }; /** * @ingroup iface_wl_buffer */ static inline int wl_buffer_add_listener(struct wl_buffer *wl_buffer, const struct wl_buffer_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) wl_buffer, (void (**)(void)) listener, data); } #define WL_BUFFER_DESTROY 0 /** * @ingroup iface_wl_buffer */ #define WL_BUFFER_RELEASE_SINCE_VERSION 1 /** * @ingroup iface_wl_buffer */ #define WL_BUFFER_DESTROY_SINCE_VERSION 1 /** @ingroup iface_wl_buffer */ static inline void wl_buffer_set_user_data(struct wl_buffer *wl_buffer, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_buffer, user_data); } /** @ingroup iface_wl_buffer */ static inline void * wl_buffer_get_user_data(struct wl_buffer *wl_buffer) { return wl_proxy_get_user_data((struct wl_proxy *) wl_buffer); } static inline uint32_t wl_buffer_get_version(struct wl_buffer *wl_buffer) { return wl_proxy_get_version((struct wl_proxy *) wl_buffer); } /** * @ingroup iface_wl_buffer * * Destroy a buffer. If and how you need to release the backing * storage is defined by the buffer factory interface. * * For possible side-effects to a surface, see wl_surface.attach. */ static inline void wl_buffer_destroy(struct wl_buffer *wl_buffer) { wl_proxy_marshal_flags((struct wl_proxy *) wl_buffer, WL_BUFFER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_buffer), WL_MARSHAL_FLAG_DESTROY); } #ifndef WL_DATA_OFFER_ERROR_ENUM #define WL_DATA_OFFER_ERROR_ENUM enum wl_data_offer_error { /** * finish request was called untimely */ WL_DATA_OFFER_ERROR_INVALID_FINISH = 0, /** * action mask contains invalid values */ WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK = 1, /** * action argument has an invalid value */ WL_DATA_OFFER_ERROR_INVALID_ACTION = 2, /** * offer doesn't accept this request */ WL_DATA_OFFER_ERROR_INVALID_OFFER = 3, }; #endif /* WL_DATA_OFFER_ERROR_ENUM */ /** * @ingroup iface_wl_data_offer * @struct wl_data_offer_listener */ struct wl_data_offer_listener { /** * advertise offered mime type * * Sent immediately after creating the wl_data_offer object. One * event per offered mime type. * @param mime_type offered mime type */ void (*offer)(void *data, struct wl_data_offer *wl_data_offer, const char *mime_type); /** * notify the source-side available actions * * This event indicates the actions offered by the data source. * It will be sent right after wl_data_device.enter, or anytime the * source side changes its offered actions through * wl_data_source.set_actions. * @param source_actions actions offered by the data source * @since 3 */ void (*source_actions)(void *data, struct wl_data_offer *wl_data_offer, uint32_t source_actions); /** * notify the selected action * * This event indicates the action selected by the compositor * after matching the source/destination side actions. Only one * action (or none) will be offered here. * * This event can be emitted multiple times during the * drag-and-drop operation in response to destination side action * changes through wl_data_offer.set_actions. * * This event will no longer be emitted after wl_data_device.drop * happened on the drag-and-drop destination, the client must honor * the last action received, or the last preferred one set through * wl_data_offer.set_actions when handling an "ask" action. * * Compositors may also change the selected action on the fly, * mainly in response to keyboard modifier changes during the * drag-and-drop operation. * * The most recent action received is always the valid one. Prior * to receiving wl_data_device.drop, the chosen action may change * (e.g. due to keyboard modifiers being pressed). At the time of * receiving wl_data_device.drop the drag-and-drop destination must * honor the last action received. * * Action changes may still happen after wl_data_device.drop, * especially on "ask" actions, where the drag-and-drop destination * may choose another action afterwards. Action changes happening * at this stage are always the result of inter-client negotiation, * the compositor shall no longer be able to induce a different * action. * * Upon "ask" actions, it is expected that the drag-and-drop * destination may potentially choose a different action and/or * mime type, based on wl_data_offer.source_actions and finally * chosen by the user (e.g. popping up a menu with the available * options). The final wl_data_offer.set_actions and * wl_data_offer.accept requests must happen before the call to * wl_data_offer.finish. * @param dnd_action action selected by the compositor * @since 3 */ void (*action)(void *data, struct wl_data_offer *wl_data_offer, uint32_t dnd_action); }; /** * @ingroup iface_wl_data_offer */ static inline int wl_data_offer_add_listener(struct wl_data_offer *wl_data_offer, const struct wl_data_offer_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) wl_data_offer, (void (**)(void)) listener, data); } #define WL_DATA_OFFER_ACCEPT 0 #define WL_DATA_OFFER_RECEIVE 1 #define WL_DATA_OFFER_DESTROY 2 #define WL_DATA_OFFER_FINISH 3 #define WL_DATA_OFFER_SET_ACTIONS 4 /** * @ingroup iface_wl_data_offer */ #define WL_DATA_OFFER_OFFER_SINCE_VERSION 1 /** * @ingroup iface_wl_data_offer */ #define WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION 3 /** * @ingroup iface_wl_data_offer */ #define WL_DATA_OFFER_ACTION_SINCE_VERSION 3 /** * @ingroup iface_wl_data_offer */ #define WL_DATA_OFFER_ACCEPT_SINCE_VERSION 1 /** * @ingroup iface_wl_data_offer */ #define WL_DATA_OFFER_RECEIVE_SINCE_VERSION 1 /** * @ingroup iface_wl_data_offer */ #define WL_DATA_OFFER_DESTROY_SINCE_VERSION 1 /** * @ingroup iface_wl_data_offer */ #define WL_DATA_OFFER_FINISH_SINCE_VERSION 3 /** * @ingroup iface_wl_data_offer */ #define WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION 3 /** @ingroup iface_wl_data_offer */ static inline void wl_data_offer_set_user_data(struct wl_data_offer *wl_data_offer, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_data_offer, user_data); } /** @ingroup iface_wl_data_offer */ static inline void * wl_data_offer_get_user_data(struct wl_data_offer *wl_data_offer) { return wl_proxy_get_user_data((struct wl_proxy *) wl_data_offer); } static inline uint32_t wl_data_offer_get_version(struct wl_data_offer *wl_data_offer) { return wl_proxy_get_version((struct wl_proxy *) wl_data_offer); } /** * @ingroup iface_wl_data_offer * * Indicate that the client can accept the given mime type, or * NULL for not accepted. * * For objects of version 2 or older, this request is used by the * client to give feedback whether the client can receive the given * mime type, or NULL if none is accepted; the feedback does not * determine whether the drag-and-drop operation succeeds or not. * * For objects of version 3 or newer, this request determines the * final result of the drag-and-drop operation. If the end result * is that no mime types were accepted, the drag-and-drop operation * will be cancelled and the corresponding drag source will receive * wl_data_source.cancelled. Clients may still use this event in * conjunction with wl_data_source.action for feedback. */ static inline void wl_data_offer_accept(struct wl_data_offer *wl_data_offer, uint32_t serial, const char *mime_type) { wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, WL_DATA_OFFER_ACCEPT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, serial, mime_type); } /** * @ingroup iface_wl_data_offer * * To transfer the offered data, the client issues this request * and indicates the mime type it wants to receive. The transfer * happens through the passed file descriptor (typically created * with the pipe system call). The source client writes the data * in the mime type representation requested and then closes the * file descriptor. * * The receiving client reads from the read end of the pipe until * EOF and then closes its end, at which point the transfer is * complete. * * This request may happen multiple times for different mime types, * both before and after wl_data_device.drop. Drag-and-drop destination * clients may preemptively fetch data or examine it more closely to * determine acceptance. */ static inline void wl_data_offer_receive(struct wl_data_offer *wl_data_offer, const char *mime_type, int32_t fd) { wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, WL_DATA_OFFER_RECEIVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, mime_type, fd); } /** * @ingroup iface_wl_data_offer * * Destroy the data offer. */ static inline void wl_data_offer_destroy(struct wl_data_offer *wl_data_offer) { wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, WL_DATA_OFFER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), WL_MARSHAL_FLAG_DESTROY); } /** * @ingroup iface_wl_data_offer * * Notifies the compositor that the drag destination successfully * finished the drag-and-drop operation. * * Upon receiving this request, the compositor will emit * wl_data_source.dnd_finished on the drag source client. * * It is a client error to perform other requests than * wl_data_offer.destroy after this one. It is also an error to perform * this request after a NULL mime type has been set in * wl_data_offer.accept or no action was received through * wl_data_offer.action. */ static inline void wl_data_offer_finish(struct wl_data_offer *wl_data_offer) { wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, WL_DATA_OFFER_FINISH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0); } /** * @ingroup iface_wl_data_offer * * Sets the actions that the destination side client supports for * this operation. This request may trigger the emission of * wl_data_source.action and wl_data_offer.action events if the compositor * needs to change the selected action. * * This request can be called multiple times throughout the * drag-and-drop operation, typically in response to wl_data_device.enter * or wl_data_device.motion events. * * This request determines the final result of the drag-and-drop * operation. If the end result is that no action is accepted, * the drag source will receive wl_drag_source.cancelled. * * The dnd_actions argument must contain only values expressed in the * wl_data_device_manager.dnd_actions enum, and the preferred_action * argument must only contain one of those values set, otherwise it * will result in a protocol error. * * While managing an "ask" action, the destination drag-and-drop client * may perform further wl_data_offer.receive requests, and is expected * to perform one last wl_data_offer.set_actions request with a preferred * action other than "ask" (and optionally wl_data_offer.accept) before * requesting wl_data_offer.finish, in order to convey the action selected * by the user. If the preferred action is not in the * wl_data_offer.source_actions mask, an error will be raised. * * If the "ask" action is dismissed (e.g. user cancellation), the client * is expected to perform wl_data_offer.destroy right away. * * This request can only be made on drag-and-drop offers, a protocol error * will be raised otherwise. */ static inline void wl_data_offer_set_actions(struct wl_data_offer *wl_data_offer, uint32_t dnd_actions, uint32_t preferred_action) { wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer, WL_DATA_OFFER_SET_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, dnd_actions, preferred_action); } #ifndef WL_DATA_SOURCE_ERROR_ENUM #define WL_DATA_SOURCE_ERROR_ENUM enum wl_data_source_error { /** * action mask contains invalid values */ WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK = 0, /** * source doesn't accept this request */ WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1, }; #endif /* WL_DATA_SOURCE_ERROR_ENUM */ /** * @ingroup iface_wl_data_source * @struct wl_data_source_listener */ struct wl_data_source_listener { /** * a target accepts an offered mime type * * Sent when a target accepts pointer_focus or motion events. If * a target does not accept any of the offered types, type is NULL. * * Used for feedback during drag-and-drop. * @param mime_type mime type accepted by the target */ void (*target)(void *data, struct wl_data_source *wl_data_source, const char *mime_type); /** * send the data * * Request for data from the client. Send the data as the * specified mime type over the passed file descriptor, then close * it. * @param mime_type mime type for the data * @param fd file descriptor for the data */ void (*send)(void *data, struct wl_data_source *wl_data_source, const char *mime_type, int32_t fd); /** * selection was cancelled * * This data source is no longer valid. There are several reasons * why this could happen: * * - The data source has been replaced by another data source. - * The drag-and-drop operation was performed, but the drop * destination did not accept any of the mime types offered through * wl_data_source.target. - The drag-and-drop operation was * performed, but the drop destination did not select any of the * actions present in the mask offered through * wl_data_source.action. - The drag-and-drop operation was * performed but didn't happen over a surface. - The compositor * cancelled the drag-and-drop operation (e.g. compositor dependent * timeouts to avoid stale drag-and-drop transfers). * * The client should clean up and destroy this data source. * * For objects of version 2 or older, wl_data_source.cancelled will * only be emitted if the data source was replaced by another data * source. */ void (*cancelled)(void *data, struct wl_data_source *wl_data_source); /** * the drag-and-drop operation physically finished * * The user performed the drop action. This event does not * indicate acceptance, wl_data_source.cancelled may still be * emitted afterwards if the drop destination does not accept any * mime type. * * However, this event might however not be received if the * compositor cancelled the drag-and-drop operation before this * event could happen. * * Note that the data_source may still be used in the future and * should not be destroyed here. * @since 3 */ void (*dnd_drop_performed)(void *data, struct wl_data_source *wl_data_source); /** * the drag-and-drop operation concluded * * The drop destination finished interoperating with this data * source, so the client is now free to destroy this data source * and free all associated data. * * If the action used to perform the operation was "move", the * source can now delete the transferred data. * @since 3 */ void (*dnd_finished)(void *data, struct wl_data_source *wl_data_source); /** * notify the selected action * * This event indicates the action selected by the compositor * after matching the source/destination side actions. Only one * action (or none) will be offered here. * * This event can be emitted multiple times during the * drag-and-drop operation, mainly in response to destination side * changes through wl_data_offer.set_actions, and as the data * device enters/leaves surfaces. * * It is only possible to receive this event after * wl_data_source.dnd_drop_performed if the drag-and-drop operation * ended in an "ask" action, in which case the final * wl_data_source.action event will happen immediately before * wl_data_source.dnd_finished. * * Compositors may also change the selected action on the fly, * mainly in response to keyboard modifier changes during the * drag-and-drop operation. * * The most recent action received is always the valid one. The * chosen action may change alongside negotiation (e.g. an "ask" * action can turn into a "move" operation), so the effects of the * final action must always be applied in * wl_data_offer.dnd_finished. * * Clients can trigger cursor surface changes from this point, so * they reflect the current action. * @param dnd_action action selected by the compositor * @since 3 */ void (*action)(void *data, struct wl_data_source *wl_data_source, uint32_t dnd_action); }; /** * @ingroup iface_wl_data_source */ static inline int wl_data_source_add_listener(struct wl_data_source *wl_data_source, const struct wl_data_source_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) wl_data_source, (void (**)(void)) listener, data); } #define WL_DATA_SOURCE_OFFER 0 #define WL_DATA_SOURCE_DESTROY 1 #define WL_DATA_SOURCE_SET_ACTIONS 2 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_TARGET_SINCE_VERSION 1 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_SEND_SINCE_VERSION 1 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_CANCELLED_SINCE_VERSION 1 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION 3 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION 3 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_ACTION_SINCE_VERSION 3 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_OFFER_SINCE_VERSION 1 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_DESTROY_SINCE_VERSION 1 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION 3 /** @ingroup iface_wl_data_source */ static inline void wl_data_source_set_user_data(struct wl_data_source *wl_data_source, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_data_source, user_data); } /** @ingroup iface_wl_data_source */ static inline void * wl_data_source_get_user_data(struct wl_data_source *wl_data_source) { return wl_proxy_get_user_data((struct wl_proxy *) wl_data_source); } static inline uint32_t wl_data_source_get_version(struct wl_data_source *wl_data_source) { return wl_proxy_get_version((struct wl_proxy *) wl_data_source); } /** * @ingroup iface_wl_data_source * * This request adds a mime type to the set of mime types * advertised to targets. Can be called several times to offer * multiple types. */ static inline void wl_data_source_offer(struct wl_data_source *wl_data_source, const char *mime_type) { wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source, WL_DATA_SOURCE_OFFER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), 0, mime_type); } /** * @ingroup iface_wl_data_source * * Destroy the data source. */ static inline void wl_data_source_destroy(struct wl_data_source *wl_data_source) { wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source, WL_DATA_SOURCE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), WL_MARSHAL_FLAG_DESTROY); } /** * @ingroup iface_wl_data_source * * Sets the actions that the source side client supports for this * operation. This request may trigger wl_data_source.action and * wl_data_offer.action events if the compositor needs to change the * selected action. * * The dnd_actions argument must contain only values expressed in the * wl_data_device_manager.dnd_actions enum, otherwise it will result * in a protocol error. * * This request must be made once only, and can only be made on sources * used in drag-and-drop, so it must be performed before * wl_data_device.start_drag. Attempting to use the source other than * for drag-and-drop will raise a protocol error. */ static inline void wl_data_source_set_actions(struct wl_data_source *wl_data_source, uint32_t dnd_actions) { wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source, WL_DATA_SOURCE_SET_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), 0, dnd_actions); } #ifndef WL_DATA_DEVICE_ERROR_ENUM #define WL_DATA_DEVICE_ERROR_ENUM enum wl_data_device_error { /** * given wl_surface has another role */ WL_DATA_DEVICE_ERROR_ROLE = 0, }; #endif /* WL_DATA_DEVICE_ERROR_ENUM */ /** * @ingroup iface_wl_data_device * @struct wl_data_device_listener */ struct wl_data_device_listener { /** * introduce a new wl_data_offer * * The data_offer event introduces a new wl_data_offer object, * which will subsequently be used in either the data_device.enter * event (for drag-and-drop) or the data_device.selection event * (for selections). Immediately following the * data_device.data_offer event, the new data_offer object will * send out data_offer.offer events to describe the mime types it * offers. * @param id the new data_offer object */ void (*data_offer)(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *id); /** * initiate drag-and-drop session * * This event is sent when an active drag-and-drop pointer enters * a surface owned by the client. The position of the pointer at * enter time is provided by the x and y arguments, in * surface-local coordinates. * @param serial serial number of the enter event * @param surface client surface entered * @param x surface-local x coordinate * @param y surface-local y coordinate * @param id source data_offer object */ void (*enter)(void *data, struct wl_data_device *wl_data_device, uint32_t serial, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id); /** * end drag-and-drop session * * This event is sent when the drag-and-drop pointer leaves the * surface and the session ends. The client must destroy the * wl_data_offer introduced at enter time at this point. */ void (*leave)(void *data, struct wl_data_device *wl_data_device); /** * drag-and-drop session motion * * This event is sent when the drag-and-drop pointer moves within * the currently focused surface. The new position of the pointer * is provided by the x and y arguments, in surface-local * coordinates. * @param time timestamp with millisecond granularity * @param x surface-local x coordinate * @param y surface-local y coordinate */ void (*motion)(void *data, struct wl_data_device *wl_data_device, uint32_t time, wl_fixed_t x, wl_fixed_t y); /** * end drag-and-drop session successfully * * The event is sent when a drag-and-drop operation is ended * because the implicit grab is removed. * * The drag-and-drop destination is expected to honor the last * action received through wl_data_offer.action, if the resulting * action is "copy" or "move", the destination can still perform * wl_data_offer.receive requests, and is expected to end all * transfers with a wl_data_offer.finish request. * * If the resulting action is "ask", the action will not be * considered final. The drag-and-drop destination is expected to * perform one last wl_data_offer.set_actions request, or * wl_data_offer.destroy in order to cancel the operation. */ void (*drop)(void *data, struct wl_data_device *wl_data_device); /** * advertise new selection * * The selection event is sent out to notify the client of a new * wl_data_offer for the selection for this device. The * data_device.data_offer and the data_offer.offer events are sent * out immediately before this event to introduce the data offer * object. The selection event is sent to a client immediately * before receiving keyboard focus and when a new selection is set * while the client has keyboard focus. The data_offer is valid * until a new data_offer or NULL is received or until the client * loses keyboard focus. The client must destroy the previous * selection data_offer, if any, upon receiving this event. * @param id selection data_offer object */ void (*selection)(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *id); }; /** * @ingroup iface_wl_data_device */ static inline int wl_data_device_add_listener(struct wl_data_device *wl_data_device, const struct wl_data_device_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) wl_data_device, (void (**)(void)) listener, data); } #define WL_DATA_DEVICE_START_DRAG 0 #define WL_DATA_DEVICE_SET_SELECTION 1 #define WL_DATA_DEVICE_RELEASE 2 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_DATA_OFFER_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_ENTER_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_LEAVE_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_MOTION_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_DROP_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_SELECTION_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_START_DRAG_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_SET_SELECTION_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_RELEASE_SINCE_VERSION 2 /** @ingroup iface_wl_data_device */ static inline void wl_data_device_set_user_data(struct wl_data_device *wl_data_device, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_data_device, user_data); } /** @ingroup iface_wl_data_device */ static inline void * wl_data_device_get_user_data(struct wl_data_device *wl_data_device) { return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device); } static inline uint32_t wl_data_device_get_version(struct wl_data_device *wl_data_device) { return wl_proxy_get_version((struct wl_proxy *) wl_data_device); } /** @ingroup iface_wl_data_device */ static inline void wl_data_device_destroy(struct wl_data_device *wl_data_device) { wl_proxy_destroy((struct wl_proxy *) wl_data_device); } /** * @ingroup iface_wl_data_device * * This request asks the compositor to start a drag-and-drop * operation on behalf of the client. * * The source argument is the data source that provides the data * for the eventual data transfer. If source is NULL, enter, leave * and motion events are sent only to the client that initiated the * drag and the client is expected to handle the data passing * internally. * * The origin surface is the surface where the drag originates and * the client must have an active implicit grab that matches the * serial. * * The icon surface is an optional (can be NULL) surface that * provides an icon to be moved around with the cursor. Initially, * the top-left corner of the icon surface is placed at the cursor * hotspot, but subsequent wl_surface.attach request can move the * relative position. Attach requests must be confirmed with * wl_surface.commit as usual. The icon surface is given the role of * a drag-and-drop icon. If the icon surface already has another role, * it raises a protocol error. * * The current and pending input regions of the icon wl_surface are * cleared, and wl_surface.set_input_region is ignored until the * wl_surface is no longer used as the icon surface. When the use * as an icon ends, the current and pending input regions become * undefined, and the wl_surface is unmapped. */ static inline void wl_data_device_start_drag(struct wl_data_device *wl_data_device, struct wl_data_source *source, struct wl_surface *origin, struct wl_surface *icon, uint32_t serial) { wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device, WL_DATA_DEVICE_START_DRAG, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), 0, source, origin, icon, serial); } /** * @ingroup iface_wl_data_device * * This request asks the compositor to set the selection * to the data from the source on behalf of the client. * * To unset the selection, set the source to NULL. */ static inline void wl_data_device_set_selection(struct wl_data_device *wl_data_device, struct wl_data_source *source, uint32_t serial) { wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device, WL_DATA_DEVICE_SET_SELECTION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), 0, source, serial); } /** * @ingroup iface_wl_data_device * * This request destroys the data device. */ static inline void wl_data_device_release(struct wl_data_device *wl_data_device) { wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device, WL_DATA_DEVICE_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), WL_MARSHAL_FLAG_DESTROY); } #ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM #define WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM /** * @ingroup iface_wl_data_device_manager * drag and drop actions * * This is a bitmask of the available/preferred actions in a * drag-and-drop operation. * * In the compositor, the selected action is a result of matching the * actions offered by the source and destination sides. "action" events * with a "none" action will be sent to both source and destination if * there is no match. All further checks will effectively happen on * (source actions ∩ destination actions). * * In addition, compositors may also pick different actions in * reaction to key modifiers being pressed. One common design that * is used in major toolkits (and the behavior recommended for * compositors) is: * * - If no modifiers are pressed, the first match (in bit order) * will be used. * - Pressing Shift selects "move", if enabled in the mask. * - Pressing Control selects "copy", if enabled in the mask. * * Behavior beyond that is considered implementation-dependent. * Compositors may for example bind other modifiers (like Alt/Meta) * or drags initiated with other buttons than BTN_LEFT to specific * actions (e.g. "ask"). */ enum wl_data_device_manager_dnd_action { /** * no action */ WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE = 0, /** * copy action */ WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY = 1, /** * move action */ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE = 2, /** * ask action */ WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4, }; #endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */ #define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE 0 #define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE 1 /** * @ingroup iface_wl_data_device_manager */ #define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device_manager */ #define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE_SINCE_VERSION 1 /** @ingroup iface_wl_data_device_manager */ static inline void wl_data_device_manager_set_user_data(struct wl_data_device_manager *wl_data_device_manager, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_data_device_manager, user_data); } /** @ingroup iface_wl_data_device_manager */ static inline void * wl_data_device_manager_get_user_data(struct wl_data_device_manager *wl_data_device_manager) { return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device_manager); } static inline uint32_t wl_data_device_manager_get_version(struct wl_data_device_manager *wl_data_device_manager) { return wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager); } /** @ingroup iface_wl_data_device_manager */ static inline void wl_data_device_manager_destroy(struct wl_data_device_manager *wl_data_device_manager) { wl_proxy_destroy((struct wl_proxy *) wl_data_device_manager); } /** * @ingroup iface_wl_data_device_manager * * Create a new data source. */ static inline struct wl_data_source * wl_data_device_manager_create_data_source(struct wl_data_device_manager *wl_data_device_manager) { struct wl_proxy *id; id = wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device_manager, WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE, &wl_data_source_interface, wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager), 0, NULL); return (struct wl_data_source *) id; } /** * @ingroup iface_wl_data_device_manager * * Create a new data device for a given seat. */ static inline struct wl_data_device * wl_data_device_manager_get_data_device(struct wl_data_device_manager *wl_data_device_manager, struct wl_seat *seat) { struct wl_proxy *id; id = wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device_manager, WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE, &wl_data_device_interface, wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager), 0, NULL, seat); return (struct wl_data_device *) id; } #ifndef WL_SHELL_ERROR_ENUM #define WL_SHELL_ERROR_ENUM enum wl_shell_error { /** * given wl_surface has another role */ WL_SHELL_ERROR_ROLE = 0, }; #endif /* WL_SHELL_ERROR_ENUM */ #define WL_SHELL_GET_SHELL_SURFACE 0 /** * @ingroup iface_wl_shell */ #define WL_SHELL_GET_SHELL_SURFACE_SINCE_VERSION 1 /** @ingroup iface_wl_shell */ static inline void wl_shell_set_user_data(struct wl_shell *wl_shell, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_shell, user_data); } /** @ingroup iface_wl_shell */ static inline void * wl_shell_get_user_data(struct wl_shell *wl_shell) { return wl_proxy_get_user_data((struct wl_proxy *) wl_shell); } static inline uint32_t wl_shell_get_version(struct wl_shell *wl_shell) { return wl_proxy_get_version((struct wl_proxy *) wl_shell); } /** @ingroup iface_wl_shell */ static inline void wl_shell_destroy(struct wl_shell *wl_shell) { wl_proxy_destroy((struct wl_proxy *) wl_shell); } /** * @ingroup iface_wl_shell * * Create a shell surface for an existing surface. This gives * the wl_surface the role of a shell surface. If the wl_surface * already has another role, it raises a protocol error. * * Only one shell surface can be associated with a given surface. */ static inline struct wl_shell_surface * wl_shell_get_shell_surface(struct wl_shell *wl_shell, struct wl_surface *surface) { struct wl_proxy *id; id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shell, WL_SHELL_GET_SHELL_SURFACE, &wl_shell_surface_interface, wl_proxy_get_version((struct wl_proxy *) wl_shell), 0, NULL, surface); return (struct wl_shell_surface *) id; } #ifndef WL_SHELL_SURFACE_RESIZE_ENUM #define WL_SHELL_SURFACE_RESIZE_ENUM /** * @ingroup iface_wl_shell_surface * edge values for resizing * * These values are used to indicate which edge of a surface * is being dragged in a resize operation. The server may * use this information to adapt its behavior, e.g. choose * an appropriate cursor image. */ enum wl_shell_surface_resize { /** * no edge */ WL_SHELL_SURFACE_RESIZE_NONE = 0, /** * top edge */ WL_SHELL_SURFACE_RESIZE_TOP = 1, /** * bottom edge */ WL_SHELL_SURFACE_RESIZE_BOTTOM = 2, /** * left edge */ WL_SHELL_SURFACE_RESIZE_LEFT = 4, /** * top and left edges */ WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5, /** * bottom and left edges */ WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6, /** * right edge */ WL_SHELL_SURFACE_RESIZE_RIGHT = 8, /** * top and right edges */ WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9, /** * bottom and right edges */ WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10, }; #endif /* WL_SHELL_SURFACE_RESIZE_ENUM */ #ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM #define WL_SHELL_SURFACE_TRANSIENT_ENUM /** * @ingroup iface_wl_shell_surface * details of transient behaviour * * These flags specify details of the expected behaviour * of transient surfaces. Used in the set_transient request. */ enum wl_shell_surface_transient { /** * do not set keyboard focus */ WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1, }; #endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */ #ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM #define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM /** * @ingroup iface_wl_shell_surface * different method to set the surface fullscreen * * Hints to indicate to the compositor how to deal with a conflict * between the dimensions of the surface and the dimensions of the * output. The compositor is free to ignore this parameter. */ enum wl_shell_surface_fullscreen_method { /** * no preference, apply default policy */ WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0, /** * scale, preserve the surface's aspect ratio and center on output */ WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1, /** * switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch */ WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2, /** * no upscaling, center on output and add black borders to compensate size mismatch */ WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3, }; #endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */ /** * @ingroup iface_wl_shell_surface * @struct wl_shell_surface_listener */ struct wl_shell_surface_listener { /** * ping client * * Ping a client to check if it is receiving events and sending * requests. A client is expected to reply with a pong request. * @param serial serial number of the ping */ void (*ping)(void *data, struct wl_shell_surface *wl_shell_surface, uint32_t serial); /** * suggest resize * * The configure event asks the client to resize its surface. * * The size is a hint, in the sense that the client is free to * ignore it if it doesn't resize, pick a smaller size (to satisfy * aspect ratio or resize in steps of NxM pixels). * * The edges parameter provides a hint about how the surface was * resized. The client may use this information to decide how to * adjust its content to the new size (e.g. a scrolling area might * adjust its content position to leave the viewable content * unmoved). * * The client is free to dismiss all but the last configure event * it received. * * The width and height arguments specify the size of the window in * surface-local coordinates. * @param edges how the surface was resized * @param width new width of the surface * @param height new height of the surface */ void (*configure)(void *data, struct wl_shell_surface *wl_shell_surface, uint32_t edges, int32_t width, int32_t height); /** * popup interaction is done * * The popup_done event is sent out when a popup grab is broken, * that is, when the user clicks a surface that doesn't belong to * the client owning the popup surface. */ void (*popup_done)(void *data, struct wl_shell_surface *wl_shell_surface); }; /** * @ingroup iface_wl_shell_surface */ static inline int wl_shell_surface_add_listener(struct wl_shell_surface *wl_shell_surface, const struct wl_shell_surface_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) wl_shell_surface, (void (**)(void)) listener, data); } #define WL_SHELL_SURFACE_PONG 0 #define WL_SHELL_SURFACE_MOVE 1 #define WL_SHELL_SURFACE_RESIZE 2 #define WL_SHELL_SURFACE_SET_TOPLEVEL 3 #define WL_SHELL_SURFACE_SET_TRANSIENT 4 #define WL_SHELL_SURFACE_SET_FULLSCREEN 5 #define WL_SHELL_SURFACE_SET_POPUP 6 #define WL_SHELL_SURFACE_SET_MAXIMIZED 7 #define WL_SHELL_SURFACE_SET_TITLE 8 #define WL_SHELL_SURFACE_SET_CLASS 9 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_PING_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_CONFIGURE_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_POPUP_DONE_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_PONG_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_MOVE_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_RESIZE_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_SET_TOPLEVEL_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_SET_TRANSIENT_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_SET_FULLSCREEN_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_SET_POPUP_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_SET_MAXIMIZED_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_SET_TITLE_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_SET_CLASS_SINCE_VERSION 1 /** @ingroup iface_wl_shell_surface */ static inline void wl_shell_surface_set_user_data(struct wl_shell_surface *wl_shell_surface, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_shell_surface, user_data); } /** @ingroup iface_wl_shell_surface */ static inline void * wl_shell_surface_get_user_data(struct wl_shell_surface *wl_shell_surface) { return wl_proxy_get_user_data((struct wl_proxy *) wl_shell_surface); } static inline uint32_t wl_shell_surface_get_version(struct wl_shell_surface *wl_shell_surface) { return wl_proxy_get_version((struct wl_proxy *) wl_shell_surface); } /** @ingroup iface_wl_shell_surface */ static inline void wl_shell_surface_destroy(struct wl_shell_surface *wl_shell_surface) { wl_proxy_destroy((struct wl_proxy *) wl_shell_surface); } /** * @ingroup iface_wl_shell_surface * * A client must respond to a ping event with a pong request or * the client may be deemed unresponsive. */ static inline void wl_shell_surface_pong(struct wl_shell_surface *wl_shell_surface, uint32_t serial) { wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, WL_SHELL_SURFACE_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, serial); } /** * @ingroup iface_wl_shell_surface * * Start a pointer-driven move of the surface. * * This request must be used in response to a button press event. * The server may ignore move requests depending on the state of * the surface (e.g. fullscreen or maximized). */ static inline void wl_shell_surface_move(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial) { wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, WL_SHELL_SURFACE_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial); } /** * @ingroup iface_wl_shell_surface * * Start a pointer-driven resizing of the surface. * * This request must be used in response to a button press event. * The server may ignore resize requests depending on the state of * the surface (e.g. fullscreen or maximized). */ static inline void wl_shell_surface_resize(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, uint32_t edges) { wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, WL_SHELL_SURFACE_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial, edges); } /** * @ingroup iface_wl_shell_surface * * Map the surface as a toplevel surface. * * A toplevel surface is not fullscreen, maximized or transient. */ static inline void wl_shell_surface_set_toplevel(struct wl_shell_surface *wl_shell_surface) { wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, WL_SHELL_SURFACE_SET_TOPLEVEL, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0); } /** * @ingroup iface_wl_shell_surface * * Map the surface relative to an existing surface. * * The x and y arguments specify the location of the upper left * corner of the surface relative to the upper left corner of the * parent surface, in surface-local coordinates. * * The flags argument controls details of the transient behaviour. */ static inline void wl_shell_surface_set_transient(struct wl_shell_surface *wl_shell_surface, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags) { wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, WL_SHELL_SURFACE_SET_TRANSIENT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, parent, x, y, flags); } /** * @ingroup iface_wl_shell_surface * * Map the surface as a fullscreen surface. * * If an output parameter is given then the surface will be made * fullscreen on that output. If the client does not specify the * output then the compositor will apply its policy - usually * choosing the output on which the surface has the biggest surface * area. * * The client may specify a method to resolve a size conflict * between the output size and the surface size - this is provided * through the method parameter. * * The framerate parameter is used only when the method is set * to "driver", to indicate the preferred framerate. A value of 0 * indicates that the client does not care about framerate. The * framerate is specified in mHz, that is framerate of 60000 is 60Hz. * * A method of "scale" or "driver" implies a scaling operation of * the surface, either via a direct scaling operation or a change of * the output mode. This will override any kind of output scaling, so * that mapping a surface with a buffer size equal to the mode can * fill the screen independent of buffer_scale. * * A method of "fill" means we don't scale up the buffer, however * any output scale is applied. This means that you may run into * an edge case where the application maps a buffer with the same * size of the output mode but buffer_scale 1 (thus making a * surface larger than the output). In this case it is allowed to * downscale the results to fit the screen. * * The compositor must reply to this request with a configure event * with the dimensions for the output on which the surface will * be made fullscreen. */ static inline void wl_shell_surface_set_fullscreen(struct wl_shell_surface *wl_shell_surface, uint32_t method, uint32_t framerate, struct wl_output *output) { wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, WL_SHELL_SURFACE_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, method, framerate, output); } /** * @ingroup iface_wl_shell_surface * * Map the surface as a popup. * * A popup surface is a transient surface with an added pointer * grab. * * An existing implicit grab will be changed to owner-events mode, * and the popup grab will continue after the implicit grab ends * (i.e. releasing the mouse button does not cause the popup to * be unmapped). * * The popup grab continues until the window is destroyed or a * mouse button is pressed in any other client's window. A click * in any of the client's surfaces is reported as normal, however, * clicks in other clients' surfaces will be discarded and trigger * the callback. * * The x and y arguments specify the location of the upper left * corner of the surface relative to the upper left corner of the * parent surface, in surface-local coordinates. */ static inline void wl_shell_surface_set_popup(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags) { wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, WL_SHELL_SURFACE_SET_POPUP, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial, parent, x, y, flags); } /** * @ingroup iface_wl_shell_surface * * Map the surface as a maximized surface. * * If an output parameter is given then the surface will be * maximized on that output. If the client does not specify the * output then the compositor will apply its policy - usually * choosing the output on which the surface has the biggest surface * area. * * The compositor will reply with a configure event telling * the expected new surface size. The operation is completed * on the next buffer attach to this surface. * * A maximized surface typically fills the entire output it is * bound to, except for desktop elements such as panels. This is * the main difference between a maximized shell surface and a * fullscreen shell surface. * * The details depend on the compositor implementation. */ static inline void wl_shell_surface_set_maximized(struct wl_shell_surface *wl_shell_surface, struct wl_output *output) { wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, WL_SHELL_SURFACE_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, output); } /** * @ingroup iface_wl_shell_surface * * Set a short title for the surface. * * This string may be used to identify the surface in a task bar, * window list, or other user interface elements provided by the * compositor. * * The string must be encoded in UTF-8. */ static inline void wl_shell_surface_set_title(struct wl_shell_surface *wl_shell_surface, const char *title) { wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, WL_SHELL_SURFACE_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, title); } /** * @ingroup iface_wl_shell_surface * * Set a class for the surface. * * The surface class identifies the general class of applications * to which the surface belongs. A common convention is to use the * file name (or the full path if it is a non-standard location) of * the application's .desktop file as the class. */ static inline void wl_shell_surface_set_class(struct wl_shell_surface *wl_shell_surface, const char *class_) { wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface, WL_SHELL_SURFACE_SET_CLASS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, class_); } #ifndef WL_SURFACE_ERROR_ENUM #define WL_SURFACE_ERROR_ENUM /** * @ingroup iface_wl_surface * wl_surface error values * * These errors can be emitted in response to wl_surface requests. */ enum wl_surface_error { /** * buffer scale value is invalid */ WL_SURFACE_ERROR_INVALID_SCALE = 0, /** * buffer transform value is invalid */ WL_SURFACE_ERROR_INVALID_TRANSFORM = 1, }; #endif /* WL_SURFACE_ERROR_ENUM */ /** * @ingroup iface_wl_surface * @struct wl_surface_listener */ struct wl_surface_listener { /** * surface enters an output * * This is emitted whenever a surface's creation, movement, or * resizing results in some part of it being within the scanout * region of an output. * * Note that a surface may be overlapping with zero or more * outputs. * @param output output entered by the surface */ void (*enter)(void *data, struct wl_surface *wl_surface, struct wl_output *output); /** * surface leaves an output * * This is emitted whenever a surface's creation, movement, or * resizing results in it no longer having any part of it within * the scanout region of an output. * @param output output left by the surface */ void (*leave)(void *data, struct wl_surface *wl_surface, struct wl_output *output); }; /** * @ingroup iface_wl_surface */ static inline int wl_surface_add_listener(struct wl_surface *wl_surface, const struct wl_surface_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) wl_surface, (void (**)(void)) listener, data); } #define WL_SURFACE_DESTROY 0 #define WL_SURFACE_ATTACH 1 #define WL_SURFACE_DAMAGE 2 #define WL_SURFACE_FRAME 3 #define WL_SURFACE_SET_OPAQUE_REGION 4 #define WL_SURFACE_SET_INPUT_REGION 5 #define WL_SURFACE_COMMIT 6 #define WL_SURFACE_SET_BUFFER_TRANSFORM 7 #define WL_SURFACE_SET_BUFFER_SCALE 8 #define WL_SURFACE_DAMAGE_BUFFER 9 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_ENTER_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_LEAVE_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_DESTROY_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_ATTACH_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_DAMAGE_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_FRAME_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_SET_OPAQUE_REGION_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_SET_INPUT_REGION_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_COMMIT_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_SET_BUFFER_TRANSFORM_SINCE_VERSION 2 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION 3 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION 4 /** @ingroup iface_wl_surface */ static inline void wl_surface_set_user_data(struct wl_surface *wl_surface, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_surface, user_data); } /** @ingroup iface_wl_surface */ static inline void * wl_surface_get_user_data(struct wl_surface *wl_surface) { return wl_proxy_get_user_data((struct wl_proxy *) wl_surface); } static inline uint32_t wl_surface_get_version(struct wl_surface *wl_surface) { return wl_proxy_get_version((struct wl_proxy *) wl_surface); } /** * @ingroup iface_wl_surface * * Deletes the surface and invalidates its object ID. */ static inline void wl_surface_destroy(struct wl_surface *wl_surface) { wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, WL_SURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), WL_MARSHAL_FLAG_DESTROY); } /** * @ingroup iface_wl_surface * * Set a buffer as the content of this surface. * * The new size of the surface is calculated based on the buffer * size transformed by the inverse buffer_transform and the * inverse buffer_scale. This means that the supplied buffer * must be an integer multiple of the buffer_scale. * * The x and y arguments specify the location of the new pending * buffer's upper left corner, relative to the current buffer's upper * left corner, in surface-local coordinates. In other words, the * x and y, combined with the new surface size define in which * directions the surface's size changes. * * Surface contents are double-buffered state, see wl_surface.commit. * * The initial surface contents are void; there is no content. * wl_surface.attach assigns the given wl_buffer as the pending * wl_buffer. wl_surface.commit makes the pending wl_buffer the new * surface contents, and the size of the surface becomes the size * calculated from the wl_buffer, as described above. After commit, * there is no pending buffer until the next attach. * * Committing a pending wl_buffer allows the compositor to read the * pixels in the wl_buffer. The compositor may access the pixels at * any time after the wl_surface.commit request. When the compositor * will not access the pixels anymore, it will send the * wl_buffer.release event. Only after receiving wl_buffer.release, * the client may reuse the wl_buffer. A wl_buffer that has been * attached and then replaced by another attach instead of committed * will not receive a release event, and is not used by the * compositor. * * Destroying the wl_buffer after wl_buffer.release does not change * the surface contents. However, if the client destroys the * wl_buffer before receiving the wl_buffer.release event, the surface * contents become undefined immediately. * * If wl_surface.attach is sent with a NULL wl_buffer, the * following wl_surface.commit will remove the surface content. */ static inline void wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32_t x, int32_t y) { wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, WL_SURFACE_ATTACH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, buffer, x, y); } /** * @ingroup iface_wl_surface * * This request is used to describe the regions where the pending * buffer is different from the current surface contents, and where * the surface therefore needs to be repainted. The compositor * ignores the parts of the damage that fall outside of the surface. * * Damage is double-buffered state, see wl_surface.commit. * * The damage rectangle is specified in surface-local coordinates, * where x and y specify the upper left corner of the damage rectangle. * * The initial value for pending damage is empty: no damage. * wl_surface.damage adds pending damage: the new pending damage * is the union of old pending damage and the given rectangle. * * wl_surface.commit assigns pending damage as the current damage, * and clears pending damage. The server will clear the current * damage as it repaints the surface. * * Alternatively, damage can be posted with wl_surface.damage_buffer * which uses buffer coordinates instead of surface coordinates, * and is probably the preferred and intuitive way of doing this. */ static inline void wl_surface_damage(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height) { wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, WL_SURFACE_DAMAGE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y, width, height); } /** * @ingroup iface_wl_surface * * Request a notification when it is a good time to start drawing a new * frame, by creating a frame callback. This is useful for throttling * redrawing operations, and driving animations. * * When a client is animating on a wl_surface, it can use the 'frame' * request to get notified when it is a good time to draw and commit the * next frame of animation. If the client commits an update earlier than * that, it is likely that some updates will not make it to the display, * and the client is wasting resources by drawing too often. * * The frame request will take effect on the next wl_surface.commit. * The notification will only be posted for one frame unless * requested again. For a wl_surface, the notifications are posted in * the order the frame requests were committed. * * The server must send the notifications so that a client * will not send excessive updates, while still allowing * the highest possible update rate for clients that wait for the reply * before drawing again. The server should give some time for the client * to draw and commit after sending the frame callback events to let it * hit the next output refresh. * * A server should avoid signaling the frame callbacks if the * surface is not visible in any way, e.g. the surface is off-screen, * or completely obscured by other opaque surfaces. * * The object returned by this request will be destroyed by the * compositor after the callback is fired and as such the client must not * attempt to use it after that point. * * The callback_data passed in the callback is the current time, in * milliseconds, with an undefined base. */ static inline struct wl_callback * wl_surface_frame(struct wl_surface *wl_surface) { struct wl_proxy *callback; callback = wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, WL_SURFACE_FRAME, &wl_callback_interface, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, NULL); return (struct wl_callback *) callback; } /** * @ingroup iface_wl_surface * * This request sets the region of the surface that contains * opaque content. * * The opaque region is an optimization hint for the compositor * that lets it optimize the redrawing of content behind opaque * regions. Setting an opaque region is not required for correct * behaviour, but marking transparent content as opaque will result * in repaint artifacts. * * The opaque region is specified in surface-local coordinates. * * The compositor ignores the parts of the opaque region that fall * outside of the surface. * * Opaque region is double-buffered state, see wl_surface.commit. * * wl_surface.set_opaque_region changes the pending opaque region. * wl_surface.commit copies the pending region to the current region. * Otherwise, the pending and current regions are never changed. * * The initial value for an opaque region is empty. Setting the pending * opaque region has copy semantics, and the wl_region object can be * destroyed immediately. A NULL wl_region causes the pending opaque * region to be set to empty. */ static inline void wl_surface_set_opaque_region(struct wl_surface *wl_surface, struct wl_region *region) { wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, WL_SURFACE_SET_OPAQUE_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, region); } /** * @ingroup iface_wl_surface * * This request sets the region of the surface that can receive * pointer and touch events. * * Input events happening outside of this region will try the next * surface in the server surface stack. The compositor ignores the * parts of the input region that fall outside of the surface. * * The input region is specified in surface-local coordinates. * * Input region is double-buffered state, see wl_surface.commit. * * wl_surface.set_input_region changes the pending input region. * wl_surface.commit copies the pending region to the current region. * Otherwise the pending and current regions are never changed, * except cursor and icon surfaces are special cases, see * wl_pointer.set_cursor and wl_data_device.start_drag. * * The initial value for an input region is infinite. That means the * whole surface will accept input. Setting the pending input region * has copy semantics, and the wl_region object can be destroyed * immediately. A NULL wl_region causes the input region to be set * to infinite. */ static inline void wl_surface_set_input_region(struct wl_surface *wl_surface, struct wl_region *region) { wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, WL_SURFACE_SET_INPUT_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, region); } /** * @ingroup iface_wl_surface * * Surface state (input, opaque, and damage regions, attached buffers, * etc.) is double-buffered. Protocol requests modify the pending state, * as opposed to the current state in use by the compositor. A commit * request atomically applies all pending state, replacing the current * state. After commit, the new pending state is as documented for each * related request. * * On commit, a pending wl_buffer is applied first, and all other state * second. This means that all coordinates in double-buffered state are * relative to the new wl_buffer coming into use, except for * wl_surface.attach itself. If there is no pending wl_buffer, the * coordinates are relative to the current surface contents. * * All requests that need a commit to become effective are documented * to affect double-buffered state. * * Other interfaces may add further double-buffered surface state. */ static inline void wl_surface_commit(struct wl_surface *wl_surface) { wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, WL_SURFACE_COMMIT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0); } /** * @ingroup iface_wl_surface * * This request sets an optional transformation on how the compositor * interprets the contents of the buffer attached to the surface. The * accepted values for the transform parameter are the values for * wl_output.transform. * * Buffer transform is double-buffered state, see wl_surface.commit. * * A newly created surface has its buffer transformation set to normal. * * wl_surface.set_buffer_transform changes the pending buffer * transformation. wl_surface.commit copies the pending buffer * transformation to the current one. Otherwise, the pending and current * values are never changed. * * The purpose of this request is to allow clients to render content * according to the output transform, thus permitting the compositor to * use certain optimizations even if the display is rotated. Using * hardware overlays and scanning out a client buffer for fullscreen * surfaces are examples of such optimizations. Those optimizations are * highly dependent on the compositor implementation, so the use of this * request should be considered on a case-by-case basis. * * Note that if the transform value includes 90 or 270 degree rotation, * the width of the buffer will become the surface height and the height * of the buffer will become the surface width. * * If transform is not one of the values from the * wl_output.transform enum the invalid_transform protocol error * is raised. */ static inline void wl_surface_set_buffer_transform(struct wl_surface *wl_surface, int32_t transform) { wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, WL_SURFACE_SET_BUFFER_TRANSFORM, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, transform); } /** * @ingroup iface_wl_surface * * This request sets an optional scaling factor on how the compositor * interprets the contents of the buffer attached to the window. * * Buffer scale is double-buffered state, see wl_surface.commit. * * A newly created surface has its buffer scale set to 1. * * wl_surface.set_buffer_scale changes the pending buffer scale. * wl_surface.commit copies the pending buffer scale to the current one. * Otherwise, the pending and current values are never changed. * * The purpose of this request is to allow clients to supply higher * resolution buffer data for use on high resolution outputs. It is * intended that you pick the same buffer scale as the scale of the * output that the surface is displayed on. This means the compositor * can avoid scaling when rendering the surface on that output. * * Note that if the scale is larger than 1, then you have to attach * a buffer that is larger (by a factor of scale in each dimension) * than the desired surface size. * * If scale is not positive the invalid_scale protocol error is * raised. */ static inline void wl_surface_set_buffer_scale(struct wl_surface *wl_surface, int32_t scale) { wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, WL_SURFACE_SET_BUFFER_SCALE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, scale); } /** * @ingroup iface_wl_surface * * This request is used to describe the regions where the pending * buffer is different from the current surface contents, and where * the surface therefore needs to be repainted. The compositor * ignores the parts of the damage that fall outside of the surface. * * Damage is double-buffered state, see wl_surface.commit. * * The damage rectangle is specified in buffer coordinates, * where x and y specify the upper left corner of the damage rectangle. * * The initial value for pending damage is empty: no damage. * wl_surface.damage_buffer adds pending damage: the new pending * damage is the union of old pending damage and the given rectangle. * * wl_surface.commit assigns pending damage as the current damage, * and clears pending damage. The server will clear the current * damage as it repaints the surface. * * This request differs from wl_surface.damage in only one way - it * takes damage in buffer coordinates instead of surface-local * coordinates. While this generally is more intuitive than surface * coordinates, it is especially desirable when using wp_viewport * or when a drawing library (like EGL) is unaware of buffer scale * and buffer transform. * * Note: Because buffer transformation changes and damage requests may * be interleaved in the protocol stream, it is impossible to determine * the actual mapping between surface and buffer damage until * wl_surface.commit time. Therefore, compositors wishing to take both * kinds of damage into account will have to accumulate damage from the * two requests separately and only transform from one to the other * after receiving the wl_surface.commit. */ static inline void wl_surface_damage_buffer(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height) { wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, WL_SURFACE_DAMAGE_BUFFER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y, width, height); } #ifndef WL_SEAT_CAPABILITY_ENUM #define WL_SEAT_CAPABILITY_ENUM /** * @ingroup iface_wl_seat * seat capability bitmask * * This is a bitmask of capabilities this seat has; if a member is * set, then it is present on the seat. */ enum wl_seat_capability { /** * the seat has pointer devices */ WL_SEAT_CAPABILITY_POINTER = 1, /** * the seat has one or more keyboards */ WL_SEAT_CAPABILITY_KEYBOARD = 2, /** * the seat has touch devices */ WL_SEAT_CAPABILITY_TOUCH = 4, }; #endif /* WL_SEAT_CAPABILITY_ENUM */ /** * @ingroup iface_wl_seat * @struct wl_seat_listener */ struct wl_seat_listener { /** * seat capabilities changed * * This is emitted whenever a seat gains or loses the pointer, * keyboard or touch capabilities. The argument is a capability * enum containing the complete set of capabilities this seat has. * * When the pointer capability is added, a client may create a * wl_pointer object using the wl_seat.get_pointer request. This * object will receive pointer events until the capability is * removed in the future. * * When the pointer capability is removed, a client should destroy * the wl_pointer objects associated with the seat where the * capability was removed, using the wl_pointer.release request. No * further pointer events will be received on these objects. * * In some compositors, if a seat regains the pointer capability * and a client has a previously obtained wl_pointer object of * version 4 or less, that object may start sending pointer events * again. This behavior is considered a misinterpretation of the * intended behavior and must not be relied upon by the client. * wl_pointer objects of version 5 or later must not send events if * created before the most recent event notifying the client of an * added pointer capability. * * The above behavior also applies to wl_keyboard and wl_touch with * the keyboard and touch capabilities, respectively. * @param capabilities capabilities of the seat */ void (*capabilities)(void *data, struct wl_seat *wl_seat, uint32_t capabilities); /** * unique identifier for this seat * * In a multiseat configuration this can be used by the client to * help identify which physical devices the seat represents. Based * on the seat configuration used by the compositor. * @param name seat identifier * @since 2 */ void (*name)(void *data, struct wl_seat *wl_seat, const char *name); }; /** * @ingroup iface_wl_seat */ static inline int wl_seat_add_listener(struct wl_seat *wl_seat, const struct wl_seat_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) wl_seat, (void (**)(void)) listener, data); } #define WL_SEAT_GET_POINTER 0 #define WL_SEAT_GET_KEYBOARD 1 #define WL_SEAT_GET_TOUCH 2 #define WL_SEAT_RELEASE 3 /** * @ingroup iface_wl_seat */ #define WL_SEAT_CAPABILITIES_SINCE_VERSION 1 /** * @ingroup iface_wl_seat */ #define WL_SEAT_NAME_SINCE_VERSION 2 /** * @ingroup iface_wl_seat */ #define WL_SEAT_GET_POINTER_SINCE_VERSION 1 /** * @ingroup iface_wl_seat */ #define WL_SEAT_GET_KEYBOARD_SINCE_VERSION 1 /** * @ingroup iface_wl_seat */ #define WL_SEAT_GET_TOUCH_SINCE_VERSION 1 /** * @ingroup iface_wl_seat */ #define WL_SEAT_RELEASE_SINCE_VERSION 5 /** @ingroup iface_wl_seat */ static inline void wl_seat_set_user_data(struct wl_seat *wl_seat, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_seat, user_data); } /** @ingroup iface_wl_seat */ static inline void * wl_seat_get_user_data(struct wl_seat *wl_seat) { return wl_proxy_get_user_data((struct wl_proxy *) wl_seat); } static inline uint32_t wl_seat_get_version(struct wl_seat *wl_seat) { return wl_proxy_get_version((struct wl_proxy *) wl_seat); } /** @ingroup iface_wl_seat */ static inline void wl_seat_destroy(struct wl_seat *wl_seat) { wl_proxy_destroy((struct wl_proxy *) wl_seat); } /** * @ingroup iface_wl_seat * * The ID provided will be initialized to the wl_pointer interface * for this seat. * * This request only takes effect if the seat has the pointer * capability, or has had the pointer capability in the past. * It is a protocol violation to issue this request on a seat that has * never had the pointer capability. */ static inline struct wl_pointer * wl_seat_get_pointer(struct wl_seat *wl_seat) { struct wl_proxy *id; id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, WL_SEAT_GET_POINTER, &wl_pointer_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL); return (struct wl_pointer *) id; } /** * @ingroup iface_wl_seat * * The ID provided will be initialized to the wl_keyboard interface * for this seat. * * This request only takes effect if the seat has the keyboard * capability, or has had the keyboard capability in the past. * It is a protocol violation to issue this request on a seat that has * never had the keyboard capability. */ static inline struct wl_keyboard * wl_seat_get_keyboard(struct wl_seat *wl_seat) { struct wl_proxy *id; id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, WL_SEAT_GET_KEYBOARD, &wl_keyboard_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL); return (struct wl_keyboard *) id; } /** * @ingroup iface_wl_seat * * The ID provided will be initialized to the wl_touch interface * for this seat. * * This request only takes effect if the seat has the touch * capability, or has had the touch capability in the past. * It is a protocol violation to issue this request on a seat that has * never had the touch capability. */ static inline struct wl_touch * wl_seat_get_touch(struct wl_seat *wl_seat) { struct wl_proxy *id; id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, WL_SEAT_GET_TOUCH, &wl_touch_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL); return (struct wl_touch *) id; } /** * @ingroup iface_wl_seat * * Using this request a client can tell the server that it is not going to * use the seat object anymore. */ static inline void wl_seat_release(struct wl_seat *wl_seat) { wl_proxy_marshal_flags((struct wl_proxy *) wl_seat, WL_SEAT_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_seat), WL_MARSHAL_FLAG_DESTROY); } #ifndef WL_POINTER_ERROR_ENUM #define WL_POINTER_ERROR_ENUM enum wl_pointer_error { /** * given wl_surface has another role */ WL_POINTER_ERROR_ROLE = 0, }; #endif /* WL_POINTER_ERROR_ENUM */ #ifndef WL_POINTER_BUTTON_STATE_ENUM #define WL_POINTER_BUTTON_STATE_ENUM /** * @ingroup iface_wl_pointer * physical button state * * Describes the physical state of a button that produced the button * event. */ enum wl_pointer_button_state { /** * the button is not pressed */ WL_POINTER_BUTTON_STATE_RELEASED = 0, /** * the button is pressed */ WL_POINTER_BUTTON_STATE_PRESSED = 1, }; #endif /* WL_POINTER_BUTTON_STATE_ENUM */ #ifndef WL_POINTER_AXIS_ENUM #define WL_POINTER_AXIS_ENUM /** * @ingroup iface_wl_pointer * axis types * * Describes the axis types of scroll events. */ enum wl_pointer_axis { /** * vertical axis */ WL_POINTER_AXIS_VERTICAL_SCROLL = 0, /** * horizontal axis */ WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1, }; #endif /* WL_POINTER_AXIS_ENUM */ #ifndef WL_POINTER_AXIS_SOURCE_ENUM #define WL_POINTER_AXIS_SOURCE_ENUM /** * @ingroup iface_wl_pointer * axis source types * * Describes the source types for axis events. This indicates to the * client how an axis event was physically generated; a client may * adjust the user interface accordingly. For example, scroll events * from a "finger" source may be in a smooth coordinate space with * kinetic scrolling whereas a "wheel" source may be in discrete steps * of a number of lines. */ enum wl_pointer_axis_source { /** * a physical wheel rotation */ WL_POINTER_AXIS_SOURCE_WHEEL = 0, /** * finger on a touch surface */ WL_POINTER_AXIS_SOURCE_FINGER = 1, /** * continuous coordinate space * * A device generating events in a continuous coordinate space, * but using something other than a finger. One example for this * source is button-based scrolling where the vertical motion of a * device is converted to scroll events while a button is held * down. */ WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2, /** * a physical wheel tilt * * Indicates that the actual device is a wheel but the scroll * event is not caused by a rotation but a (usually sideways) tilt * of the wheel. * @since 6 */ WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3, }; /** * @ingroup iface_wl_pointer */ #define WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION 6 #endif /* WL_POINTER_AXIS_SOURCE_ENUM */ /** * @ingroup iface_wl_pointer * @struct wl_pointer_listener */ struct wl_pointer_listener { /** * enter event * * Notification that this seat's pointer is focused on a certain * surface. * * When a seat's focus enters a surface, the pointer image is * undefined and a client should respond to this event by setting * an appropriate pointer image with the set_cursor request. * @param serial serial number of the enter event * @param surface surface entered by the pointer * @param surface_x surface-local x coordinate * @param surface_y surface-local y coordinate */ void (*enter)(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y); /** * leave event * * Notification that this seat's pointer is no longer focused on * a certain surface. * * The leave notification is sent before the enter notification for * the new focus. * @param serial serial number of the leave event * @param surface surface left by the pointer */ void (*leave)(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface); /** * pointer motion event * * Notification of pointer location change. The arguments * surface_x and surface_y are the location relative to the focused * surface. * @param time timestamp with millisecond granularity * @param surface_x surface-local x coordinate * @param surface_y surface-local y coordinate */ void (*motion)(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y); /** * pointer button event * * Mouse button click and release notifications. * * The location of the click is given by the last motion or enter * event. The time argument is a timestamp with millisecond * granularity, with an undefined base. * * The button is a button code as defined in the Linux kernel's * linux/input-event-codes.h header file, e.g. BTN_LEFT. * * Any 16-bit button code value is reserved for future additions to * the kernel's event code list. All other button codes above * 0xFFFF are currently undefined but may be used in future * versions of this protocol. * @param serial serial number of the button event * @param time timestamp with millisecond granularity * @param button button that produced the event * @param state physical state of the button */ void (*button)(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state); /** * axis event * * Scroll and other axis notifications. * * For scroll events (vertical and horizontal scroll axes), the * value parameter is the length of a vector along the specified * axis in a coordinate space identical to those of motion events, * representing a relative movement along the specified axis. * * For devices that support movements non-parallel to axes multiple * axis events will be emitted. * * When applicable, for example for touch pads, the server can * choose to emit scroll events where the motion vector is * equivalent to a motion event vector. * * When applicable, a client can transform its content relative to * the scroll distance. * @param time timestamp with millisecond granularity * @param axis axis type * @param value length of vector in surface-local coordinate space */ void (*axis)(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value); /** * end of a pointer event sequence * * Indicates the end of a set of events that logically belong * together. A client is expected to accumulate the data in all * events within the frame before proceeding. * * All wl_pointer events before a wl_pointer.frame event belong * logically together. For example, in a diagonal scroll motion the * compositor will send an optional wl_pointer.axis_source event, * two wl_pointer.axis events (horizontal and vertical) and finally * a wl_pointer.frame event. The client may use this information to * calculate a diagonal vector for scrolling. * * When multiple wl_pointer.axis events occur within the same * frame, the motion vector is the combined motion of all events. * When a wl_pointer.axis and a wl_pointer.axis_stop event occur * within the same frame, this indicates that axis movement in one * axis has stopped but continues in the other axis. When multiple * wl_pointer.axis_stop events occur within the same frame, this * indicates that these axes stopped in the same instance. * * A wl_pointer.frame event is sent for every logical event group, * even if the group only contains a single wl_pointer event. * Specifically, a client may get a sequence: motion, frame, * button, frame, axis, frame, axis_stop, frame. * * The wl_pointer.enter and wl_pointer.leave events are logical * events generated by the compositor and not the hardware. These * events are also grouped by a wl_pointer.frame. When a pointer * moves from one surface to another, a compositor should group the * wl_pointer.leave event within the same wl_pointer.frame. * However, a client must not rely on wl_pointer.leave and * wl_pointer.enter being in the same wl_pointer.frame. * Compositor-specific policies may require the wl_pointer.leave * and wl_pointer.enter event being split across multiple * wl_pointer.frame groups. * @since 5 */ void (*frame)(void *data, struct wl_pointer *wl_pointer); /** * axis source event * * Source information for scroll and other axes. * * This event does not occur on its own. It is sent before a * wl_pointer.frame event and carries the source information for * all events within that frame. * * The source specifies how this event was generated. If the source * is wl_pointer.axis_source.finger, a wl_pointer.axis_stop event * will be sent when the user lifts the finger off the device. * * If the source is wl_pointer.axis_source.wheel, * wl_pointer.axis_source.wheel_tilt or * wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event * may or may not be sent. Whether a compositor sends an axis_stop * event for these sources is hardware-specific and * implementation-dependent; clients must not rely on receiving an * axis_stop event for these scroll sources and should treat scroll * sequences from these scroll sources as unterminated by default. * * This event is optional. If the source is unknown for a * particular axis event sequence, no event is sent. Only one * wl_pointer.axis_source event is permitted per frame. * * The order of wl_pointer.axis_discrete and wl_pointer.axis_source * is not guaranteed. * @param axis_source source of the axis event * @since 5 */ void (*axis_source)(void *data, struct wl_pointer *wl_pointer, uint32_t axis_source); /** * axis stop event * * Stop notification for scroll and other axes. * * For some wl_pointer.axis_source types, a wl_pointer.axis_stop * event is sent to notify a client that the axis sequence has * terminated. This enables the client to implement kinetic * scrolling. See the wl_pointer.axis_source documentation for * information on when this event may be generated. * * Any wl_pointer.axis events with the same axis_source after this * event should be considered as the start of a new axis motion. * * The timestamp is to be interpreted identical to the timestamp in * the wl_pointer.axis event. The timestamp value may be the same * as a preceding wl_pointer.axis event. * @param time timestamp with millisecond granularity * @param axis the axis stopped with this event * @since 5 */ void (*axis_stop)(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis); /** * axis click event * * Discrete step information for scroll and other axes. * * This event carries the axis value of the wl_pointer.axis event * in discrete steps (e.g. mouse wheel clicks). * * This event does not occur on its own, it is coupled with a * wl_pointer.axis event that represents this axis value on a * continuous scale. The protocol guarantees that each * axis_discrete event is always followed by exactly one axis event * with the same axis number within the same wl_pointer.frame. Note * that the protocol allows for other events to occur between the * axis_discrete and its coupled axis event, including other * axis_discrete or axis events. * * This event is optional; continuous scrolling devices like * two-finger scrolling on touchpads do not have discrete steps and * do not generate this event. * * The discrete value carries the directional information. e.g. a * value of -2 is two steps towards the negative direction of this * axis. * * The axis number is identical to the axis number in the * associated axis event. * * The order of wl_pointer.axis_discrete and wl_pointer.axis_source * is not guaranteed. * @param axis axis type * @param discrete number of steps * @since 5 */ void (*axis_discrete)(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete); }; /** * @ingroup iface_wl_pointer */ static inline int wl_pointer_add_listener(struct wl_pointer *wl_pointer, const struct wl_pointer_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) wl_pointer, (void (**)(void)) listener, data); } #define WL_POINTER_SET_CURSOR 0 #define WL_POINTER_RELEASE 1 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_ENTER_SINCE_VERSION 1 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_LEAVE_SINCE_VERSION 1 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_MOTION_SINCE_VERSION 1 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_BUTTON_SINCE_VERSION 1 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_AXIS_SINCE_VERSION 1 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_FRAME_SINCE_VERSION 5 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_AXIS_SOURCE_SINCE_VERSION 5 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_AXIS_STOP_SINCE_VERSION 5 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_AXIS_DISCRETE_SINCE_VERSION 5 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_SET_CURSOR_SINCE_VERSION 1 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_RELEASE_SINCE_VERSION 3 /** @ingroup iface_wl_pointer */ static inline void wl_pointer_set_user_data(struct wl_pointer *wl_pointer, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_pointer, user_data); } /** @ingroup iface_wl_pointer */ static inline void * wl_pointer_get_user_data(struct wl_pointer *wl_pointer) { return wl_proxy_get_user_data((struct wl_proxy *) wl_pointer); } static inline uint32_t wl_pointer_get_version(struct wl_pointer *wl_pointer) { return wl_proxy_get_version((struct wl_proxy *) wl_pointer); } /** @ingroup iface_wl_pointer */ static inline void wl_pointer_destroy(struct wl_pointer *wl_pointer) { wl_proxy_destroy((struct wl_proxy *) wl_pointer); } /** * @ingroup iface_wl_pointer * * Set the pointer surface, i.e., the surface that contains the * pointer image (cursor). This request gives the surface the role * of a cursor. If the surface already has another role, it raises * a protocol error. * * The cursor actually changes only if the pointer * focus for this device is one of the requesting client's surfaces * or the surface parameter is the current pointer surface. If * there was a previous surface set with this request it is * replaced. If surface is NULL, the pointer image is hidden. * * The parameters hotspot_x and hotspot_y define the position of * the pointer surface relative to the pointer location. Its * top-left corner is always at (x, y) - (hotspot_x, hotspot_y), * where (x, y) are the coordinates of the pointer location, in * surface-local coordinates. * * On surface.attach requests to the pointer surface, hotspot_x * and hotspot_y are decremented by the x and y parameters * passed to the request. Attach must be confirmed by * wl_surface.commit as usual. * * The hotspot can also be updated by passing the currently set * pointer surface to this request with new values for hotspot_x * and hotspot_y. * * The current and pending input regions of the wl_surface are * cleared, and wl_surface.set_input_region is ignored until the * wl_surface is no longer used as the cursor. When the use as a * cursor ends, the current and pending input regions become * undefined, and the wl_surface is unmapped. */ static inline void wl_pointer_set_cursor(struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, int32_t hotspot_x, int32_t hotspot_y) { wl_proxy_marshal_flags((struct wl_proxy *) wl_pointer, WL_POINTER_SET_CURSOR, NULL, wl_proxy_get_version((struct wl_proxy *) wl_pointer), 0, serial, surface, hotspot_x, hotspot_y); } /** * @ingroup iface_wl_pointer * * Using this request a client can tell the server that it is not going to * use the pointer object anymore. * * This request destroys the pointer proxy object, so clients must not call * wl_pointer_destroy() after using this request. */ static inline void wl_pointer_release(struct wl_pointer *wl_pointer) { wl_proxy_marshal_flags((struct wl_proxy *) wl_pointer, WL_POINTER_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_pointer), WL_MARSHAL_FLAG_DESTROY); } #ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM #define WL_KEYBOARD_KEYMAP_FORMAT_ENUM /** * @ingroup iface_wl_keyboard * keyboard mapping format * * This specifies the format of the keymap provided to the * client with the wl_keyboard.keymap event. */ enum wl_keyboard_keymap_format { /** * no keymap; client must understand how to interpret the raw keycode */ WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0, /** * libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode */ WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1, }; #endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */ #ifndef WL_KEYBOARD_KEY_STATE_ENUM #define WL_KEYBOARD_KEY_STATE_ENUM /** * @ingroup iface_wl_keyboard * physical key state * * Describes the physical state of a key that produced the key event. */ enum wl_keyboard_key_state { /** * key is not pressed */ WL_KEYBOARD_KEY_STATE_RELEASED = 0, /** * key is pressed */ WL_KEYBOARD_KEY_STATE_PRESSED = 1, }; #endif /* WL_KEYBOARD_KEY_STATE_ENUM */ /** * @ingroup iface_wl_keyboard * @struct wl_keyboard_listener */ struct wl_keyboard_listener { /** * keyboard mapping * * This event provides a file descriptor to the client which can * be memory-mapped to provide a keyboard mapping description. * @param format keymap format * @param fd keymap file descriptor * @param size keymap size, in bytes */ void (*keymap)(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size); /** * enter event * * Notification that this seat's keyboard focus is on a certain * surface. * @param serial serial number of the enter event * @param surface surface gaining keyboard focus * @param keys the currently pressed keys */ void (*enter)(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys); /** * leave event * * Notification that this seat's keyboard focus is no longer on a * certain surface. * * The leave notification is sent before the enter notification for * the new focus. * @param serial serial number of the leave event * @param surface surface that lost keyboard focus */ void (*leave)(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface); /** * key event * * A key was pressed or released. The time argument is a * timestamp with millisecond granularity, with an undefined base. * @param serial serial number of the key event * @param time timestamp with millisecond granularity * @param key key that produced the event * @param state physical state of the key */ void (*key)(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state); /** * modifier and group state * * Notifies clients that the modifier and/or group state has * changed, and it should update its local state. * @param serial serial number of the modifiers event * @param mods_depressed depressed modifiers * @param mods_latched latched modifiers * @param mods_locked locked modifiers * @param group keyboard layout */ void (*modifiers)(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group); /** * repeat rate and delay * * Informs the client about the keyboard's repeat rate and delay. * * This event is sent as soon as the wl_keyboard object has been * created, and is guaranteed to be received by the client before * any key press event. * * Negative values for either rate or delay are illegal. A rate of * zero will disable any repeating (regardless of the value of * delay). * * This event can be sent later on as well with a new value if * necessary, so clients should continue listening for the event * past the creation of wl_keyboard. * @param rate the rate of repeating keys in characters per second * @param delay delay in milliseconds since key down until repeating starts * @since 4 */ void (*repeat_info)(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay); }; /** * @ingroup iface_wl_keyboard */ static inline int wl_keyboard_add_listener(struct wl_keyboard *wl_keyboard, const struct wl_keyboard_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) wl_keyboard, (void (**)(void)) listener, data); } #define WL_KEYBOARD_RELEASE 0 /** * @ingroup iface_wl_keyboard */ #define WL_KEYBOARD_KEYMAP_SINCE_VERSION 1 /** * @ingroup iface_wl_keyboard */ #define WL_KEYBOARD_ENTER_SINCE_VERSION 1 /** * @ingroup iface_wl_keyboard */ #define WL_KEYBOARD_LEAVE_SINCE_VERSION 1 /** * @ingroup iface_wl_keyboard */ #define WL_KEYBOARD_KEY_SINCE_VERSION 1 /** * @ingroup iface_wl_keyboard */ #define WL_KEYBOARD_MODIFIERS_SINCE_VERSION 1 /** * @ingroup iface_wl_keyboard */ #define WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION 4 /** * @ingroup iface_wl_keyboard */ #define WL_KEYBOARD_RELEASE_SINCE_VERSION 3 /** @ingroup iface_wl_keyboard */ static inline void wl_keyboard_set_user_data(struct wl_keyboard *wl_keyboard, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_keyboard, user_data); } /** @ingroup iface_wl_keyboard */ static inline void * wl_keyboard_get_user_data(struct wl_keyboard *wl_keyboard) { return wl_proxy_get_user_data((struct wl_proxy *) wl_keyboard); } static inline uint32_t wl_keyboard_get_version(struct wl_keyboard *wl_keyboard) { return wl_proxy_get_version((struct wl_proxy *) wl_keyboard); } /** @ingroup iface_wl_keyboard */ static inline void wl_keyboard_destroy(struct wl_keyboard *wl_keyboard) { wl_proxy_destroy((struct wl_proxy *) wl_keyboard); } /** * @ingroup iface_wl_keyboard */ static inline void wl_keyboard_release(struct wl_keyboard *wl_keyboard) { wl_proxy_marshal_flags((struct wl_proxy *) wl_keyboard, WL_KEYBOARD_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_keyboard), WL_MARSHAL_FLAG_DESTROY); } /** * @ingroup iface_wl_touch * @struct wl_touch_listener */ struct wl_touch_listener { /** * touch down event and beginning of a touch sequence * * A new touch point has appeared on the surface. This touch * point is assigned a unique ID. Future events from this touch * point reference this ID. The ID ceases to be valid after a touch * up event and may be reused in the future. * @param serial serial number of the touch down event * @param time timestamp with millisecond granularity * @param surface surface touched * @param id the unique ID of this touch point * @param x surface-local x coordinate * @param y surface-local y coordinate */ void (*down)(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, struct wl_surface *surface, int32_t id, wl_fixed_t x, wl_fixed_t y); /** * end of a touch event sequence * * The touch point has disappeared. No further events will be * sent for this touch point and the touch point's ID is released * and may be reused in a future touch down event. * @param serial serial number of the touch up event * @param time timestamp with millisecond granularity * @param id the unique ID of this touch point */ void (*up)(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, int32_t id); /** * update of touch point coordinates * * A touch point has changed coordinates. * @param time timestamp with millisecond granularity * @param id the unique ID of this touch point * @param x surface-local x coordinate * @param y surface-local y coordinate */ void (*motion)(void *data, struct wl_touch *wl_touch, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y); /** * end of touch frame event * * Indicates the end of a set of events that logically belong * together. A client is expected to accumulate the data in all * events within the frame before proceeding. * * A wl_touch.frame terminates at least one event but otherwise no * guarantee is provided about the set of events within a frame. A * client must assume that any state not updated in a frame is * unchanged from the previously known state. */ void (*frame)(void *data, struct wl_touch *wl_touch); /** * touch session cancelled * * Sent if the compositor decides the touch stream is a global * gesture. No further events are sent to the clients from that * particular gesture. Touch cancellation applies to all touch * points currently active on this client's surface. The client is * responsible for finalizing the touch points, future touch points * on this surface may reuse the touch point ID. */ void (*cancel)(void *data, struct wl_touch *wl_touch); /** * update shape of touch point * * Sent when a touchpoint has changed its shape. * * This event does not occur on its own. It is sent before a * wl_touch.frame event and carries the new shape information for * any previously reported, or new touch points of that frame. * * Other events describing the touch point such as wl_touch.down, * wl_touch.motion or wl_touch.orientation may be sent within the * same wl_touch.frame. A client should treat these events as a * single logical touch point update. The order of wl_touch.shape, * wl_touch.orientation and wl_touch.motion is not guaranteed. A * wl_touch.down event is guaranteed to occur before the first * wl_touch.shape event for this touch ID but both events may occur * within the same wl_touch.frame. * * A touchpoint shape is approximated by an ellipse through the * major and minor axis length. The major axis length describes the * longer diameter of the ellipse, while the minor axis length * describes the shorter diameter. Major and minor are orthogonal * and both are specified in surface-local coordinates. The center * of the ellipse is always at the touchpoint location as reported * by wl_touch.down or wl_touch.move. * * This event is only sent by the compositor if the touch device * supports shape reports. The client has to make reasonable * assumptions about the shape if it did not receive this event. * @param id the unique ID of this touch point * @param major length of the major axis in surface-local coordinates * @param minor length of the minor axis in surface-local coordinates * @since 6 */ void (*shape)(void *data, struct wl_touch *wl_touch, int32_t id, wl_fixed_t major, wl_fixed_t minor); /** * update orientation of touch point * * Sent when a touchpoint has changed its orientation. * * This event does not occur on its own. It is sent before a * wl_touch.frame event and carries the new shape information for * any previously reported, or new touch points of that frame. * * Other events describing the touch point such as wl_touch.down, * wl_touch.motion or wl_touch.shape may be sent within the same * wl_touch.frame. A client should treat these events as a single * logical touch point update. The order of wl_touch.shape, * wl_touch.orientation and wl_touch.motion is not guaranteed. A * wl_touch.down event is guaranteed to occur before the first * wl_touch.orientation event for this touch ID but both events may * occur within the same wl_touch.frame. * * The orientation describes the clockwise angle of a touchpoint's * major axis to the positive surface y-axis and is normalized to * the -180 to +180 degree range. The granularity of orientation * depends on the touch device, some devices only support binary * rotation values between 0 and 90 degrees. * * This event is only sent by the compositor if the touch device * supports orientation reports. * @param id the unique ID of this touch point * @param orientation angle between major axis and positive surface y-axis in degrees * @since 6 */ void (*orientation)(void *data, struct wl_touch *wl_touch, int32_t id, wl_fixed_t orientation); }; /** * @ingroup iface_wl_touch */ static inline int wl_touch_add_listener(struct wl_touch *wl_touch, const struct wl_touch_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) wl_touch, (void (**)(void)) listener, data); } #define WL_TOUCH_RELEASE 0 /** * @ingroup iface_wl_touch */ #define WL_TOUCH_DOWN_SINCE_VERSION 1 /** * @ingroup iface_wl_touch */ #define WL_TOUCH_UP_SINCE_VERSION 1 /** * @ingroup iface_wl_touch */ #define WL_TOUCH_MOTION_SINCE_VERSION 1 /** * @ingroup iface_wl_touch */ #define WL_TOUCH_FRAME_SINCE_VERSION 1 /** * @ingroup iface_wl_touch */ #define WL_TOUCH_CANCEL_SINCE_VERSION 1 /** * @ingroup iface_wl_touch */ #define WL_TOUCH_SHAPE_SINCE_VERSION 6 /** * @ingroup iface_wl_touch */ #define WL_TOUCH_ORIENTATION_SINCE_VERSION 6 /** * @ingroup iface_wl_touch */ #define WL_TOUCH_RELEASE_SINCE_VERSION 3 /** @ingroup iface_wl_touch */ static inline void wl_touch_set_user_data(struct wl_touch *wl_touch, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_touch, user_data); } /** @ingroup iface_wl_touch */ static inline void * wl_touch_get_user_data(struct wl_touch *wl_touch) { return wl_proxy_get_user_data((struct wl_proxy *) wl_touch); } static inline uint32_t wl_touch_get_version(struct wl_touch *wl_touch) { return wl_proxy_get_version((struct wl_proxy *) wl_touch); } /** @ingroup iface_wl_touch */ static inline void wl_touch_destroy(struct wl_touch *wl_touch) { wl_proxy_destroy((struct wl_proxy *) wl_touch); } /** * @ingroup iface_wl_touch */ static inline void wl_touch_release(struct wl_touch *wl_touch) { wl_proxy_marshal_flags((struct wl_proxy *) wl_touch, WL_TOUCH_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_touch), WL_MARSHAL_FLAG_DESTROY); } #ifndef WL_OUTPUT_SUBPIXEL_ENUM #define WL_OUTPUT_SUBPIXEL_ENUM /** * @ingroup iface_wl_output * subpixel geometry information * * This enumeration describes how the physical * pixels on an output are laid out. */ enum wl_output_subpixel { /** * unknown geometry */ WL_OUTPUT_SUBPIXEL_UNKNOWN = 0, /** * no geometry */ WL_OUTPUT_SUBPIXEL_NONE = 1, /** * horizontal RGB */ WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2, /** * horizontal BGR */ WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3, /** * vertical RGB */ WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4, /** * vertical BGR */ WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5, }; #endif /* WL_OUTPUT_SUBPIXEL_ENUM */ #ifndef WL_OUTPUT_TRANSFORM_ENUM #define WL_OUTPUT_TRANSFORM_ENUM /** * @ingroup iface_wl_output * transform from framebuffer to output * * This describes the transform that a compositor will apply to a * surface to compensate for the rotation or mirroring of an * output device. * * The flipped values correspond to an initial flip around a * vertical axis followed by rotation. * * The purpose is mainly to allow clients to render accordingly and * tell the compositor, so that for fullscreen surfaces, the * compositor will still be able to scan out directly from client * surfaces. */ enum wl_output_transform { /** * no transform */ WL_OUTPUT_TRANSFORM_NORMAL = 0, /** * 90 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_90 = 1, /** * 180 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_180 = 2, /** * 270 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_270 = 3, /** * 180 degree flip around a vertical axis */ WL_OUTPUT_TRANSFORM_FLIPPED = 4, /** * flip and rotate 90 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5, /** * flip and rotate 180 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6, /** * flip and rotate 270 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7, }; #endif /* WL_OUTPUT_TRANSFORM_ENUM */ #ifndef WL_OUTPUT_MODE_ENUM #define WL_OUTPUT_MODE_ENUM /** * @ingroup iface_wl_output * mode information * * These flags describe properties of an output mode. * They are used in the flags bitfield of the mode event. */ enum wl_output_mode { /** * indicates this is the current mode */ WL_OUTPUT_MODE_CURRENT = 0x1, /** * indicates this is the preferred mode */ WL_OUTPUT_MODE_PREFERRED = 0x2, }; #endif /* WL_OUTPUT_MODE_ENUM */ /** * @ingroup iface_wl_output * @struct wl_output_listener */ struct wl_output_listener { /** * properties of the output * * The geometry event describes geometric properties of the * output. The event is sent when binding to the output object and * whenever any of the properties change. * @param x x position within the global compositor space * @param y y position within the global compositor space * @param physical_width width in millimeters of the output * @param physical_height height in millimeters of the output * @param subpixel subpixel orientation of the output * @param make textual description of the manufacturer * @param model textual description of the model * @param transform transform that maps framebuffer to output */ void (*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 transform); /** * advertise available modes for the output * * The mode event describes an available mode for the output. * * The event is sent when binding to the output object and there * will always be one mode, the current mode. The event is sent * again if an output changes mode, for the mode that is now * current. In other words, the current mode is always the last * mode that was received with the current flag set. * * The size of a mode is given in physical hardware units of the * output device. This is not necessarily the same as the output * size in the global compositor space. For instance, the output * may be scaled, as described in wl_output.scale, or transformed, * as described in wl_output.transform. * @param flags bitfield of mode flags * @param width width of the mode in hardware units * @param height height of the mode in hardware units * @param refresh vertical refresh rate in mHz */ void (*mode)(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh); /** * sent all information about output * * This event is sent after all other properties have been sent * after binding to the output object and after any other property * changes done after that. This allows changes to the output * properties to be seen as atomic, even if they happen via * multiple events. * @since 2 */ void (*done)(void *data, struct wl_output *wl_output); /** * output scaling properties * * This event contains scaling geometry information that is not * in the geometry event. It may be sent after binding the output * object or if the output scale changes later. If it is not sent, * the client should assume a scale of 1. * * A scale larger than 1 means that the compositor will * automatically scale surface buffers by this amount when * rendering. This is used for very high resolution displays where * applications rendering at the native resolution would be too * small to be legible. * * It is intended that scaling aware clients track the current * output of a surface, and if it is on a scaled output it should * use wl_surface.set_buffer_scale with the scale of the output. * That way the compositor can avoid scaling the surface, and the * client can supply a higher detail image. * @param factor scaling factor of output * @since 2 */ void (*scale)(void *data, struct wl_output *wl_output, int32_t factor); }; /** * @ingroup iface_wl_output */ static inline int wl_output_add_listener(struct wl_output *wl_output, const struct wl_output_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) wl_output, (void (**)(void)) listener, data); } #define WL_OUTPUT_RELEASE 0 /** * @ingroup iface_wl_output */ #define WL_OUTPUT_GEOMETRY_SINCE_VERSION 1 /** * @ingroup iface_wl_output */ #define WL_OUTPUT_MODE_SINCE_VERSION 1 /** * @ingroup iface_wl_output */ #define WL_OUTPUT_DONE_SINCE_VERSION 2 /** * @ingroup iface_wl_output */ #define WL_OUTPUT_SCALE_SINCE_VERSION 2 /** * @ingroup iface_wl_output */ #define WL_OUTPUT_RELEASE_SINCE_VERSION 3 /** @ingroup iface_wl_output */ static inline void wl_output_set_user_data(struct wl_output *wl_output, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_output, user_data); } /** @ingroup iface_wl_output */ static inline void * wl_output_get_user_data(struct wl_output *wl_output) { return wl_proxy_get_user_data((struct wl_proxy *) wl_output); } static inline uint32_t wl_output_get_version(struct wl_output *wl_output) { return wl_proxy_get_version((struct wl_proxy *) wl_output); } /** @ingroup iface_wl_output */ static inline void wl_output_destroy(struct wl_output *wl_output) { wl_proxy_destroy((struct wl_proxy *) wl_output); } /** * @ingroup iface_wl_output * * Using this request a client can tell the server that it is not going to * use the output object anymore. */ static inline void wl_output_release(struct wl_output *wl_output) { wl_proxy_marshal_flags((struct wl_proxy *) wl_output, WL_OUTPUT_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_output), WL_MARSHAL_FLAG_DESTROY); } #define WL_REGION_DESTROY 0 #define WL_REGION_ADD 1 #define WL_REGION_SUBTRACT 2 /** * @ingroup iface_wl_region */ #define WL_REGION_DESTROY_SINCE_VERSION 1 /** * @ingroup iface_wl_region */ #define WL_REGION_ADD_SINCE_VERSION 1 /** * @ingroup iface_wl_region */ #define WL_REGION_SUBTRACT_SINCE_VERSION 1 /** @ingroup iface_wl_region */ static inline void wl_region_set_user_data(struct wl_region *wl_region, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_region, user_data); } /** @ingroup iface_wl_region */ static inline void * wl_region_get_user_data(struct wl_region *wl_region) { return wl_proxy_get_user_data((struct wl_proxy *) wl_region); } static inline uint32_t wl_region_get_version(struct wl_region *wl_region) { return wl_proxy_get_version((struct wl_proxy *) wl_region); } /** * @ingroup iface_wl_region * * Destroy the region. This will invalidate the object ID. */ static inline void wl_region_destroy(struct wl_region *wl_region) { wl_proxy_marshal_flags((struct wl_proxy *) wl_region, WL_REGION_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), WL_MARSHAL_FLAG_DESTROY); } /** * @ingroup iface_wl_region * * Add the specified rectangle to the region. */ static inline void wl_region_add(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height) { wl_proxy_marshal_flags((struct wl_proxy *) wl_region, WL_REGION_ADD, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), 0, x, y, width, height); } /** * @ingroup iface_wl_region * * Subtract the specified rectangle from the region. */ static inline void wl_region_subtract(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height) { wl_proxy_marshal_flags((struct wl_proxy *) wl_region, WL_REGION_SUBTRACT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), 0, x, y, width, height); } #ifndef WL_SUBCOMPOSITOR_ERROR_ENUM #define WL_SUBCOMPOSITOR_ERROR_ENUM enum wl_subcompositor_error { /** * the to-be sub-surface is invalid */ WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0, }; #endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */ #define WL_SUBCOMPOSITOR_DESTROY 0 #define WL_SUBCOMPOSITOR_GET_SUBSURFACE 1 /** * @ingroup iface_wl_subcompositor */ #define WL_SUBCOMPOSITOR_DESTROY_SINCE_VERSION 1 /** * @ingroup iface_wl_subcompositor */ #define WL_SUBCOMPOSITOR_GET_SUBSURFACE_SINCE_VERSION 1 /** @ingroup iface_wl_subcompositor */ static inline void wl_subcompositor_set_user_data(struct wl_subcompositor *wl_subcompositor, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_subcompositor, user_data); } /** @ingroup iface_wl_subcompositor */ static inline void * wl_subcompositor_get_user_data(struct wl_subcompositor *wl_subcompositor) { return wl_proxy_get_user_data((struct wl_proxy *) wl_subcompositor); } static inline uint32_t wl_subcompositor_get_version(struct wl_subcompositor *wl_subcompositor) { return wl_proxy_get_version((struct wl_proxy *) wl_subcompositor); } /** * @ingroup iface_wl_subcompositor * * Informs the server that the client will not be using this * protocol object anymore. This does not affect any other * objects, wl_subsurface objects included. */ static inline void wl_subcompositor_destroy(struct wl_subcompositor *wl_subcompositor) { wl_proxy_marshal_flags((struct wl_proxy *) wl_subcompositor, WL_SUBCOMPOSITOR_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subcompositor), WL_MARSHAL_FLAG_DESTROY); } /** * @ingroup iface_wl_subcompositor * * Create a sub-surface interface for the given surface, and * associate it with the given parent surface. This turns a * plain wl_surface into a sub-surface. * * The to-be sub-surface must not already have another role, and it * must not have an existing wl_subsurface object. Otherwise a protocol * error is raised. */ static inline struct wl_subsurface * wl_subcompositor_get_subsurface(struct wl_subcompositor *wl_subcompositor, struct wl_surface *surface, struct wl_surface *parent) { struct wl_proxy *id; id = wl_proxy_marshal_flags((struct wl_proxy *) wl_subcompositor, WL_SUBCOMPOSITOR_GET_SUBSURFACE, &wl_subsurface_interface, wl_proxy_get_version((struct wl_proxy *) wl_subcompositor), 0, NULL, surface, parent); return (struct wl_subsurface *) id; } #ifndef WL_SUBSURFACE_ERROR_ENUM #define WL_SUBSURFACE_ERROR_ENUM enum wl_subsurface_error { /** * wl_surface is not a sibling or the parent */ WL_SUBSURFACE_ERROR_BAD_SURFACE = 0, }; #endif /* WL_SUBSURFACE_ERROR_ENUM */ #define WL_SUBSURFACE_DESTROY 0 #define WL_SUBSURFACE_SET_POSITION 1 #define WL_SUBSURFACE_PLACE_ABOVE 2 #define WL_SUBSURFACE_PLACE_BELOW 3 #define WL_SUBSURFACE_SET_SYNC 4 #define WL_SUBSURFACE_SET_DESYNC 5 /** * @ingroup iface_wl_subsurface */ #define WL_SUBSURFACE_DESTROY_SINCE_VERSION 1 /** * @ingroup iface_wl_subsurface */ #define WL_SUBSURFACE_SET_POSITION_SINCE_VERSION 1 /** * @ingroup iface_wl_subsurface */ #define WL_SUBSURFACE_PLACE_ABOVE_SINCE_VERSION 1 /** * @ingroup iface_wl_subsurface */ #define WL_SUBSURFACE_PLACE_BELOW_SINCE_VERSION 1 /** * @ingroup iface_wl_subsurface */ #define WL_SUBSURFACE_SET_SYNC_SINCE_VERSION 1 /** * @ingroup iface_wl_subsurface */ #define WL_SUBSURFACE_SET_DESYNC_SINCE_VERSION 1 /** @ingroup iface_wl_subsurface */ static inline void wl_subsurface_set_user_data(struct wl_subsurface *wl_subsurface, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) wl_subsurface, user_data); } /** @ingroup iface_wl_subsurface */ static inline void * wl_subsurface_get_user_data(struct wl_subsurface *wl_subsurface) { return wl_proxy_get_user_data((struct wl_proxy *) wl_subsurface); } static inline uint32_t wl_subsurface_get_version(struct wl_subsurface *wl_subsurface) { return wl_proxy_get_version((struct wl_proxy *) wl_subsurface); } /** * @ingroup iface_wl_subsurface * * The sub-surface interface is removed from the wl_surface object * that was turned into a sub-surface with a * wl_subcompositor.get_subsurface request. The wl_surface's association * to the parent is deleted, and the wl_surface loses its role as * a sub-surface. The wl_surface is unmapped. */ static inline void wl_subsurface_destroy(struct wl_subsurface *wl_subsurface) { wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, WL_SUBSURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), WL_MARSHAL_FLAG_DESTROY); } /** * @ingroup iface_wl_subsurface * * This schedules a sub-surface position change. * The sub-surface will be moved so that its origin (top left * corner pixel) will be at the location x, y of the parent surface * coordinate system. The coordinates are not restricted to the parent * surface area. Negative values are allowed. * * The scheduled coordinates will take effect whenever the state of the * parent surface is applied. When this happens depends on whether the * parent surface is in synchronized mode or not. See * wl_subsurface.set_sync and wl_subsurface.set_desync for details. * * If more than one set_position request is invoked by the client before * the commit of the parent surface, the position of a new request always * replaces the scheduled position from any previous request. * * The initial position is 0, 0. */ static inline void wl_subsurface_set_position(struct wl_subsurface *wl_subsurface, int32_t x, int32_t y) { wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, WL_SUBSURFACE_SET_POSITION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, x, y); } /** * @ingroup iface_wl_subsurface * * This sub-surface is taken from the stack, and put back just * above the reference surface, changing the z-order of the sub-surfaces. * The reference surface must be one of the sibling surfaces, or the * parent surface. Using any other surface, including this sub-surface, * will cause a protocol error. * * The z-order is double-buffered. Requests are handled in order and * applied immediately to a pending state. The final pending state is * copied to the active state the next time the state of the parent * surface is applied. When this happens depends on whether the parent * surface is in synchronized mode or not. See wl_subsurface.set_sync and * wl_subsurface.set_desync for details. * * A new sub-surface is initially added as the top-most in the stack * of its siblings and parent. */ static inline void wl_subsurface_place_above(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling) { wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, WL_SUBSURFACE_PLACE_ABOVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, sibling); } /** * @ingroup iface_wl_subsurface * * The sub-surface is placed just below the reference surface. * See wl_subsurface.place_above. */ static inline void wl_subsurface_place_below(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling) { wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, WL_SUBSURFACE_PLACE_BELOW, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, sibling); } /** * @ingroup iface_wl_subsurface * * Change the commit behaviour of the sub-surface to synchronized * mode, also described as the parent dependent mode. * * In synchronized mode, wl_surface.commit on a sub-surface will * accumulate the committed state in a cache, but the state will * not be applied and hence will not change the compositor output. * The cached state is applied to the sub-surface immediately after * the parent surface's state is applied. This ensures atomic * updates of the parent and all its synchronized sub-surfaces. * Applying the cached state will invalidate the cache, so further * parent surface commits do not (re-)apply old state. * * See wl_subsurface for the recursive effect of this mode. */ static inline void wl_subsurface_set_sync(struct wl_subsurface *wl_subsurface) { wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, WL_SUBSURFACE_SET_SYNC, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0); } /** * @ingroup iface_wl_subsurface * * Change the commit behaviour of the sub-surface to desynchronized * mode, also described as independent or freely running mode. * * In desynchronized mode, wl_surface.commit on a sub-surface will * apply the pending state directly, without caching, as happens * normally with a wl_surface. Calling wl_surface.commit on the * parent surface has no effect on the sub-surface's wl_surface * state. This mode allows a sub-surface to be updated on its own. * * If cached state exists when wl_surface.commit is called in * desynchronized mode, the pending state is added to the cached * state, and applied as a whole. This invalidates the cache. * * Note: even if a sub-surface is set to desynchronized, a parent * sub-surface may override it to behave as synchronized. For details, * see wl_subsurface. * * If a surface's parent surface behaves as desynchronized, then * the cached state is applied on set_desync. */ static inline void wl_subsurface_set_desync(struct wl_subsurface *wl_subsurface) { wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface, WL_SUBSURFACE_SET_DESYNC, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0); } #ifdef __cplusplus } #endif #endif wayland-1.23.1/tests/data/example-code.c000066400000000000000000000331701466237767300200500ustar00rootroot00000000000000/* SCANNER TEST */ /* * Copyright © 2008-2011 Kristian Høgsberg * Copyright © 2010-2011 Intel Corporation * Copyright © 2012-2013 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 #include #include #include "wayland-util.h" extern const struct wl_interface wl_buffer_interface; extern const struct wl_interface wl_callback_interface; extern const struct wl_interface wl_data_device_interface; extern const struct wl_interface wl_data_offer_interface; extern const struct wl_interface wl_data_source_interface; extern const struct wl_interface wl_keyboard_interface; extern const struct wl_interface wl_output_interface; extern const struct wl_interface wl_pointer_interface; extern const struct wl_interface wl_region_interface; extern const struct wl_interface wl_registry_interface; extern const struct wl_interface wl_seat_interface; extern const struct wl_interface wl_shell_surface_interface; extern const struct wl_interface wl_shm_pool_interface; extern const struct wl_interface wl_subsurface_interface; extern const struct wl_interface wl_surface_interface; extern const struct wl_interface wl_touch_interface; static const struct wl_interface *wayland_types[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &wl_callback_interface, &wl_registry_interface, &wl_surface_interface, &wl_region_interface, &wl_buffer_interface, NULL, NULL, NULL, NULL, NULL, &wl_shm_pool_interface, NULL, NULL, &wl_data_source_interface, &wl_surface_interface, &wl_surface_interface, NULL, &wl_data_source_interface, NULL, &wl_data_offer_interface, NULL, &wl_surface_interface, NULL, NULL, &wl_data_offer_interface, &wl_data_offer_interface, &wl_data_source_interface, &wl_data_device_interface, &wl_seat_interface, &wl_shell_surface_interface, &wl_surface_interface, &wl_seat_interface, NULL, &wl_seat_interface, NULL, NULL, &wl_surface_interface, NULL, NULL, NULL, NULL, NULL, &wl_output_interface, &wl_seat_interface, NULL, &wl_surface_interface, NULL, NULL, NULL, &wl_output_interface, &wl_buffer_interface, NULL, NULL, &wl_callback_interface, &wl_region_interface, &wl_region_interface, &wl_output_interface, &wl_output_interface, &wl_pointer_interface, &wl_keyboard_interface, &wl_touch_interface, NULL, &wl_surface_interface, NULL, NULL, NULL, &wl_surface_interface, NULL, NULL, NULL, &wl_surface_interface, NULL, &wl_surface_interface, NULL, NULL, &wl_surface_interface, NULL, NULL, &wl_surface_interface, NULL, NULL, NULL, &wl_subsurface_interface, &wl_surface_interface, &wl_surface_interface, &wl_surface_interface, &wl_surface_interface, }; static const struct wl_message wl_display_requests[] = { { "sync", "n", wayland_types + 8 }, { "get_registry", "n", wayland_types + 9 }, }; static const struct wl_message wl_display_events[] = { { "error", "ous", wayland_types + 0 }, { "delete_id", "u", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_display_interface = { "wl_display", 1, 2, wl_display_requests, 2, wl_display_events, }; static const struct wl_message wl_registry_requests[] = { { "bind", "usun", wayland_types + 0 }, }; static const struct wl_message wl_registry_events[] = { { "global", "usu", wayland_types + 0 }, { "global_remove", "u", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_registry_interface = { "wl_registry", 1, 1, wl_registry_requests, 2, wl_registry_events, }; static const struct wl_message wl_callback_events[] = { { "done", "u", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_callback_interface = { "wl_callback", 1, 0, NULL, 1, wl_callback_events, }; static const struct wl_message wl_compositor_requests[] = { { "create_surface", "n", wayland_types + 10 }, { "create_region", "n", wayland_types + 11 }, }; WL_EXPORT const struct wl_interface wl_compositor_interface = { "wl_compositor", 4, 2, wl_compositor_requests, 0, NULL, }; static const struct wl_message wl_shm_pool_requests[] = { { "create_buffer", "niiiiu", wayland_types + 12 }, { "destroy", "", wayland_types + 0 }, { "resize", "i", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_shm_pool_interface = { "wl_shm_pool", 1, 3, wl_shm_pool_requests, 0, NULL, }; static const struct wl_message wl_shm_requests[] = { { "create_pool", "nhi", wayland_types + 18 }, }; static const struct wl_message wl_shm_events[] = { { "format", "u", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_shm_interface = { "wl_shm", 1, 1, wl_shm_requests, 1, wl_shm_events, }; static const struct wl_message wl_buffer_requests[] = { { "destroy", "", wayland_types + 0 }, }; static const struct wl_message wl_buffer_events[] = { { "release", "", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_buffer_interface = { "wl_buffer", 1, 1, wl_buffer_requests, 1, wl_buffer_events, }; static const struct wl_message wl_data_offer_requests[] = { { "accept", "u?s", wayland_types + 0 }, { "receive", "sh", wayland_types + 0 }, { "destroy", "", wayland_types + 0 }, { "finish", "3", wayland_types + 0 }, { "set_actions", "3uu", wayland_types + 0 }, }; static const struct wl_message wl_data_offer_events[] = { { "offer", "s", wayland_types + 0 }, { "source_actions", "3u", wayland_types + 0 }, { "action", "3u", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_data_offer_interface = { "wl_data_offer", 3, 5, wl_data_offer_requests, 3, wl_data_offer_events, }; static const struct wl_message wl_data_source_requests[] = { { "offer", "s", wayland_types + 0 }, { "destroy", "", wayland_types + 0 }, { "set_actions", "3u", wayland_types + 0 }, }; static const struct wl_message wl_data_source_events[] = { { "target", "?s", wayland_types + 0 }, { "send", "sh", wayland_types + 0 }, { "cancelled", "", wayland_types + 0 }, { "dnd_drop_performed", "3", wayland_types + 0 }, { "dnd_finished", "3", wayland_types + 0 }, { "action", "3u", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_data_source_interface = { "wl_data_source", 3, 3, wl_data_source_requests, 6, wl_data_source_events, }; static const struct wl_message wl_data_device_requests[] = { { "start_drag", "?oo?ou", wayland_types + 21 }, { "set_selection", "?ou", wayland_types + 25 }, { "release", "2", wayland_types + 0 }, }; static const struct wl_message wl_data_device_events[] = { { "data_offer", "n", wayland_types + 27 }, { "enter", "uoff?o", wayland_types + 28 }, { "leave", "", wayland_types + 0 }, { "motion", "uff", wayland_types + 0 }, { "drop", "", wayland_types + 0 }, { "selection", "?o", wayland_types + 33 }, }; WL_EXPORT const struct wl_interface wl_data_device_interface = { "wl_data_device", 3, 3, wl_data_device_requests, 6, wl_data_device_events, }; static const struct wl_message wl_data_device_manager_requests[] = { { "create_data_source", "n", wayland_types + 34 }, { "get_data_device", "no", wayland_types + 35 }, }; WL_EXPORT const struct wl_interface wl_data_device_manager_interface = { "wl_data_device_manager", 3, 2, wl_data_device_manager_requests, 0, NULL, }; static const struct wl_message wl_shell_requests[] = { { "get_shell_surface", "no", wayland_types + 37 }, }; WL_EXPORT const struct wl_interface wl_shell_interface = { "wl_shell", 1, 1, wl_shell_requests, 0, NULL, }; static const struct wl_message wl_shell_surface_requests[] = { { "pong", "u", wayland_types + 0 }, { "move", "ou", wayland_types + 39 }, { "resize", "ouu", wayland_types + 41 }, { "set_toplevel", "", wayland_types + 0 }, { "set_transient", "oiiu", wayland_types + 44 }, { "set_fullscreen", "uu?o", wayland_types + 48 }, { "set_popup", "ouoiiu", wayland_types + 51 }, { "set_maximized", "?o", wayland_types + 57 }, { "set_title", "s", wayland_types + 0 }, { "set_class", "s", wayland_types + 0 }, }; static const struct wl_message wl_shell_surface_events[] = { { "ping", "u", wayland_types + 0 }, { "configure", "uii", wayland_types + 0 }, { "popup_done", "", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_shell_surface_interface = { "wl_shell_surface", 1, 10, wl_shell_surface_requests, 3, wl_shell_surface_events, }; static const struct wl_message wl_surface_requests[] = { { "destroy", "", wayland_types + 0 }, { "attach", "?oii", wayland_types + 58 }, { "damage", "iiii", wayland_types + 0 }, { "frame", "n", wayland_types + 61 }, { "set_opaque_region", "?o", wayland_types + 62 }, { "set_input_region", "?o", wayland_types + 63 }, { "commit", "", wayland_types + 0 }, { "set_buffer_transform", "2i", wayland_types + 0 }, { "set_buffer_scale", "3i", wayland_types + 0 }, { "damage_buffer", "4iiii", wayland_types + 0 }, }; static const struct wl_message wl_surface_events[] = { { "enter", "o", wayland_types + 64 }, { "leave", "o", wayland_types + 65 }, }; WL_EXPORT const struct wl_interface wl_surface_interface = { "wl_surface", 4, 10, wl_surface_requests, 2, wl_surface_events, }; static const struct wl_message wl_seat_requests[] = { { "get_pointer", "n", wayland_types + 66 }, { "get_keyboard", "n", wayland_types + 67 }, { "get_touch", "n", wayland_types + 68 }, { "release", "5", wayland_types + 0 }, }; static const struct wl_message wl_seat_events[] = { { "capabilities", "u", wayland_types + 0 }, { "name", "2s", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_seat_interface = { "wl_seat", 6, 4, wl_seat_requests, 2, wl_seat_events, }; static const struct wl_message wl_pointer_requests[] = { { "set_cursor", "u?oii", wayland_types + 69 }, { "release", "3", wayland_types + 0 }, }; static const struct wl_message wl_pointer_events[] = { { "enter", "uoff", wayland_types + 73 }, { "leave", "uo", wayland_types + 77 }, { "motion", "uff", wayland_types + 0 }, { "button", "uuuu", wayland_types + 0 }, { "axis", "uuf", wayland_types + 0 }, { "frame", "5", wayland_types + 0 }, { "axis_source", "5u", wayland_types + 0 }, { "axis_stop", "5uu", wayland_types + 0 }, { "axis_discrete", "5ui", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_pointer_interface = { "wl_pointer", 6, 2, wl_pointer_requests, 9, wl_pointer_events, }; static const struct wl_message wl_keyboard_requests[] = { { "release", "3", wayland_types + 0 }, }; static const struct wl_message wl_keyboard_events[] = { { "keymap", "uhu", wayland_types + 0 }, { "enter", "uoa", wayland_types + 79 }, { "leave", "uo", wayland_types + 82 }, { "key", "uuuu", wayland_types + 0 }, { "modifiers", "uuuuu", wayland_types + 0 }, { "repeat_info", "4ii", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_keyboard_interface = { "wl_keyboard", 6, 1, wl_keyboard_requests, 6, wl_keyboard_events, }; static const struct wl_message wl_touch_requests[] = { { "release", "3", wayland_types + 0 }, }; static const struct wl_message wl_touch_events[] = { { "down", "uuoiff", wayland_types + 84 }, { "up", "uui", wayland_types + 0 }, { "motion", "uiff", wayland_types + 0 }, { "frame", "", wayland_types + 0 }, { "cancel", "", wayland_types + 0 }, { "shape", "6iff", wayland_types + 0 }, { "orientation", "6if", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_touch_interface = { "wl_touch", 6, 1, wl_touch_requests, 7, wl_touch_events, }; static const struct wl_message wl_output_requests[] = { { "release", "3", wayland_types + 0 }, }; static const struct wl_message wl_output_events[] = { { "geometry", "iiiiissi", wayland_types + 0 }, { "mode", "uiii", wayland_types + 0 }, { "done", "2", wayland_types + 0 }, { "scale", "2i", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_output_interface = { "wl_output", 3, 1, wl_output_requests, 4, wl_output_events, }; static const struct wl_message wl_region_requests[] = { { "destroy", "", wayland_types + 0 }, { "add", "iiii", wayland_types + 0 }, { "subtract", "iiii", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_region_interface = { "wl_region", 1, 3, wl_region_requests, 0, NULL, }; static const struct wl_message wl_subcompositor_requests[] = { { "destroy", "", wayland_types + 0 }, { "get_subsurface", "noo", wayland_types + 90 }, }; WL_EXPORT const struct wl_interface wl_subcompositor_interface = { "wl_subcompositor", 1, 2, wl_subcompositor_requests, 0, NULL, }; static const struct wl_message wl_subsurface_requests[] = { { "destroy", "", wayland_types + 0 }, { "set_position", "ii", wayland_types + 0 }, { "place_above", "o", wayland_types + 93 }, { "place_below", "o", wayland_types + 94 }, { "set_sync", "", wayland_types + 0 }, { "set_desync", "", wayland_types + 0 }, }; WL_EXPORT const struct wl_interface wl_subsurface_interface = { "wl_subsurface", 1, 6, wl_subsurface_requests, 0, NULL, }; wayland-1.23.1/tests/data/example-enum.h000066400000000000000000000503251466237767300201100ustar00rootroot00000000000000/* SCANNER TEST */ #ifndef WAYLAND_ENUM_PROTOCOL_H #define WAYLAND_ENUM_PROTOCOL_H #ifdef __cplusplus extern "C" { #endif #ifndef WL_DISPLAY_ERROR_ENUM #define WL_DISPLAY_ERROR_ENUM /** * @ingroup iface_wl_display * global error values * * These errors are global and can be emitted in response to any * server request. */ enum wl_display_error { /** * server couldn't find object */ WL_DISPLAY_ERROR_INVALID_OBJECT = 0, /** * method doesn't exist on the specified interface */ WL_DISPLAY_ERROR_INVALID_METHOD = 1, /** * server is out of memory */ WL_DISPLAY_ERROR_NO_MEMORY = 2, }; #endif /* WL_DISPLAY_ERROR_ENUM */ #ifndef WL_SHM_ERROR_ENUM #define WL_SHM_ERROR_ENUM /** * @ingroup iface_wl_shm * wl_shm error values * * These errors can be emitted in response to wl_shm requests. */ enum wl_shm_error { /** * buffer format is not known */ WL_SHM_ERROR_INVALID_FORMAT = 0, /** * invalid size or stride during pool or buffer creation */ WL_SHM_ERROR_INVALID_STRIDE = 1, /** * mmapping the file descriptor failed */ WL_SHM_ERROR_INVALID_FD = 2, }; #endif /* WL_SHM_ERROR_ENUM */ #ifndef WL_SHM_FORMAT_ENUM #define WL_SHM_FORMAT_ENUM /** * @ingroup iface_wl_shm * pixel formats * * This describes the memory layout of an individual pixel. * * All renderers should support argb8888 and xrgb8888 but any other * formats are optional and may not be supported by the particular * renderer in use. * * The drm format codes match the macros defined in drm_fourcc.h. * The formats actually supported by the compositor will be * reported by the format event. */ enum wl_shm_format { /** * 32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian */ WL_SHM_FORMAT_ARGB8888 = 0, /** * 32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian */ WL_SHM_FORMAT_XRGB8888 = 1, /** * 8-bit color index format, [7:0] C */ WL_SHM_FORMAT_C8 = 0x20203843, /** * 8-bit RGB format, [7:0] R:G:B 3:3:2 */ WL_SHM_FORMAT_RGB332 = 0x38424752, /** * 8-bit BGR format, [7:0] B:G:R 2:3:3 */ WL_SHM_FORMAT_BGR233 = 0x38524742, /** * 16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian */ WL_SHM_FORMAT_XRGB4444 = 0x32315258, /** * 16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian */ WL_SHM_FORMAT_XBGR4444 = 0x32314258, /** * 16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian */ WL_SHM_FORMAT_RGBX4444 = 0x32315852, /** * 16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian */ WL_SHM_FORMAT_BGRX4444 = 0x32315842, /** * 16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian */ WL_SHM_FORMAT_ARGB4444 = 0x32315241, /** * 16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian */ WL_SHM_FORMAT_ABGR4444 = 0x32314241, /** * 16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian */ WL_SHM_FORMAT_RGBA4444 = 0x32314152, /** * 16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian */ WL_SHM_FORMAT_BGRA4444 = 0x32314142, /** * 16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian */ WL_SHM_FORMAT_XRGB1555 = 0x35315258, /** * 16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian */ WL_SHM_FORMAT_XBGR1555 = 0x35314258, /** * 16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian */ WL_SHM_FORMAT_RGBX5551 = 0x35315852, /** * 16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian */ WL_SHM_FORMAT_BGRX5551 = 0x35315842, /** * 16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian */ WL_SHM_FORMAT_ARGB1555 = 0x35315241, /** * 16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian */ WL_SHM_FORMAT_ABGR1555 = 0x35314241, /** * 16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian */ WL_SHM_FORMAT_RGBA5551 = 0x35314152, /** * 16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian */ WL_SHM_FORMAT_BGRA5551 = 0x35314142, /** * 16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian */ WL_SHM_FORMAT_RGB565 = 0x36314752, /** * 16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian */ WL_SHM_FORMAT_BGR565 = 0x36314742, /** * 24-bit RGB format, [23:0] R:G:B little endian */ WL_SHM_FORMAT_RGB888 = 0x34324752, /** * 24-bit BGR format, [23:0] B:G:R little endian */ WL_SHM_FORMAT_BGR888 = 0x34324742, /** * 32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian */ WL_SHM_FORMAT_XBGR8888 = 0x34324258, /** * 32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian */ WL_SHM_FORMAT_RGBX8888 = 0x34325852, /** * 32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian */ WL_SHM_FORMAT_BGRX8888 = 0x34325842, /** * 32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian */ WL_SHM_FORMAT_ABGR8888 = 0x34324241, /** * 32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian */ WL_SHM_FORMAT_RGBA8888 = 0x34324152, /** * 32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian */ WL_SHM_FORMAT_BGRA8888 = 0x34324142, /** * 32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian */ WL_SHM_FORMAT_XRGB2101010 = 0x30335258, /** * 32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian */ WL_SHM_FORMAT_XBGR2101010 = 0x30334258, /** * 32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian */ WL_SHM_FORMAT_RGBX1010102 = 0x30335852, /** * 32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian */ WL_SHM_FORMAT_BGRX1010102 = 0x30335842, /** * 32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian */ WL_SHM_FORMAT_ARGB2101010 = 0x30335241, /** * 32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian */ WL_SHM_FORMAT_ABGR2101010 = 0x30334241, /** * 32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian */ WL_SHM_FORMAT_RGBA1010102 = 0x30334152, /** * 32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian */ WL_SHM_FORMAT_BGRA1010102 = 0x30334142, /** * packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */ WL_SHM_FORMAT_YUYV = 0x56595559, /** * packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian */ WL_SHM_FORMAT_YVYU = 0x55595659, /** * packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian */ WL_SHM_FORMAT_UYVY = 0x59565955, /** * packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian */ WL_SHM_FORMAT_VYUY = 0x59555956, /** * packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */ WL_SHM_FORMAT_AYUV = 0x56555941, /** * 2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane */ WL_SHM_FORMAT_NV12 = 0x3231564e, /** * 2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane */ WL_SHM_FORMAT_NV21 = 0x3132564e, /** * 2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane */ WL_SHM_FORMAT_NV16 = 0x3631564e, /** * 2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane */ WL_SHM_FORMAT_NV61 = 0x3136564e, /** * 3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes */ WL_SHM_FORMAT_YUV410 = 0x39565559, /** * 3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes */ WL_SHM_FORMAT_YVU410 = 0x39555659, /** * 3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes */ WL_SHM_FORMAT_YUV411 = 0x31315559, /** * 3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes */ WL_SHM_FORMAT_YVU411 = 0x31315659, /** * 3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes */ WL_SHM_FORMAT_YUV420 = 0x32315559, /** * 3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes */ WL_SHM_FORMAT_YVU420 = 0x32315659, /** * 3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes */ WL_SHM_FORMAT_YUV422 = 0x36315559, /** * 3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes */ WL_SHM_FORMAT_YVU422 = 0x36315659, /** * 3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes */ WL_SHM_FORMAT_YUV444 = 0x34325559, /** * 3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes */ WL_SHM_FORMAT_YVU444 = 0x34325659, }; #endif /* WL_SHM_FORMAT_ENUM */ #ifndef WL_DATA_OFFER_ERROR_ENUM #define WL_DATA_OFFER_ERROR_ENUM enum wl_data_offer_error { /** * finish request was called untimely */ WL_DATA_OFFER_ERROR_INVALID_FINISH = 0, /** * action mask contains invalid values */ WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK = 1, /** * action argument has an invalid value */ WL_DATA_OFFER_ERROR_INVALID_ACTION = 2, /** * offer doesn't accept this request */ WL_DATA_OFFER_ERROR_INVALID_OFFER = 3, }; #endif /* WL_DATA_OFFER_ERROR_ENUM */ #ifndef WL_DATA_SOURCE_ERROR_ENUM #define WL_DATA_SOURCE_ERROR_ENUM enum wl_data_source_error { /** * action mask contains invalid values */ WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK = 0, /** * source doesn't accept this request */ WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1, }; #endif /* WL_DATA_SOURCE_ERROR_ENUM */ #ifndef WL_DATA_DEVICE_ERROR_ENUM #define WL_DATA_DEVICE_ERROR_ENUM enum wl_data_device_error { /** * given wl_surface has another role */ WL_DATA_DEVICE_ERROR_ROLE = 0, }; #endif /* WL_DATA_DEVICE_ERROR_ENUM */ #ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM #define WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM /** * @ingroup iface_wl_data_device_manager * drag and drop actions * * This is a bitmask of the available/preferred actions in a * drag-and-drop operation. * * In the compositor, the selected action is a result of matching the * actions offered by the source and destination sides. "action" events * with a "none" action will be sent to both source and destination if * there is no match. All further checks will effectively happen on * (source actions ∩ destination actions). * * In addition, compositors may also pick different actions in * reaction to key modifiers being pressed. One common design that * is used in major toolkits (and the behavior recommended for * compositors) is: * * - If no modifiers are pressed, the first match (in bit order) * will be used. * - Pressing Shift selects "move", if enabled in the mask. * - Pressing Control selects "copy", if enabled in the mask. * * Behavior beyond that is considered implementation-dependent. * Compositors may for example bind other modifiers (like Alt/Meta) * or drags initiated with other buttons than BTN_LEFT to specific * actions (e.g. "ask"). */ enum wl_data_device_manager_dnd_action { /** * no action */ WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE = 0, /** * copy action */ WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY = 1, /** * move action */ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE = 2, /** * ask action */ WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4, }; #endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */ #ifndef WL_SHELL_ERROR_ENUM #define WL_SHELL_ERROR_ENUM enum wl_shell_error { /** * given wl_surface has another role */ WL_SHELL_ERROR_ROLE = 0, }; #endif /* WL_SHELL_ERROR_ENUM */ #ifndef WL_SHELL_SURFACE_RESIZE_ENUM #define WL_SHELL_SURFACE_RESIZE_ENUM /** * @ingroup iface_wl_shell_surface * edge values for resizing * * These values are used to indicate which edge of a surface * is being dragged in a resize operation. The server may * use this information to adapt its behavior, e.g. choose * an appropriate cursor image. */ enum wl_shell_surface_resize { /** * no edge */ WL_SHELL_SURFACE_RESIZE_NONE = 0, /** * top edge */ WL_SHELL_SURFACE_RESIZE_TOP = 1, /** * bottom edge */ WL_SHELL_SURFACE_RESIZE_BOTTOM = 2, /** * left edge */ WL_SHELL_SURFACE_RESIZE_LEFT = 4, /** * top and left edges */ WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5, /** * bottom and left edges */ WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6, /** * right edge */ WL_SHELL_SURFACE_RESIZE_RIGHT = 8, /** * top and right edges */ WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9, /** * bottom and right edges */ WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10, }; #endif /* WL_SHELL_SURFACE_RESIZE_ENUM */ #ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM #define WL_SHELL_SURFACE_TRANSIENT_ENUM /** * @ingroup iface_wl_shell_surface * details of transient behaviour * * These flags specify details of the expected behaviour * of transient surfaces. Used in the set_transient request. */ enum wl_shell_surface_transient { /** * do not set keyboard focus */ WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1, }; #endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */ #ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM #define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM /** * @ingroup iface_wl_shell_surface * different method to set the surface fullscreen * * Hints to indicate to the compositor how to deal with a conflict * between the dimensions of the surface and the dimensions of the * output. The compositor is free to ignore this parameter. */ enum wl_shell_surface_fullscreen_method { /** * no preference, apply default policy */ WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0, /** * scale, preserve the surface's aspect ratio and center on output */ WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1, /** * switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch */ WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2, /** * no upscaling, center on output and add black borders to compensate size mismatch */ WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3, }; #endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */ #ifndef WL_SURFACE_ERROR_ENUM #define WL_SURFACE_ERROR_ENUM /** * @ingroup iface_wl_surface * wl_surface error values * * These errors can be emitted in response to wl_surface requests. */ enum wl_surface_error { /** * buffer scale value is invalid */ WL_SURFACE_ERROR_INVALID_SCALE = 0, /** * buffer transform value is invalid */ WL_SURFACE_ERROR_INVALID_TRANSFORM = 1, }; #endif /* WL_SURFACE_ERROR_ENUM */ #ifndef WL_SEAT_CAPABILITY_ENUM #define WL_SEAT_CAPABILITY_ENUM /** * @ingroup iface_wl_seat * seat capability bitmask * * This is a bitmask of capabilities this seat has; if a member is * set, then it is present on the seat. */ enum wl_seat_capability { /** * the seat has pointer devices */ WL_SEAT_CAPABILITY_POINTER = 1, /** * the seat has one or more keyboards */ WL_SEAT_CAPABILITY_KEYBOARD = 2, /** * the seat has touch devices */ WL_SEAT_CAPABILITY_TOUCH = 4, }; #endif /* WL_SEAT_CAPABILITY_ENUM */ #ifndef WL_POINTER_ERROR_ENUM #define WL_POINTER_ERROR_ENUM enum wl_pointer_error { /** * given wl_surface has another role */ WL_POINTER_ERROR_ROLE = 0, }; #endif /* WL_POINTER_ERROR_ENUM */ #ifndef WL_POINTER_BUTTON_STATE_ENUM #define WL_POINTER_BUTTON_STATE_ENUM /** * @ingroup iface_wl_pointer * physical button state * * Describes the physical state of a button that produced the button * event. */ enum wl_pointer_button_state { /** * the button is not pressed */ WL_POINTER_BUTTON_STATE_RELEASED = 0, /** * the button is pressed */ WL_POINTER_BUTTON_STATE_PRESSED = 1, }; #endif /* WL_POINTER_BUTTON_STATE_ENUM */ #ifndef WL_POINTER_AXIS_ENUM #define WL_POINTER_AXIS_ENUM /** * @ingroup iface_wl_pointer * axis types * * Describes the axis types of scroll events. */ enum wl_pointer_axis { /** * vertical axis */ WL_POINTER_AXIS_VERTICAL_SCROLL = 0, /** * horizontal axis */ WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1, }; #endif /* WL_POINTER_AXIS_ENUM */ #ifndef WL_POINTER_AXIS_SOURCE_ENUM #define WL_POINTER_AXIS_SOURCE_ENUM /** * @ingroup iface_wl_pointer * axis source types * * Describes the source types for axis events. This indicates to the * client how an axis event was physically generated; a client may * adjust the user interface accordingly. For example, scroll events * from a "finger" source may be in a smooth coordinate space with * kinetic scrolling whereas a "wheel" source may be in discrete steps * of a number of lines. */ enum wl_pointer_axis_source { /** * a physical wheel rotation */ WL_POINTER_AXIS_SOURCE_WHEEL = 0, /** * finger on a touch surface */ WL_POINTER_AXIS_SOURCE_FINGER = 1, /** * continuous coordinate space * * A device generating events in a continuous coordinate space, * but using something other than a finger. One example for this * source is button-based scrolling where the vertical motion of a * device is converted to scroll events while a button is held * down. */ WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2, /** * a physical wheel tilt * * Indicates that the actual device is a wheel but the scroll * event is not caused by a rotation but a (usually sideways) tilt * of the wheel. * @since 6 */ WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3, }; /** * @ingroup iface_wl_pointer */ #define WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION 6 #endif /* WL_POINTER_AXIS_SOURCE_ENUM */ #ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM #define WL_KEYBOARD_KEYMAP_FORMAT_ENUM /** * @ingroup iface_wl_keyboard * keyboard mapping format * * This specifies the format of the keymap provided to the * client with the wl_keyboard.keymap event. */ enum wl_keyboard_keymap_format { /** * no keymap; client must understand how to interpret the raw keycode */ WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0, /** * libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode */ WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1, }; #endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */ #ifndef WL_KEYBOARD_KEY_STATE_ENUM #define WL_KEYBOARD_KEY_STATE_ENUM /** * @ingroup iface_wl_keyboard * physical key state * * Describes the physical state of a key that produced the key event. */ enum wl_keyboard_key_state { /** * key is not pressed */ WL_KEYBOARD_KEY_STATE_RELEASED = 0, /** * key is pressed */ WL_KEYBOARD_KEY_STATE_PRESSED = 1, }; #endif /* WL_KEYBOARD_KEY_STATE_ENUM */ #ifndef WL_OUTPUT_SUBPIXEL_ENUM #define WL_OUTPUT_SUBPIXEL_ENUM /** * @ingroup iface_wl_output * subpixel geometry information * * This enumeration describes how the physical * pixels on an output are laid out. */ enum wl_output_subpixel { /** * unknown geometry */ WL_OUTPUT_SUBPIXEL_UNKNOWN = 0, /** * no geometry */ WL_OUTPUT_SUBPIXEL_NONE = 1, /** * horizontal RGB */ WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2, /** * horizontal BGR */ WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3, /** * vertical RGB */ WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4, /** * vertical BGR */ WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5, }; #endif /* WL_OUTPUT_SUBPIXEL_ENUM */ #ifndef WL_OUTPUT_TRANSFORM_ENUM #define WL_OUTPUT_TRANSFORM_ENUM /** * @ingroup iface_wl_output * transform from framebuffer to output * * This describes the transform that a compositor will apply to a * surface to compensate for the rotation or mirroring of an * output device. * * The flipped values correspond to an initial flip around a * vertical axis followed by rotation. * * The purpose is mainly to allow clients to render accordingly and * tell the compositor, so that for fullscreen surfaces, the * compositor will still be able to scan out directly from client * surfaces. */ enum wl_output_transform { /** * no transform */ WL_OUTPUT_TRANSFORM_NORMAL = 0, /** * 90 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_90 = 1, /** * 180 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_180 = 2, /** * 270 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_270 = 3, /** * 180 degree flip around a vertical axis */ WL_OUTPUT_TRANSFORM_FLIPPED = 4, /** * flip and rotate 90 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5, /** * flip and rotate 180 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6, /** * flip and rotate 270 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7, }; #endif /* WL_OUTPUT_TRANSFORM_ENUM */ #ifndef WL_OUTPUT_MODE_ENUM #define WL_OUTPUT_MODE_ENUM /** * @ingroup iface_wl_output * mode information * * These flags describe properties of an output mode. * They are used in the flags bitfield of the mode event. */ enum wl_output_mode { /** * indicates this is the current mode */ WL_OUTPUT_MODE_CURRENT = 0x1, /** * indicates this is the preferred mode */ WL_OUTPUT_MODE_PREFERRED = 0x2, }; #endif /* WL_OUTPUT_MODE_ENUM */ #ifndef WL_SUBCOMPOSITOR_ERROR_ENUM #define WL_SUBCOMPOSITOR_ERROR_ENUM enum wl_subcompositor_error { /** * the to-be sub-surface is invalid */ WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0, }; #endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */ #ifndef WL_SUBSURFACE_ERROR_ENUM #define WL_SUBSURFACE_ERROR_ENUM enum wl_subsurface_error { /** * wl_surface is not a sibling or the parent */ WL_SUBSURFACE_ERROR_BAD_SURFACE = 0, }; #endif /* WL_SUBSURFACE_ERROR_ENUM */ #ifdef __cplusplus } #endif #endif wayland-1.23.1/tests/data/example-server.h000066400000000000000000004556271466237767300204700ustar00rootroot00000000000000/* SCANNER TEST */ #ifndef WAYLAND_SERVER_PROTOCOL_H #define WAYLAND_SERVER_PROTOCOL_H #include #include #include "wayland-server.h" #ifdef __cplusplus extern "C" { #endif struct wl_client; struct wl_resource; /** * @page page_wayland The wayland protocol * @section page_ifaces_wayland Interfaces * - @subpage page_iface_wl_display - core global object * - @subpage page_iface_wl_registry - global registry object * - @subpage page_iface_wl_callback - callback object * - @subpage page_iface_wl_compositor - the compositor singleton * - @subpage page_iface_wl_shm_pool - a shared memory pool * - @subpage page_iface_wl_shm - shared memory support * - @subpage page_iface_wl_buffer - content for a wl_surface * - @subpage page_iface_wl_data_offer - offer to transfer data * - @subpage page_iface_wl_data_source - offer to transfer data * - @subpage page_iface_wl_data_device - data transfer device * - @subpage page_iface_wl_data_device_manager - data transfer interface * - @subpage page_iface_wl_shell - create desktop-style surfaces * - @subpage page_iface_wl_shell_surface - desktop-style metadata interface * - @subpage page_iface_wl_surface - an onscreen surface * - @subpage page_iface_wl_seat - group of input devices * - @subpage page_iface_wl_pointer - pointer input device * - @subpage page_iface_wl_keyboard - keyboard input device * - @subpage page_iface_wl_touch - touchscreen input device * - @subpage page_iface_wl_output - compositor output region * - @subpage page_iface_wl_region - region interface * - @subpage page_iface_wl_subcompositor - sub-surface compositing * - @subpage page_iface_wl_subsurface - sub-surface interface to a wl_surface * @section page_copyright_wayland Copyright *
 *
 * Copyright © 2008-2011 Kristian Høgsberg
 * Copyright © 2010-2011 Intel Corporation
 * Copyright © 2012-2013 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.
 * 
*/ struct wl_buffer; struct wl_callback; struct wl_compositor; struct wl_data_device; struct wl_data_device_manager; struct wl_data_offer; struct wl_data_source; struct wl_display; struct wl_keyboard; struct wl_output; struct wl_pointer; struct wl_region; struct wl_registry; struct wl_seat; struct wl_shell; struct wl_shell_surface; struct wl_shm; struct wl_shm_pool; struct wl_subcompositor; struct wl_subsurface; struct wl_surface; struct wl_touch; #ifndef WL_DISPLAY_INTERFACE #define WL_DISPLAY_INTERFACE /** * @page page_iface_wl_display wl_display * @section page_iface_wl_display_desc Description * * The core global object. This is a special singleton object. It * is used for internal Wayland protocol features. * @section page_iface_wl_display_api API * See @ref iface_wl_display. */ /** * @defgroup iface_wl_display The wl_display interface * * The core global object. This is a special singleton object. It * is used for internal Wayland protocol features. */ extern const struct wl_interface wl_display_interface; #endif #ifndef WL_REGISTRY_INTERFACE #define WL_REGISTRY_INTERFACE /** * @page page_iface_wl_registry wl_registry * @section page_iface_wl_registry_desc Description * * The singleton global registry object. The server has a number of * global objects that are available to all clients. These objects * typically represent an actual object in the server (for example, * an input device) or they are singleton objects that provide * extension functionality. * * When a client creates a registry object, the registry object * will emit a global event for each global currently in the * registry. Globals come and go as a result of device or * monitor hotplugs, reconfiguration or other events, and the * registry will send out global and global_remove events to * keep the client up to date with the changes. To mark the end * of the initial burst of events, the client can use the * wl_display.sync request immediately after calling * wl_display.get_registry. * * A client can bind to a global object by using the bind * request. This creates a client-side handle that lets the object * emit events to the client and lets the client invoke requests on * the object. * @section page_iface_wl_registry_api API * See @ref iface_wl_registry. */ /** * @defgroup iface_wl_registry The wl_registry interface * * The singleton global registry object. The server has a number of * global objects that are available to all clients. These objects * typically represent an actual object in the server (for example, * an input device) or they are singleton objects that provide * extension functionality. * * When a client creates a registry object, the registry object * will emit a global event for each global currently in the * registry. Globals come and go as a result of device or * monitor hotplugs, reconfiguration or other events, and the * registry will send out global and global_remove events to * keep the client up to date with the changes. To mark the end * of the initial burst of events, the client can use the * wl_display.sync request immediately after calling * wl_display.get_registry. * * A client can bind to a global object by using the bind * request. This creates a client-side handle that lets the object * emit events to the client and lets the client invoke requests on * the object. */ extern const struct wl_interface wl_registry_interface; #endif #ifndef WL_CALLBACK_INTERFACE #define WL_CALLBACK_INTERFACE /** * @page page_iface_wl_callback wl_callback * @section page_iface_wl_callback_desc Description * * Clients can handle the 'done' event to get notified when * the related request is done. * @section page_iface_wl_callback_api API * See @ref iface_wl_callback. */ /** * @defgroup iface_wl_callback The wl_callback interface * * Clients can handle the 'done' event to get notified when * the related request is done. */ extern const struct wl_interface wl_callback_interface; #endif #ifndef WL_COMPOSITOR_INTERFACE #define WL_COMPOSITOR_INTERFACE /** * @page page_iface_wl_compositor wl_compositor * @section page_iface_wl_compositor_desc Description * * A compositor. This object is a singleton global. The * compositor is in charge of combining the contents of multiple * surfaces into one displayable output. * @section page_iface_wl_compositor_api API * See @ref iface_wl_compositor. */ /** * @defgroup iface_wl_compositor The wl_compositor interface * * A compositor. This object is a singleton global. The * compositor is in charge of combining the contents of multiple * surfaces into one displayable output. */ extern const struct wl_interface wl_compositor_interface; #endif #ifndef WL_SHM_POOL_INTERFACE #define WL_SHM_POOL_INTERFACE /** * @page page_iface_wl_shm_pool wl_shm_pool * @section page_iface_wl_shm_pool_desc Description * * The wl_shm_pool object encapsulates a piece of memory shared * between the compositor and client. Through the wl_shm_pool * object, the client can allocate shared memory wl_buffer objects. * All objects created through the same pool share the same * underlying mapped memory. Reusing the mapped memory avoids the * setup/teardown overhead and is useful when interactively resizing * a surface or for many small buffers. * @section page_iface_wl_shm_pool_api API * See @ref iface_wl_shm_pool. */ /** * @defgroup iface_wl_shm_pool The wl_shm_pool interface * * The wl_shm_pool object encapsulates a piece of memory shared * between the compositor and client. Through the wl_shm_pool * object, the client can allocate shared memory wl_buffer objects. * All objects created through the same pool share the same * underlying mapped memory. Reusing the mapped memory avoids the * setup/teardown overhead and is useful when interactively resizing * a surface or for many small buffers. */ extern const struct wl_interface wl_shm_pool_interface; #endif #ifndef WL_SHM_INTERFACE #define WL_SHM_INTERFACE /** * @page page_iface_wl_shm wl_shm * @section page_iface_wl_shm_desc Description * * A singleton global object that provides support for shared * memory. * * Clients can create wl_shm_pool objects using the create_pool * request. * * At connection setup time, the wl_shm object emits one or more * format events to inform clients about the valid pixel formats * that can be used for buffers. * @section page_iface_wl_shm_api API * See @ref iface_wl_shm. */ /** * @defgroup iface_wl_shm The wl_shm interface * * A singleton global object that provides support for shared * memory. * * Clients can create wl_shm_pool objects using the create_pool * request. * * At connection setup time, the wl_shm object emits one or more * format events to inform clients about the valid pixel formats * that can be used for buffers. */ extern const struct wl_interface wl_shm_interface; #endif #ifndef WL_BUFFER_INTERFACE #define WL_BUFFER_INTERFACE /** * @page page_iface_wl_buffer wl_buffer * @section page_iface_wl_buffer_desc Description * * A buffer provides the content for a wl_surface. Buffers are * created through factory interfaces such as wl_drm, wl_shm or * similar. It has a width and a height and can be attached to a * wl_surface, but the mechanism by which a client provides and * updates the contents is defined by the buffer factory interface. * @section page_iface_wl_buffer_api API * See @ref iface_wl_buffer. */ /** * @defgroup iface_wl_buffer The wl_buffer interface * * A buffer provides the content for a wl_surface. Buffers are * created through factory interfaces such as wl_drm, wl_shm or * similar. It has a width and a height and can be attached to a * wl_surface, but the mechanism by which a client provides and * updates the contents is defined by the buffer factory interface. */ extern const struct wl_interface wl_buffer_interface; #endif #ifndef WL_DATA_OFFER_INTERFACE #define WL_DATA_OFFER_INTERFACE /** * @page page_iface_wl_data_offer wl_data_offer * @section page_iface_wl_data_offer_desc Description * * A wl_data_offer represents a piece of data offered for transfer * by another client (the source client). It is used by the * copy-and-paste and drag-and-drop mechanisms. The offer * describes the different mime types that the data can be * converted to and provides the mechanism for transferring the * data directly from the source client. * @section page_iface_wl_data_offer_api API * See @ref iface_wl_data_offer. */ /** * @defgroup iface_wl_data_offer The wl_data_offer interface * * A wl_data_offer represents a piece of data offered for transfer * by another client (the source client). It is used by the * copy-and-paste and drag-and-drop mechanisms. The offer * describes the different mime types that the data can be * converted to and provides the mechanism for transferring the * data directly from the source client. */ extern const struct wl_interface wl_data_offer_interface; #endif #ifndef WL_DATA_SOURCE_INTERFACE #define WL_DATA_SOURCE_INTERFACE /** * @page page_iface_wl_data_source wl_data_source * @section page_iface_wl_data_source_desc Description * * The wl_data_source object is the source side of a wl_data_offer. * It is created by the source client in a data transfer and * provides a way to describe the offered data and a way to respond * to requests to transfer the data. * @section page_iface_wl_data_source_api API * See @ref iface_wl_data_source. */ /** * @defgroup iface_wl_data_source The wl_data_source interface * * The wl_data_source object is the source side of a wl_data_offer. * It is created by the source client in a data transfer and * provides a way to describe the offered data and a way to respond * to requests to transfer the data. */ extern const struct wl_interface wl_data_source_interface; #endif #ifndef WL_DATA_DEVICE_INTERFACE #define WL_DATA_DEVICE_INTERFACE /** * @page page_iface_wl_data_device wl_data_device * @section page_iface_wl_data_device_desc Description * * There is one wl_data_device per seat which can be obtained * from the global wl_data_device_manager singleton. * * A wl_data_device provides access to inter-client data transfer * mechanisms such as copy-and-paste and drag-and-drop. * @section page_iface_wl_data_device_api API * See @ref iface_wl_data_device. */ /** * @defgroup iface_wl_data_device The wl_data_device interface * * There is one wl_data_device per seat which can be obtained * from the global wl_data_device_manager singleton. * * A wl_data_device provides access to inter-client data transfer * mechanisms such as copy-and-paste and drag-and-drop. */ extern const struct wl_interface wl_data_device_interface; #endif #ifndef WL_DATA_DEVICE_MANAGER_INTERFACE #define WL_DATA_DEVICE_MANAGER_INTERFACE /** * @page page_iface_wl_data_device_manager wl_data_device_manager * @section page_iface_wl_data_device_manager_desc Description * * The wl_data_device_manager is a singleton global object that * provides access to inter-client data transfer mechanisms such as * copy-and-paste and drag-and-drop. These mechanisms are tied to * a wl_seat and this interface lets a client get a wl_data_device * corresponding to a wl_seat. * * Depending on the version bound, the objects created from the bound * wl_data_device_manager object will have different requirements for * functioning properly. See wl_data_source.set_actions, * wl_data_offer.accept and wl_data_offer.finish for details. * @section page_iface_wl_data_device_manager_api API * See @ref iface_wl_data_device_manager. */ /** * @defgroup iface_wl_data_device_manager The wl_data_device_manager interface * * The wl_data_device_manager is a singleton global object that * provides access to inter-client data transfer mechanisms such as * copy-and-paste and drag-and-drop. These mechanisms are tied to * a wl_seat and this interface lets a client get a wl_data_device * corresponding to a wl_seat. * * Depending on the version bound, the objects created from the bound * wl_data_device_manager object will have different requirements for * functioning properly. See wl_data_source.set_actions, * wl_data_offer.accept and wl_data_offer.finish for details. */ extern const struct wl_interface wl_data_device_manager_interface; #endif #ifndef WL_SHELL_INTERFACE #define WL_SHELL_INTERFACE /** * @page page_iface_wl_shell wl_shell * @section page_iface_wl_shell_desc Description * * This interface is implemented by servers that provide * desktop-style user interfaces. * * It allows clients to associate a wl_shell_surface with * a basic surface. * @section page_iface_wl_shell_api API * See @ref iface_wl_shell. */ /** * @defgroup iface_wl_shell The wl_shell interface * * This interface is implemented by servers that provide * desktop-style user interfaces. * * It allows clients to associate a wl_shell_surface with * a basic surface. */ extern const struct wl_interface wl_shell_interface; #endif #ifndef WL_SHELL_SURFACE_INTERFACE #define WL_SHELL_SURFACE_INTERFACE /** * @page page_iface_wl_shell_surface wl_shell_surface * @section page_iface_wl_shell_surface_desc Description * * An interface that may be implemented by a wl_surface, for * implementations that provide a desktop-style user interface. * * It provides requests to treat surfaces like toplevel, fullscreen * or popup windows, move, resize or maximize them, associate * metadata like title and class, etc. * * On the server side the object is automatically destroyed when * the related wl_surface is destroyed. On the client side, * wl_shell_surface_destroy() must be called before destroying * the wl_surface object. * @section page_iface_wl_shell_surface_api API * See @ref iface_wl_shell_surface. */ /** * @defgroup iface_wl_shell_surface The wl_shell_surface interface * * An interface that may be implemented by a wl_surface, for * implementations that provide a desktop-style user interface. * * It provides requests to treat surfaces like toplevel, fullscreen * or popup windows, move, resize or maximize them, associate * metadata like title and class, etc. * * On the server side the object is automatically destroyed when * the related wl_surface is destroyed. On the client side, * wl_shell_surface_destroy() must be called before destroying * the wl_surface object. */ extern const struct wl_interface wl_shell_surface_interface; #endif #ifndef WL_SURFACE_INTERFACE #define WL_SURFACE_INTERFACE /** * @page page_iface_wl_surface wl_surface * @section page_iface_wl_surface_desc Description * * A surface is a rectangular area that is displayed on the screen. * It has a location, size and pixel contents. * * The size of a surface (and relative positions on it) is described * in surface-local coordinates, which may differ from the buffer * coordinates of the pixel content, in case a buffer_transform * or a buffer_scale is used. * * A surface without a "role" is fairly useless: a compositor does * not know where, when or how to present it. The role is the * purpose of a wl_surface. Examples of roles are a cursor for a * pointer (as set by wl_pointer.set_cursor), a drag icon * (wl_data_device.start_drag), a sub-surface * (wl_subcompositor.get_subsurface), and a window as defined by a * shell protocol (e.g. wl_shell.get_shell_surface). * * A surface can have only one role at a time. Initially a * wl_surface does not have a role. Once a wl_surface is given a * role, it is set permanently for the whole lifetime of the * wl_surface object. Giving the current role again is allowed, * unless explicitly forbidden by the relevant interface * specification. * * Surface roles are given by requests in other interfaces such as * wl_pointer.set_cursor. The request should explicitly mention * that this request gives a role to a wl_surface. Often, this * request also creates a new protocol object that represents the * role and adds additional functionality to wl_surface. When a * client wants to destroy a wl_surface, they must destroy this 'role * object' before the wl_surface. * * Destroying the role object does not remove the role from the * wl_surface, but it may stop the wl_surface from "playing the role". * For instance, if a wl_subsurface object is destroyed, the wl_surface * it was created for will be unmapped and forget its position and * z-order. It is allowed to create a wl_subsurface for the same * wl_surface again, but it is not allowed to use the wl_surface as * a cursor (cursor is a different role than sub-surface, and role * switching is not allowed). * @section page_iface_wl_surface_api API * See @ref iface_wl_surface. */ /** * @defgroup iface_wl_surface The wl_surface interface * * A surface is a rectangular area that is displayed on the screen. * It has a location, size and pixel contents. * * The size of a surface (and relative positions on it) is described * in surface-local coordinates, which may differ from the buffer * coordinates of the pixel content, in case a buffer_transform * or a buffer_scale is used. * * A surface without a "role" is fairly useless: a compositor does * not know where, when or how to present it. The role is the * purpose of a wl_surface. Examples of roles are a cursor for a * pointer (as set by wl_pointer.set_cursor), a drag icon * (wl_data_device.start_drag), a sub-surface * (wl_subcompositor.get_subsurface), and a window as defined by a * shell protocol (e.g. wl_shell.get_shell_surface). * * A surface can have only one role at a time. Initially a * wl_surface does not have a role. Once a wl_surface is given a * role, it is set permanently for the whole lifetime of the * wl_surface object. Giving the current role again is allowed, * unless explicitly forbidden by the relevant interface * specification. * * Surface roles are given by requests in other interfaces such as * wl_pointer.set_cursor. The request should explicitly mention * that this request gives a role to a wl_surface. Often, this * request also creates a new protocol object that represents the * role and adds additional functionality to wl_surface. When a * client wants to destroy a wl_surface, they must destroy this 'role * object' before the wl_surface. * * Destroying the role object does not remove the role from the * wl_surface, but it may stop the wl_surface from "playing the role". * For instance, if a wl_subsurface object is destroyed, the wl_surface * it was created for will be unmapped and forget its position and * z-order. It is allowed to create a wl_subsurface for the same * wl_surface again, but it is not allowed to use the wl_surface as * a cursor (cursor is a different role than sub-surface, and role * switching is not allowed). */ extern const struct wl_interface wl_surface_interface; #endif #ifndef WL_SEAT_INTERFACE #define WL_SEAT_INTERFACE /** * @page page_iface_wl_seat wl_seat * @section page_iface_wl_seat_desc Description * * A seat is a group of keyboards, pointer and touch devices. This * object is published as a global during start up, or when such a * device is hot plugged. A seat typically has a pointer and * maintains a keyboard focus and a pointer focus. * @section page_iface_wl_seat_api API * See @ref iface_wl_seat. */ /** * @defgroup iface_wl_seat The wl_seat interface * * A seat is a group of keyboards, pointer and touch devices. This * object is published as a global during start up, or when such a * device is hot plugged. A seat typically has a pointer and * maintains a keyboard focus and a pointer focus. */ extern const struct wl_interface wl_seat_interface; #endif #ifndef WL_POINTER_INTERFACE #define WL_POINTER_INTERFACE /** * @page page_iface_wl_pointer wl_pointer * @section page_iface_wl_pointer_desc Description * * The wl_pointer interface represents one or more input devices, * such as mice, which control the pointer location and pointer_focus * of a seat. * * The wl_pointer interface generates motion, enter and leave * events for the surfaces that the pointer is located over, * and button and axis events for button presses, button releases * and scrolling. * @section page_iface_wl_pointer_api API * See @ref iface_wl_pointer. */ /** * @defgroup iface_wl_pointer The wl_pointer interface * * The wl_pointer interface represents one or more input devices, * such as mice, which control the pointer location and pointer_focus * of a seat. * * The wl_pointer interface generates motion, enter and leave * events for the surfaces that the pointer is located over, * and button and axis events for button presses, button releases * and scrolling. */ extern const struct wl_interface wl_pointer_interface; #endif #ifndef WL_KEYBOARD_INTERFACE #define WL_KEYBOARD_INTERFACE /** * @page page_iface_wl_keyboard wl_keyboard * @section page_iface_wl_keyboard_desc Description * * The wl_keyboard interface represents one or more keyboards * associated with a seat. * @section page_iface_wl_keyboard_api API * See @ref iface_wl_keyboard. */ /** * @defgroup iface_wl_keyboard The wl_keyboard interface * * The wl_keyboard interface represents one or more keyboards * associated with a seat. */ extern const struct wl_interface wl_keyboard_interface; #endif #ifndef WL_TOUCH_INTERFACE #define WL_TOUCH_INTERFACE /** * @page page_iface_wl_touch wl_touch * @section page_iface_wl_touch_desc Description * * The wl_touch interface represents a touchscreen * associated with a seat. * * Touch interactions can consist of one or more contacts. * For each contact, a series of events is generated, starting * with a down event, followed by zero or more motion events, * and ending with an up event. Events relating to the same * contact point can be identified by the ID of the sequence. * @section page_iface_wl_touch_api API * See @ref iface_wl_touch. */ /** * @defgroup iface_wl_touch The wl_touch interface * * The wl_touch interface represents a touchscreen * associated with a seat. * * Touch interactions can consist of one or more contacts. * For each contact, a series of events is generated, starting * with a down event, followed by zero or more motion events, * and ending with an up event. Events relating to the same * contact point can be identified by the ID of the sequence. */ extern const struct wl_interface wl_touch_interface; #endif #ifndef WL_OUTPUT_INTERFACE #define WL_OUTPUT_INTERFACE /** * @page page_iface_wl_output wl_output * @section page_iface_wl_output_desc Description * * An output describes part of the compositor geometry. The * compositor works in the 'compositor coordinate system' and an * output corresponds to a rectangular area in that space that is * actually visible. This typically corresponds to a monitor that * displays part of the compositor space. This object is published * as global during start up, or when a monitor is hotplugged. * @section page_iface_wl_output_api API * See @ref iface_wl_output. */ /** * @defgroup iface_wl_output The wl_output interface * * An output describes part of the compositor geometry. The * compositor works in the 'compositor coordinate system' and an * output corresponds to a rectangular area in that space that is * actually visible. This typically corresponds to a monitor that * displays part of the compositor space. This object is published * as global during start up, or when a monitor is hotplugged. */ extern const struct wl_interface wl_output_interface; #endif #ifndef WL_REGION_INTERFACE #define WL_REGION_INTERFACE /** * @page page_iface_wl_region wl_region * @section page_iface_wl_region_desc Description * * A region object describes an area. * * Region objects are used to describe the opaque and input * regions of a surface. * @section page_iface_wl_region_api API * See @ref iface_wl_region. */ /** * @defgroup iface_wl_region The wl_region interface * * A region object describes an area. * * Region objects are used to describe the opaque and input * regions of a surface. */ extern const struct wl_interface wl_region_interface; #endif #ifndef WL_SUBCOMPOSITOR_INTERFACE #define WL_SUBCOMPOSITOR_INTERFACE /** * @page page_iface_wl_subcompositor wl_subcompositor * @section page_iface_wl_subcompositor_desc Description * * The global interface exposing sub-surface compositing capabilities. * A wl_surface, that has sub-surfaces associated, is called the * parent surface. Sub-surfaces can be arbitrarily nested and create * a tree of sub-surfaces. * * The root surface in a tree of sub-surfaces is the main * surface. The main surface cannot be a sub-surface, because * sub-surfaces must always have a parent. * * A main surface with its sub-surfaces forms a (compound) window. * For window management purposes, this set of wl_surface objects is * to be considered as a single window, and it should also behave as * such. * * The aim of sub-surfaces is to offload some of the compositing work * within a window from clients to the compositor. A prime example is * a video player with decorations and video in separate wl_surface * objects. This should allow the compositor to pass YUV video buffer * processing to dedicated overlay hardware when possible. * @section page_iface_wl_subcompositor_api API * See @ref iface_wl_subcompositor. */ /** * @defgroup iface_wl_subcompositor The wl_subcompositor interface * * The global interface exposing sub-surface compositing capabilities. * A wl_surface, that has sub-surfaces associated, is called the * parent surface. Sub-surfaces can be arbitrarily nested and create * a tree of sub-surfaces. * * The root surface in a tree of sub-surfaces is the main * surface. The main surface cannot be a sub-surface, because * sub-surfaces must always have a parent. * * A main surface with its sub-surfaces forms a (compound) window. * For window management purposes, this set of wl_surface objects is * to be considered as a single window, and it should also behave as * such. * * The aim of sub-surfaces is to offload some of the compositing work * within a window from clients to the compositor. A prime example is * a video player with decorations and video in separate wl_surface * objects. This should allow the compositor to pass YUV video buffer * processing to dedicated overlay hardware when possible. */ extern const struct wl_interface wl_subcompositor_interface; #endif #ifndef WL_SUBSURFACE_INTERFACE #define WL_SUBSURFACE_INTERFACE /** * @page page_iface_wl_subsurface wl_subsurface * @section page_iface_wl_subsurface_desc Description * * An additional interface to a wl_surface object, which has been * made a sub-surface. A sub-surface has one parent surface. A * sub-surface's size and position are not limited to that of the parent. * Particularly, a sub-surface is not automatically clipped to its * parent's area. * * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied * and the parent surface is mapped. The order of which one happens * first is irrelevant. A sub-surface is hidden if the parent becomes * hidden, or if a NULL wl_buffer is applied. These rules apply * recursively through the tree of surfaces. * * The behaviour of a wl_surface.commit request on a sub-surface * depends on the sub-surface's mode. The possible modes are * synchronized and desynchronized, see methods * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized * mode caches the wl_surface state to be applied when the parent's * state gets applied, and desynchronized mode applies the pending * wl_surface state directly. A sub-surface is initially in the * synchronized mode. * * Sub-surfaces have also other kind of state, which is managed by * wl_subsurface requests, as opposed to wl_surface requests. This * state includes the sub-surface position relative to the parent * surface (wl_subsurface.set_position), and the stacking order of * the parent and its sub-surfaces (wl_subsurface.place_above and * .place_below). This state is applied when the parent surface's * wl_surface state is applied, regardless of the sub-surface's mode. * As the exception, set_sync and set_desync are effective immediately. * * The main surface can be thought to be always in desynchronized mode, * since it does not have a parent in the sub-surfaces sense. * * Even if a sub-surface is in desynchronized mode, it will behave as * in synchronized mode, if its parent surface behaves as in * synchronized mode. This rule is applied recursively throughout the * tree of surfaces. This means, that one can set a sub-surface into * synchronized mode, and then assume that all its child and grand-child * sub-surfaces are synchronized, too, without explicitly setting them. * * If the wl_surface associated with the wl_subsurface is destroyed, the * wl_subsurface object becomes inert. Note, that destroying either object * takes effect immediately. If you need to synchronize the removal * of a sub-surface to the parent surface update, unmap the sub-surface * first by attaching a NULL wl_buffer, update parent, and then destroy * the sub-surface. * * If the parent wl_surface object is destroyed, the sub-surface is * unmapped. * @section page_iface_wl_subsurface_api API * See @ref iface_wl_subsurface. */ /** * @defgroup iface_wl_subsurface The wl_subsurface interface * * An additional interface to a wl_surface object, which has been * made a sub-surface. A sub-surface has one parent surface. A * sub-surface's size and position are not limited to that of the parent. * Particularly, a sub-surface is not automatically clipped to its * parent's area. * * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied * and the parent surface is mapped. The order of which one happens * first is irrelevant. A sub-surface is hidden if the parent becomes * hidden, or if a NULL wl_buffer is applied. These rules apply * recursively through the tree of surfaces. * * The behaviour of a wl_surface.commit request on a sub-surface * depends on the sub-surface's mode. The possible modes are * synchronized and desynchronized, see methods * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized * mode caches the wl_surface state to be applied when the parent's * state gets applied, and desynchronized mode applies the pending * wl_surface state directly. A sub-surface is initially in the * synchronized mode. * * Sub-surfaces have also other kind of state, which is managed by * wl_subsurface requests, as opposed to wl_surface requests. This * state includes the sub-surface position relative to the parent * surface (wl_subsurface.set_position), and the stacking order of * the parent and its sub-surfaces (wl_subsurface.place_above and * .place_below). This state is applied when the parent surface's * wl_surface state is applied, regardless of the sub-surface's mode. * As the exception, set_sync and set_desync are effective immediately. * * The main surface can be thought to be always in desynchronized mode, * since it does not have a parent in the sub-surfaces sense. * * Even if a sub-surface is in desynchronized mode, it will behave as * in synchronized mode, if its parent surface behaves as in * synchronized mode. This rule is applied recursively throughout the * tree of surfaces. This means, that one can set a sub-surface into * synchronized mode, and then assume that all its child and grand-child * sub-surfaces are synchronized, too, without explicitly setting them. * * If the wl_surface associated with the wl_subsurface is destroyed, the * wl_subsurface object becomes inert. Note, that destroying either object * takes effect immediately. If you need to synchronize the removal * of a sub-surface to the parent surface update, unmap the sub-surface * first by attaching a NULL wl_buffer, update parent, and then destroy * the sub-surface. * * If the parent wl_surface object is destroyed, the sub-surface is * unmapped. */ extern const struct wl_interface wl_subsurface_interface; #endif #ifndef WL_DISPLAY_ERROR_ENUM #define WL_DISPLAY_ERROR_ENUM /** * @ingroup iface_wl_display * global error values * * These errors are global and can be emitted in response to any * server request. */ enum wl_display_error { /** * server couldn't find object */ WL_DISPLAY_ERROR_INVALID_OBJECT = 0, /** * method doesn't exist on the specified interface */ WL_DISPLAY_ERROR_INVALID_METHOD = 1, /** * server is out of memory */ WL_DISPLAY_ERROR_NO_MEMORY = 2, }; /** * @ingroup iface_wl_display * Validate a wl_display error value. * * @return true on success, false on error. * @ref wl_display_error */ static inline bool wl_display_error_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_DISPLAY_ERROR_INVALID_OBJECT: return version >= 1; case WL_DISPLAY_ERROR_INVALID_METHOD: return version >= 1; case WL_DISPLAY_ERROR_NO_MEMORY: return version >= 1; default: return false; } } #endif /* WL_DISPLAY_ERROR_ENUM */ /** * @ingroup iface_wl_display * @struct wl_display_interface */ struct wl_display_interface { /** * asynchronous roundtrip * * The sync request asks the server to emit the 'done' event on * the returned wl_callback object. Since requests are handled * in-order and events are delivered in-order, this can be used as * a barrier to ensure all previous requests and the resulting * events have been handled. * * The object returned by this request will be destroyed by the * compositor after the callback is fired and as such the client * must not attempt to use it after that point. * * The callback_data passed in the callback is the event serial. * @param callback callback object for the sync request */ void (*sync)(struct wl_client *client, struct wl_resource *resource, uint32_t callback); /** * get global registry object * * This request creates a registry object that allows the client * to list and bind the global objects available from the * compositor. * @param registry global registry object */ void (*get_registry)(struct wl_client *client, struct wl_resource *resource, uint32_t registry); }; #define WL_DISPLAY_ERROR 0 #define WL_DISPLAY_DELETE_ID 1 /** * @ingroup iface_wl_display */ #define WL_DISPLAY_ERROR_SINCE_VERSION 1 /** * @ingroup iface_wl_display */ #define WL_DISPLAY_DELETE_ID_SINCE_VERSION 1 /** * @ingroup iface_wl_display */ #define WL_DISPLAY_SYNC_SINCE_VERSION 1 /** * @ingroup iface_wl_display */ #define WL_DISPLAY_GET_REGISTRY_SINCE_VERSION 1 /** * @ingroup iface_wl_registry * @struct wl_registry_interface */ struct wl_registry_interface { /** * bind an object to the display * * Binds a new, client-created object to the server using the * specified name as the identifier. * @param name unique numeric name of the object * @param interface name of the objects interface * @param version version of the objects interface * @param id bounded object */ void (*bind)(struct wl_client *client, struct wl_resource *resource, uint32_t name, const char *interface, uint32_t version, uint32_t id); }; #define WL_REGISTRY_GLOBAL 0 #define WL_REGISTRY_GLOBAL_REMOVE 1 /** * @ingroup iface_wl_registry */ #define WL_REGISTRY_GLOBAL_SINCE_VERSION 1 /** * @ingroup iface_wl_registry */ #define WL_REGISTRY_GLOBAL_REMOVE_SINCE_VERSION 1 /** * @ingroup iface_wl_registry */ #define WL_REGISTRY_BIND_SINCE_VERSION 1 /** * @ingroup iface_wl_registry * Sends an global event to the client owning the resource. * @param resource_ The client's resource * @param name numeric name of the global object * @param interface interface implemented by the object * @param version interface version */ static inline void wl_registry_send_global(struct wl_resource *resource_, uint32_t name, const char *interface, uint32_t version) { wl_resource_post_event(resource_, WL_REGISTRY_GLOBAL, name, interface, version); } /** * @ingroup iface_wl_registry * Sends an global_remove event to the client owning the resource. * @param resource_ The client's resource * @param name numeric name of the global object */ static inline void wl_registry_send_global_remove(struct wl_resource *resource_, uint32_t name) { wl_resource_post_event(resource_, WL_REGISTRY_GLOBAL_REMOVE, name); } #define WL_CALLBACK_DONE 0 /** * @ingroup iface_wl_callback */ #define WL_CALLBACK_DONE_SINCE_VERSION 1 /** * @ingroup iface_wl_callback * Sends an done event to the client owning the resource. * @param resource_ The client's resource * @param callback_data request-specific data for the callback */ static inline void wl_callback_send_done(struct wl_resource *resource_, uint32_t callback_data) { wl_resource_post_event(resource_, WL_CALLBACK_DONE, callback_data); } /** * @ingroup iface_wl_compositor * @struct wl_compositor_interface */ struct wl_compositor_interface { /** * create new surface * * Ask the compositor to create a new surface. * @param id the new surface */ void (*create_surface)(struct wl_client *client, struct wl_resource *resource, uint32_t id); /** * create new region * * Ask the compositor to create a new region. * @param id the new region */ void (*create_region)(struct wl_client *client, struct wl_resource *resource, uint32_t id); }; /** * @ingroup iface_wl_compositor */ #define WL_COMPOSITOR_CREATE_SURFACE_SINCE_VERSION 1 /** * @ingroup iface_wl_compositor */ #define WL_COMPOSITOR_CREATE_REGION_SINCE_VERSION 1 /** * @ingroup iface_wl_shm_pool * @struct wl_shm_pool_interface */ struct wl_shm_pool_interface { /** * create a buffer from the pool * * Create a wl_buffer object from the pool. * * The buffer is created offset bytes into the pool and has width * and height as specified. The stride argument specifies the * number of bytes from the beginning of one row to the beginning * of the next. The format is the pixel format of the buffer and * must be one of those advertised through the wl_shm.format event. * * A buffer will keep a reference to the pool it was created from * so it is valid to destroy the pool immediately after creating a * buffer from it. * @param id buffer to create * @param offset buffer byte offset within the pool * @param width buffer width, in pixels * @param height buffer height, in pixels * @param stride number of bytes from the beginning of one row to the beginning of the next row * @param format buffer pixel format */ void (*create_buffer)(struct wl_client *client, struct wl_resource *resource, uint32_t id, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format); /** * destroy the pool * * Destroy the shared memory pool. * * The mmapped memory will be released when all buffers that have * been created from this pool are gone. */ void (*destroy)(struct wl_client *client, struct wl_resource *resource); /** * change the size of the pool mapping * * This request will cause the server to remap the backing memory * for the pool from the file descriptor passed when the pool was * created, but using the new size. This request can only be used * to make the pool bigger. * @param size new size of the pool, in bytes */ void (*resize)(struct wl_client *client, struct wl_resource *resource, int32_t size); }; /** * @ingroup iface_wl_shm_pool */ #define WL_SHM_POOL_CREATE_BUFFER_SINCE_VERSION 1 /** * @ingroup iface_wl_shm_pool */ #define WL_SHM_POOL_DESTROY_SINCE_VERSION 1 /** * @ingroup iface_wl_shm_pool */ #define WL_SHM_POOL_RESIZE_SINCE_VERSION 1 #ifndef WL_SHM_ERROR_ENUM #define WL_SHM_ERROR_ENUM /** * @ingroup iface_wl_shm * wl_shm error values * * These errors can be emitted in response to wl_shm requests. */ enum wl_shm_error { /** * buffer format is not known */ WL_SHM_ERROR_INVALID_FORMAT = 0, /** * invalid size or stride during pool or buffer creation */ WL_SHM_ERROR_INVALID_STRIDE = 1, /** * mmapping the file descriptor failed */ WL_SHM_ERROR_INVALID_FD = 2, }; /** * @ingroup iface_wl_shm * Validate a wl_shm error value. * * @return true on success, false on error. * @ref wl_shm_error */ static inline bool wl_shm_error_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_SHM_ERROR_INVALID_FORMAT: return version >= 1; case WL_SHM_ERROR_INVALID_STRIDE: return version >= 1; case WL_SHM_ERROR_INVALID_FD: return version >= 1; default: return false; } } #endif /* WL_SHM_ERROR_ENUM */ #ifndef WL_SHM_FORMAT_ENUM #define WL_SHM_FORMAT_ENUM /** * @ingroup iface_wl_shm * pixel formats * * This describes the memory layout of an individual pixel. * * All renderers should support argb8888 and xrgb8888 but any other * formats are optional and may not be supported by the particular * renderer in use. * * The drm format codes match the macros defined in drm_fourcc.h. * The formats actually supported by the compositor will be * reported by the format event. */ enum wl_shm_format { /** * 32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian */ WL_SHM_FORMAT_ARGB8888 = 0, /** * 32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian */ WL_SHM_FORMAT_XRGB8888 = 1, /** * 8-bit color index format, [7:0] C */ WL_SHM_FORMAT_C8 = 0x20203843, /** * 8-bit RGB format, [7:0] R:G:B 3:3:2 */ WL_SHM_FORMAT_RGB332 = 0x38424752, /** * 8-bit BGR format, [7:0] B:G:R 2:3:3 */ WL_SHM_FORMAT_BGR233 = 0x38524742, /** * 16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian */ WL_SHM_FORMAT_XRGB4444 = 0x32315258, /** * 16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian */ WL_SHM_FORMAT_XBGR4444 = 0x32314258, /** * 16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian */ WL_SHM_FORMAT_RGBX4444 = 0x32315852, /** * 16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian */ WL_SHM_FORMAT_BGRX4444 = 0x32315842, /** * 16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian */ WL_SHM_FORMAT_ARGB4444 = 0x32315241, /** * 16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian */ WL_SHM_FORMAT_ABGR4444 = 0x32314241, /** * 16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian */ WL_SHM_FORMAT_RGBA4444 = 0x32314152, /** * 16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian */ WL_SHM_FORMAT_BGRA4444 = 0x32314142, /** * 16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian */ WL_SHM_FORMAT_XRGB1555 = 0x35315258, /** * 16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian */ WL_SHM_FORMAT_XBGR1555 = 0x35314258, /** * 16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian */ WL_SHM_FORMAT_RGBX5551 = 0x35315852, /** * 16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian */ WL_SHM_FORMAT_BGRX5551 = 0x35315842, /** * 16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian */ WL_SHM_FORMAT_ARGB1555 = 0x35315241, /** * 16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian */ WL_SHM_FORMAT_ABGR1555 = 0x35314241, /** * 16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian */ WL_SHM_FORMAT_RGBA5551 = 0x35314152, /** * 16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian */ WL_SHM_FORMAT_BGRA5551 = 0x35314142, /** * 16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian */ WL_SHM_FORMAT_RGB565 = 0x36314752, /** * 16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian */ WL_SHM_FORMAT_BGR565 = 0x36314742, /** * 24-bit RGB format, [23:0] R:G:B little endian */ WL_SHM_FORMAT_RGB888 = 0x34324752, /** * 24-bit BGR format, [23:0] B:G:R little endian */ WL_SHM_FORMAT_BGR888 = 0x34324742, /** * 32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian */ WL_SHM_FORMAT_XBGR8888 = 0x34324258, /** * 32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian */ WL_SHM_FORMAT_RGBX8888 = 0x34325852, /** * 32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian */ WL_SHM_FORMAT_BGRX8888 = 0x34325842, /** * 32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian */ WL_SHM_FORMAT_ABGR8888 = 0x34324241, /** * 32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian */ WL_SHM_FORMAT_RGBA8888 = 0x34324152, /** * 32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian */ WL_SHM_FORMAT_BGRA8888 = 0x34324142, /** * 32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian */ WL_SHM_FORMAT_XRGB2101010 = 0x30335258, /** * 32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian */ WL_SHM_FORMAT_XBGR2101010 = 0x30334258, /** * 32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian */ WL_SHM_FORMAT_RGBX1010102 = 0x30335852, /** * 32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian */ WL_SHM_FORMAT_BGRX1010102 = 0x30335842, /** * 32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian */ WL_SHM_FORMAT_ARGB2101010 = 0x30335241, /** * 32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian */ WL_SHM_FORMAT_ABGR2101010 = 0x30334241, /** * 32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian */ WL_SHM_FORMAT_RGBA1010102 = 0x30334152, /** * 32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian */ WL_SHM_FORMAT_BGRA1010102 = 0x30334142, /** * packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */ WL_SHM_FORMAT_YUYV = 0x56595559, /** * packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian */ WL_SHM_FORMAT_YVYU = 0x55595659, /** * packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian */ WL_SHM_FORMAT_UYVY = 0x59565955, /** * packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian */ WL_SHM_FORMAT_VYUY = 0x59555956, /** * packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */ WL_SHM_FORMAT_AYUV = 0x56555941, /** * 2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane */ WL_SHM_FORMAT_NV12 = 0x3231564e, /** * 2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane */ WL_SHM_FORMAT_NV21 = 0x3132564e, /** * 2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane */ WL_SHM_FORMAT_NV16 = 0x3631564e, /** * 2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane */ WL_SHM_FORMAT_NV61 = 0x3136564e, /** * 3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes */ WL_SHM_FORMAT_YUV410 = 0x39565559, /** * 3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes */ WL_SHM_FORMAT_YVU410 = 0x39555659, /** * 3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes */ WL_SHM_FORMAT_YUV411 = 0x31315559, /** * 3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes */ WL_SHM_FORMAT_YVU411 = 0x31315659, /** * 3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes */ WL_SHM_FORMAT_YUV420 = 0x32315559, /** * 3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes */ WL_SHM_FORMAT_YVU420 = 0x32315659, /** * 3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes */ WL_SHM_FORMAT_YUV422 = 0x36315559, /** * 3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes */ WL_SHM_FORMAT_YVU422 = 0x36315659, /** * 3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes */ WL_SHM_FORMAT_YUV444 = 0x34325559, /** * 3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes */ WL_SHM_FORMAT_YVU444 = 0x34325659, }; /** * @ingroup iface_wl_shm * Validate a wl_shm format value. * * @return true on success, false on error. * @ref wl_shm_format */ static inline bool wl_shm_format_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_SHM_FORMAT_ARGB8888: return version >= 1; case WL_SHM_FORMAT_XRGB8888: return version >= 1; case WL_SHM_FORMAT_C8: return version >= 1; case WL_SHM_FORMAT_RGB332: return version >= 1; case WL_SHM_FORMAT_BGR233: return version >= 1; case WL_SHM_FORMAT_XRGB4444: return version >= 1; case WL_SHM_FORMAT_XBGR4444: return version >= 1; case WL_SHM_FORMAT_RGBX4444: return version >= 1; case WL_SHM_FORMAT_BGRX4444: return version >= 1; case WL_SHM_FORMAT_ARGB4444: return version >= 1; case WL_SHM_FORMAT_ABGR4444: return version >= 1; case WL_SHM_FORMAT_RGBA4444: return version >= 1; case WL_SHM_FORMAT_BGRA4444: return version >= 1; case WL_SHM_FORMAT_XRGB1555: return version >= 1; case WL_SHM_FORMAT_XBGR1555: return version >= 1; case WL_SHM_FORMAT_RGBX5551: return version >= 1; case WL_SHM_FORMAT_BGRX5551: return version >= 1; case WL_SHM_FORMAT_ARGB1555: return version >= 1; case WL_SHM_FORMAT_ABGR1555: return version >= 1; case WL_SHM_FORMAT_RGBA5551: return version >= 1; case WL_SHM_FORMAT_BGRA5551: return version >= 1; case WL_SHM_FORMAT_RGB565: return version >= 1; case WL_SHM_FORMAT_BGR565: return version >= 1; case WL_SHM_FORMAT_RGB888: return version >= 1; case WL_SHM_FORMAT_BGR888: return version >= 1; case WL_SHM_FORMAT_XBGR8888: return version >= 1; case WL_SHM_FORMAT_RGBX8888: return version >= 1; case WL_SHM_FORMAT_BGRX8888: return version >= 1; case WL_SHM_FORMAT_ABGR8888: return version >= 1; case WL_SHM_FORMAT_RGBA8888: return version >= 1; case WL_SHM_FORMAT_BGRA8888: return version >= 1; case WL_SHM_FORMAT_XRGB2101010: return version >= 1; case WL_SHM_FORMAT_XBGR2101010: return version >= 1; case WL_SHM_FORMAT_RGBX1010102: return version >= 1; case WL_SHM_FORMAT_BGRX1010102: return version >= 1; case WL_SHM_FORMAT_ARGB2101010: return version >= 1; case WL_SHM_FORMAT_ABGR2101010: return version >= 1; case WL_SHM_FORMAT_RGBA1010102: return version >= 1; case WL_SHM_FORMAT_BGRA1010102: return version >= 1; case WL_SHM_FORMAT_YUYV: return version >= 1; case WL_SHM_FORMAT_YVYU: return version >= 1; case WL_SHM_FORMAT_UYVY: return version >= 1; case WL_SHM_FORMAT_VYUY: return version >= 1; case WL_SHM_FORMAT_AYUV: return version >= 1; case WL_SHM_FORMAT_NV12: return version >= 1; case WL_SHM_FORMAT_NV21: return version >= 1; case WL_SHM_FORMAT_NV16: return version >= 1; case WL_SHM_FORMAT_NV61: return version >= 1; case WL_SHM_FORMAT_YUV410: return version >= 1; case WL_SHM_FORMAT_YVU410: return version >= 1; case WL_SHM_FORMAT_YUV411: return version >= 1; case WL_SHM_FORMAT_YVU411: return version >= 1; case WL_SHM_FORMAT_YUV420: return version >= 1; case WL_SHM_FORMAT_YVU420: return version >= 1; case WL_SHM_FORMAT_YUV422: return version >= 1; case WL_SHM_FORMAT_YVU422: return version >= 1; case WL_SHM_FORMAT_YUV444: return version >= 1; case WL_SHM_FORMAT_YVU444: return version >= 1; default: return false; } } #endif /* WL_SHM_FORMAT_ENUM */ /** * @ingroup iface_wl_shm * @struct wl_shm_interface */ struct wl_shm_interface { /** * create a shm pool * * Create a new wl_shm_pool object. * * The pool can be used to create shared memory based buffer * objects. The server will mmap size bytes of the passed file * descriptor, to use as backing memory for the pool. * @param id pool to create * @param fd file descriptor for the pool * @param size pool size, in bytes */ void (*create_pool)(struct wl_client *client, struct wl_resource *resource, uint32_t id, int32_t fd, int32_t size); }; #define WL_SHM_FORMAT 0 /** * @ingroup iface_wl_shm */ #define WL_SHM_FORMAT_SINCE_VERSION 1 /** * @ingroup iface_wl_shm */ #define WL_SHM_CREATE_POOL_SINCE_VERSION 1 /** * @ingroup iface_wl_shm * Sends an format event to the client owning the resource. * @param resource_ The client's resource * @param format buffer pixel format */ static inline void wl_shm_send_format(struct wl_resource *resource_, uint32_t format) { wl_resource_post_event(resource_, WL_SHM_FORMAT, format); } /** * @ingroup iface_wl_buffer * @struct wl_buffer_interface */ struct wl_buffer_interface { /** * destroy a buffer * * Destroy a buffer. If and how you need to release the backing * storage is defined by the buffer factory interface. * * For possible side-effects to a surface, see wl_surface.attach. */ void (*destroy)(struct wl_client *client, struct wl_resource *resource); }; #define WL_BUFFER_RELEASE 0 /** * @ingroup iface_wl_buffer */ #define WL_BUFFER_RELEASE_SINCE_VERSION 1 /** * @ingroup iface_wl_buffer */ #define WL_BUFFER_DESTROY_SINCE_VERSION 1 /** * @ingroup iface_wl_buffer * Sends an release event to the client owning the resource. * @param resource_ The client's resource */ static inline void wl_buffer_send_release(struct wl_resource *resource_) { wl_resource_post_event(resource_, WL_BUFFER_RELEASE); } #ifndef WL_DATA_OFFER_ERROR_ENUM #define WL_DATA_OFFER_ERROR_ENUM enum wl_data_offer_error { /** * finish request was called untimely */ WL_DATA_OFFER_ERROR_INVALID_FINISH = 0, /** * action mask contains invalid values */ WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK = 1, /** * action argument has an invalid value */ WL_DATA_OFFER_ERROR_INVALID_ACTION = 2, /** * offer doesn't accept this request */ WL_DATA_OFFER_ERROR_INVALID_OFFER = 3, }; /** * @ingroup iface_wl_data_offer * Validate a wl_data_offer error value. * * @return true on success, false on error. * @ref wl_data_offer_error */ static inline bool wl_data_offer_error_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_DATA_OFFER_ERROR_INVALID_FINISH: return version >= 1; case WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK: return version >= 1; case WL_DATA_OFFER_ERROR_INVALID_ACTION: return version >= 1; case WL_DATA_OFFER_ERROR_INVALID_OFFER: return version >= 1; default: return false; } } #endif /* WL_DATA_OFFER_ERROR_ENUM */ /** * @ingroup iface_wl_data_offer * @struct wl_data_offer_interface */ struct wl_data_offer_interface { /** * accept one of the offered mime types * * Indicate that the client can accept the given mime type, or * NULL for not accepted. * * For objects of version 2 or older, this request is used by the * client to give feedback whether the client can receive the given * mime type, or NULL if none is accepted; the feedback does not * determine whether the drag-and-drop operation succeeds or not. * * For objects of version 3 or newer, this request determines the * final result of the drag-and-drop operation. If the end result * is that no mime types were accepted, the drag-and-drop operation * will be cancelled and the corresponding drag source will receive * wl_data_source.cancelled. Clients may still use this event in * conjunction with wl_data_source.action for feedback. * @param serial serial number of the accept request * @param mime_type mime type accepted by the client */ void (*accept)(struct wl_client *client, struct wl_resource *resource, uint32_t serial, const char *mime_type); /** * request that the data is transferred * * To transfer the offered data, the client issues this request * and indicates the mime type it wants to receive. The transfer * happens through the passed file descriptor (typically created * with the pipe system call). The source client writes the data in * the mime type representation requested and then closes the file * descriptor. * * The receiving client reads from the read end of the pipe until * EOF and then closes its end, at which point the transfer is * complete. * * This request may happen multiple times for different mime types, * both before and after wl_data_device.drop. Drag-and-drop * destination clients may preemptively fetch data or examine it * more closely to determine acceptance. * @param mime_type mime type desired by receiver * @param fd file descriptor for data transfer */ void (*receive)(struct wl_client *client, struct wl_resource *resource, const char *mime_type, int32_t fd); /** * destroy data offer * * Destroy the data offer. */ void (*destroy)(struct wl_client *client, struct wl_resource *resource); /** * the offer will no longer be used * * Notifies the compositor that the drag destination successfully * finished the drag-and-drop operation. * * Upon receiving this request, the compositor will emit * wl_data_source.dnd_finished on the drag source client. * * It is a client error to perform other requests than * wl_data_offer.destroy after this one. It is also an error to * perform this request after a NULL mime type has been set in * wl_data_offer.accept or no action was received through * wl_data_offer.action. * @since 3 */ void (*finish)(struct wl_client *client, struct wl_resource *resource); /** * set the available/preferred drag-and-drop actions * * Sets the actions that the destination side client supports for * this operation. This request may trigger the emission of * wl_data_source.action and wl_data_offer.action events if the * compositor needs to change the selected action. * * This request can be called multiple times throughout the * drag-and-drop operation, typically in response to * wl_data_device.enter or wl_data_device.motion events. * * This request determines the final result of the drag-and-drop * operation. If the end result is that no action is accepted, the * drag source will receive wl_drag_source.cancelled. * * The dnd_actions argument must contain only values expressed in * the wl_data_device_manager.dnd_actions enum, and the * preferred_action argument must only contain one of those values * set, otherwise it will result in a protocol error. * * While managing an "ask" action, the destination drag-and-drop * client may perform further wl_data_offer.receive requests, and * is expected to perform one last wl_data_offer.set_actions * request with a preferred action other than "ask" (and optionally * wl_data_offer.accept) before requesting wl_data_offer.finish, in * order to convey the action selected by the user. If the * preferred action is not in the wl_data_offer.source_actions * mask, an error will be raised. * * If the "ask" action is dismissed (e.g. user cancellation), the * client is expected to perform wl_data_offer.destroy right away. * * This request can only be made on drag-and-drop offers, a * protocol error will be raised otherwise. * @param dnd_actions actions supported by the destination client * @param preferred_action action preferred by the destination client * @since 3 */ void (*set_actions)(struct wl_client *client, struct wl_resource *resource, uint32_t dnd_actions, uint32_t preferred_action); }; #define WL_DATA_OFFER_OFFER 0 #define WL_DATA_OFFER_SOURCE_ACTIONS 1 #define WL_DATA_OFFER_ACTION 2 /** * @ingroup iface_wl_data_offer */ #define WL_DATA_OFFER_OFFER_SINCE_VERSION 1 /** * @ingroup iface_wl_data_offer */ #define WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION 3 /** * @ingroup iface_wl_data_offer */ #define WL_DATA_OFFER_ACTION_SINCE_VERSION 3 /** * @ingroup iface_wl_data_offer */ #define WL_DATA_OFFER_ACCEPT_SINCE_VERSION 1 /** * @ingroup iface_wl_data_offer */ #define WL_DATA_OFFER_RECEIVE_SINCE_VERSION 1 /** * @ingroup iface_wl_data_offer */ #define WL_DATA_OFFER_DESTROY_SINCE_VERSION 1 /** * @ingroup iface_wl_data_offer */ #define WL_DATA_OFFER_FINISH_SINCE_VERSION 3 /** * @ingroup iface_wl_data_offer */ #define WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION 3 /** * @ingroup iface_wl_data_offer * Sends an offer event to the client owning the resource. * @param resource_ The client's resource * @param mime_type offered mime type */ static inline void wl_data_offer_send_offer(struct wl_resource *resource_, const char *mime_type) { wl_resource_post_event(resource_, WL_DATA_OFFER_OFFER, mime_type); } /** * @ingroup iface_wl_data_offer * Sends an source_actions event to the client owning the resource. * @param resource_ The client's resource * @param source_actions actions offered by the data source */ static inline void wl_data_offer_send_source_actions(struct wl_resource *resource_, uint32_t source_actions) { wl_resource_post_event(resource_, WL_DATA_OFFER_SOURCE_ACTIONS, source_actions); } /** * @ingroup iface_wl_data_offer * Sends an action event to the client owning the resource. * @param resource_ The client's resource * @param dnd_action action selected by the compositor */ static inline void wl_data_offer_send_action(struct wl_resource *resource_, uint32_t dnd_action) { wl_resource_post_event(resource_, WL_DATA_OFFER_ACTION, dnd_action); } #ifndef WL_DATA_SOURCE_ERROR_ENUM #define WL_DATA_SOURCE_ERROR_ENUM enum wl_data_source_error { /** * action mask contains invalid values */ WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK = 0, /** * source doesn't accept this request */ WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1, }; /** * @ingroup iface_wl_data_source * Validate a wl_data_source error value. * * @return true on success, false on error. * @ref wl_data_source_error */ static inline bool wl_data_source_error_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK: return version >= 1; case WL_DATA_SOURCE_ERROR_INVALID_SOURCE: return version >= 1; default: return false; } } #endif /* WL_DATA_SOURCE_ERROR_ENUM */ /** * @ingroup iface_wl_data_source * @struct wl_data_source_interface */ struct wl_data_source_interface { /** * add an offered mime type * * This request adds a mime type to the set of mime types * advertised to targets. Can be called several times to offer * multiple types. * @param mime_type mime type offered by the data source */ void (*offer)(struct wl_client *client, struct wl_resource *resource, const char *mime_type); /** * destroy the data source * * Destroy the data source. */ void (*destroy)(struct wl_client *client, struct wl_resource *resource); /** * set the available drag-and-drop actions * * Sets the actions that the source side client supports for this * operation. This request may trigger wl_data_source.action and * wl_data_offer.action events if the compositor needs to change * the selected action. * * The dnd_actions argument must contain only values expressed in * the wl_data_device_manager.dnd_actions enum, otherwise it will * result in a protocol error. * * This request must be made once only, and can only be made on * sources used in drag-and-drop, so it must be performed before * wl_data_device.start_drag. Attempting to use the source other * than for drag-and-drop will raise a protocol error. * @param dnd_actions actions supported by the data source * @since 3 */ void (*set_actions)(struct wl_client *client, struct wl_resource *resource, uint32_t dnd_actions); }; #define WL_DATA_SOURCE_TARGET 0 #define WL_DATA_SOURCE_SEND 1 #define WL_DATA_SOURCE_CANCELLED 2 #define WL_DATA_SOURCE_DND_DROP_PERFORMED 3 #define WL_DATA_SOURCE_DND_FINISHED 4 #define WL_DATA_SOURCE_ACTION 5 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_TARGET_SINCE_VERSION 1 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_SEND_SINCE_VERSION 1 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_CANCELLED_SINCE_VERSION 1 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION 3 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION 3 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_ACTION_SINCE_VERSION 3 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_OFFER_SINCE_VERSION 1 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_DESTROY_SINCE_VERSION 1 /** * @ingroup iface_wl_data_source */ #define WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION 3 /** * @ingroup iface_wl_data_source * Sends an target event to the client owning the resource. * @param resource_ The client's resource * @param mime_type mime type accepted by the target */ static inline void wl_data_source_send_target(struct wl_resource *resource_, const char *mime_type) { wl_resource_post_event(resource_, WL_DATA_SOURCE_TARGET, mime_type); } /** * @ingroup iface_wl_data_source * Sends an send event to the client owning the resource. * @param resource_ The client's resource * @param mime_type mime type for the data * @param fd file descriptor for the data */ static inline void wl_data_source_send_send(struct wl_resource *resource_, const char *mime_type, int32_t fd) { wl_resource_post_event(resource_, WL_DATA_SOURCE_SEND, mime_type, fd); } /** * @ingroup iface_wl_data_source * Sends an cancelled event to the client owning the resource. * @param resource_ The client's resource */ static inline void wl_data_source_send_cancelled(struct wl_resource *resource_) { wl_resource_post_event(resource_, WL_DATA_SOURCE_CANCELLED); } /** * @ingroup iface_wl_data_source * Sends an dnd_drop_performed event to the client owning the resource. * @param resource_ The client's resource */ static inline void wl_data_source_send_dnd_drop_performed(struct wl_resource *resource_) { wl_resource_post_event(resource_, WL_DATA_SOURCE_DND_DROP_PERFORMED); } /** * @ingroup iface_wl_data_source * Sends an dnd_finished event to the client owning the resource. * @param resource_ The client's resource */ static inline void wl_data_source_send_dnd_finished(struct wl_resource *resource_) { wl_resource_post_event(resource_, WL_DATA_SOURCE_DND_FINISHED); } /** * @ingroup iface_wl_data_source * Sends an action event to the client owning the resource. * @param resource_ The client's resource * @param dnd_action action selected by the compositor */ static inline void wl_data_source_send_action(struct wl_resource *resource_, uint32_t dnd_action) { wl_resource_post_event(resource_, WL_DATA_SOURCE_ACTION, dnd_action); } #ifndef WL_DATA_DEVICE_ERROR_ENUM #define WL_DATA_DEVICE_ERROR_ENUM enum wl_data_device_error { /** * given wl_surface has another role */ WL_DATA_DEVICE_ERROR_ROLE = 0, }; /** * @ingroup iface_wl_data_device * Validate a wl_data_device error value. * * @return true on success, false on error. * @ref wl_data_device_error */ static inline bool wl_data_device_error_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_DATA_DEVICE_ERROR_ROLE: return version >= 1; default: return false; } } #endif /* WL_DATA_DEVICE_ERROR_ENUM */ /** * @ingroup iface_wl_data_device * @struct wl_data_device_interface */ struct wl_data_device_interface { /** * start drag-and-drop operation * * This request asks the compositor to start a drag-and-drop * operation on behalf of the client. * * The source argument is the data source that provides the data * for the eventual data transfer. If source is NULL, enter, leave * and motion events are sent only to the client that initiated the * drag and the client is expected to handle the data passing * internally. * * The origin surface is the surface where the drag originates and * the client must have an active implicit grab that matches the * serial. * * The icon surface is an optional (can be NULL) surface that * provides an icon to be moved around with the cursor. Initially, * the top-left corner of the icon surface is placed at the cursor * hotspot, but subsequent wl_surface.attach request can move the * relative position. Attach requests must be confirmed with * wl_surface.commit as usual. The icon surface is given the role * of a drag-and-drop icon. If the icon surface already has another * role, it raises a protocol error. * * The current and pending input regions of the icon wl_surface are * cleared, and wl_surface.set_input_region is ignored until the * wl_surface is no longer used as the icon surface. When the use * as an icon ends, the current and pending input regions become * undefined, and the wl_surface is unmapped. * @param source data source for the eventual transfer * @param origin surface where the drag originates * @param icon drag-and-drop icon surface * @param serial serial number of the implicit grab on the origin */ void (*start_drag)(struct wl_client *client, struct wl_resource *resource, struct wl_resource *source, struct wl_resource *origin, struct wl_resource *icon, uint32_t serial); /** * copy data to the selection * * This request asks the compositor to set the selection to the * data from the source on behalf of the client. * * To unset the selection, set the source to NULL. * @param source data source for the selection * @param serial serial number of the event that triggered this request */ void (*set_selection)(struct wl_client *client, struct wl_resource *resource, struct wl_resource *source, uint32_t serial); /** * destroy data device * * This request destroys the data device. * @since 2 */ void (*release)(struct wl_client *client, struct wl_resource *resource); }; #define WL_DATA_DEVICE_DATA_OFFER 0 #define WL_DATA_DEVICE_ENTER 1 #define WL_DATA_DEVICE_LEAVE 2 #define WL_DATA_DEVICE_MOTION 3 #define WL_DATA_DEVICE_DROP 4 #define WL_DATA_DEVICE_SELECTION 5 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_DATA_OFFER_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_ENTER_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_LEAVE_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_MOTION_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_DROP_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_SELECTION_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_START_DRAG_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_SET_SELECTION_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device */ #define WL_DATA_DEVICE_RELEASE_SINCE_VERSION 2 /** * @ingroup iface_wl_data_device * Sends an data_offer event to the client owning the resource. * @param resource_ The client's resource * @param id the new data_offer object */ static inline void wl_data_device_send_data_offer(struct wl_resource *resource_, struct wl_resource *id) { wl_resource_post_event(resource_, WL_DATA_DEVICE_DATA_OFFER, id); } /** * @ingroup iface_wl_data_device * Sends an enter event to the client owning the resource. * @param resource_ The client's resource * @param serial serial number of the enter event * @param surface client surface entered * @param x surface-local x coordinate * @param y surface-local y coordinate * @param id source data_offer object */ static inline void wl_data_device_send_enter(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface, wl_fixed_t x, wl_fixed_t y, struct wl_resource *id) { wl_resource_post_event(resource_, WL_DATA_DEVICE_ENTER, serial, surface, x, y, id); } /** * @ingroup iface_wl_data_device * Sends an leave event to the client owning the resource. * @param resource_ The client's resource */ static inline void wl_data_device_send_leave(struct wl_resource *resource_) { wl_resource_post_event(resource_, WL_DATA_DEVICE_LEAVE); } /** * @ingroup iface_wl_data_device * Sends an motion event to the client owning the resource. * @param resource_ The client's resource * @param time timestamp with millisecond granularity * @param x surface-local x coordinate * @param y surface-local y coordinate */ static inline void wl_data_device_send_motion(struct wl_resource *resource_, uint32_t time, wl_fixed_t x, wl_fixed_t y) { wl_resource_post_event(resource_, WL_DATA_DEVICE_MOTION, time, x, y); } /** * @ingroup iface_wl_data_device * Sends an drop event to the client owning the resource. * @param resource_ The client's resource */ static inline void wl_data_device_send_drop(struct wl_resource *resource_) { wl_resource_post_event(resource_, WL_DATA_DEVICE_DROP); } /** * @ingroup iface_wl_data_device * Sends an selection event to the client owning the resource. * @param resource_ The client's resource * @param id selection data_offer object */ static inline void wl_data_device_send_selection(struct wl_resource *resource_, struct wl_resource *id) { wl_resource_post_event(resource_, WL_DATA_DEVICE_SELECTION, id); } #ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM #define WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM /** * @ingroup iface_wl_data_device_manager * drag and drop actions * * This is a bitmask of the available/preferred actions in a * drag-and-drop operation. * * In the compositor, the selected action is a result of matching the * actions offered by the source and destination sides. "action" events * with a "none" action will be sent to both source and destination if * there is no match. All further checks will effectively happen on * (source actions ∩ destination actions). * * In addition, compositors may also pick different actions in * reaction to key modifiers being pressed. One common design that * is used in major toolkits (and the behavior recommended for * compositors) is: * * - If no modifiers are pressed, the first match (in bit order) * will be used. * - Pressing Shift selects "move", if enabled in the mask. * - Pressing Control selects "copy", if enabled in the mask. * * Behavior beyond that is considered implementation-dependent. * Compositors may for example bind other modifiers (like Alt/Meta) * or drags initiated with other buttons than BTN_LEFT to specific * actions (e.g. "ask"). */ enum wl_data_device_manager_dnd_action { /** * no action */ WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE = 0, /** * copy action */ WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY = 1, /** * move action */ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE = 2, /** * ask action */ WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4, }; /** * @ingroup iface_wl_data_device_manager * Validate a wl_data_device_manager dnd_action value. * * @return true on success, false on error. * @ref wl_data_device_manager_dnd_action */ static inline bool wl_data_device_manager_dnd_action_is_valid(uint32_t value, uint32_t version) { uint32_t valid = 0; if (version >= 1) valid |= WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; if (version >= 1) valid |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; if (version >= 1) valid |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE; if (version >= 1) valid |= WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK; return (value & ~valid) == 0; } #endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */ /** * @ingroup iface_wl_data_device_manager * @struct wl_data_device_manager_interface */ struct wl_data_device_manager_interface { /** * create a new data source * * Create a new data source. * @param id data source to create */ void (*create_data_source)(struct wl_client *client, struct wl_resource *resource, uint32_t id); /** * create a new data device * * Create a new data device for a given seat. * @param id data device to create * @param seat seat associated with the data device */ void (*get_data_device)(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *seat); }; /** * @ingroup iface_wl_data_device_manager */ #define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE_SINCE_VERSION 1 /** * @ingroup iface_wl_data_device_manager */ #define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE_SINCE_VERSION 1 #ifndef WL_SHELL_ERROR_ENUM #define WL_SHELL_ERROR_ENUM enum wl_shell_error { /** * given wl_surface has another role */ WL_SHELL_ERROR_ROLE = 0, }; /** * @ingroup iface_wl_shell * Validate a wl_shell error value. * * @return true on success, false on error. * @ref wl_shell_error */ static inline bool wl_shell_error_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_SHELL_ERROR_ROLE: return version >= 1; default: return false; } } #endif /* WL_SHELL_ERROR_ENUM */ /** * @ingroup iface_wl_shell * @struct wl_shell_interface */ struct wl_shell_interface { /** * create a shell surface from a surface * * Create a shell surface for an existing surface. This gives the * wl_surface the role of a shell surface. If the wl_surface * already has another role, it raises a protocol error. * * Only one shell surface can be associated with a given surface. * @param id shell surface to create * @param surface surface to be given the shell surface role */ void (*get_shell_surface)(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface); }; /** * @ingroup iface_wl_shell */ #define WL_SHELL_GET_SHELL_SURFACE_SINCE_VERSION 1 #ifndef WL_SHELL_SURFACE_RESIZE_ENUM #define WL_SHELL_SURFACE_RESIZE_ENUM /** * @ingroup iface_wl_shell_surface * edge values for resizing * * These values are used to indicate which edge of a surface * is being dragged in a resize operation. The server may * use this information to adapt its behavior, e.g. choose * an appropriate cursor image. */ enum wl_shell_surface_resize { /** * no edge */ WL_SHELL_SURFACE_RESIZE_NONE = 0, /** * top edge */ WL_SHELL_SURFACE_RESIZE_TOP = 1, /** * bottom edge */ WL_SHELL_SURFACE_RESIZE_BOTTOM = 2, /** * left edge */ WL_SHELL_SURFACE_RESIZE_LEFT = 4, /** * top and left edges */ WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5, /** * bottom and left edges */ WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6, /** * right edge */ WL_SHELL_SURFACE_RESIZE_RIGHT = 8, /** * top and right edges */ WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9, /** * bottom and right edges */ WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10, }; /** * @ingroup iface_wl_shell_surface * Validate a wl_shell_surface resize value. * * @return true on success, false on error. * @ref wl_shell_surface_resize */ static inline bool wl_shell_surface_resize_is_valid(uint32_t value, uint32_t version) { uint32_t valid = 0; if (version >= 1) valid |= WL_SHELL_SURFACE_RESIZE_NONE; if (version >= 1) valid |= WL_SHELL_SURFACE_RESIZE_TOP; if (version >= 1) valid |= WL_SHELL_SURFACE_RESIZE_BOTTOM; if (version >= 1) valid |= WL_SHELL_SURFACE_RESIZE_LEFT; if (version >= 1) valid |= WL_SHELL_SURFACE_RESIZE_TOP_LEFT; if (version >= 1) valid |= WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT; if (version >= 1) valid |= WL_SHELL_SURFACE_RESIZE_RIGHT; if (version >= 1) valid |= WL_SHELL_SURFACE_RESIZE_TOP_RIGHT; if (version >= 1) valid |= WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT; return (value & ~valid) == 0; } #endif /* WL_SHELL_SURFACE_RESIZE_ENUM */ #ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM #define WL_SHELL_SURFACE_TRANSIENT_ENUM /** * @ingroup iface_wl_shell_surface * details of transient behaviour * * These flags specify details of the expected behaviour * of transient surfaces. Used in the set_transient request. */ enum wl_shell_surface_transient { /** * do not set keyboard focus */ WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1, }; /** * @ingroup iface_wl_shell_surface * Validate a wl_shell_surface transient value. * * @return true on success, false on error. * @ref wl_shell_surface_transient */ static inline bool wl_shell_surface_transient_is_valid(uint32_t value, uint32_t version) { uint32_t valid = 0; if (version >= 1) valid |= WL_SHELL_SURFACE_TRANSIENT_INACTIVE; return (value & ~valid) == 0; } #endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */ #ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM #define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM /** * @ingroup iface_wl_shell_surface * different method to set the surface fullscreen * * Hints to indicate to the compositor how to deal with a conflict * between the dimensions of the surface and the dimensions of the * output. The compositor is free to ignore this parameter. */ enum wl_shell_surface_fullscreen_method { /** * no preference, apply default policy */ WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0, /** * scale, preserve the surface's aspect ratio and center on output */ WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1, /** * switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch */ WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2, /** * no upscaling, center on output and add black borders to compensate size mismatch */ WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3, }; /** * @ingroup iface_wl_shell_surface * Validate a wl_shell_surface fullscreen_method value. * * @return true on success, false on error. * @ref wl_shell_surface_fullscreen_method */ static inline bool wl_shell_surface_fullscreen_method_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT: return version >= 1; case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE: return version >= 1; case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER: return version >= 1; case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL: return version >= 1; default: return false; } } #endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */ /** * @ingroup iface_wl_shell_surface * @struct wl_shell_surface_interface */ struct wl_shell_surface_interface { /** * respond to a ping event * * A client must respond to a ping event with a pong request or * the client may be deemed unresponsive. * @param serial serial number of the ping event */ void (*pong)(struct wl_client *client, struct wl_resource *resource, uint32_t serial); /** * start an interactive move * * Start a pointer-driven move of the surface. * * This request must be used in response to a button press event. * The server may ignore move requests depending on the state of * the surface (e.g. fullscreen or maximized). * @param seat seat whose pointer is used * @param serial serial number of the implicit grab on the pointer */ void (*move)(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, uint32_t serial); /** * start an interactive resize * * Start a pointer-driven resizing of the surface. * * This request must be used in response to a button press event. * The server may ignore resize requests depending on the state of * the surface (e.g. fullscreen or maximized). * @param seat seat whose pointer is used * @param serial serial number of the implicit grab on the pointer * @param edges which edge or corner is being dragged */ void (*resize)(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, uint32_t serial, uint32_t edges); /** * make the surface a toplevel surface * * Map the surface as a toplevel surface. * * A toplevel surface is not fullscreen, maximized or transient. */ void (*set_toplevel)(struct wl_client *client, struct wl_resource *resource); /** * make the surface a transient surface * * Map the surface relative to an existing surface. * * The x and y arguments specify the location of the upper left * corner of the surface relative to the upper left corner of the * parent surface, in surface-local coordinates. * * The flags argument controls details of the transient behaviour. * @param parent parent surface * @param x surface-local x coordinate * @param y surface-local y coordinate * @param flags transient surface behavior */ void (*set_transient)(struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent, int32_t x, int32_t y, uint32_t flags); /** * make the surface a fullscreen surface * * Map the surface as a fullscreen surface. * * If an output parameter is given then the surface will be made * fullscreen on that output. If the client does not specify the * output then the compositor will apply its policy - usually * choosing the output on which the surface has the biggest surface * area. * * The client may specify a method to resolve a size conflict * between the output size and the surface size - this is provided * through the method parameter. * * The framerate parameter is used only when the method is set to * "driver", to indicate the preferred framerate. A value of 0 * indicates that the client does not care about framerate. The * framerate is specified in mHz, that is framerate of 60000 is * 60Hz. * * A method of "scale" or "driver" implies a scaling operation of * the surface, either via a direct scaling operation or a change * of the output mode. This will override any kind of output * scaling, so that mapping a surface with a buffer size equal to * the mode can fill the screen independent of buffer_scale. * * A method of "fill" means we don't scale up the buffer, however * any output scale is applied. This means that you may run into an * edge case where the application maps a buffer with the same size * of the output mode but buffer_scale 1 (thus making a surface * larger than the output). In this case it is allowed to downscale * the results to fit the screen. * * The compositor must reply to this request with a configure event * with the dimensions for the output on which the surface will be * made fullscreen. * @param method method for resolving size conflict * @param framerate framerate in mHz * @param output output on which the surface is to be fullscreen */ void (*set_fullscreen)(struct wl_client *client, struct wl_resource *resource, uint32_t method, uint32_t framerate, struct wl_resource *output); /** * make the surface a popup surface * * Map the surface as a popup. * * A popup surface is a transient surface with an added pointer * grab. * * An existing implicit grab will be changed to owner-events mode, * and the popup grab will continue after the implicit grab ends * (i.e. releasing the mouse button does not cause the popup to be * unmapped). * * The popup grab continues until the window is destroyed or a * mouse button is pressed in any other client's window. A click in * any of the client's surfaces is reported as normal, however, * clicks in other clients' surfaces will be discarded and trigger * the callback. * * The x and y arguments specify the location of the upper left * corner of the surface relative to the upper left corner of the * parent surface, in surface-local coordinates. * @param seat seat whose pointer is used * @param serial serial number of the implicit grab on the pointer * @param parent parent surface * @param x surface-local x coordinate * @param y surface-local y coordinate * @param flags transient surface behavior */ void (*set_popup)(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, uint32_t serial, struct wl_resource *parent, int32_t x, int32_t y, uint32_t flags); /** * make the surface a maximized surface * * Map the surface as a maximized surface. * * If an output parameter is given then the surface will be * maximized on that output. If the client does not specify the * output then the compositor will apply its policy - usually * choosing the output on which the surface has the biggest surface * area. * * The compositor will reply with a configure event telling the * expected new surface size. The operation is completed on the * next buffer attach to this surface. * * A maximized surface typically fills the entire output it is * bound to, except for desktop elements such as panels. This is * the main difference between a maximized shell surface and a * fullscreen shell surface. * * The details depend on the compositor implementation. * @param output output on which the surface is to be maximized */ void (*set_maximized)(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output); /** * set surface title * * Set a short title for the surface. * * This string may be used to identify the surface in a task bar, * window list, or other user interface elements provided by the * compositor. * * The string must be encoded in UTF-8. * @param title surface title */ void (*set_title)(struct wl_client *client, struct wl_resource *resource, const char *title); /** * set surface class * * Set a class for the surface. * * The surface class identifies the general class of applications * to which the surface belongs. A common convention is to use the * file name (or the full path if it is a non-standard location) of * the application's .desktop file as the class. * @param class_ surface class */ void (*set_class)(struct wl_client *client, struct wl_resource *resource, const char *class_); }; #define WL_SHELL_SURFACE_PING 0 #define WL_SHELL_SURFACE_CONFIGURE 1 #define WL_SHELL_SURFACE_POPUP_DONE 2 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_PING_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_CONFIGURE_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_POPUP_DONE_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_PONG_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_MOVE_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_RESIZE_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_SET_TOPLEVEL_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_SET_TRANSIENT_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_SET_FULLSCREEN_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_SET_POPUP_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_SET_MAXIMIZED_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_SET_TITLE_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface */ #define WL_SHELL_SURFACE_SET_CLASS_SINCE_VERSION 1 /** * @ingroup iface_wl_shell_surface * Sends an ping event to the client owning the resource. * @param resource_ The client's resource * @param serial serial number of the ping */ static inline void wl_shell_surface_send_ping(struct wl_resource *resource_, uint32_t serial) { wl_resource_post_event(resource_, WL_SHELL_SURFACE_PING, serial); } /** * @ingroup iface_wl_shell_surface * Sends an configure event to the client owning the resource. * @param resource_ The client's resource * @param edges how the surface was resized * @param width new width of the surface * @param height new height of the surface */ static inline void wl_shell_surface_send_configure(struct wl_resource *resource_, uint32_t edges, int32_t width, int32_t height) { wl_resource_post_event(resource_, WL_SHELL_SURFACE_CONFIGURE, edges, width, height); } /** * @ingroup iface_wl_shell_surface * Sends an popup_done event to the client owning the resource. * @param resource_ The client's resource */ static inline void wl_shell_surface_send_popup_done(struct wl_resource *resource_) { wl_resource_post_event(resource_, WL_SHELL_SURFACE_POPUP_DONE); } #ifndef WL_SURFACE_ERROR_ENUM #define WL_SURFACE_ERROR_ENUM /** * @ingroup iface_wl_surface * wl_surface error values * * These errors can be emitted in response to wl_surface requests. */ enum wl_surface_error { /** * buffer scale value is invalid */ WL_SURFACE_ERROR_INVALID_SCALE = 0, /** * buffer transform value is invalid */ WL_SURFACE_ERROR_INVALID_TRANSFORM = 1, }; /** * @ingroup iface_wl_surface * Validate a wl_surface error value. * * @return true on success, false on error. * @ref wl_surface_error */ static inline bool wl_surface_error_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_SURFACE_ERROR_INVALID_SCALE: return version >= 1; case WL_SURFACE_ERROR_INVALID_TRANSFORM: return version >= 1; default: return false; } } #endif /* WL_SURFACE_ERROR_ENUM */ /** * @ingroup iface_wl_surface * @struct wl_surface_interface */ struct wl_surface_interface { /** * delete surface * * Deletes the surface and invalidates its object ID. */ void (*destroy)(struct wl_client *client, struct wl_resource *resource); /** * set the surface contents * * Set a buffer as the content of this surface. * * The new size of the surface is calculated based on the buffer * size transformed by the inverse buffer_transform and the inverse * buffer_scale. This means that the supplied buffer must be an * integer multiple of the buffer_scale. * * The x and y arguments specify the location of the new pending * buffer's upper left corner, relative to the current buffer's * upper left corner, in surface-local coordinates. In other words, * the x and y, combined with the new surface size define in which * directions the surface's size changes. * * Surface contents are double-buffered state, see * wl_surface.commit. * * The initial surface contents are void; there is no content. * wl_surface.attach assigns the given wl_buffer as the pending * wl_buffer. wl_surface.commit makes the pending wl_buffer the new * surface contents, and the size of the surface becomes the size * calculated from the wl_buffer, as described above. After commit, * there is no pending buffer until the next attach. * * Committing a pending wl_buffer allows the compositor to read the * pixels in the wl_buffer. The compositor may access the pixels at * any time after the wl_surface.commit request. When the * compositor will not access the pixels anymore, it will send the * wl_buffer.release event. Only after receiving wl_buffer.release, * the client may reuse the wl_buffer. A wl_buffer that has been * attached and then replaced by another attach instead of * committed will not receive a release event, and is not used by * the compositor. * * Destroying the wl_buffer after wl_buffer.release does not change * the surface contents. However, if the client destroys the * wl_buffer before receiving the wl_buffer.release event, the * surface contents become undefined immediately. * * If wl_surface.attach is sent with a NULL wl_buffer, the * following wl_surface.commit will remove the surface content. * @param buffer buffer of surface contents * @param x surface-local x coordinate * @param y surface-local y coordinate */ void (*attach)(struct wl_client *client, struct wl_resource *resource, struct wl_resource *buffer, int32_t x, int32_t y); /** * mark part of the surface damaged * * This request is used to describe the regions where the pending * buffer is different from the current surface contents, and where * the surface therefore needs to be repainted. The compositor * ignores the parts of the damage that fall outside of the * surface. * * Damage is double-buffered state, see wl_surface.commit. * * The damage rectangle is specified in surface-local coordinates, * where x and y specify the upper left corner of the damage * rectangle. * * The initial value for pending damage is empty: no damage. * wl_surface.damage adds pending damage: the new pending damage is * the union of old pending damage and the given rectangle. * * wl_surface.commit assigns pending damage as the current damage, * and clears pending damage. The server will clear the current * damage as it repaints the surface. * * Alternatively, damage can be posted with * wl_surface.damage_buffer which uses buffer coordinates instead * of surface coordinates, and is probably the preferred and * intuitive way of doing this. * @param x surface-local x coordinate * @param y surface-local y coordinate * @param width width of damage rectangle * @param height height of damage rectangle */ void (*damage)(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height); /** * request a frame throttling hint * * Request a notification when it is a good time to start drawing * a new frame, by creating a frame callback. This is useful for * throttling redrawing operations, and driving animations. * * When a client is animating on a wl_surface, it can use the * 'frame' request to get notified when it is a good time to draw * and commit the next frame of animation. If the client commits an * update earlier than that, it is likely that some updates will * not make it to the display, and the client is wasting resources * by drawing too often. * * The frame request will take effect on the next * wl_surface.commit. The notification will only be posted for one * frame unless requested again. For a wl_surface, the * notifications are posted in the order the frame requests were * committed. * * The server must send the notifications so that a client will not * send excessive updates, while still allowing the highest * possible update rate for clients that wait for the reply before * drawing again. The server should give some time for the client * to draw and commit after sending the frame callback events to * let it hit the next output refresh. * * A server should avoid signaling the frame callbacks if the * surface is not visible in any way, e.g. the surface is * off-screen, or completely obscured by other opaque surfaces. * * The object returned by this request will be destroyed by the * compositor after the callback is fired and as such the client * must not attempt to use it after that point. * * The callback_data passed in the callback is the current time, in * milliseconds, with an undefined base. * @param callback callback object for the frame request */ void (*frame)(struct wl_client *client, struct wl_resource *resource, uint32_t callback); /** * set opaque region * * This request sets the region of the surface that contains * opaque content. * * The opaque region is an optimization hint for the compositor * that lets it optimize the redrawing of content behind opaque * regions. Setting an opaque region is not required for correct * behaviour, but marking transparent content as opaque will result * in repaint artifacts. * * The opaque region is specified in surface-local coordinates. * * The compositor ignores the parts of the opaque region that fall * outside of the surface. * * Opaque region is double-buffered state, see wl_surface.commit. * * wl_surface.set_opaque_region changes the pending opaque region. * wl_surface.commit copies the pending region to the current * region. Otherwise, the pending and current regions are never * changed. * * The initial value for an opaque region is empty. Setting the * pending opaque region has copy semantics, and the wl_region * object can be destroyed immediately. A NULL wl_region causes the * pending opaque region to be set to empty. * @param region opaque region of the surface */ void (*set_opaque_region)(struct wl_client *client, struct wl_resource *resource, struct wl_resource *region); /** * set input region * * This request sets the region of the surface that can receive * pointer and touch events. * * Input events happening outside of this region will try the next * surface in the server surface stack. The compositor ignores the * parts of the input region that fall outside of the surface. * * The input region is specified in surface-local coordinates. * * Input region is double-buffered state, see wl_surface.commit. * * wl_surface.set_input_region changes the pending input region. * wl_surface.commit copies the pending region to the current * region. Otherwise the pending and current regions are never * changed, except cursor and icon surfaces are special cases, see * wl_pointer.set_cursor and wl_data_device.start_drag. * * The initial value for an input region is infinite. That means * the whole surface will accept input. Setting the pending input * region has copy semantics, and the wl_region object can be * destroyed immediately. A NULL wl_region causes the input region * to be set to infinite. * @param region input region of the surface */ void (*set_input_region)(struct wl_client *client, struct wl_resource *resource, struct wl_resource *region); /** * commit pending surface state * * Surface state (input, opaque, and damage regions, attached * buffers, etc.) is double-buffered. Protocol requests modify the * pending state, as opposed to the current state in use by the * compositor. A commit request atomically applies all pending * state, replacing the current state. After commit, the new * pending state is as documented for each related request. * * On commit, a pending wl_buffer is applied first, and all other * state second. This means that all coordinates in double-buffered * state are relative to the new wl_buffer coming into use, except * for wl_surface.attach itself. If there is no pending wl_buffer, * the coordinates are relative to the current surface contents. * * All requests that need a commit to become effective are * documented to affect double-buffered state. * * Other interfaces may add further double-buffered surface state. */ void (*commit)(struct wl_client *client, struct wl_resource *resource); /** * sets the buffer transformation * * This request sets an optional transformation on how the * compositor interprets the contents of the buffer attached to the * surface. The accepted values for the transform parameter are the * values for wl_output.transform. * * Buffer transform is double-buffered state, see * wl_surface.commit. * * A newly created surface has its buffer transformation set to * normal. * * wl_surface.set_buffer_transform changes the pending buffer * transformation. wl_surface.commit copies the pending buffer * transformation to the current one. Otherwise, the pending and * current values are never changed. * * The purpose of this request is to allow clients to render * content according to the output transform, thus permitting the * compositor to use certain optimizations even if the display is * rotated. Using hardware overlays and scanning out a client * buffer for fullscreen surfaces are examples of such * optimizations. Those optimizations are highly dependent on the * compositor implementation, so the use of this request should be * considered on a case-by-case basis. * * Note that if the transform value includes 90 or 270 degree * rotation, the width of the buffer will become the surface height * and the height of the buffer will become the surface width. * * If transform is not one of the values from the * wl_output.transform enum the invalid_transform protocol error is * raised. * @param transform transform for interpreting buffer contents * @since 2 */ void (*set_buffer_transform)(struct wl_client *client, struct wl_resource *resource, int32_t transform); /** * sets the buffer scaling factor * * This request sets an optional scaling factor on how the * compositor interprets the contents of the buffer attached to the * window. * * Buffer scale is double-buffered state, see wl_surface.commit. * * A newly created surface has its buffer scale set to 1. * * wl_surface.set_buffer_scale changes the pending buffer scale. * wl_surface.commit copies the pending buffer scale to the current * one. Otherwise, the pending and current values are never * changed. * * The purpose of this request is to allow clients to supply higher * resolution buffer data for use on high resolution outputs. It is * intended that you pick the same buffer scale as the scale of the * output that the surface is displayed on. This means the * compositor can avoid scaling when rendering the surface on that * output. * * Note that if the scale is larger than 1, then you have to attach * a buffer that is larger (by a factor of scale in each dimension) * than the desired surface size. * * If scale is not positive the invalid_scale protocol error is * raised. * @param scale positive scale for interpreting buffer contents * @since 3 */ void (*set_buffer_scale)(struct wl_client *client, struct wl_resource *resource, int32_t scale); /** * mark part of the surface damaged using buffer coordinates * * This request is used to describe the regions where the pending * buffer is different from the current surface contents, and where * the surface therefore needs to be repainted. The compositor * ignores the parts of the damage that fall outside of the * surface. * * Damage is double-buffered state, see wl_surface.commit. * * The damage rectangle is specified in buffer coordinates, where x * and y specify the upper left corner of the damage rectangle. * * The initial value for pending damage is empty: no damage. * wl_surface.damage_buffer adds pending damage: the new pending * damage is the union of old pending damage and the given * rectangle. * * wl_surface.commit assigns pending damage as the current damage, * and clears pending damage. The server will clear the current * damage as it repaints the surface. * * This request differs from wl_surface.damage in only one way - it * takes damage in buffer coordinates instead of surface-local * coordinates. While this generally is more intuitive than surface * coordinates, it is especially desirable when using wp_viewport * or when a drawing library (like EGL) is unaware of buffer scale * and buffer transform. * * Note: Because buffer transformation changes and damage requests * may be interleaved in the protocol stream, it is impossible to * determine the actual mapping between surface and buffer damage * until wl_surface.commit time. Therefore, compositors wishing to * take both kinds of damage into account will have to accumulate * damage from the two requests separately and only transform from * one to the other after receiving the wl_surface.commit. * @param x buffer-local x coordinate * @param y buffer-local y coordinate * @param width width of damage rectangle * @param height height of damage rectangle * @since 4 */ void (*damage_buffer)(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height); }; #define WL_SURFACE_ENTER 0 #define WL_SURFACE_LEAVE 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_ENTER_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_LEAVE_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_DESTROY_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_ATTACH_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_DAMAGE_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_FRAME_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_SET_OPAQUE_REGION_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_SET_INPUT_REGION_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_COMMIT_SINCE_VERSION 1 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_SET_BUFFER_TRANSFORM_SINCE_VERSION 2 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION 3 /** * @ingroup iface_wl_surface */ #define WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION 4 /** * @ingroup iface_wl_surface * Sends an enter event to the client owning the resource. * @param resource_ The client's resource * @param output output entered by the surface */ static inline void wl_surface_send_enter(struct wl_resource *resource_, struct wl_resource *output) { wl_resource_post_event(resource_, WL_SURFACE_ENTER, output); } /** * @ingroup iface_wl_surface * Sends an leave event to the client owning the resource. * @param resource_ The client's resource * @param output output left by the surface */ static inline void wl_surface_send_leave(struct wl_resource *resource_, struct wl_resource *output) { wl_resource_post_event(resource_, WL_SURFACE_LEAVE, output); } #ifndef WL_SEAT_CAPABILITY_ENUM #define WL_SEAT_CAPABILITY_ENUM /** * @ingroup iface_wl_seat * seat capability bitmask * * This is a bitmask of capabilities this seat has; if a member is * set, then it is present on the seat. */ enum wl_seat_capability { /** * the seat has pointer devices */ WL_SEAT_CAPABILITY_POINTER = 1, /** * the seat has one or more keyboards */ WL_SEAT_CAPABILITY_KEYBOARD = 2, /** * the seat has touch devices */ WL_SEAT_CAPABILITY_TOUCH = 4, }; /** * @ingroup iface_wl_seat * Validate a wl_seat capability value. * * @return true on success, false on error. * @ref wl_seat_capability */ static inline bool wl_seat_capability_is_valid(uint32_t value, uint32_t version) { uint32_t valid = 0; if (version >= 1) valid |= WL_SEAT_CAPABILITY_POINTER; if (version >= 1) valid |= WL_SEAT_CAPABILITY_KEYBOARD; if (version >= 1) valid |= WL_SEAT_CAPABILITY_TOUCH; return (value & ~valid) == 0; } #endif /* WL_SEAT_CAPABILITY_ENUM */ /** * @ingroup iface_wl_seat * @struct wl_seat_interface */ struct wl_seat_interface { /** * return pointer object * * The ID provided will be initialized to the wl_pointer * interface for this seat. * * This request only takes effect if the seat has the pointer * capability, or has had the pointer capability in the past. It is * a protocol violation to issue this request on a seat that has * never had the pointer capability. * @param id seat pointer */ void (*get_pointer)(struct wl_client *client, struct wl_resource *resource, uint32_t id); /** * return keyboard object * * The ID provided will be initialized to the wl_keyboard * interface for this seat. * * This request only takes effect if the seat has the keyboard * capability, or has had the keyboard capability in the past. It * is a protocol violation to issue this request on a seat that has * never had the keyboard capability. * @param id seat keyboard */ void (*get_keyboard)(struct wl_client *client, struct wl_resource *resource, uint32_t id); /** * return touch object * * The ID provided will be initialized to the wl_touch interface * for this seat. * * This request only takes effect if the seat has the touch * capability, or has had the touch capability in the past. It is a * protocol violation to issue this request on a seat that has * never had the touch capability. * @param id seat touch interface */ void (*get_touch)(struct wl_client *client, struct wl_resource *resource, uint32_t id); /** * release the seat object * * Using this request a client can tell the server that it is not * going to use the seat object anymore. * @since 5 */ void (*release)(struct wl_client *client, struct wl_resource *resource); }; #define WL_SEAT_CAPABILITIES 0 #define WL_SEAT_NAME 1 /** * @ingroup iface_wl_seat */ #define WL_SEAT_CAPABILITIES_SINCE_VERSION 1 /** * @ingroup iface_wl_seat */ #define WL_SEAT_NAME_SINCE_VERSION 2 /** * @ingroup iface_wl_seat */ #define WL_SEAT_GET_POINTER_SINCE_VERSION 1 /** * @ingroup iface_wl_seat */ #define WL_SEAT_GET_KEYBOARD_SINCE_VERSION 1 /** * @ingroup iface_wl_seat */ #define WL_SEAT_GET_TOUCH_SINCE_VERSION 1 /** * @ingroup iface_wl_seat */ #define WL_SEAT_RELEASE_SINCE_VERSION 5 /** * @ingroup iface_wl_seat * Sends an capabilities event to the client owning the resource. * @param resource_ The client's resource * @param capabilities capabilities of the seat */ static inline void wl_seat_send_capabilities(struct wl_resource *resource_, uint32_t capabilities) { wl_resource_post_event(resource_, WL_SEAT_CAPABILITIES, capabilities); } /** * @ingroup iface_wl_seat * Sends an name event to the client owning the resource. * @param resource_ The client's resource * @param name seat identifier */ static inline void wl_seat_send_name(struct wl_resource *resource_, const char *name) { wl_resource_post_event(resource_, WL_SEAT_NAME, name); } #ifndef WL_POINTER_ERROR_ENUM #define WL_POINTER_ERROR_ENUM enum wl_pointer_error { /** * given wl_surface has another role */ WL_POINTER_ERROR_ROLE = 0, }; /** * @ingroup iface_wl_pointer * Validate a wl_pointer error value. * * @return true on success, false on error. * @ref wl_pointer_error */ static inline bool wl_pointer_error_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_POINTER_ERROR_ROLE: return version >= 1; default: return false; } } #endif /* WL_POINTER_ERROR_ENUM */ #ifndef WL_POINTER_BUTTON_STATE_ENUM #define WL_POINTER_BUTTON_STATE_ENUM /** * @ingroup iface_wl_pointer * physical button state * * Describes the physical state of a button that produced the button * event. */ enum wl_pointer_button_state { /** * the button is not pressed */ WL_POINTER_BUTTON_STATE_RELEASED = 0, /** * the button is pressed */ WL_POINTER_BUTTON_STATE_PRESSED = 1, }; /** * @ingroup iface_wl_pointer * Validate a wl_pointer button_state value. * * @return true on success, false on error. * @ref wl_pointer_button_state */ static inline bool wl_pointer_button_state_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_POINTER_BUTTON_STATE_RELEASED: return version >= 1; case WL_POINTER_BUTTON_STATE_PRESSED: return version >= 1; default: return false; } } #endif /* WL_POINTER_BUTTON_STATE_ENUM */ #ifndef WL_POINTER_AXIS_ENUM #define WL_POINTER_AXIS_ENUM /** * @ingroup iface_wl_pointer * axis types * * Describes the axis types of scroll events. */ enum wl_pointer_axis { /** * vertical axis */ WL_POINTER_AXIS_VERTICAL_SCROLL = 0, /** * horizontal axis */ WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1, }; /** * @ingroup iface_wl_pointer * Validate a wl_pointer axis value. * * @return true on success, false on error. * @ref wl_pointer_axis */ static inline bool wl_pointer_axis_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_POINTER_AXIS_VERTICAL_SCROLL: return version >= 1; case WL_POINTER_AXIS_HORIZONTAL_SCROLL: return version >= 1; default: return false; } } #endif /* WL_POINTER_AXIS_ENUM */ #ifndef WL_POINTER_AXIS_SOURCE_ENUM #define WL_POINTER_AXIS_SOURCE_ENUM /** * @ingroup iface_wl_pointer * axis source types * * Describes the source types for axis events. This indicates to the * client how an axis event was physically generated; a client may * adjust the user interface accordingly. For example, scroll events * from a "finger" source may be in a smooth coordinate space with * kinetic scrolling whereas a "wheel" source may be in discrete steps * of a number of lines. */ enum wl_pointer_axis_source { /** * a physical wheel rotation */ WL_POINTER_AXIS_SOURCE_WHEEL = 0, /** * finger on a touch surface */ WL_POINTER_AXIS_SOURCE_FINGER = 1, /** * continuous coordinate space * * A device generating events in a continuous coordinate space, * but using something other than a finger. One example for this * source is button-based scrolling where the vertical motion of a * device is converted to scroll events while a button is held * down. */ WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2, /** * a physical wheel tilt * * Indicates that the actual device is a wheel but the scroll * event is not caused by a rotation but a (usually sideways) tilt * of the wheel. * @since 6 */ WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3, }; /** * @ingroup iface_wl_pointer */ #define WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION 6 /** * @ingroup iface_wl_pointer * Validate a wl_pointer axis_source value. * * @return true on success, false on error. * @ref wl_pointer_axis_source */ static inline bool wl_pointer_axis_source_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_POINTER_AXIS_SOURCE_WHEEL: return version >= 1; case WL_POINTER_AXIS_SOURCE_FINGER: return version >= 1; case WL_POINTER_AXIS_SOURCE_CONTINUOUS: return version >= 1; case WL_POINTER_AXIS_SOURCE_WHEEL_TILT: return version >= 6; default: return false; } } #endif /* WL_POINTER_AXIS_SOURCE_ENUM */ /** * @ingroup iface_wl_pointer * @struct wl_pointer_interface */ struct wl_pointer_interface { /** * set the pointer surface * * Set the pointer surface, i.e., the surface that contains the * pointer image (cursor). This request gives the surface the role * of a cursor. If the surface already has another role, it raises * a protocol error. * * The cursor actually changes only if the pointer focus for this * device is one of the requesting client's surfaces or the surface * parameter is the current pointer surface. If there was a * previous surface set with this request it is replaced. If * surface is NULL, the pointer image is hidden. * * The parameters hotspot_x and hotspot_y define the position of * the pointer surface relative to the pointer location. Its * top-left corner is always at (x, y) - (hotspot_x, hotspot_y), * where (x, y) are the coordinates of the pointer location, in * surface-local coordinates. * * On surface.attach requests to the pointer surface, hotspot_x and * hotspot_y are decremented by the x and y parameters passed to * the request. Attach must be confirmed by wl_surface.commit as * usual. * * The hotspot can also be updated by passing the currently set * pointer surface to this request with new values for hotspot_x * and hotspot_y. * * The current and pending input regions of the wl_surface are * cleared, and wl_surface.set_input_region is ignored until the * wl_surface is no longer used as the cursor. When the use as a * cursor ends, the current and pending input regions become * undefined, and the wl_surface is unmapped. * @param serial serial number of the enter event * @param surface pointer surface * @param hotspot_x surface-local x coordinate * @param hotspot_y surface-local y coordinate */ void (*set_cursor)(struct wl_client *client, struct wl_resource *resource, uint32_t serial, struct wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y); /** * release the pointer object * * Using this request a client can tell the server that it is not * going to use the pointer object anymore. * * This request destroys the pointer proxy object, so clients must * not call wl_pointer_destroy() after using this request. * @since 3 */ void (*release)(struct wl_client *client, struct wl_resource *resource); }; #define WL_POINTER_ENTER 0 #define WL_POINTER_LEAVE 1 #define WL_POINTER_MOTION 2 #define WL_POINTER_BUTTON 3 #define WL_POINTER_AXIS 4 #define WL_POINTER_FRAME 5 #define WL_POINTER_AXIS_SOURCE 6 #define WL_POINTER_AXIS_STOP 7 #define WL_POINTER_AXIS_DISCRETE 8 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_ENTER_SINCE_VERSION 1 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_LEAVE_SINCE_VERSION 1 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_MOTION_SINCE_VERSION 1 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_BUTTON_SINCE_VERSION 1 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_AXIS_SINCE_VERSION 1 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_FRAME_SINCE_VERSION 5 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_AXIS_SOURCE_SINCE_VERSION 5 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_AXIS_STOP_SINCE_VERSION 5 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_AXIS_DISCRETE_SINCE_VERSION 5 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_SET_CURSOR_SINCE_VERSION 1 /** * @ingroup iface_wl_pointer */ #define WL_POINTER_RELEASE_SINCE_VERSION 3 /** * @ingroup iface_wl_pointer * Sends an enter event to the client owning the resource. * @param resource_ The client's resource * @param serial serial number of the enter event * @param surface surface entered by the pointer * @param surface_x surface-local x coordinate * @param surface_y surface-local y coordinate */ static inline void wl_pointer_send_enter(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { wl_resource_post_event(resource_, WL_POINTER_ENTER, serial, surface, surface_x, surface_y); } /** * @ingroup iface_wl_pointer * Sends an leave event to the client owning the resource. * @param resource_ The client's resource * @param serial serial number of the leave event * @param surface surface left by the pointer */ static inline void wl_pointer_send_leave(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface) { wl_resource_post_event(resource_, WL_POINTER_LEAVE, serial, surface); } /** * @ingroup iface_wl_pointer * Sends an motion event to the client owning the resource. * @param resource_ The client's resource * @param time timestamp with millisecond granularity * @param surface_x surface-local x coordinate * @param surface_y surface-local y coordinate */ static inline void wl_pointer_send_motion(struct wl_resource *resource_, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { wl_resource_post_event(resource_, WL_POINTER_MOTION, time, surface_x, surface_y); } /** * @ingroup iface_wl_pointer * Sends an button event to the client owning the resource. * @param resource_ The client's resource * @param serial serial number of the button event * @param time timestamp with millisecond granularity * @param button button that produced the event * @param state physical state of the button */ static inline void wl_pointer_send_button(struct wl_resource *resource_, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { wl_resource_post_event(resource_, WL_POINTER_BUTTON, serial, time, button, state); } /** * @ingroup iface_wl_pointer * Sends an axis event to the client owning the resource. * @param resource_ The client's resource * @param time timestamp with millisecond granularity * @param axis axis type * @param value length of vector in surface-local coordinate space */ static inline void wl_pointer_send_axis(struct wl_resource *resource_, uint32_t time, uint32_t axis, wl_fixed_t value) { wl_resource_post_event(resource_, WL_POINTER_AXIS, time, axis, value); } /** * @ingroup iface_wl_pointer * Sends an frame event to the client owning the resource. * @param resource_ The client's resource */ static inline void wl_pointer_send_frame(struct wl_resource *resource_) { wl_resource_post_event(resource_, WL_POINTER_FRAME); } /** * @ingroup iface_wl_pointer * Sends an axis_source event to the client owning the resource. * @param resource_ The client's resource * @param axis_source source of the axis event */ static inline void wl_pointer_send_axis_source(struct wl_resource *resource_, uint32_t axis_source) { wl_resource_post_event(resource_, WL_POINTER_AXIS_SOURCE, axis_source); } /** * @ingroup iface_wl_pointer * Sends an axis_stop event to the client owning the resource. * @param resource_ The client's resource * @param time timestamp with millisecond granularity * @param axis the axis stopped with this event */ static inline void wl_pointer_send_axis_stop(struct wl_resource *resource_, uint32_t time, uint32_t axis) { wl_resource_post_event(resource_, WL_POINTER_AXIS_STOP, time, axis); } /** * @ingroup iface_wl_pointer * Sends an axis_discrete event to the client owning the resource. * @param resource_ The client's resource * @param axis axis type * @param discrete number of steps */ static inline void wl_pointer_send_axis_discrete(struct wl_resource *resource_, uint32_t axis, int32_t discrete) { wl_resource_post_event(resource_, WL_POINTER_AXIS_DISCRETE, axis, discrete); } #ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM #define WL_KEYBOARD_KEYMAP_FORMAT_ENUM /** * @ingroup iface_wl_keyboard * keyboard mapping format * * This specifies the format of the keymap provided to the * client with the wl_keyboard.keymap event. */ enum wl_keyboard_keymap_format { /** * no keymap; client must understand how to interpret the raw keycode */ WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0, /** * libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode */ WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1, }; /** * @ingroup iface_wl_keyboard * Validate a wl_keyboard keymap_format value. * * @return true on success, false on error. * @ref wl_keyboard_keymap_format */ static inline bool wl_keyboard_keymap_format_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP: return version >= 1; case WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1: return version >= 1; default: return false; } } #endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */ #ifndef WL_KEYBOARD_KEY_STATE_ENUM #define WL_KEYBOARD_KEY_STATE_ENUM /** * @ingroup iface_wl_keyboard * physical key state * * Describes the physical state of a key that produced the key event. */ enum wl_keyboard_key_state { /** * key is not pressed */ WL_KEYBOARD_KEY_STATE_RELEASED = 0, /** * key is pressed */ WL_KEYBOARD_KEY_STATE_PRESSED = 1, }; /** * @ingroup iface_wl_keyboard * Validate a wl_keyboard key_state value. * * @return true on success, false on error. * @ref wl_keyboard_key_state */ static inline bool wl_keyboard_key_state_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_KEYBOARD_KEY_STATE_RELEASED: return version >= 1; case WL_KEYBOARD_KEY_STATE_PRESSED: return version >= 1; default: return false; } } #endif /* WL_KEYBOARD_KEY_STATE_ENUM */ /** * @ingroup iface_wl_keyboard * @struct wl_keyboard_interface */ struct wl_keyboard_interface { /** * release the keyboard object * * * @since 3 */ void (*release)(struct wl_client *client, struct wl_resource *resource); }; #define WL_KEYBOARD_KEYMAP 0 #define WL_KEYBOARD_ENTER 1 #define WL_KEYBOARD_LEAVE 2 #define WL_KEYBOARD_KEY 3 #define WL_KEYBOARD_MODIFIERS 4 #define WL_KEYBOARD_REPEAT_INFO 5 /** * @ingroup iface_wl_keyboard */ #define WL_KEYBOARD_KEYMAP_SINCE_VERSION 1 /** * @ingroup iface_wl_keyboard */ #define WL_KEYBOARD_ENTER_SINCE_VERSION 1 /** * @ingroup iface_wl_keyboard */ #define WL_KEYBOARD_LEAVE_SINCE_VERSION 1 /** * @ingroup iface_wl_keyboard */ #define WL_KEYBOARD_KEY_SINCE_VERSION 1 /** * @ingroup iface_wl_keyboard */ #define WL_KEYBOARD_MODIFIERS_SINCE_VERSION 1 /** * @ingroup iface_wl_keyboard */ #define WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION 4 /** * @ingroup iface_wl_keyboard */ #define WL_KEYBOARD_RELEASE_SINCE_VERSION 3 /** * @ingroup iface_wl_keyboard * Sends an keymap event to the client owning the resource. * @param resource_ The client's resource * @param format keymap format * @param fd keymap file descriptor * @param size keymap size, in bytes */ static inline void wl_keyboard_send_keymap(struct wl_resource *resource_, uint32_t format, int32_t fd, uint32_t size) { wl_resource_post_event(resource_, WL_KEYBOARD_KEYMAP, format, fd, size); } /** * @ingroup iface_wl_keyboard * Sends an enter event to the client owning the resource. * @param resource_ The client's resource * @param serial serial number of the enter event * @param surface surface gaining keyboard focus * @param keys the currently pressed keys */ static inline void wl_keyboard_send_enter(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface, struct wl_array *keys) { wl_resource_post_event(resource_, WL_KEYBOARD_ENTER, serial, surface, keys); } /** * @ingroup iface_wl_keyboard * Sends an leave event to the client owning the resource. * @param resource_ The client's resource * @param serial serial number of the leave event * @param surface surface that lost keyboard focus */ static inline void wl_keyboard_send_leave(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface) { wl_resource_post_event(resource_, WL_KEYBOARD_LEAVE, serial, surface); } /** * @ingroup iface_wl_keyboard * Sends an key event to the client owning the resource. * @param resource_ The client's resource * @param serial serial number of the key event * @param time timestamp with millisecond granularity * @param key key that produced the event * @param state physical state of the key */ static inline void wl_keyboard_send_key(struct wl_resource *resource_, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { wl_resource_post_event(resource_, WL_KEYBOARD_KEY, serial, time, key, state); } /** * @ingroup iface_wl_keyboard * Sends an modifiers event to the client owning the resource. * @param resource_ The client's resource * @param serial serial number of the modifiers event * @param mods_depressed depressed modifiers * @param mods_latched latched modifiers * @param mods_locked locked modifiers * @param group keyboard layout */ static inline void wl_keyboard_send_modifiers(struct wl_resource *resource_, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { wl_resource_post_event(resource_, WL_KEYBOARD_MODIFIERS, serial, mods_depressed, mods_latched, mods_locked, group); } /** * @ingroup iface_wl_keyboard * Sends an repeat_info event to the client owning the resource. * @param resource_ The client's resource * @param rate the rate of repeating keys in characters per second * @param delay delay in milliseconds since key down until repeating starts */ static inline void wl_keyboard_send_repeat_info(struct wl_resource *resource_, int32_t rate, int32_t delay) { wl_resource_post_event(resource_, WL_KEYBOARD_REPEAT_INFO, rate, delay); } /** * @ingroup iface_wl_touch * @struct wl_touch_interface */ struct wl_touch_interface { /** * release the touch object * * * @since 3 */ void (*release)(struct wl_client *client, struct wl_resource *resource); }; #define WL_TOUCH_DOWN 0 #define WL_TOUCH_UP 1 #define WL_TOUCH_MOTION 2 #define WL_TOUCH_FRAME 3 #define WL_TOUCH_CANCEL 4 #define WL_TOUCH_SHAPE 5 #define WL_TOUCH_ORIENTATION 6 /** * @ingroup iface_wl_touch */ #define WL_TOUCH_DOWN_SINCE_VERSION 1 /** * @ingroup iface_wl_touch */ #define WL_TOUCH_UP_SINCE_VERSION 1 /** * @ingroup iface_wl_touch */ #define WL_TOUCH_MOTION_SINCE_VERSION 1 /** * @ingroup iface_wl_touch */ #define WL_TOUCH_FRAME_SINCE_VERSION 1 /** * @ingroup iface_wl_touch */ #define WL_TOUCH_CANCEL_SINCE_VERSION 1 /** * @ingroup iface_wl_touch */ #define WL_TOUCH_SHAPE_SINCE_VERSION 6 /** * @ingroup iface_wl_touch */ #define WL_TOUCH_ORIENTATION_SINCE_VERSION 6 /** * @ingroup iface_wl_touch */ #define WL_TOUCH_RELEASE_SINCE_VERSION 3 /** * @ingroup iface_wl_touch * Sends an down event to the client owning the resource. * @param resource_ The client's resource * @param serial serial number of the touch down event * @param time timestamp with millisecond granularity * @param surface surface touched * @param id the unique ID of this touch point * @param x surface-local x coordinate * @param y surface-local y coordinate */ static inline void wl_touch_send_down(struct wl_resource *resource_, uint32_t serial, uint32_t time, struct wl_resource *surface, int32_t id, wl_fixed_t x, wl_fixed_t y) { wl_resource_post_event(resource_, WL_TOUCH_DOWN, serial, time, surface, id, x, y); } /** * @ingroup iface_wl_touch * Sends an up event to the client owning the resource. * @param resource_ The client's resource * @param serial serial number of the touch up event * @param time timestamp with millisecond granularity * @param id the unique ID of this touch point */ static inline void wl_touch_send_up(struct wl_resource *resource_, uint32_t serial, uint32_t time, int32_t id) { wl_resource_post_event(resource_, WL_TOUCH_UP, serial, time, id); } /** * @ingroup iface_wl_touch * Sends an motion event to the client owning the resource. * @param resource_ The client's resource * @param time timestamp with millisecond granularity * @param id the unique ID of this touch point * @param x surface-local x coordinate * @param y surface-local y coordinate */ static inline void wl_touch_send_motion(struct wl_resource *resource_, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) { wl_resource_post_event(resource_, WL_TOUCH_MOTION, time, id, x, y); } /** * @ingroup iface_wl_touch * Sends an frame event to the client owning the resource. * @param resource_ The client's resource */ static inline void wl_touch_send_frame(struct wl_resource *resource_) { wl_resource_post_event(resource_, WL_TOUCH_FRAME); } /** * @ingroup iface_wl_touch * Sends an cancel event to the client owning the resource. * @param resource_ The client's resource */ static inline void wl_touch_send_cancel(struct wl_resource *resource_) { wl_resource_post_event(resource_, WL_TOUCH_CANCEL); } /** * @ingroup iface_wl_touch * Sends an shape event to the client owning the resource. * @param resource_ The client's resource * @param id the unique ID of this touch point * @param major length of the major axis in surface-local coordinates * @param minor length of the minor axis in surface-local coordinates */ static inline void wl_touch_send_shape(struct wl_resource *resource_, int32_t id, wl_fixed_t major, wl_fixed_t minor) { wl_resource_post_event(resource_, WL_TOUCH_SHAPE, id, major, minor); } /** * @ingroup iface_wl_touch * Sends an orientation event to the client owning the resource. * @param resource_ The client's resource * @param id the unique ID of this touch point * @param orientation angle between major axis and positive surface y-axis in degrees */ static inline void wl_touch_send_orientation(struct wl_resource *resource_, int32_t id, wl_fixed_t orientation) { wl_resource_post_event(resource_, WL_TOUCH_ORIENTATION, id, orientation); } #ifndef WL_OUTPUT_SUBPIXEL_ENUM #define WL_OUTPUT_SUBPIXEL_ENUM /** * @ingroup iface_wl_output * subpixel geometry information * * This enumeration describes how the physical * pixels on an output are laid out. */ enum wl_output_subpixel { /** * unknown geometry */ WL_OUTPUT_SUBPIXEL_UNKNOWN = 0, /** * no geometry */ WL_OUTPUT_SUBPIXEL_NONE = 1, /** * horizontal RGB */ WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2, /** * horizontal BGR */ WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3, /** * vertical RGB */ WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4, /** * vertical BGR */ WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5, }; /** * @ingroup iface_wl_output * Validate a wl_output subpixel value. * * @return true on success, false on error. * @ref wl_output_subpixel */ static inline bool wl_output_subpixel_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_OUTPUT_SUBPIXEL_UNKNOWN: return version >= 1; case WL_OUTPUT_SUBPIXEL_NONE: return version >= 1; case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB: return version >= 1; case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR: return version >= 1; case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB: return version >= 1; case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR: return version >= 1; default: return false; } } #endif /* WL_OUTPUT_SUBPIXEL_ENUM */ #ifndef WL_OUTPUT_TRANSFORM_ENUM #define WL_OUTPUT_TRANSFORM_ENUM /** * @ingroup iface_wl_output * transform from framebuffer to output * * This describes the transform that a compositor will apply to a * surface to compensate for the rotation or mirroring of an * output device. * * The flipped values correspond to an initial flip around a * vertical axis followed by rotation. * * The purpose is mainly to allow clients to render accordingly and * tell the compositor, so that for fullscreen surfaces, the * compositor will still be able to scan out directly from client * surfaces. */ enum wl_output_transform { /** * no transform */ WL_OUTPUT_TRANSFORM_NORMAL = 0, /** * 90 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_90 = 1, /** * 180 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_180 = 2, /** * 270 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_270 = 3, /** * 180 degree flip around a vertical axis */ WL_OUTPUT_TRANSFORM_FLIPPED = 4, /** * flip and rotate 90 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5, /** * flip and rotate 180 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6, /** * flip and rotate 270 degrees counter-clockwise */ WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7, }; /** * @ingroup iface_wl_output * Validate a wl_output transform value. * * @return true on success, false on error. * @ref wl_output_transform */ static inline bool wl_output_transform_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_OUTPUT_TRANSFORM_NORMAL: return version >= 1; case WL_OUTPUT_TRANSFORM_90: return version >= 1; case WL_OUTPUT_TRANSFORM_180: return version >= 1; case WL_OUTPUT_TRANSFORM_270: return version >= 1; case WL_OUTPUT_TRANSFORM_FLIPPED: return version >= 1; case WL_OUTPUT_TRANSFORM_FLIPPED_90: return version >= 1; case WL_OUTPUT_TRANSFORM_FLIPPED_180: return version >= 1; case WL_OUTPUT_TRANSFORM_FLIPPED_270: return version >= 1; default: return false; } } #endif /* WL_OUTPUT_TRANSFORM_ENUM */ #ifndef WL_OUTPUT_MODE_ENUM #define WL_OUTPUT_MODE_ENUM /** * @ingroup iface_wl_output * mode information * * These flags describe properties of an output mode. * They are used in the flags bitfield of the mode event. */ enum wl_output_mode { /** * indicates this is the current mode */ WL_OUTPUT_MODE_CURRENT = 0x1, /** * indicates this is the preferred mode */ WL_OUTPUT_MODE_PREFERRED = 0x2, }; /** * @ingroup iface_wl_output * Validate a wl_output mode value. * * @return true on success, false on error. * @ref wl_output_mode */ static inline bool wl_output_mode_is_valid(uint32_t value, uint32_t version) { uint32_t valid = 0; if (version >= 1) valid |= WL_OUTPUT_MODE_CURRENT; if (version >= 1) valid |= WL_OUTPUT_MODE_PREFERRED; return (value & ~valid) == 0; } #endif /* WL_OUTPUT_MODE_ENUM */ /** * @ingroup iface_wl_output * @struct wl_output_interface */ struct wl_output_interface { /** * release the output object * * Using this request a client can tell the server that it is not * going to use the output object anymore. * @since 3 */ void (*release)(struct wl_client *client, struct wl_resource *resource); }; #define WL_OUTPUT_GEOMETRY 0 #define WL_OUTPUT_MODE 1 #define WL_OUTPUT_DONE 2 #define WL_OUTPUT_SCALE 3 /** * @ingroup iface_wl_output */ #define WL_OUTPUT_GEOMETRY_SINCE_VERSION 1 /** * @ingroup iface_wl_output */ #define WL_OUTPUT_MODE_SINCE_VERSION 1 /** * @ingroup iface_wl_output */ #define WL_OUTPUT_DONE_SINCE_VERSION 2 /** * @ingroup iface_wl_output */ #define WL_OUTPUT_SCALE_SINCE_VERSION 2 /** * @ingroup iface_wl_output */ #define WL_OUTPUT_RELEASE_SINCE_VERSION 3 /** * @ingroup iface_wl_output * Sends an geometry event to the client owning the resource. * @param resource_ The client's resource * @param x x position within the global compositor space * @param y y position within the global compositor space * @param physical_width width in millimeters of the output * @param physical_height height in millimeters of the output * @param subpixel subpixel orientation of the output * @param make textual description of the manufacturer * @param model textual description of the model * @param transform transform that maps framebuffer to output */ static inline void wl_output_send_geometry(struct wl_resource *resource_, 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 transform) { wl_resource_post_event(resource_, WL_OUTPUT_GEOMETRY, x, y, physical_width, physical_height, subpixel, make, model, transform); } /** * @ingroup iface_wl_output * Sends an mode event to the client owning the resource. * @param resource_ The client's resource * @param flags bitfield of mode flags * @param width width of the mode in hardware units * @param height height of the mode in hardware units * @param refresh vertical refresh rate in mHz */ static inline void wl_output_send_mode(struct wl_resource *resource_, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { wl_resource_post_event(resource_, WL_OUTPUT_MODE, flags, width, height, refresh); } /** * @ingroup iface_wl_output * Sends an done event to the client owning the resource. * @param resource_ The client's resource */ static inline void wl_output_send_done(struct wl_resource *resource_) { wl_resource_post_event(resource_, WL_OUTPUT_DONE); } /** * @ingroup iface_wl_output * Sends an scale event to the client owning the resource. * @param resource_ The client's resource * @param factor scaling factor of output */ static inline void wl_output_send_scale(struct wl_resource *resource_, int32_t factor) { wl_resource_post_event(resource_, WL_OUTPUT_SCALE, factor); } /** * @ingroup iface_wl_region * @struct wl_region_interface */ struct wl_region_interface { /** * destroy region * * Destroy the region. This will invalidate the object ID. */ void (*destroy)(struct wl_client *client, struct wl_resource *resource); /** * add rectangle to region * * Add the specified rectangle to the region. * @param x region-local x coordinate * @param y region-local y coordinate * @param width rectangle width * @param height rectangle height */ void (*add)(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height); /** * subtract rectangle from region * * Subtract the specified rectangle from the region. * @param x region-local x coordinate * @param y region-local y coordinate * @param width rectangle width * @param height rectangle height */ void (*subtract)(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height); }; /** * @ingroup iface_wl_region */ #define WL_REGION_DESTROY_SINCE_VERSION 1 /** * @ingroup iface_wl_region */ #define WL_REGION_ADD_SINCE_VERSION 1 /** * @ingroup iface_wl_region */ #define WL_REGION_SUBTRACT_SINCE_VERSION 1 #ifndef WL_SUBCOMPOSITOR_ERROR_ENUM #define WL_SUBCOMPOSITOR_ERROR_ENUM enum wl_subcompositor_error { /** * the to-be sub-surface is invalid */ WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0, }; /** * @ingroup iface_wl_subcompositor * Validate a wl_subcompositor error value. * * @return true on success, false on error. * @ref wl_subcompositor_error */ static inline bool wl_subcompositor_error_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE: return version >= 1; default: return false; } } #endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */ /** * @ingroup iface_wl_subcompositor * @struct wl_subcompositor_interface */ struct wl_subcompositor_interface { /** * unbind from the subcompositor interface * * Informs the server that the client will not be using this * protocol object anymore. This does not affect any other objects, * wl_subsurface objects included. */ void (*destroy)(struct wl_client *client, struct wl_resource *resource); /** * give a surface the role sub-surface * * Create a sub-surface interface for the given surface, and * associate it with the given parent surface. This turns a plain * wl_surface into a sub-surface. * * The to-be sub-surface must not already have another role, and it * must not have an existing wl_subsurface object. Otherwise a * protocol error is raised. * @param id the new sub-surface object ID * @param surface the surface to be turned into a sub-surface * @param parent the parent surface */ void (*get_subsurface)(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface, struct wl_resource *parent); }; /** * @ingroup iface_wl_subcompositor */ #define WL_SUBCOMPOSITOR_DESTROY_SINCE_VERSION 1 /** * @ingroup iface_wl_subcompositor */ #define WL_SUBCOMPOSITOR_GET_SUBSURFACE_SINCE_VERSION 1 #ifndef WL_SUBSURFACE_ERROR_ENUM #define WL_SUBSURFACE_ERROR_ENUM enum wl_subsurface_error { /** * wl_surface is not a sibling or the parent */ WL_SUBSURFACE_ERROR_BAD_SURFACE = 0, }; /** * @ingroup iface_wl_subsurface * Validate a wl_subsurface error value. * * @return true on success, false on error. * @ref wl_subsurface_error */ static inline bool wl_subsurface_error_is_valid(uint32_t value, uint32_t version) { switch (value) { case WL_SUBSURFACE_ERROR_BAD_SURFACE: return version >= 1; default: return false; } } #endif /* WL_SUBSURFACE_ERROR_ENUM */ /** * @ingroup iface_wl_subsurface * @struct wl_subsurface_interface */ struct wl_subsurface_interface { /** * remove sub-surface interface * * The sub-surface interface is removed from the wl_surface * object that was turned into a sub-surface with a * wl_subcompositor.get_subsurface request. The wl_surface's * association to the parent is deleted, and the wl_surface loses * its role as a sub-surface. The wl_surface is unmapped. */ void (*destroy)(struct wl_client *client, struct wl_resource *resource); /** * reposition the sub-surface * * This schedules a sub-surface position change. The sub-surface * will be moved so that its origin (top left corner pixel) will be * at the location x, y of the parent surface coordinate system. * The coordinates are not restricted to the parent surface area. * Negative values are allowed. * * The scheduled coordinates will take effect whenever the state of * the parent surface is applied. When this happens depends on * whether the parent surface is in synchronized mode or not. See * wl_subsurface.set_sync and wl_subsurface.set_desync for details. * * If more than one set_position request is invoked by the client * before the commit of the parent surface, the position of a new * request always replaces the scheduled position from any previous * request. * * The initial position is 0, 0. * @param x x coordinate in the parent surface * @param y y coordinate in the parent surface */ void (*set_position)(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y); /** * restack the sub-surface * * This sub-surface is taken from the stack, and put back just * above the reference surface, changing the z-order of the * sub-surfaces. The reference surface must be one of the sibling * surfaces, or the parent surface. Using any other surface, * including this sub-surface, will cause a protocol error. * * The z-order is double-buffered. Requests are handled in order * and applied immediately to a pending state. The final pending * state is copied to the active state the next time the state of * the parent surface is applied. When this happens depends on * whether the parent surface is in synchronized mode or not. See * wl_subsurface.set_sync and wl_subsurface.set_desync for details. * * A new sub-surface is initially added as the top-most in the * stack of its siblings and parent. * @param sibling the reference surface */ void (*place_above)(struct wl_client *client, struct wl_resource *resource, struct wl_resource *sibling); /** * restack the sub-surface * * The sub-surface is placed just below the reference surface. * See wl_subsurface.place_above. * @param sibling the reference surface */ void (*place_below)(struct wl_client *client, struct wl_resource *resource, struct wl_resource *sibling); /** * set sub-surface to synchronized mode * * Change the commit behaviour of the sub-surface to synchronized * mode, also described as the parent dependent mode. * * In synchronized mode, wl_surface.commit on a sub-surface will * accumulate the committed state in a cache, but the state will * not be applied and hence will not change the compositor output. * The cached state is applied to the sub-surface immediately after * the parent surface's state is applied. This ensures atomic * updates of the parent and all its synchronized sub-surfaces. * Applying the cached state will invalidate the cache, so further * parent surface commits do not (re-)apply old state. * * See wl_subsurface for the recursive effect of this mode. */ void (*set_sync)(struct wl_client *client, struct wl_resource *resource); /** * set sub-surface to desynchronized mode * * Change the commit behaviour of the sub-surface to * desynchronized mode, also described as independent or freely * running mode. * * In desynchronized mode, wl_surface.commit on a sub-surface will * apply the pending state directly, without caching, as happens * normally with a wl_surface. Calling wl_surface.commit on the * parent surface has no effect on the sub-surface's wl_surface * state. This mode allows a sub-surface to be updated on its own. * * If cached state exists when wl_surface.commit is called in * desynchronized mode, the pending state is added to the cached * state, and applied as a whole. This invalidates the cache. * * Note: even if a sub-surface is set to desynchronized, a parent * sub-surface may override it to behave as synchronized. For * details, see wl_subsurface. * * If a surface's parent surface behaves as desynchronized, then * the cached state is applied on set_desync. */ void (*set_desync)(struct wl_client *client, struct wl_resource *resource); }; /** * @ingroup iface_wl_subsurface */ #define WL_SUBSURFACE_DESTROY_SINCE_VERSION 1 /** * @ingroup iface_wl_subsurface */ #define WL_SUBSURFACE_SET_POSITION_SINCE_VERSION 1 /** * @ingroup iface_wl_subsurface */ #define WL_SUBSURFACE_PLACE_ABOVE_SINCE_VERSION 1 /** * @ingroup iface_wl_subsurface */ #define WL_SUBSURFACE_PLACE_BELOW_SINCE_VERSION 1 /** * @ingroup iface_wl_subsurface */ #define WL_SUBSURFACE_SET_SYNC_SINCE_VERSION 1 /** * @ingroup iface_wl_subsurface */ #define WL_SUBSURFACE_SET_DESYNC_SINCE_VERSION 1 #ifdef __cplusplus } #endif #endif wayland-1.23.1/tests/data/example.xml000066400000000000000000003626461466237767300175330ustar00rootroot00000000000000 Copyright © 2008-2011 Kristian Høgsberg Copyright © 2010-2011 Intel Corporation Copyright © 2012-2013 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. The core global object. This is a special singleton object. It is used for internal Wayland protocol features. The sync request asks the server to emit the 'done' event on the returned wl_callback object. Since requests are handled in-order and events are delivered in-order, this can be used as a barrier to ensure all previous requests and the resulting events have been handled. The object returned by this request will be destroyed by the compositor after the callback is fired and as such the client must not attempt to use it after that point. The callback_data passed in the callback is the event serial. This request creates a registry object that allows the client to list and bind the global objects available from the compositor. The error event is sent out when a fatal (non-recoverable) error has occurred. The object_id argument is the object where the error occurred, most often in response to a request to that object. The code identifies the error and is defined by the object interface. As such, each interface defines its own set of error codes. The message is a brief description of the error, for (debugging) convenience. These errors are global and can be emitted in response to any server request. This event is used internally by the object ID management logic. When a client deletes an object, the server will send this event to acknowledge that it has seen the delete request. When the client receives this event, it will know that it can safely reuse the object ID. The singleton global registry object. The server has a number of global objects that are available to all clients. These objects typically represent an actual object in the server (for example, an input device) or they are singleton objects that provide extension functionality. When a client creates a registry object, the registry object will emit a global event for each global currently in the registry. Globals come and go as a result of device or monitor hotplugs, reconfiguration or other events, and the registry will send out global and global_remove events to keep the client up to date with the changes. To mark the end of the initial burst of events, the client can use the wl_display.sync request immediately after calling wl_display.get_registry. A client can bind to a global object by using the bind request. This creates a client-side handle that lets the object emit events to the client and lets the client invoke requests on the object. Binds a new, client-created object to the server using the specified name as the identifier. Notify the client of global objects. The event notifies the client that a global object with the given name is now available, and it implements the given version of the given interface. Notify the client of removed global objects. This event notifies the client that the global identified by name is no longer available. If the client bound to the global using the bind request, the client should now destroy that object. The object remains valid and requests to the object will be ignored until the client destroys it, to avoid races between the global going away and a client sending a request to it. Clients can handle the 'done' event to get notified when the related request is done. Notify the client when the related request is done. A compositor. This object is a singleton global. The compositor is in charge of combining the contents of multiple surfaces into one displayable output. Ask the compositor to create a new surface. Ask the compositor to create a new region. The wl_shm_pool object encapsulates a piece of memory shared between the compositor and client. Through the wl_shm_pool object, the client can allocate shared memory wl_buffer objects. All objects created through the same pool share the same underlying mapped memory. Reusing the mapped memory avoids the setup/teardown overhead and is useful when interactively resizing a surface or for many small buffers. Create a wl_buffer object from the pool. The buffer is created offset bytes into the pool and has width and height as specified. The stride argument specifies the number of bytes from the beginning of one row to the beginning of the next. The format is the pixel format of the buffer and must be one of those advertised through the wl_shm.format event. A buffer will keep a reference to the pool it was created from so it is valid to destroy the pool immediately after creating a buffer from it. Destroy the shared memory pool. The mmapped memory will be released when all buffers that have been created from this pool are gone. This request will cause the server to remap the backing memory for the pool from the file descriptor passed when the pool was created, but using the new size. This request can only be used to make the pool bigger. A singleton global object that provides support for shared memory. Clients can create wl_shm_pool objects using the create_pool request. At connection setup time, the wl_shm object emits one or more format events to inform clients about the valid pixel formats that can be used for buffers. These errors can be emitted in response to wl_shm requests. This describes the memory layout of an individual pixel. All renderers should support argb8888 and xrgb8888 but any other formats are optional and may not be supported by the particular renderer in use. The drm format codes match the macros defined in drm_fourcc.h. The formats actually supported by the compositor will be reported by the format event. Create a new wl_shm_pool object. The pool can be used to create shared memory based buffer objects. The server will mmap size bytes of the passed file descriptor, to use as backing memory for the pool. Informs the client about a valid pixel format that can be used for buffers. Known formats include argb8888 and xrgb8888. A buffer provides the content for a wl_surface. Buffers are created through factory interfaces such as wl_drm, wl_shm or similar. It has a width and a height and can be attached to a wl_surface, but the mechanism by which a client provides and updates the contents is defined by the buffer factory interface. Destroy a buffer. If and how you need to release the backing storage is defined by the buffer factory interface. For possible side-effects to a surface, see wl_surface.attach. Sent when this wl_buffer is no longer used by the compositor. The client is now free to reuse or destroy this buffer and its backing storage. If a client receives a release event before the frame callback requested in the same wl_surface.commit that attaches this wl_buffer to a surface, then the client is immediately free to reuse the buffer and its backing storage, and does not need a second buffer for the next surface content update. Typically this is possible, when the compositor maintains a copy of the wl_surface contents, e.g. as a GL texture. This is an important optimization for GL(ES) compositors with wl_shm clients. A wl_data_offer represents a piece of data offered for transfer by another client (the source client). It is used by the copy-and-paste and drag-and-drop mechanisms. The offer describes the different mime types that the data can be converted to and provides the mechanism for transferring the data directly from the source client. Indicate that the client can accept the given mime type, or NULL for not accepted. For objects of version 2 or older, this request is used by the client to give feedback whether the client can receive the given mime type, or NULL if none is accepted; the feedback does not determine whether the drag-and-drop operation succeeds or not. For objects of version 3 or newer, this request determines the final result of the drag-and-drop operation. If the end result is that no mime types were accepted, the drag-and-drop operation will be cancelled and the corresponding drag source will receive wl_data_source.cancelled. Clients may still use this event in conjunction with wl_data_source.action for feedback. To transfer the offered data, the client issues this request and indicates the mime type it wants to receive. The transfer happens through the passed file descriptor (typically created with the pipe system call). The source client writes the data in the mime type representation requested and then closes the file descriptor. The receiving client reads from the read end of the pipe until EOF and then closes its end, at which point the transfer is complete. This request may happen multiple times for different mime types, both before and after wl_data_device.drop. Drag-and-drop destination clients may preemptively fetch data or examine it more closely to determine acceptance. Destroy the data offer. Sent immediately after creating the wl_data_offer object. One event per offered mime type. Notifies the compositor that the drag destination successfully finished the drag-and-drop operation. Upon receiving this request, the compositor will emit wl_data_source.dnd_finished on the drag source client. It is a client error to perform other requests than wl_data_offer.destroy after this one. It is also an error to perform this request after a NULL mime type has been set in wl_data_offer.accept or no action was received through wl_data_offer.action. Sets the actions that the destination side client supports for this operation. This request may trigger the emission of wl_data_source.action and wl_data_offer.action events if the compositor needs to change the selected action. This request can be called multiple times throughout the drag-and-drop operation, typically in response to wl_data_device.enter or wl_data_device.motion events. This request determines the final result of the drag-and-drop operation. If the end result is that no action is accepted, the drag source will receive wl_drag_source.cancelled. The dnd_actions argument must contain only values expressed in the wl_data_device_manager.dnd_actions enum, and the preferred_action argument must only contain one of those values set, otherwise it will result in a protocol error. While managing an "ask" action, the destination drag-and-drop client may perform further wl_data_offer.receive requests, and is expected to perform one last wl_data_offer.set_actions request with a preferred action other than "ask" (and optionally wl_data_offer.accept) before requesting wl_data_offer.finish, in order to convey the action selected by the user. If the preferred action is not in the wl_data_offer.source_actions mask, an error will be raised. If the "ask" action is dismissed (e.g. user cancellation), the client is expected to perform wl_data_offer.destroy right away. This request can only be made on drag-and-drop offers, a protocol error will be raised otherwise. This event indicates the actions offered by the data source. It will be sent right after wl_data_device.enter, or anytime the source side changes its offered actions through wl_data_source.set_actions. This event indicates the action selected by the compositor after matching the source/destination side actions. Only one action (or none) will be offered here. This event can be emitted multiple times during the drag-and-drop operation in response to destination side action changes through wl_data_offer.set_actions. This event will no longer be emitted after wl_data_device.drop happened on the drag-and-drop destination, the client must honor the last action received, or the last preferred one set through wl_data_offer.set_actions when handling an "ask" action. Compositors may also change the selected action on the fly, mainly in response to keyboard modifier changes during the drag-and-drop operation. The most recent action received is always the valid one. Prior to receiving wl_data_device.drop, the chosen action may change (e.g. due to keyboard modifiers being pressed). At the time of receiving wl_data_device.drop the drag-and-drop destination must honor the last action received. Action changes may still happen after wl_data_device.drop, especially on "ask" actions, where the drag-and-drop destination may choose another action afterwards. Action changes happening at this stage are always the result of inter-client negotiation, the compositor shall no longer be able to induce a different action. Upon "ask" actions, it is expected that the drag-and-drop destination may potentially choose a different action and/or mime type, based on wl_data_offer.source_actions and finally chosen by the user (e.g. popping up a menu with the available options). The final wl_data_offer.set_actions and wl_data_offer.accept requests must happen before the call to wl_data_offer.finish. The wl_data_source object is the source side of a wl_data_offer. It is created by the source client in a data transfer and provides a way to describe the offered data and a way to respond to requests to transfer the data. This request adds a mime type to the set of mime types advertised to targets. Can be called several times to offer multiple types. Destroy the data source. Sent when a target accepts pointer_focus or motion events. If a target does not accept any of the offered types, type is NULL. Used for feedback during drag-and-drop. Request for data from the client. Send the data as the specified mime type over the passed file descriptor, then close it. This data source is no longer valid. There are several reasons why this could happen: - The data source has been replaced by another data source. - The drag-and-drop operation was performed, but the drop destination did not accept any of the mime types offered through wl_data_source.target. - The drag-and-drop operation was performed, but the drop destination did not select any of the actions present in the mask offered through wl_data_source.action. - The drag-and-drop operation was performed but didn't happen over a surface. - The compositor cancelled the drag-and-drop operation (e.g. compositor dependent timeouts to avoid stale drag-and-drop transfers). The client should clean up and destroy this data source. For objects of version 2 or older, wl_data_source.cancelled will only be emitted if the data source was replaced by another data source. Sets the actions that the source side client supports for this operation. This request may trigger wl_data_source.action and wl_data_offer.action events if the compositor needs to change the selected action. The dnd_actions argument must contain only values expressed in the wl_data_device_manager.dnd_actions enum, otherwise it will result in a protocol error. This request must be made once only, and can only be made on sources used in drag-and-drop, so it must be performed before wl_data_device.start_drag. Attempting to use the source other than for drag-and-drop will raise a protocol error. The user performed the drop action. This event does not indicate acceptance, wl_data_source.cancelled may still be emitted afterwards if the drop destination does not accept any mime type. However, this event might however not be received if the compositor cancelled the drag-and-drop operation before this event could happen. Note that the data_source may still be used in the future and should not be destroyed here. The drop destination finished interoperating with this data source, so the client is now free to destroy this data source and free all associated data. If the action used to perform the operation was "move", the source can now delete the transferred data. This event indicates the action selected by the compositor after matching the source/destination side actions. Only one action (or none) will be offered here. This event can be emitted multiple times during the drag-and-drop operation, mainly in response to destination side changes through wl_data_offer.set_actions, and as the data device enters/leaves surfaces. It is only possible to receive this event after wl_data_source.dnd_drop_performed if the drag-and-drop operation ended in an "ask" action, in which case the final wl_data_source.action event will happen immediately before wl_data_source.dnd_finished. Compositors may also change the selected action on the fly, mainly in response to keyboard modifier changes during the drag-and-drop operation. The most recent action received is always the valid one. The chosen action may change alongside negotiation (e.g. an "ask" action can turn into a "move" operation), so the effects of the final action must always be applied in wl_data_offer.dnd_finished. Clients can trigger cursor surface changes from this point, so they reflect the current action. There is one wl_data_device per seat which can be obtained from the global wl_data_device_manager singleton. A wl_data_device provides access to inter-client data transfer mechanisms such as copy-and-paste and drag-and-drop. This request asks the compositor to start a drag-and-drop operation on behalf of the client. The source argument is the data source that provides the data for the eventual data transfer. If source is NULL, enter, leave and motion events are sent only to the client that initiated the drag and the client is expected to handle the data passing internally. The origin surface is the surface where the drag originates and the client must have an active implicit grab that matches the serial. The icon surface is an optional (can be NULL) surface that provides an icon to be moved around with the cursor. Initially, the top-left corner of the icon surface is placed at the cursor hotspot, but subsequent wl_surface.attach request can move the relative position. Attach requests must be confirmed with wl_surface.commit as usual. The icon surface is given the role of a drag-and-drop icon. If the icon surface already has another role, it raises a protocol error. The current and pending input regions of the icon wl_surface are cleared, and wl_surface.set_input_region is ignored until the wl_surface is no longer used as the icon surface. When the use as an icon ends, the current and pending input regions become undefined, and the wl_surface is unmapped. This request asks the compositor to set the selection to the data from the source on behalf of the client. To unset the selection, set the source to NULL. The data_offer event introduces a new wl_data_offer object, which will subsequently be used in either the data_device.enter event (for drag-and-drop) or the data_device.selection event (for selections). Immediately following the data_device.data_offer event, the new data_offer object will send out data_offer.offer events to describe the mime types it offers. This event is sent when an active drag-and-drop pointer enters a surface owned by the client. The position of the pointer at enter time is provided by the x and y arguments, in surface-local coordinates. This event is sent when the drag-and-drop pointer leaves the surface and the session ends. The client must destroy the wl_data_offer introduced at enter time at this point. This event is sent when the drag-and-drop pointer moves within the currently focused surface. The new position of the pointer is provided by the x and y arguments, in surface-local coordinates. The event is sent when a drag-and-drop operation is ended because the implicit grab is removed. The drag-and-drop destination is expected to honor the last action received through wl_data_offer.action, if the resulting action is "copy" or "move", the destination can still perform wl_data_offer.receive requests, and is expected to end all transfers with a wl_data_offer.finish request. If the resulting action is "ask", the action will not be considered final. The drag-and-drop destination is expected to perform one last wl_data_offer.set_actions request, or wl_data_offer.destroy in order to cancel the operation. The selection event is sent out to notify the client of a new wl_data_offer for the selection for this device. The data_device.data_offer and the data_offer.offer events are sent out immediately before this event to introduce the data offer object. The selection event is sent to a client immediately before receiving keyboard focus and when a new selection is set while the client has keyboard focus. The data_offer is valid until a new data_offer or NULL is received or until the client loses keyboard focus. The client must destroy the previous selection data_offer, if any, upon receiving this event. This request destroys the data device. The wl_data_device_manager is a singleton global object that provides access to inter-client data transfer mechanisms such as copy-and-paste and drag-and-drop. These mechanisms are tied to a wl_seat and this interface lets a client get a wl_data_device corresponding to a wl_seat. Depending on the version bound, the objects created from the bound wl_data_device_manager object will have different requirements for functioning properly. See wl_data_source.set_actions, wl_data_offer.accept and wl_data_offer.finish for details. Create a new data source. Create a new data device for a given seat. This is a bitmask of the available/preferred actions in a drag-and-drop operation. In the compositor, the selected action is a result of matching the actions offered by the source and destination sides. "action" events with a "none" action will be sent to both source and destination if there is no match. All further checks will effectively happen on (source actions ∩ destination actions). In addition, compositors may also pick different actions in reaction to key modifiers being pressed. One common design that is used in major toolkits (and the behavior recommended for compositors) is: - If no modifiers are pressed, the first match (in bit order) will be used. - Pressing Shift selects "move", if enabled in the mask. - Pressing Control selects "copy", if enabled in the mask. Behavior beyond that is considered implementation-dependent. Compositors may for example bind other modifiers (like Alt/Meta) or drags initiated with other buttons than BTN_LEFT to specific actions (e.g. "ask"). This interface is implemented by servers that provide desktop-style user interfaces. It allows clients to associate a wl_shell_surface with a basic surface. Create a shell surface for an existing surface. This gives the wl_surface the role of a shell surface. If the wl_surface already has another role, it raises a protocol error. Only one shell surface can be associated with a given surface. An interface that may be implemented by a wl_surface, for implementations that provide a desktop-style user interface. It provides requests to treat surfaces like toplevel, fullscreen or popup windows, move, resize or maximize them, associate metadata like title and class, etc. On the server side the object is automatically destroyed when the related wl_surface is destroyed. On the client side, wl_shell_surface_destroy() must be called before destroying the wl_surface object. A client must respond to a ping event with a pong request or the client may be deemed unresponsive. Start a pointer-driven move of the surface. This request must be used in response to a button press event. The server may ignore move requests depending on the state of the surface (e.g. fullscreen or maximized). These values are used to indicate which edge of a surface is being dragged in a resize operation. The server may use this information to adapt its behavior, e.g. choose an appropriate cursor image. Start a pointer-driven resizing of the surface. This request must be used in response to a button press event. The server may ignore resize requests depending on the state of the surface (e.g. fullscreen or maximized). Map the surface as a toplevel surface. A toplevel surface is not fullscreen, maximized or transient. These flags specify details of the expected behaviour of transient surfaces. Used in the set_transient request. Map the surface relative to an existing surface. The x and y arguments specify the location of the upper left corner of the surface relative to the upper left corner of the parent surface, in surface-local coordinates. The flags argument controls details of the transient behaviour. Hints to indicate to the compositor how to deal with a conflict between the dimensions of the surface and the dimensions of the output. The compositor is free to ignore this parameter. Map the surface as a fullscreen surface. If an output parameter is given then the surface will be made fullscreen on that output. If the client does not specify the output then the compositor will apply its policy - usually choosing the output on which the surface has the biggest surface area. The client may specify a method to resolve a size conflict between the output size and the surface size - this is provided through the method parameter. The framerate parameter is used only when the method is set to "driver", to indicate the preferred framerate. A value of 0 indicates that the client does not care about framerate. The framerate is specified in mHz, that is framerate of 60000 is 60Hz. A method of "scale" or "driver" implies a scaling operation of the surface, either via a direct scaling operation or a change of the output mode. This will override any kind of output scaling, so that mapping a surface with a buffer size equal to the mode can fill the screen independent of buffer_scale. A method of "fill" means we don't scale up the buffer, however any output scale is applied. This means that you may run into an edge case where the application maps a buffer with the same size of the output mode but buffer_scale 1 (thus making a surface larger than the output). In this case it is allowed to downscale the results to fit the screen. The compositor must reply to this request with a configure event with the dimensions for the output on which the surface will be made fullscreen. Map the surface as a popup. A popup surface is a transient surface with an added pointer grab. An existing implicit grab will be changed to owner-events mode, and the popup grab will continue after the implicit grab ends (i.e. releasing the mouse button does not cause the popup to be unmapped). The popup grab continues until the window is destroyed or a mouse button is pressed in any other client's window. A click in any of the client's surfaces is reported as normal, however, clicks in other clients' surfaces will be discarded and trigger the callback. The x and y arguments specify the location of the upper left corner of the surface relative to the upper left corner of the parent surface, in surface-local coordinates. Map the surface as a maximized surface. If an output parameter is given then the surface will be maximized on that output. If the client does not specify the output then the compositor will apply its policy - usually choosing the output on which the surface has the biggest surface area. The compositor will reply with a configure event telling the expected new surface size. The operation is completed on the next buffer attach to this surface. A maximized surface typically fills the entire output it is bound to, except for desktop elements such as panels. This is the main difference between a maximized shell surface and a fullscreen shell surface. The details depend on the compositor implementation. Set a short title for the surface. This string may be used to identify the surface in a task bar, window list, or other user interface elements provided by the compositor. The string must be encoded in UTF-8. Set a class for the surface. The surface class identifies the general class of applications to which the surface belongs. A common convention is to use the file name (or the full path if it is a non-standard location) of the application's .desktop file as the class. Ping a client to check if it is receiving events and sending requests. A client is expected to reply with a pong request. The configure event asks the client to resize its surface. The size is a hint, in the sense that the client is free to ignore it if it doesn't resize, pick a smaller size (to satisfy aspect ratio or resize in steps of NxM pixels). The edges parameter provides a hint about how the surface was resized. The client may use this information to decide how to adjust its content to the new size (e.g. a scrolling area might adjust its content position to leave the viewable content unmoved). The client is free to dismiss all but the last configure event it received. The width and height arguments specify the size of the window in surface-local coordinates. The popup_done event is sent out when a popup grab is broken, that is, when the user clicks a surface that doesn't belong to the client owning the popup surface. A surface is a rectangular area that is displayed on the screen. It has a location, size and pixel contents. The size of a surface (and relative positions on it) is described in surface-local coordinates, which may differ from the buffer coordinates of the pixel content, in case a buffer_transform or a buffer_scale is used. A surface without a "role" is fairly useless: a compositor does not know where, when or how to present it. The role is the purpose of a wl_surface. Examples of roles are a cursor for a pointer (as set by wl_pointer.set_cursor), a drag icon (wl_data_device.start_drag), a sub-surface (wl_subcompositor.get_subsurface), and a window as defined by a shell protocol (e.g. wl_shell.get_shell_surface). A surface can have only one role at a time. Initially a wl_surface does not have a role. Once a wl_surface is given a role, it is set permanently for the whole lifetime of the wl_surface object. Giving the current role again is allowed, unless explicitly forbidden by the relevant interface specification. Surface roles are given by requests in other interfaces such as wl_pointer.set_cursor. The request should explicitly mention that this request gives a role to a wl_surface. Often, this request also creates a new protocol object that represents the role and adds additional functionality to wl_surface. When a client wants to destroy a wl_surface, they must destroy this 'role object' before the wl_surface. Destroying the role object does not remove the role from the wl_surface, but it may stop the wl_surface from "playing the role". For instance, if a wl_subsurface object is destroyed, the wl_surface it was created for will be unmapped and forget its position and z-order. It is allowed to create a wl_subsurface for the same wl_surface again, but it is not allowed to use the wl_surface as a cursor (cursor is a different role than sub-surface, and role switching is not allowed). These errors can be emitted in response to wl_surface requests. Deletes the surface and invalidates its object ID. Set a buffer as the content of this surface. The new size of the surface is calculated based on the buffer size transformed by the inverse buffer_transform and the inverse buffer_scale. This means that the supplied buffer must be an integer multiple of the buffer_scale. The x and y arguments specify the location of the new pending buffer's upper left corner, relative to the current buffer's upper left corner, in surface-local coordinates. In other words, the x and y, combined with the new surface size define in which directions the surface's size changes. Surface contents are double-buffered state, see wl_surface.commit. The initial surface contents are void; there is no content. wl_surface.attach assigns the given wl_buffer as the pending wl_buffer. wl_surface.commit makes the pending wl_buffer the new surface contents, and the size of the surface becomes the size calculated from the wl_buffer, as described above. After commit, there is no pending buffer until the next attach. Committing a pending wl_buffer allows the compositor to read the pixels in the wl_buffer. The compositor may access the pixels at any time after the wl_surface.commit request. When the compositor will not access the pixels anymore, it will send the wl_buffer.release event. Only after receiving wl_buffer.release, the client may reuse the wl_buffer. A wl_buffer that has been attached and then replaced by another attach instead of committed will not receive a release event, and is not used by the compositor. Destroying the wl_buffer after wl_buffer.release does not change the surface contents. However, if the client destroys the wl_buffer before receiving the wl_buffer.release event, the surface contents become undefined immediately. If wl_surface.attach is sent with a NULL wl_buffer, the following wl_surface.commit will remove the surface content. This request is used to describe the regions where the pending buffer is different from the current surface contents, and where the surface therefore needs to be repainted. The compositor ignores the parts of the damage that fall outside of the surface. Damage is double-buffered state, see wl_surface.commit. The damage rectangle is specified in surface-local coordinates, where x and y specify the upper left corner of the damage rectangle. The initial value for pending damage is empty: no damage. wl_surface.damage adds pending damage: the new pending damage is the union of old pending damage and the given rectangle. wl_surface.commit assigns pending damage as the current damage, and clears pending damage. The server will clear the current damage as it repaints the surface. Alternatively, damage can be posted with wl_surface.damage_buffer which uses buffer coordinates instead of surface coordinates, and is probably the preferred and intuitive way of doing this. Request a notification when it is a good time to start drawing a new frame, by creating a frame callback. This is useful for throttling redrawing operations, and driving animations. When a client is animating on a wl_surface, it can use the 'frame' request to get notified when it is a good time to draw and commit the next frame of animation. If the client commits an update earlier than that, it is likely that some updates will not make it to the display, and the client is wasting resources by drawing too often. The frame request will take effect on the next wl_surface.commit. The notification will only be posted for one frame unless requested again. For a wl_surface, the notifications are posted in the order the frame requests were committed. The server must send the notifications so that a client will not send excessive updates, while still allowing the highest possible update rate for clients that wait for the reply before drawing again. The server should give some time for the client to draw and commit after sending the frame callback events to let it hit the next output refresh. A server should avoid signaling the frame callbacks if the surface is not visible in any way, e.g. the surface is off-screen, or completely obscured by other opaque surfaces. The object returned by this request will be destroyed by the compositor after the callback is fired and as such the client must not attempt to use it after that point. The callback_data passed in the callback is the current time, in milliseconds, with an undefined base. This request sets the region of the surface that contains opaque content. The opaque region is an optimization hint for the compositor that lets it optimize the redrawing of content behind opaque regions. Setting an opaque region is not required for correct behaviour, but marking transparent content as opaque will result in repaint artifacts. The opaque region is specified in surface-local coordinates. The compositor ignores the parts of the opaque region that fall outside of the surface. Opaque region is double-buffered state, see wl_surface.commit. wl_surface.set_opaque_region changes the pending opaque region. wl_surface.commit copies the pending region to the current region. Otherwise, the pending and current regions are never changed. The initial value for an opaque region is empty. Setting the pending opaque region has copy semantics, and the wl_region object can be destroyed immediately. A NULL wl_region causes the pending opaque region to be set to empty. This request sets the region of the surface that can receive pointer and touch events. Input events happening outside of this region will try the next surface in the server surface stack. The compositor ignores the parts of the input region that fall outside of the surface. The input region is specified in surface-local coordinates. Input region is double-buffered state, see wl_surface.commit. wl_surface.set_input_region changes the pending input region. wl_surface.commit copies the pending region to the current region. Otherwise the pending and current regions are never changed, except cursor and icon surfaces are special cases, see wl_pointer.set_cursor and wl_data_device.start_drag. The initial value for an input region is infinite. That means the whole surface will accept input. Setting the pending input region has copy semantics, and the wl_region object can be destroyed immediately. A NULL wl_region causes the input region to be set to infinite. Surface state (input, opaque, and damage regions, attached buffers, etc.) is double-buffered. Protocol requests modify the pending state, as opposed to the current state in use by the compositor. A commit request atomically applies all pending state, replacing the current state. After commit, the new pending state is as documented for each related request. On commit, a pending wl_buffer is applied first, and all other state second. This means that all coordinates in double-buffered state are relative to the new wl_buffer coming into use, except for wl_surface.attach itself. If there is no pending wl_buffer, the coordinates are relative to the current surface contents. All requests that need a commit to become effective are documented to affect double-buffered state. Other interfaces may add further double-buffered surface state. This is emitted whenever a surface's creation, movement, or resizing results in some part of it being within the scanout region of an output. Note that a surface may be overlapping with zero or more outputs. This is emitted whenever a surface's creation, movement, or resizing results in it no longer having any part of it within the scanout region of an output. This request sets an optional transformation on how the compositor interprets the contents of the buffer attached to the surface. The accepted values for the transform parameter are the values for wl_output.transform. Buffer transform is double-buffered state, see wl_surface.commit. A newly created surface has its buffer transformation set to normal. wl_surface.set_buffer_transform changes the pending buffer transformation. wl_surface.commit copies the pending buffer transformation to the current one. Otherwise, the pending and current values are never changed. The purpose of this request is to allow clients to render content according to the output transform, thus permitting the compositor to use certain optimizations even if the display is rotated. Using hardware overlays and scanning out a client buffer for fullscreen surfaces are examples of such optimizations. Those optimizations are highly dependent on the compositor implementation, so the use of this request should be considered on a case-by-case basis. Note that if the transform value includes 90 or 270 degree rotation, the width of the buffer will become the surface height and the height of the buffer will become the surface width. If transform is not one of the values from the wl_output.transform enum the invalid_transform protocol error is raised. This request sets an optional scaling factor on how the compositor interprets the contents of the buffer attached to the window. Buffer scale is double-buffered state, see wl_surface.commit. A newly created surface has its buffer scale set to 1. wl_surface.set_buffer_scale changes the pending buffer scale. wl_surface.commit copies the pending buffer scale to the current one. Otherwise, the pending and current values are never changed. The purpose of this request is to allow clients to supply higher resolution buffer data for use on high resolution outputs. It is intended that you pick the same buffer scale as the scale of the output that the surface is displayed on. This means the compositor can avoid scaling when rendering the surface on that output. Note that if the scale is larger than 1, then you have to attach a buffer that is larger (by a factor of scale in each dimension) than the desired surface size. If scale is not positive the invalid_scale protocol error is raised. This request is used to describe the regions where the pending buffer is different from the current surface contents, and where the surface therefore needs to be repainted. The compositor ignores the parts of the damage that fall outside of the surface. Damage is double-buffered state, see wl_surface.commit. The damage rectangle is specified in buffer coordinates, where x and y specify the upper left corner of the damage rectangle. The initial value for pending damage is empty: no damage. wl_surface.damage_buffer adds pending damage: the new pending damage is the union of old pending damage and the given rectangle. wl_surface.commit assigns pending damage as the current damage, and clears pending damage. The server will clear the current damage as it repaints the surface. This request differs from wl_surface.damage in only one way - it takes damage in buffer coordinates instead of surface-local coordinates. While this generally is more intuitive than surface coordinates, it is especially desirable when using wp_viewport or when a drawing library (like EGL) is unaware of buffer scale and buffer transform. Note: Because buffer transformation changes and damage requests may be interleaved in the protocol stream, it is impossible to determine the actual mapping between surface and buffer damage until wl_surface.commit time. Therefore, compositors wishing to take both kinds of damage into account will have to accumulate damage from the two requests separately and only transform from one to the other after receiving the wl_surface.commit. A seat is a group of keyboards, pointer and touch devices. This object is published as a global during start up, or when such a device is hot plugged. A seat typically has a pointer and maintains a keyboard focus and a pointer focus. This is a bitmask of capabilities this seat has; if a member is set, then it is present on the seat. This is emitted whenever a seat gains or loses the pointer, keyboard or touch capabilities. The argument is a capability enum containing the complete set of capabilities this seat has. When the pointer capability is added, a client may create a wl_pointer object using the wl_seat.get_pointer request. This object will receive pointer events until the capability is removed in the future. When the pointer capability is removed, a client should destroy the wl_pointer objects associated with the seat where the capability was removed, using the wl_pointer.release request. No further pointer events will be received on these objects. In some compositors, if a seat regains the pointer capability and a client has a previously obtained wl_pointer object of version 4 or less, that object may start sending pointer events again. This behavior is considered a misinterpretation of the intended behavior and must not be relied upon by the client. wl_pointer objects of version 5 or later must not send events if created before the most recent event notifying the client of an added pointer capability. The above behavior also applies to wl_keyboard and wl_touch with the keyboard and touch capabilities, respectively. The ID provided will be initialized to the wl_pointer interface for this seat. This request only takes effect if the seat has the pointer capability, or has had the pointer capability in the past. It is a protocol violation to issue this request on a seat that has never had the pointer capability. The ID provided will be initialized to the wl_keyboard interface for this seat. This request only takes effect if the seat has the keyboard capability, or has had the keyboard capability in the past. It is a protocol violation to issue this request on a seat that has never had the keyboard capability. The ID provided will be initialized to the wl_touch interface for this seat. This request only takes effect if the seat has the touch capability, or has had the touch capability in the past. It is a protocol violation to issue this request on a seat that has never had the touch capability. In a multiseat configuration this can be used by the client to help identify which physical devices the seat represents. Based on the seat configuration used by the compositor. Using this request a client can tell the server that it is not going to use the seat object anymore. The wl_pointer interface represents one or more input devices, such as mice, which control the pointer location and pointer_focus of a seat. The wl_pointer interface generates motion, enter and leave events for the surfaces that the pointer is located over, and button and axis events for button presses, button releases and scrolling. Set the pointer surface, i.e., the surface that contains the pointer image (cursor). This request gives the surface the role of a cursor. If the surface already has another role, it raises a protocol error. The cursor actually changes only if the pointer focus for this device is one of the requesting client's surfaces or the surface parameter is the current pointer surface. If there was a previous surface set with this request it is replaced. If surface is NULL, the pointer image is hidden. The parameters hotspot_x and hotspot_y define the position of the pointer surface relative to the pointer location. Its top-left corner is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the coordinates of the pointer location, in surface-local coordinates. On surface.attach requests to the pointer surface, hotspot_x and hotspot_y are decremented by the x and y parameters passed to the request. Attach must be confirmed by wl_surface.commit as usual. The hotspot can also be updated by passing the currently set pointer surface to this request with new values for hotspot_x and hotspot_y. The current and pending input regions of the wl_surface are cleared, and wl_surface.set_input_region is ignored until the wl_surface is no longer used as the cursor. When the use as a cursor ends, the current and pending input regions become undefined, and the wl_surface is unmapped. Notification that this seat's pointer is focused on a certain surface. When a seat's focus enters a surface, the pointer image is undefined and a client should respond to this event by setting an appropriate pointer image with the set_cursor request. Notification that this seat's pointer is no longer focused on a certain surface. The leave notification is sent before the enter notification for the new focus. Notification of pointer location change. The arguments surface_x and surface_y are the location relative to the focused surface. Describes the physical state of a button that produced the button event. Mouse button click and release notifications. The location of the click is given by the last motion or enter event. The time argument is a timestamp with millisecond granularity, with an undefined base. The button is a button code as defined in the Linux kernel's linux/input-event-codes.h header file, e.g. BTN_LEFT. Any 16-bit button code value is reserved for future additions to the kernel's event code list. All other button codes above 0xFFFF are currently undefined but may be used in future versions of this protocol. Describes the axis types of scroll events. Scroll and other axis notifications. For scroll events (vertical and horizontal scroll axes), the value parameter is the length of a vector along the specified axis in a coordinate space identical to those of motion events, representing a relative movement along the specified axis. For devices that support movements non-parallel to axes multiple axis events will be emitted. When applicable, for example for touch pads, the server can choose to emit scroll events where the motion vector is equivalent to a motion event vector. When applicable, a client can transform its content relative to the scroll distance. Using this request a client can tell the server that it is not going to use the pointer object anymore. This request destroys the pointer proxy object, so clients must not call wl_pointer_destroy() after using this request. Indicates the end of a set of events that logically belong together. A client is expected to accumulate the data in all events within the frame before proceeding. All wl_pointer events before a wl_pointer.frame event belong logically together. For example, in a diagonal scroll motion the compositor will send an optional wl_pointer.axis_source event, two wl_pointer.axis events (horizontal and vertical) and finally a wl_pointer.frame event. The client may use this information to calculate a diagonal vector for scrolling. When multiple wl_pointer.axis events occur within the same frame, the motion vector is the combined motion of all events. When a wl_pointer.axis and a wl_pointer.axis_stop event occur within the same frame, this indicates that axis movement in one axis has stopped but continues in the other axis. When multiple wl_pointer.axis_stop events occur within the same frame, this indicates that these axes stopped in the same instance. A wl_pointer.frame event is sent for every logical event group, even if the group only contains a single wl_pointer event. Specifically, a client may get a sequence: motion, frame, button, frame, axis, frame, axis_stop, frame. The wl_pointer.enter and wl_pointer.leave events are logical events generated by the compositor and not the hardware. These events are also grouped by a wl_pointer.frame. When a pointer moves from one surface to another, a compositor should group the wl_pointer.leave event within the same wl_pointer.frame. However, a client must not rely on wl_pointer.leave and wl_pointer.enter being in the same wl_pointer.frame. Compositor-specific policies may require the wl_pointer.leave and wl_pointer.enter event being split across multiple wl_pointer.frame groups. Describes the source types for axis events. This indicates to the client how an axis event was physically generated; a client may adjust the user interface accordingly. For example, scroll events from a "finger" source may be in a smooth coordinate space with kinetic scrolling whereas a "wheel" source may be in discrete steps of a number of lines. A device generating events in a continuous coordinate space, but using something other than a finger. One example for this source is button-based scrolling where the vertical motion of a device is converted to scroll events while a button is held down. Indicates that the actual device is a wheel but the scroll event is not caused by a rotation but a (usually sideways) tilt of the wheel. Source information for scroll and other axes. This event does not occur on its own. It is sent before a wl_pointer.frame event and carries the source information for all events within that frame. The source specifies how this event was generated. If the source is wl_pointer.axis_source.finger, a wl_pointer.axis_stop event will be sent when the user lifts the finger off the device. If the source is wl_pointer.axis_source.wheel, wl_pointer.axis_source.wheel_tilt or wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event may or may not be sent. Whether a compositor sends an axis_stop event for these sources is hardware-specific and implementation-dependent; clients must not rely on receiving an axis_stop event for these scroll sources and should treat scroll sequences from these scroll sources as unterminated by default. This event is optional. If the source is unknown for a particular axis event sequence, no event is sent. Only one wl_pointer.axis_source event is permitted per frame. The order of wl_pointer.axis_discrete and wl_pointer.axis_source is not guaranteed. Stop notification for scroll and other axes. For some wl_pointer.axis_source types, a wl_pointer.axis_stop event is sent to notify a client that the axis sequence has terminated. This enables the client to implement kinetic scrolling. See the wl_pointer.axis_source documentation for information on when this event may be generated. Any wl_pointer.axis events with the same axis_source after this event should be considered as the start of a new axis motion. The timestamp is to be interpreted identical to the timestamp in the wl_pointer.axis event. The timestamp value may be the same as a preceding wl_pointer.axis event. Discrete step information for scroll and other axes. This event carries the axis value of the wl_pointer.axis event in discrete steps (e.g. mouse wheel clicks). This event does not occur on its own, it is coupled with a wl_pointer.axis event that represents this axis value on a continuous scale. The protocol guarantees that each axis_discrete event is always followed by exactly one axis event with the same axis number within the same wl_pointer.frame. Note that the protocol allows for other events to occur between the axis_discrete and its coupled axis event, including other axis_discrete or axis events. This event is optional; continuous scrolling devices like two-finger scrolling on touchpads do not have discrete steps and do not generate this event. The discrete value carries the directional information. e.g. a value of -2 is two steps towards the negative direction of this axis. The axis number is identical to the axis number in the associated axis event. The order of wl_pointer.axis_discrete and wl_pointer.axis_source is not guaranteed. The wl_keyboard interface represents one or more keyboards associated with a seat. This specifies the format of the keymap provided to the client with the wl_keyboard.keymap event. This event provides a file descriptor to the client which can be memory-mapped to provide a keyboard mapping description. Notification that this seat's keyboard focus is on a certain surface. Notification that this seat's keyboard focus is no longer on a certain surface. The leave notification is sent before the enter notification for the new focus. Describes the physical state of a key that produced the key event. A key was pressed or released. The time argument is a timestamp with millisecond granularity, with an undefined base. Notifies clients that the modifier and/or group state has changed, and it should update its local state. Informs the client about the keyboard's repeat rate and delay. This event is sent as soon as the wl_keyboard object has been created, and is guaranteed to be received by the client before any key press event. Negative values for either rate or delay are illegal. A rate of zero will disable any repeating (regardless of the value of delay). This event can be sent later on as well with a new value if necessary, so clients should continue listening for the event past the creation of wl_keyboard. The wl_touch interface represents a touchscreen associated with a seat. Touch interactions can consist of one or more contacts. For each contact, a series of events is generated, starting with a down event, followed by zero or more motion events, and ending with an up event. Events relating to the same contact point can be identified by the ID of the sequence. A new touch point has appeared on the surface. This touch point is assigned a unique ID. Future events from this touch point reference this ID. The ID ceases to be valid after a touch up event and may be reused in the future. The touch point has disappeared. No further events will be sent for this touch point and the touch point's ID is released and may be reused in a future touch down event. A touch point has changed coordinates. Indicates the end of a set of events that logically belong together. A client is expected to accumulate the data in all events within the frame before proceeding. A wl_touch.frame terminates at least one event but otherwise no guarantee is provided about the set of events within a frame. A client must assume that any state not updated in a frame is unchanged from the previously known state. Sent if the compositor decides the touch stream is a global gesture. No further events are sent to the clients from that particular gesture. Touch cancellation applies to all touch points currently active on this client's surface. The client is responsible for finalizing the touch points, future touch points on this surface may reuse the touch point ID. Sent when a touchpoint has changed its shape. This event does not occur on its own. It is sent before a wl_touch.frame event and carries the new shape information for any previously reported, or new touch points of that frame. Other events describing the touch point such as wl_touch.down, wl_touch.motion or wl_touch.orientation may be sent within the same wl_touch.frame. A client should treat these events as a single logical touch point update. The order of wl_touch.shape, wl_touch.orientation and wl_touch.motion is not guaranteed. A wl_touch.down event is guaranteed to occur before the first wl_touch.shape event for this touch ID but both events may occur within the same wl_touch.frame. A touchpoint shape is approximated by an ellipse through the major and minor axis length. The major axis length describes the longer diameter of the ellipse, while the minor axis length describes the shorter diameter. Major and minor are orthogonal and both are specified in surface-local coordinates. The center of the ellipse is always at the touchpoint location as reported by wl_touch.down or wl_touch.move. This event is only sent by the compositor if the touch device supports shape reports. The client has to make reasonable assumptions about the shape if it did not receive this event. Sent when a touchpoint has changed its orientation. This event does not occur on its own. It is sent before a wl_touch.frame event and carries the new shape information for any previously reported, or new touch points of that frame. Other events describing the touch point such as wl_touch.down, wl_touch.motion or wl_touch.shape may be sent within the same wl_touch.frame. A client should treat these events as a single logical touch point update. The order of wl_touch.shape, wl_touch.orientation and wl_touch.motion is not guaranteed. A wl_touch.down event is guaranteed to occur before the first wl_touch.orientation event for this touch ID but both events may occur within the same wl_touch.frame. The orientation describes the clockwise angle of a touchpoint's major axis to the positive surface y-axis and is normalized to the -180 to +180 degree range. The granularity of orientation depends on the touch device, some devices only support binary rotation values between 0 and 90 degrees. This event is only sent by the compositor if the touch device supports orientation reports. An output describes part of the compositor geometry. The compositor works in the 'compositor coordinate system' and an output corresponds to a rectangular area in that space that is actually visible. This typically corresponds to a monitor that displays part of the compositor space. This object is published as global during start up, or when a monitor is hotplugged. This enumeration describes how the physical pixels on an output are laid out. This describes the transform that a compositor will apply to a surface to compensate for the rotation or mirroring of an output device. The flipped values correspond to an initial flip around a vertical axis followed by rotation. The purpose is mainly to allow clients to render accordingly and tell the compositor, so that for fullscreen surfaces, the compositor will still be able to scan out directly from client surfaces. The geometry event describes geometric properties of the output. The event is sent when binding to the output object and whenever any of the properties change. These flags describe properties of an output mode. They are used in the flags bitfield of the mode event. The mode event describes an available mode for the output. The event is sent when binding to the output object and there will always be one mode, the current mode. The event is sent again if an output changes mode, for the mode that is now current. In other words, the current mode is always the last mode that was received with the current flag set. The size of a mode is given in physical hardware units of the output device. This is not necessarily the same as the output size in the global compositor space. For instance, the output may be scaled, as described in wl_output.scale, or transformed, as described in wl_output.transform. This event is sent after all other properties have been sent after binding to the output object and after any other property changes done after that. This allows changes to the output properties to be seen as atomic, even if they happen via multiple events. This event contains scaling geometry information that is not in the geometry event. It may be sent after binding the output object or if the output scale changes later. If it is not sent, the client should assume a scale of 1. A scale larger than 1 means that the compositor will automatically scale surface buffers by this amount when rendering. This is used for very high resolution displays where applications rendering at the native resolution would be too small to be legible. It is intended that scaling aware clients track the current output of a surface, and if it is on a scaled output it should use wl_surface.set_buffer_scale with the scale of the output. That way the compositor can avoid scaling the surface, and the client can supply a higher detail image. Using this request a client can tell the server that it is not going to use the output object anymore. A region object describes an area. Region objects are used to describe the opaque and input regions of a surface. Destroy the region. This will invalidate the object ID. Add the specified rectangle to the region. Subtract the specified rectangle from the region. The global interface exposing sub-surface compositing capabilities. A wl_surface, that has sub-surfaces associated, is called the parent surface. Sub-surfaces can be arbitrarily nested and create a tree of sub-surfaces. The root surface in a tree of sub-surfaces is the main surface. The main surface cannot be a sub-surface, because sub-surfaces must always have a parent. A main surface with its sub-surfaces forms a (compound) window. For window management purposes, this set of wl_surface objects is to be considered as a single window, and it should also behave as such. The aim of sub-surfaces is to offload some of the compositing work within a window from clients to the compositor. A prime example is a video player with decorations and video in separate wl_surface objects. This should allow the compositor to pass YUV video buffer processing to dedicated overlay hardware when possible. Informs the server that the client will not be using this protocol object anymore. This does not affect any other objects, wl_subsurface objects included. Create a sub-surface interface for the given surface, and associate it with the given parent surface. This turns a plain wl_surface into a sub-surface. The to-be sub-surface must not already have another role, and it must not have an existing wl_subsurface object. Otherwise a protocol error is raised. An additional interface to a wl_surface object, which has been made a sub-surface. A sub-surface has one parent surface. A sub-surface's size and position are not limited to that of the parent. Particularly, a sub-surface is not automatically clipped to its parent's area. A sub-surface becomes mapped, when a non-NULL wl_buffer is applied and the parent surface is mapped. The order of which one happens first is irrelevant. A sub-surface is hidden if the parent becomes hidden, or if a NULL wl_buffer is applied. These rules apply recursively through the tree of surfaces. The behaviour of a wl_surface.commit request on a sub-surface depends on the sub-surface's mode. The possible modes are synchronized and desynchronized, see methods wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized mode caches the wl_surface state to be applied when the parent's state gets applied, and desynchronized mode applies the pending wl_surface state directly. A sub-surface is initially in the synchronized mode. Sub-surfaces have also other kind of state, which is managed by wl_subsurface requests, as opposed to wl_surface requests. This state includes the sub-surface position relative to the parent surface (wl_subsurface.set_position), and the stacking order of the parent and its sub-surfaces (wl_subsurface.place_above and .place_below). This state is applied when the parent surface's wl_surface state is applied, regardless of the sub-surface's mode. As the exception, set_sync and set_desync are effective immediately. The main surface can be thought to be always in desynchronized mode, since it does not have a parent in the sub-surfaces sense. Even if a sub-surface is in desynchronized mode, it will behave as in synchronized mode, if its parent surface behaves as in synchronized mode. This rule is applied recursively throughout the tree of surfaces. This means, that one can set a sub-surface into synchronized mode, and then assume that all its child and grand-child sub-surfaces are synchronized, too, without explicitly setting them. If the wl_surface associated with the wl_subsurface is destroyed, the wl_subsurface object becomes inert. Note, that destroying either object takes effect immediately. If you need to synchronize the removal of a sub-surface to the parent surface update, unmap the sub-surface first by attaching a NULL wl_buffer, update parent, and then destroy the sub-surface. If the parent wl_surface object is destroyed, the sub-surface is unmapped. The sub-surface interface is removed from the wl_surface object that was turned into a sub-surface with a wl_subcompositor.get_subsurface request. The wl_surface's association to the parent is deleted, and the wl_surface loses its role as a sub-surface. The wl_surface is unmapped. This schedules a sub-surface position change. The sub-surface will be moved so that its origin (top left corner pixel) will be at the location x, y of the parent surface coordinate system. The coordinates are not restricted to the parent surface area. Negative values are allowed. The scheduled coordinates will take effect whenever the state of the parent surface is applied. When this happens depends on whether the parent surface is in synchronized mode or not. See wl_subsurface.set_sync and wl_subsurface.set_desync for details. If more than one set_position request is invoked by the client before the commit of the parent surface, the position of a new request always replaces the scheduled position from any previous request. The initial position is 0, 0. This sub-surface is taken from the stack, and put back just above the reference surface, changing the z-order of the sub-surfaces. The reference surface must be one of the sibling surfaces, or the parent surface. Using any other surface, including this sub-surface, will cause a protocol error. The z-order is double-buffered. Requests are handled in order and applied immediately to a pending state. The final pending state is copied to the active state the next time the state of the parent surface is applied. When this happens depends on whether the parent surface is in synchronized mode or not. See wl_subsurface.set_sync and wl_subsurface.set_desync for details. A new sub-surface is initially added as the top-most in the stack of its siblings and parent. The sub-surface is placed just below the reference surface. See wl_subsurface.place_above. Change the commit behaviour of the sub-surface to synchronized mode, also described as the parent dependent mode. In synchronized mode, wl_surface.commit on a sub-surface will accumulate the committed state in a cache, but the state will not be applied and hence will not change the compositor output. The cached state is applied to the sub-surface immediately after the parent surface's state is applied. This ensures atomic updates of the parent and all its synchronized sub-surfaces. Applying the cached state will invalidate the cache, so further parent surface commits do not (re-)apply old state. See wl_subsurface for the recursive effect of this mode. Change the commit behaviour of the sub-surface to desynchronized mode, also described as independent or freely running mode. In desynchronized mode, wl_surface.commit on a sub-surface will apply the pending state directly, without caching, as happens normally with a wl_surface. Calling wl_surface.commit on the parent surface has no effect on the sub-surface's wl_surface state. This mode allows a sub-surface to be updated on its own. If cached state exists when wl_surface.commit is called in desynchronized mode, the pending state is added to the cached state, and applied as a whole. This invalidates the cache. Note: even if a sub-surface is set to desynchronized, a parent sub-surface may override it to behave as synchronized. For details, see wl_subsurface. If a surface's parent surface behaves as desynchronized, then the cached state is applied on set_desync. wayland-1.23.1/tests/data/small-client-core.h000066400000000000000000000130241466237767300210200ustar00rootroot00000000000000/* SCANNER TEST */ #ifndef SMALL_TEST_CLIENT_PROTOCOL_H #define SMALL_TEST_CLIENT_PROTOCOL_H #include #include #include "wayland-client-core.h" #ifdef __cplusplus extern "C" { #endif /** * @page page_small_test The small_test protocol * @section page_ifaces_small_test Interfaces * - @subpage page_iface_intf_A - the thing A * @section page_copyright_small_test Copyright *
 *
 * Copyright © 2016 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.
 * 
*/ struct another_intf; struct intf_A; struct intf_not_here; #ifndef INTF_A_INTERFACE #define INTF_A_INTERFACE /** * @page page_iface_intf_A intf_A * @section page_iface_intf_A_desc Description * * A useless example trying to tickle the scanner. * @section page_iface_intf_A_api API * See @ref iface_intf_A. */ /** * @defgroup iface_intf_A The intf_A interface * * A useless example trying to tickle the scanner. */ extern const struct wl_interface intf_A_interface; #endif #ifndef INTF_A_FOO_ENUM #define INTF_A_FOO_ENUM enum intf_A_foo { /** * this is the first */ INTF_A_FOO_FIRST = 0, /** * this is the second */ INTF_A_FOO_SECOND = 1, /** * this is the third * @since 2 */ INTF_A_FOO_THIRD = 2, /** * this is a negative value * @since 2 */ INTF_A_FOO_NEGATIVE = -1, /** * this is a deprecated value * @since 2 * @deprecated Deprecated since version 3 */ INTF_A_FOO_DEPRECATED = 3, }; /** * @ingroup iface_intf_A */ #define INTF_A_FOO_THIRD_SINCE_VERSION 2 /** * @ingroup iface_intf_A */ #define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2 /** * @ingroup iface_intf_A */ #define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2 #endif /* INTF_A_FOO_ENUM */ #ifndef INTF_A_BAR_ENUM #define INTF_A_BAR_ENUM enum intf_A_bar { /** * this is the first */ INTF_A_BAR_FIRST = 0x01, /** * this is the second */ INTF_A_BAR_SECOND = 0x02, /** * this is the third * @since 2 */ INTF_A_BAR_THIRD = 0x04, }; /** * @ingroup iface_intf_A */ #define INTF_A_BAR_THIRD_SINCE_VERSION 2 #endif /* INTF_A_BAR_ENUM */ /** * @ingroup iface_intf_A * @struct intf_A_listener */ struct intf_A_listener { /** */ void (*hey)(void *data, struct intf_A *intf_A); /** * @since 2 * @deprecated Deprecated since version 3 */ void (*yo)(void *data, struct intf_A *intf_A); }; /** * @ingroup iface_intf_A */ static inline int intf_A_add_listener(struct intf_A *intf_A, const struct intf_A_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) intf_A, (void (**)(void)) listener, data); } #define INTF_A_RQ1 0 #define INTF_A_RQ2 1 #define INTF_A_DESTROY 2 /** * @ingroup iface_intf_A */ #define INTF_A_HEY_SINCE_VERSION 1 /** * @ingroup iface_intf_A */ #define INTF_A_YO_SINCE_VERSION 2 /** * @ingroup iface_intf_A */ #define INTF_A_RQ1_SINCE_VERSION 1 /** * @ingroup iface_intf_A */ #define INTF_A_RQ2_SINCE_VERSION 1 /** * @ingroup iface_intf_A */ #define INTF_A_DESTROY_SINCE_VERSION 1 /** @ingroup iface_intf_A */ static inline void intf_A_set_user_data(struct intf_A *intf_A, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) intf_A, user_data); } /** @ingroup iface_intf_A */ static inline void * intf_A_get_user_data(struct intf_A *intf_A) { return wl_proxy_get_user_data((struct wl_proxy *) intf_A); } static inline uint32_t intf_A_get_version(struct intf_A *intf_A) { return wl_proxy_get_version((struct wl_proxy *) intf_A); } /** * @ingroup iface_intf_A */ static inline void * intf_A_rq1(struct intf_A *intf_A, const struct wl_interface *interface, uint32_t version) { struct wl_proxy *untyped_new; untyped_new = wl_proxy_marshal_flags((struct wl_proxy *) intf_A, INTF_A_RQ1, interface, version, 0, interface->name, version, NULL); return (void *) untyped_new; } /** * @ingroup iface_intf_A */ static inline struct intf_not_here * intf_A_rq2(struct intf_A *intf_A, const char *str, int32_t i, uint32_t u, wl_fixed_t f, int32_t fd, struct another_intf *obj) { struct wl_proxy *typed_new; typed_new = wl_proxy_marshal_flags((struct wl_proxy *) intf_A, INTF_A_RQ2, &intf_not_here_interface, wl_proxy_get_version((struct wl_proxy *) intf_A), 0, NULL, str, i, u, f, fd, obj); return (struct intf_not_here *) typed_new; } /** * @ingroup iface_intf_A */ static inline void intf_A_destroy(struct intf_A *intf_A) { wl_proxy_marshal_flags((struct wl_proxy *) intf_A, INTF_A_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) intf_A), WL_MARSHAL_FLAG_DESTROY); } #ifdef __cplusplus } #endif #endif wayland-1.23.1/tests/data/small-client.h000066400000000000000000000130171466237767300200740ustar00rootroot00000000000000/* SCANNER TEST */ #ifndef SMALL_TEST_CLIENT_PROTOCOL_H #define SMALL_TEST_CLIENT_PROTOCOL_H #include #include #include "wayland-client.h" #ifdef __cplusplus extern "C" { #endif /** * @page page_small_test The small_test protocol * @section page_ifaces_small_test Interfaces * - @subpage page_iface_intf_A - the thing A * @section page_copyright_small_test Copyright *
 *
 * Copyright © 2016 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.
 * 
*/ struct another_intf; struct intf_A; struct intf_not_here; #ifndef INTF_A_INTERFACE #define INTF_A_INTERFACE /** * @page page_iface_intf_A intf_A * @section page_iface_intf_A_desc Description * * A useless example trying to tickle the scanner. * @section page_iface_intf_A_api API * See @ref iface_intf_A. */ /** * @defgroup iface_intf_A The intf_A interface * * A useless example trying to tickle the scanner. */ extern const struct wl_interface intf_A_interface; #endif #ifndef INTF_A_FOO_ENUM #define INTF_A_FOO_ENUM enum intf_A_foo { /** * this is the first */ INTF_A_FOO_FIRST = 0, /** * this is the second */ INTF_A_FOO_SECOND = 1, /** * this is the third * @since 2 */ INTF_A_FOO_THIRD = 2, /** * this is a negative value * @since 2 */ INTF_A_FOO_NEGATIVE = -1, /** * this is a deprecated value * @since 2 * @deprecated Deprecated since version 3 */ INTF_A_FOO_DEPRECATED = 3, }; /** * @ingroup iface_intf_A */ #define INTF_A_FOO_THIRD_SINCE_VERSION 2 /** * @ingroup iface_intf_A */ #define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2 /** * @ingroup iface_intf_A */ #define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2 #endif /* INTF_A_FOO_ENUM */ #ifndef INTF_A_BAR_ENUM #define INTF_A_BAR_ENUM enum intf_A_bar { /** * this is the first */ INTF_A_BAR_FIRST = 0x01, /** * this is the second */ INTF_A_BAR_SECOND = 0x02, /** * this is the third * @since 2 */ INTF_A_BAR_THIRD = 0x04, }; /** * @ingroup iface_intf_A */ #define INTF_A_BAR_THIRD_SINCE_VERSION 2 #endif /* INTF_A_BAR_ENUM */ /** * @ingroup iface_intf_A * @struct intf_A_listener */ struct intf_A_listener { /** */ void (*hey)(void *data, struct intf_A *intf_A); /** * @since 2 * @deprecated Deprecated since version 3 */ void (*yo)(void *data, struct intf_A *intf_A); }; /** * @ingroup iface_intf_A */ static inline int intf_A_add_listener(struct intf_A *intf_A, const struct intf_A_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) intf_A, (void (**)(void)) listener, data); } #define INTF_A_RQ1 0 #define INTF_A_RQ2 1 #define INTF_A_DESTROY 2 /** * @ingroup iface_intf_A */ #define INTF_A_HEY_SINCE_VERSION 1 /** * @ingroup iface_intf_A */ #define INTF_A_YO_SINCE_VERSION 2 /** * @ingroup iface_intf_A */ #define INTF_A_RQ1_SINCE_VERSION 1 /** * @ingroup iface_intf_A */ #define INTF_A_RQ2_SINCE_VERSION 1 /** * @ingroup iface_intf_A */ #define INTF_A_DESTROY_SINCE_VERSION 1 /** @ingroup iface_intf_A */ static inline void intf_A_set_user_data(struct intf_A *intf_A, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) intf_A, user_data); } /** @ingroup iface_intf_A */ static inline void * intf_A_get_user_data(struct intf_A *intf_A) { return wl_proxy_get_user_data((struct wl_proxy *) intf_A); } static inline uint32_t intf_A_get_version(struct intf_A *intf_A) { return wl_proxy_get_version((struct wl_proxy *) intf_A); } /** * @ingroup iface_intf_A */ static inline void * intf_A_rq1(struct intf_A *intf_A, const struct wl_interface *interface, uint32_t version) { struct wl_proxy *untyped_new; untyped_new = wl_proxy_marshal_flags((struct wl_proxy *) intf_A, INTF_A_RQ1, interface, version, 0, interface->name, version, NULL); return (void *) untyped_new; } /** * @ingroup iface_intf_A */ static inline struct intf_not_here * intf_A_rq2(struct intf_A *intf_A, const char *str, int32_t i, uint32_t u, wl_fixed_t f, int32_t fd, struct another_intf *obj) { struct wl_proxy *typed_new; typed_new = wl_proxy_marshal_flags((struct wl_proxy *) intf_A, INTF_A_RQ2, &intf_not_here_interface, wl_proxy_get_version((struct wl_proxy *) intf_A), 0, NULL, str, i, u, f, fd, obj); return (struct intf_not_here *) typed_new; } /** * @ingroup iface_intf_A */ static inline void intf_A_destroy(struct intf_A *intf_A) { wl_proxy_marshal_flags((struct wl_proxy *) intf_A, INTF_A_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) intf_A), WL_MARSHAL_FLAG_DESTROY); } #ifdef __cplusplus } #endif #endif wayland-1.23.1/tests/data/small-code-core.c000066400000000000000000000036641466237767300204600ustar00rootroot00000000000000/* SCANNER TEST */ /* * Copyright © 2016 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 #include #include #include "wayland-util.h" extern const struct wl_interface another_intf_interface; extern const struct wl_interface intf_not_here_interface; static const struct wl_interface *small_test_types[] = { NULL, &intf_not_here_interface, NULL, NULL, NULL, NULL, NULL, &another_intf_interface, }; static const struct wl_message intf_A_requests[] = { { "rq1", "sun", small_test_types + 0 }, { "rq2", "nsiufho", small_test_types + 1 }, { "destroy", "", small_test_types + 0 }, }; static const struct wl_message intf_A_events[] = { { "hey", "", small_test_types + 0 }, { "yo", "2", small_test_types + 0 }, }; WL_EXPORT const struct wl_interface intf_A_interface = { "intf_A", 3, 3, intf_A_requests, 2, intf_A_events, }; wayland-1.23.1/tests/data/small-code.c000066400000000000000000000036641466237767300175320ustar00rootroot00000000000000/* SCANNER TEST */ /* * Copyright © 2016 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 #include #include #include "wayland-util.h" extern const struct wl_interface another_intf_interface; extern const struct wl_interface intf_not_here_interface; static const struct wl_interface *small_test_types[] = { NULL, &intf_not_here_interface, NULL, NULL, NULL, NULL, NULL, &another_intf_interface, }; static const struct wl_message intf_A_requests[] = { { "rq1", "sun", small_test_types + 0 }, { "rq2", "nsiufho", small_test_types + 1 }, { "destroy", "", small_test_types + 0 }, }; static const struct wl_message intf_A_events[] = { { "hey", "", small_test_types + 0 }, { "yo", "2", small_test_types + 0 }, }; WL_EXPORT const struct wl_interface intf_A_interface = { "intf_A", 3, 3, intf_A_requests, 2, intf_A_events, }; wayland-1.23.1/tests/data/small-private-code.c000066400000000000000000000043051466237767300211730ustar00rootroot00000000000000/* SCANNER TEST */ /* * Copyright © 2016 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 #include #include #include "wayland-util.h" #ifndef __has_attribute # define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ #endif #if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) #define WL_PRIVATE __attribute__ ((visibility("hidden"))) #else #define WL_PRIVATE #endif extern const struct wl_interface another_intf_interface; extern const struct wl_interface intf_not_here_interface; static const struct wl_interface *small_test_types[] = { NULL, &intf_not_here_interface, NULL, NULL, NULL, NULL, NULL, &another_intf_interface, }; static const struct wl_message intf_A_requests[] = { { "rq1", "sun", small_test_types + 0 }, { "rq2", "nsiufho", small_test_types + 1 }, { "destroy", "", small_test_types + 0 }, }; static const struct wl_message intf_A_events[] = { { "hey", "", small_test_types + 0 }, { "yo", "2", small_test_types + 0 }, }; WL_PRIVATE const struct wl_interface intf_A_interface = { "intf_A", 3, 3, intf_A_requests, 2, intf_A_events, }; wayland-1.23.1/tests/data/small-server-core.h000066400000000000000000000130741466237767300210550ustar00rootroot00000000000000/* SCANNER TEST */ #ifndef SMALL_TEST_SERVER_PROTOCOL_H #define SMALL_TEST_SERVER_PROTOCOL_H #include #include #include "wayland-server-core.h" #ifdef __cplusplus extern "C" { #endif struct wl_client; struct wl_resource; /** * @page page_small_test The small_test protocol * @section page_ifaces_small_test Interfaces * - @subpage page_iface_intf_A - the thing A * @section page_copyright_small_test Copyright *
 *
 * Copyright © 2016 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.
 * 
*/ struct another_intf; struct intf_A; struct intf_not_here; #ifndef INTF_A_INTERFACE #define INTF_A_INTERFACE /** * @page page_iface_intf_A intf_A * @section page_iface_intf_A_desc Description * * A useless example trying to tickle the scanner. * @section page_iface_intf_A_api API * See @ref iface_intf_A. */ /** * @defgroup iface_intf_A The intf_A interface * * A useless example trying to tickle the scanner. */ extern const struct wl_interface intf_A_interface; #endif #ifndef INTF_A_FOO_ENUM #define INTF_A_FOO_ENUM enum intf_A_foo { /** * this is the first */ INTF_A_FOO_FIRST = 0, /** * this is the second */ INTF_A_FOO_SECOND = 1, /** * this is the third * @since 2 */ INTF_A_FOO_THIRD = 2, /** * this is a negative value * @since 2 */ INTF_A_FOO_NEGATIVE = -1, /** * this is a deprecated value * @since 2 * @deprecated Deprecated since version 3 */ INTF_A_FOO_DEPRECATED = 3, }; /** * @ingroup iface_intf_A */ #define INTF_A_FOO_THIRD_SINCE_VERSION 2 /** * @ingroup iface_intf_A */ #define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2 /** * @ingroup iface_intf_A */ #define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2 /** * @ingroup iface_intf_A * Validate a intf_A foo value. * * @return true on success, false on error. * @ref intf_A_foo */ static inline bool intf_A_foo_is_valid(uint32_t value, uint32_t version) { switch (value) { case INTF_A_FOO_FIRST: return version >= 1; case INTF_A_FOO_SECOND: return version >= 1; case INTF_A_FOO_THIRD: return version >= 2; case (uint32_t)INTF_A_FOO_NEGATIVE: return version >= 2; case INTF_A_FOO_DEPRECATED: return version >= 2; default: return false; } } #endif /* INTF_A_FOO_ENUM */ #ifndef INTF_A_BAR_ENUM #define INTF_A_BAR_ENUM enum intf_A_bar { /** * this is the first */ INTF_A_BAR_FIRST = 0x01, /** * this is the second */ INTF_A_BAR_SECOND = 0x02, /** * this is the third * @since 2 */ INTF_A_BAR_THIRD = 0x04, }; /** * @ingroup iface_intf_A */ #define INTF_A_BAR_THIRD_SINCE_VERSION 2 /** * @ingroup iface_intf_A * Validate a intf_A bar value. * * @return true on success, false on error. * @ref intf_A_bar */ static inline bool intf_A_bar_is_valid(uint32_t value, uint32_t version) { uint32_t valid = 0; if (version >= 1) valid |= INTF_A_BAR_FIRST; if (version >= 1) valid |= INTF_A_BAR_SECOND; if (version >= 2) valid |= INTF_A_BAR_THIRD; return (value & ~valid) == 0; } #endif /* INTF_A_BAR_ENUM */ /** * @ingroup iface_intf_A * @struct intf_A_interface */ struct intf_A_interface { /** * @param interface name of the objects interface * @param version version of the objects interface */ void (*rq1)(struct wl_client *client, struct wl_resource *resource, const char *interface, uint32_t version, uint32_t untyped_new); /** */ void (*rq2)(struct wl_client *client, struct wl_resource *resource, uint32_t typed_new, const char *str, int32_t i, uint32_t u, wl_fixed_t f, int32_t fd, struct wl_resource *obj); /** */ void (*destroy)(struct wl_client *client, struct wl_resource *resource); }; #define INTF_A_HEY 0 #define INTF_A_YO 1 /** * @ingroup iface_intf_A */ #define INTF_A_HEY_SINCE_VERSION 1 /** * @ingroup iface_intf_A */ #define INTF_A_YO_SINCE_VERSION 2 /** * @ingroup iface_intf_A */ #define INTF_A_RQ1_SINCE_VERSION 1 /** * @ingroup iface_intf_A */ #define INTF_A_RQ2_SINCE_VERSION 1 /** * @ingroup iface_intf_A */ #define INTF_A_DESTROY_SINCE_VERSION 1 /** * @ingroup iface_intf_A * Sends an hey event to the client owning the resource. * @param resource_ The client's resource */ static inline void intf_A_send_hey(struct wl_resource *resource_) { wl_resource_post_event(resource_, INTF_A_HEY); } /** * @ingroup iface_intf_A * Sends an yo event to the client owning the resource. * @param resource_ The client's resource */ static inline void intf_A_send_yo(struct wl_resource *resource_) { wl_resource_post_event(resource_, INTF_A_YO); } #ifdef __cplusplus } #endif #endif wayland-1.23.1/tests/data/small-server.h000066400000000000000000000130671466237767300201310ustar00rootroot00000000000000/* SCANNER TEST */ #ifndef SMALL_TEST_SERVER_PROTOCOL_H #define SMALL_TEST_SERVER_PROTOCOL_H #include #include #include "wayland-server.h" #ifdef __cplusplus extern "C" { #endif struct wl_client; struct wl_resource; /** * @page page_small_test The small_test protocol * @section page_ifaces_small_test Interfaces * - @subpage page_iface_intf_A - the thing A * @section page_copyright_small_test Copyright *
 *
 * Copyright © 2016 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.
 * 
*/ struct another_intf; struct intf_A; struct intf_not_here; #ifndef INTF_A_INTERFACE #define INTF_A_INTERFACE /** * @page page_iface_intf_A intf_A * @section page_iface_intf_A_desc Description * * A useless example trying to tickle the scanner. * @section page_iface_intf_A_api API * See @ref iface_intf_A. */ /** * @defgroup iface_intf_A The intf_A interface * * A useless example trying to tickle the scanner. */ extern const struct wl_interface intf_A_interface; #endif #ifndef INTF_A_FOO_ENUM #define INTF_A_FOO_ENUM enum intf_A_foo { /** * this is the first */ INTF_A_FOO_FIRST = 0, /** * this is the second */ INTF_A_FOO_SECOND = 1, /** * this is the third * @since 2 */ INTF_A_FOO_THIRD = 2, /** * this is a negative value * @since 2 */ INTF_A_FOO_NEGATIVE = -1, /** * this is a deprecated value * @since 2 * @deprecated Deprecated since version 3 */ INTF_A_FOO_DEPRECATED = 3, }; /** * @ingroup iface_intf_A */ #define INTF_A_FOO_THIRD_SINCE_VERSION 2 /** * @ingroup iface_intf_A */ #define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2 /** * @ingroup iface_intf_A */ #define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2 /** * @ingroup iface_intf_A * Validate a intf_A foo value. * * @return true on success, false on error. * @ref intf_A_foo */ static inline bool intf_A_foo_is_valid(uint32_t value, uint32_t version) { switch (value) { case INTF_A_FOO_FIRST: return version >= 1; case INTF_A_FOO_SECOND: return version >= 1; case INTF_A_FOO_THIRD: return version >= 2; case (uint32_t)INTF_A_FOO_NEGATIVE: return version >= 2; case INTF_A_FOO_DEPRECATED: return version >= 2; default: return false; } } #endif /* INTF_A_FOO_ENUM */ #ifndef INTF_A_BAR_ENUM #define INTF_A_BAR_ENUM enum intf_A_bar { /** * this is the first */ INTF_A_BAR_FIRST = 0x01, /** * this is the second */ INTF_A_BAR_SECOND = 0x02, /** * this is the third * @since 2 */ INTF_A_BAR_THIRD = 0x04, }; /** * @ingroup iface_intf_A */ #define INTF_A_BAR_THIRD_SINCE_VERSION 2 /** * @ingroup iface_intf_A * Validate a intf_A bar value. * * @return true on success, false on error. * @ref intf_A_bar */ static inline bool intf_A_bar_is_valid(uint32_t value, uint32_t version) { uint32_t valid = 0; if (version >= 1) valid |= INTF_A_BAR_FIRST; if (version >= 1) valid |= INTF_A_BAR_SECOND; if (version >= 2) valid |= INTF_A_BAR_THIRD; return (value & ~valid) == 0; } #endif /* INTF_A_BAR_ENUM */ /** * @ingroup iface_intf_A * @struct intf_A_interface */ struct intf_A_interface { /** * @param interface name of the objects interface * @param version version of the objects interface */ void (*rq1)(struct wl_client *client, struct wl_resource *resource, const char *interface, uint32_t version, uint32_t untyped_new); /** */ void (*rq2)(struct wl_client *client, struct wl_resource *resource, uint32_t typed_new, const char *str, int32_t i, uint32_t u, wl_fixed_t f, int32_t fd, struct wl_resource *obj); /** */ void (*destroy)(struct wl_client *client, struct wl_resource *resource); }; #define INTF_A_HEY 0 #define INTF_A_YO 1 /** * @ingroup iface_intf_A */ #define INTF_A_HEY_SINCE_VERSION 1 /** * @ingroup iface_intf_A */ #define INTF_A_YO_SINCE_VERSION 2 /** * @ingroup iface_intf_A */ #define INTF_A_RQ1_SINCE_VERSION 1 /** * @ingroup iface_intf_A */ #define INTF_A_RQ2_SINCE_VERSION 1 /** * @ingroup iface_intf_A */ #define INTF_A_DESTROY_SINCE_VERSION 1 /** * @ingroup iface_intf_A * Sends an hey event to the client owning the resource. * @param resource_ The client's resource */ static inline void intf_A_send_hey(struct wl_resource *resource_) { wl_resource_post_event(resource_, INTF_A_HEY); } /** * @ingroup iface_intf_A * Sends an yo event to the client owning the resource. * @param resource_ The client's resource */ static inline void intf_A_send_yo(struct wl_resource *resource_) { wl_resource_post_event(resource_, INTF_A_YO); } #ifdef __cplusplus } #endif #endif wayland-1.23.1/tests/data/small.xml000066400000000000000000000052111466237767300171660ustar00rootroot00000000000000 Copyright © 2016 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. A useless example trying to tickle the scanner. wayland-1.23.1/tests/display-test.c000066400000000000000000001210501466237767300172110ustar00rootroot00000000000000/* * Copyright © 2012 Intel Corporation * Copyright © 2013 Jason Ekstrand * * 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wayland-private.h" #include "wayland-server.h" #include "wayland-client.h" #include "test-runner.h" #include "test-compositor.h" #include "tests-server-protocol.h" #include "tests-client-protocol.h" struct display_destroy_listener { struct wl_listener listener; int done; }; static void display_destroy_notify(struct wl_listener *l, void *data) { struct display_destroy_listener *listener; listener = wl_container_of(l, listener, listener); listener->done = 1; } TEST(display_destroy_listener) { struct wl_display *display; struct display_destroy_listener a, b; display = wl_display_create(); assert(display); a.listener.notify = &display_destroy_notify; a.done = 0; wl_display_add_destroy_listener(display, &a.listener); assert(wl_display_get_destroy_listener(display, display_destroy_notify) == &a.listener); b.listener.notify = display_destroy_notify; b.done = 0; wl_display_add_destroy_listener(display, &b.listener); wl_list_remove(&a.listener.link); wl_display_destroy(display); assert(!a.done); assert(b.done); } /* Fake 'client' which does not use wl_display_connect, and thus leaves the * file descriptor passed through WAYLAND_SOCKET intact. This should not * trigger an assertion in the leak check. */ static void empty_client(void) { return; } TEST(tc_leaks_tests) { struct display *d = display_create(); client_create_noarg(d, empty_client); display_run(d); display_destroy(d); } /* This is how pre proxy-version registry binds worked, * this should create a proxy that shares the display's * version number: 0 */ static void * old_registry_bind(struct wl_registry *wl_registry, uint32_t name, const struct wl_interface *interface, uint32_t version) { struct wl_proxy *id; id = wl_proxy_marshal_constructor( (struct wl_proxy *) wl_registry, WL_REGISTRY_BIND, interface, name, interface->name, version, NULL); return (void *) id; } struct handler_info { struct wl_seat *seat; uint32_t bind_version; bool use_unversioned; }; static void registry_handle_globals(void *data, struct wl_registry *registry, uint32_t id, const char *intf, uint32_t ver) { struct handler_info *hi = data; /* This is only for the proxy version test */ if (hi->bind_version) ver = hi->bind_version; if (strcmp(intf, "wl_seat") == 0) { if (hi->use_unversioned) hi->seat = old_registry_bind(registry, id, &wl_seat_interface, ver); else hi->seat = wl_registry_bind(registry, id, &wl_seat_interface, ver); assert(hi->seat); } } static const struct wl_registry_listener registry_listener = { registry_handle_globals, NULL }; static struct wl_seat * client_get_seat_with_info(struct client *c, struct handler_info *hi) { struct wl_registry *reg = wl_display_get_registry(c->wl_display); assert(reg); assert(hi); hi->seat = NULL; wl_registry_add_listener(reg, ®istry_listener, hi); wl_display_roundtrip(c->wl_display); assert(hi->seat); wl_registry_destroy(reg); return hi->seat; } static struct wl_seat * client_get_seat(struct client *c) { struct handler_info hi; hi.use_unversioned = false; hi.bind_version = 0; return client_get_seat_with_info(c, &hi); } static void check_pending_error(struct client *c, struct wl_proxy *proxy) { uint32_t ec, id; int err; const struct wl_interface *intf; err = wl_display_get_error(c->wl_display); assert(err == EPROTO); ec = wl_display_get_protocol_error(c->wl_display, &intf, &id); assert(ec == 23); assert(intf == &wl_seat_interface); assert(id == wl_proxy_get_id(proxy)); } static void check_for_error(struct client *c, struct wl_proxy *proxy) { /* client should be disconnected */ assert(wl_display_roundtrip(c->wl_display) == -1); check_pending_error(c, proxy); } static struct client_info * find_client_info(struct display *d, struct wl_client *client) { struct client_info *ci; wl_list_for_each(ci, &d->clients, link) { if (ci->wl_client == client) return ci; } return NULL; } static void bind_seat(struct wl_client *client, void *data, uint32_t vers, uint32_t id) { struct display *d = data; struct client_info *ci; struct wl_resource *res; ci = find_client_info(d, client); assert(ci); res = wl_resource_create(client, &wl_seat_interface, vers, id); assert(res); /* save the resource as client's info data, * so that we can use it later */ ci->data = res; } static void client_disconnect_nocheck(struct client *c) { wl_proxy_destroy((struct wl_proxy *) c->tc); wl_display_disconnect(c->wl_display); free(c); } static void post_error_main(void) { struct client *c = client_connect(); struct wl_seat *seat = client_get_seat(c); /* stop display so that it can post the error. * The function should return -1, because of the posted error */ assert(stop_display(c, 1) == -1); /* display should have posted error, check it! */ check_for_error(c, (struct wl_proxy *) seat); /* don't call client_disconnect(c), because then the test would be * aborted due to checks for error in this function */ wl_proxy_destroy((struct wl_proxy *) seat); client_disconnect_nocheck(c); } TEST(post_error_to_one_client) { struct display *d = display_create(); struct client_info *cl; wl_global_create(d->wl_display, &wl_seat_interface, 1, d, bind_seat); cl = client_create_noarg(d, post_error_main); display_run(d); /* the display was stopped by client, so it can * proceed in the code and post an error */ assert(cl->data); wl_resource_post_error((struct wl_resource *) cl->data, 23, "Dummy error"); /* this one should be ignored */ wl_resource_post_error((struct wl_resource *) cl->data, 21, "Dummy error (ignore)"); display_resume(d); display_destroy(d); } static void post_error_main2(void) { struct client *c = client_connect(); struct wl_seat *seat = client_get_seat(c); /* the error should not be posted for this client */ assert(stop_display(c, 2) >= 0); wl_proxy_destroy((struct wl_proxy *) seat); client_disconnect(c); } static void post_error_main3(void) { struct client *c = client_connect(); struct wl_seat *seat = client_get_seat(c); assert(stop_display(c, 2) == -1); check_for_error(c, (struct wl_proxy *) seat); /* don't call client_disconnect(c), because then the test would be * aborted due to checks for error in this function */ wl_proxy_destroy((struct wl_proxy *) seat); client_disconnect_nocheck(c); } /* all the testcases could be in one TEST, but splitting it * apart is better for debugging when the test fails */ TEST(post_error_to_one_from_two_clients) { struct display *d = display_create(); struct client_info *cl; wl_global_create(d->wl_display, &wl_seat_interface, 1, d, bind_seat); client_create_noarg(d, post_error_main2); cl = client_create_noarg(d, post_error_main3); display_run(d); /* post error only to the second client */ assert(cl->data); wl_resource_post_error((struct wl_resource *) cl->data, 23, "Dummy error"); wl_resource_post_error((struct wl_resource *) cl->data, 21, "Dummy error (ignore)"); display_resume(d); display_destroy(d); } /* all the testcases could be in one TEST, but splitting it * apart is better for debugging when the test fails */ TEST(post_error_to_two_clients) { struct display *d = display_create(); struct client_info *cl, *cl2; wl_global_create(d->wl_display, &wl_seat_interface, 1, d, bind_seat); cl = client_create_noarg(d, post_error_main3); cl2 = client_create_noarg(d, post_error_main3); display_run(d); /* Try to send the error to both clients */ assert(cl->data && cl2->data); wl_resource_post_error((struct wl_resource *) cl->data, 23, "Dummy error"); wl_resource_post_error((struct wl_resource *) cl->data, 21, "Dummy error (ignore)"); wl_resource_post_error((struct wl_resource *) cl2->data, 23, "Dummy error"); wl_resource_post_error((struct wl_resource *) cl2->data, 21, "Dummy error (ignore)"); display_resume(d); display_destroy(d); } static void post_nomem_main(void) { struct client *c = client_connect(); struct wl_seat *seat = client_get_seat(c); assert(stop_display(c, 1) == -1); assert(wl_display_get_error(c->wl_display) == ENOMEM); wl_proxy_destroy((struct wl_proxy *) seat); client_disconnect_nocheck(c); } TEST(post_nomem_tst) { struct display *d = display_create(); struct client_info *cl; wl_global_create(d->wl_display, &wl_seat_interface, 1, d, bind_seat); cl = client_create_noarg(d, post_nomem_main); display_run(d); assert(cl->data); wl_resource_post_no_memory((struct wl_resource *) cl->data); display_resume(d); /* first client terminated. Run it again, * but post no memory to client */ cl = client_create_noarg(d, post_nomem_main); display_run(d); assert(cl->data); wl_client_post_no_memory(cl->wl_client); display_resume(d); display_destroy(d); } static void post_implementation_error_main(void) { struct client *c = client_connect(); struct wl_seat *seat = client_get_seat(c); uint32_t object_id, protocol_error; const struct wl_interface *interface; assert(stop_display(c, 1) == -1); int err = wl_display_get_error(c->wl_display); fprintf(stderr, "Err is %i\n", err); assert(err == EPROTO); protocol_error = wl_display_get_protocol_error(c->wl_display, &interface, &object_id); assert(protocol_error == WL_DISPLAY_ERROR_IMPLEMENTATION); assert(interface == &wl_display_interface); wl_proxy_destroy((struct wl_proxy *) seat); client_disconnect_nocheck(c); } TEST(post_internal_error_tst) { struct display *d = display_create(); struct client_info *cl; wl_global_create(d->wl_display, &wl_seat_interface, 1, d, bind_seat); cl = client_create_noarg(d, post_implementation_error_main); display_run(d); wl_client_post_implementation_error(cl->wl_client, "Error %i", 20); display_resume(d); display_destroy(d); } static void register_reading(struct wl_display *display) { while(wl_display_prepare_read(display) != 0 && errno == EAGAIN) assert(wl_display_dispatch_pending(display) >= 0); assert(wl_display_flush(display) >= 0); } /* create thread that will call prepare+read so that * it will block */ static pthread_t create_thread(struct client *c, void *(*func)(void*)) { pthread_t thread; c->display_stopped = 0; /* func must set display->stopped to 1 before sleeping */ assert(pthread_create(&thread, NULL, func, c) == 0); /* make sure the thread is sleeping. It's a little bit racy * (setting display_stopped to 1 and calling wl_display_read_events) * so call usleep once again after the loop ends - it should * be sufficient... */ while (c->display_stopped == 0) test_usleep(500); test_usleep(10000); return thread; } static void * thread_read_error(void *data) { struct client *c = data; register_reading(c->wl_display); /* * Calling the read right now will block this thread * until the other thread will read the data. * However, after invoking an error, this * thread should be woken up or it will block indefinitely. */ c->display_stopped = 1; assert(wl_display_read_events(c->wl_display) == -1); assert(wl_display_dispatch_pending(c->wl_display) == -1); assert(wl_display_get_error(c->wl_display)); pthread_exit(NULL); } /* test posting an error in multi-threaded environment. */ static void threading_post_err(void) { DISABLE_LEAK_CHECKS; struct client *c = client_connect(); pthread_t thread; /* register read intention */ register_reading(c->wl_display); /* use this var as an indicator that thread is sleeping */ c->display_stopped = 0; /* create new thread that will register its intention too */ thread = create_thread(c, thread_read_error); /* so now we have sleeping thread waiting for a pthread_cond signal. * The main thread must call wl_display_read_events(). * If this call fails, then it won't call broadcast at the * end of the function and the sleeping thread will block indefinitely. * Make the call fail and watch if libwayland will unblock the thread! */ /* create error on fd, so that wl_display_read_events will fail. * The same can happen when server hangs up */ close(wl_display_get_fd(c->wl_display)); /* this read events will fail and will * post an error that should wake the sleeping thread * and dispatch the incoming events */ assert(wl_display_read_events(c->wl_display) == -1); /* kill test in 3 seconds. This should be enough time for the * thread to exit if it's not blocking. If everything is OK, than * the thread was woken up and the test will end before the SIGALRM */ test_set_timeout(3); pthread_join(thread, NULL); client_disconnect_nocheck(c); } TEST(threading_errors_tst) { struct display *d = display_create(); client_create_noarg(d, threading_post_err); display_run(d); display_destroy(d); } static void * thread_prepare_and_read(void *data) { struct client *c = data; register_reading(c->wl_display); c->display_stopped = 1; assert(wl_display_read_events(c->wl_display) == 0); assert(wl_display_dispatch_pending(c->wl_display) == 0); pthread_exit(NULL); } /* test cancel read*/ static void threading_cancel_read(void) { DISABLE_LEAK_CHECKS; struct client *c = client_connect(); pthread_t th1, th2, th3; register_reading(c->wl_display); th1 = create_thread(c, thread_prepare_and_read); th2 = create_thread(c, thread_prepare_and_read); th3 = create_thread(c, thread_prepare_and_read); /* all the threads are sleeping, waiting until read or cancel * is called. Cancel the read and let the threads proceed */ wl_display_cancel_read(c->wl_display); /* kill test in 3 seconds. This should be enough time for the * thread to exit if it's not blocking. If everything is OK, than * the thread was woken up and the test will end before the SIGALRM */ test_set_timeout(3); pthread_join(th1, NULL); pthread_join(th2, NULL); pthread_join(th3, NULL); client_disconnect(c); } TEST(threading_cancel_read_tst) { struct display *d = display_create(); client_create_noarg(d, threading_cancel_read); display_run(d); display_destroy(d); } static void threading_read_eagain(void) { DISABLE_LEAK_CHECKS; struct client *c = client_connect(); pthread_t th1, th2, th3; register_reading(c->wl_display); th1 = create_thread(c, thread_prepare_and_read); th2 = create_thread(c, thread_prepare_and_read); th3 = create_thread(c, thread_prepare_and_read); /* All the threads are sleeping, waiting until read or cancel * is called. Since we have no data on socket waiting, * the wl_connection_read should end up with error and set errno * to EAGAIN. Check if the threads are woken up in this case. */ assert(wl_display_read_events(c->wl_display) == 0); /* errno should be still set to EAGAIN if wl_connection_read * set it - check if we're testing the right case */ assert(errno == EAGAIN); test_set_timeout(3); pthread_join(th1, NULL); pthread_join(th2, NULL); pthread_join(th3, NULL); client_disconnect(c); } TEST(threading_read_eagain_tst) { struct display *d = display_create(); client_create_noarg(d, threading_read_eagain); display_run(d); display_destroy(d); } static void * thread_prepare_and_read2(void *data) { struct client *c = data; while(wl_display_prepare_read(c->wl_display) != 0 && errno == EAGAIN) assert(wl_display_dispatch_pending(c->wl_display) == -1); assert(wl_display_flush(c->wl_display) == -1); c->display_stopped = 1; assert(wl_display_read_events(c->wl_display) == -1); assert(wl_display_dispatch_pending(c->wl_display) == -1); pthread_exit(NULL); } static void threading_read_after_error(void) { DISABLE_LEAK_CHECKS; struct client *c = client_connect(); pthread_t thread; /* create an error */ close(wl_display_get_fd(c->wl_display)); assert(wl_display_dispatch(c->wl_display) == -1); /* try to prepare for reading */ while(wl_display_prepare_read(c->wl_display) != 0 && errno == EAGAIN) assert(wl_display_dispatch_pending(c->wl_display) == -1); assert(wl_display_flush(c->wl_display) == -1); assert(pthread_create(&thread, NULL, thread_prepare_and_read2, c) == 0); /* make sure thread is sleeping */ while (c->display_stopped == 0) test_usleep(500); test_usleep(10000); assert(wl_display_read_events(c->wl_display) == -1); /* kill test in 3 seconds */ test_set_timeout(3); pthread_join(thread, NULL); client_disconnect_nocheck(c); } TEST(threading_read_after_error_tst) { struct display *d = display_create(); client_create_noarg(d, threading_read_after_error); display_run(d); display_destroy(d); } static void wait_for_error_using_dispatch(struct client *c, struct wl_proxy *proxy) { int ret; while (true) { /* Dispatching should eventually hit the protocol error before * any other error. */ ret = wl_display_dispatch(c->wl_display); if (ret == 0) { continue; } else { assert(errno == EPROTO); break; } } check_pending_error(c, proxy); } static void wait_for_error_using_prepare_read(struct client *c, struct wl_proxy *proxy) { int ret = 0; struct pollfd pfd[2]; while (true) { while (wl_display_prepare_read(c->wl_display) != 0 && errno == EAGAIN) { assert(wl_display_dispatch_pending(c->wl_display) >= 0); } /* Flush may fail due to EPIPE if the connection is broken, but * this must not set a fatal display error because that would * result in it being impossible to read a potential protocol * error. */ do { ret = wl_display_flush(c->wl_display); } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); assert(ret >= 0 || errno == EPIPE); assert(wl_display_get_error(c->wl_display) == 0); pfd[0].fd = wl_display_get_fd(c->wl_display); pfd[0].events = POLLIN; do { ret = poll(pfd, 1, -1); } while (ret == -1 && errno == EINTR); assert(ret != -1); /* We should always manage to read the error before the EPIPE * comes this way. */ assert(wl_display_read_events(c->wl_display) == 0); /* Dispatching should eventually hit the protocol error before * any other error. */ ret = wl_display_dispatch_pending(c->wl_display); if (ret == 0) { continue; } else { assert(errno == EPROTO); break; } } check_pending_error(c, proxy); } static void check_error_after_epipe(void *data) { bool use_dispatch_helpers = *(bool *) data; struct client *client; struct wl_seat *seat; struct wl_callback *callback; client = client_connect(); /* This will, according to the implementation below, cause the server * to post an error. */ seat = client_get_seat(client); wl_display_flush(client->wl_display); /* The server will not actually destroy the client until it receives * input, so send something to trigger the client destruction. */ callback = wl_display_sync(client->wl_display); wl_callback_destroy(callback); /* Sleep some to give the server a chance to react and destroy the * client. */ test_usleep(200000); /* Wait for the protocol error and check that we reached it before * EPIPE. */ if (use_dispatch_helpers) { wait_for_error_using_dispatch(client, (struct wl_proxy *) seat); } else { wait_for_error_using_prepare_read(client, (struct wl_proxy *) seat); } wl_seat_destroy(seat); client_disconnect_nocheck(client); } static void bind_seat_and_post_error(struct wl_client *client, void *data, uint32_t version, uint32_t id) { struct display *d = data; struct client_info *ci; struct wl_resource *resource; ci = find_client_info(d, client); assert(ci); resource = wl_resource_create(client, &wl_seat_interface, version, id); assert(resource); ci->data = resource; wl_resource_post_error(ci->data, 23, "Dummy error"); } TEST(error_code_after_epipe) { struct display *d = display_create(); bool use_dispatch_helpers; wl_global_create(d->wl_display, &wl_seat_interface, 1, d, bind_seat_and_post_error); use_dispatch_helpers = true; client_create(d, check_error_after_epipe, &use_dispatch_helpers); display_run(d); use_dispatch_helpers = false; client_create(d, check_error_after_epipe, &use_dispatch_helpers); display_run(d); display_destroy(d); } static void check_seat_versions(struct wl_seat *seat, uint32_t ev) { struct wl_pointer *pointer; assert(wl_proxy_get_version((struct wl_proxy *) seat) == ev); assert(wl_seat_get_version(seat) == ev); pointer = wl_seat_get_pointer(seat); assert(wl_pointer_get_version(pointer) == ev); assert(wl_proxy_get_version((struct wl_proxy *) pointer) == ev); wl_proxy_destroy((struct wl_proxy *) pointer); } /* Normal client with proxy versions available. */ static void seat_version(void *data) { struct handler_info *hi = data; struct client *c = client_connect(); struct wl_seat *seat; /* display proxy should always be version 0 */ assert(wl_proxy_get_version((struct wl_proxy *) c->wl_display) == 0); seat = client_get_seat_with_info(c, hi); if (hi->use_unversioned) check_seat_versions(seat, 0); else check_seat_versions(seat, hi->bind_version); wl_proxy_destroy((struct wl_proxy *) seat); client_disconnect_nocheck(c); } TEST(versions) { struct display *d = display_create(); struct wl_global *global; int i; global = wl_global_create(d->wl_display, &wl_seat_interface, 5, d, bind_seat); for (i = 1; i <= 5; i++) { struct handler_info hi; hi.bind_version = i; hi.use_unversioned = false; client_create(d, seat_version, &hi); hi.use_unversioned = true; client_create(d, seat_version, &hi); } display_run(d); wl_global_destroy(global); display_destroy(d); } static void check_error_on_destroyed_object(void *data) { struct client *c; struct wl_seat *seat; uint32_t id; const struct wl_interface *intf; c = client_connect(); seat = client_get_seat(c); /* destroy the seat proxy. The display won't know * about it yet, so it will post the error as usual */ wl_proxy_destroy((struct wl_proxy *) seat); /* let display post the error. The error will * be caught in stop_display while dispatching */ assert(stop_display(c, 1) == -1); /* check the returned error. Since the object was destroyed, * we don't know the interface and id */ assert(wl_display_get_error(c->wl_display) == EPROTO); assert(wl_display_get_protocol_error(c->wl_display, &intf, &id) == 23); assert(intf == NULL); assert(id == 0); client_disconnect_nocheck(c); } TEST(error_on_destroyed_object) { struct client_info *cl; struct display *d = display_create(); wl_global_create(d->wl_display, &wl_seat_interface, 1, d, bind_seat); cl = client_create_noarg(d, check_error_on_destroyed_object); display_run(d); /* did client bind to the seat? */ assert(cl->data); /* post error on the destroyed object */ wl_resource_post_error((struct wl_resource *) cl->data, 23, "Dummy error"); display_resume(d); display_destroy(d); } static bool global_filter(const struct wl_client *client, const struct wl_global *global, void *data) { /* Hide the wl_data_offer interface if no data was provided */ if (wl_global_get_interface(global) == &wl_data_offer_interface) return data != NULL; /* Show all the others */ return true; } static void bind_data_offer(struct wl_client *client, void *data, uint32_t vers, uint32_t id) { /* Client should not be able to bind to this interface! */ assert(false); } static void registry_handle_filtered(void *data, struct wl_registry *registry, uint32_t id, const char *intf, uint32_t ver) { uint32_t *name = data; if (strcmp (intf, "wl_data_offer") == 0) { assert(name); *name = id; } } static void registry_handle_remove_filtered(void *data, struct wl_registry *registry, uint32_t id) { assert(false); } static const struct wl_registry_listener registry_listener_filtered = { registry_handle_filtered, registry_handle_remove_filtered, }; static void get_globals(void *data) { struct client *c = client_connect(); struct wl_registry *registry; registry = wl_display_get_registry(c->wl_display); wl_registry_add_listener(registry, ®istry_listener_filtered, data); wl_display_roundtrip(c->wl_display); wl_registry_destroy(registry); client_disconnect_nocheck(c); } TEST(filtered_global_is_hidden) { struct display *d; struct wl_global *g; d = display_create(); g = wl_global_create(d->wl_display, &wl_data_offer_interface, 1, d, bind_data_offer); wl_display_set_global_filter(d->wl_display, global_filter, NULL); client_create_noarg(d, get_globals); display_run(d); wl_global_destroy(g); display_destroy(d); } static void get_dynamic_globals(void *data) { struct client *c = client_connect(); struct wl_registry *registry; registry = wl_display_get_registry(c->wl_display); wl_registry_add_listener(registry, ®istry_listener_filtered, data); wl_display_roundtrip(c->wl_display); /* Wait for the server to create a new global */ assert(stop_display(c, 1) >= 0); /* Check that we don't see it */ wl_display_roundtrip(c->wl_display); /* Wait for the server to remove that global */ assert(stop_display(c, 1) >= 0); /* Check that we don't get a global_remove event */ wl_display_roundtrip(c->wl_display); wl_registry_destroy(registry); client_disconnect_nocheck(c); } TEST(filtered_dynamic_global_is_hidden) { struct display *d; struct wl_global *g; d = display_create(); wl_display_set_global_filter(d->wl_display, global_filter, NULL); /* Create a client and let it enumerate the globals */ client_create_noarg(d, get_dynamic_globals); display_run(d); /* Dynamically create a new global */ g = wl_global_create(d->wl_display, &wl_data_offer_interface, 1, d, bind_data_offer); display_resume(d); /* Dynamically remove the global */ wl_global_destroy(g); display_resume(d); display_destroy(d); } static void check_bind_error(struct client *c) { uint32_t errorcode, id; int err; const struct wl_interface *intf; err = wl_display_get_error(c->wl_display); assert(err == EPROTO); errorcode = wl_display_get_protocol_error(c->wl_display, &intf, &id); assert(errorcode == WL_DISPLAY_ERROR_INVALID_OBJECT); } static void force_bind(void *data) { struct client *c = client_connect(); struct wl_registry *registry; void *ptr; uint32_t *name = data; registry = wl_display_get_registry(c->wl_display); ptr = wl_registry_bind (registry, *name, &wl_data_offer_interface, 1); wl_display_roundtrip(c->wl_display); check_bind_error(c); wl_proxy_destroy((struct wl_proxy *) ptr); wl_registry_destroy(registry); client_disconnect_nocheck(c); } TEST(bind_fails_on_filtered_global) { struct display *d; struct wl_global *g; uint32_t *name; /* Create a anonymous shared memory to pass the interface name */ name = mmap(NULL, sizeof(uint32_t), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); d = display_create(); g = wl_global_create(d->wl_display, &wl_data_offer_interface, 1, d, bind_data_offer); wl_display_set_global_filter(d->wl_display, global_filter, name); client_create(d, get_globals, name); *name = 0; display_run(d); /* wl_data_offer should be 2 */ assert(*name == 2); wl_display_set_global_filter(d->wl_display, global_filter, NULL); /* Try to bind to the interface name when a global filter is in place */ client_create(d, force_bind, name); display_run(d); wl_global_destroy(g); display_destroy(d); } static void pre_fd(void *data, struct fd_passer *fdp) { fd_passer_destroy(fdp); } static void fd(void *data, struct fd_passer *fdp, int32_t fd) { /* We destroyed the resource before this event */ assert(false); } struct fd_passer_listener fd_passer_listener = { pre_fd, fd, }; static void zombie_fd_handle_globals(void *data, struct wl_registry *registry, uint32_t id, const char *intf, uint32_t ver) { struct fd_passer *fdp; if (!strcmp(intf, "fd_passer")) { fdp = wl_registry_bind(registry, id, &fd_passer_interface, 1); fd_passer_add_listener(fdp, &fd_passer_listener, NULL); } } static const struct wl_registry_listener zombie_fd_registry_listener = { zombie_fd_handle_globals, NULL }; static void zombie_client(void *data) { struct client *c = client_connect(); struct wl_registry *registry; registry = wl_display_get_registry(c->wl_display); wl_registry_add_listener(registry, &zombie_fd_registry_listener, NULL); /* Gets the registry */ wl_display_roundtrip(c->wl_display); /* push out the fd_passer bind */ wl_display_roundtrip(c->wl_display); /* push out our fd_passer.destroy */ wl_display_roundtrip(c->wl_display); wl_registry_destroy(registry); client_disconnect_nocheck(c); } struct passer_data { struct wl_resource *conjoined_passer; }; static void feed_pipe(int fd, char tosend) { int count; do { count = write(fd, &tosend, 1); } while (count != 1 && errno == EAGAIN); assert(count == 1); close(fd); } static void fd_passer_clobber(struct wl_client *client, struct wl_resource *res) { struct passer_data *pdata = wl_resource_get_user_data(res); int pipes1[2], pipes2[2], ret; if (pdata->conjoined_passer) { ret = pipe(pipes1); assert(ret == 0); ret = pipe(pipes2); assert(ret == 0); wl_resource_queue_event(res, FD_PASSER_FD, pipes1[0]); fd_passer_send_fd(pdata->conjoined_passer, pipes2[0]); feed_pipe(pipes1[1], '1'); feed_pipe(pipes2[1], '2'); close(pipes1[0]); close(pipes2[0]); } wl_resource_destroy(res); } static void fd_passer_twin(struct wl_client *client, struct wl_resource *res, struct wl_resource *passer) { struct passer_data *pdata = wl_resource_get_user_data(res); pdata->conjoined_passer = passer; } static const struct fd_passer_interface fdp_interface = { fd_passer_clobber, fd_passer_twin }; static void pdata_destroy(struct wl_resource *res) { struct passer_data *pdata = wl_resource_get_user_data(res); free(pdata); } static void bind_fd_passer(struct wl_client *client, void *data, uint32_t vers, uint32_t id) { struct wl_resource *res; struct passer_data *pdata; pdata = malloc(sizeof(*pdata)); assert(pdata); pdata->conjoined_passer = NULL; res = wl_resource_create(client, &fd_passer_interface, vers, id); wl_resource_set_implementation(res, &fdp_interface, pdata, pdata_destroy); assert(res); if (vers == 1) { fd_passer_send_pre_fd(res); fd_passer_send_fd(res, fileno(stdin)); } } TEST(zombie_fd) { struct display *d; struct wl_global *g; d = display_create(); g = wl_global_create(d->wl_display, &fd_passer_interface, 1, d, bind_fd_passer); client_create_noarg(d, zombie_client); display_run(d); wl_global_destroy(g); display_destroy(d); } static void double_pre_fd(void *data, struct fd_passer *fdp) { assert(false); } static void double_fd(void *data, struct fd_passer *fdp, int32_t fd) { char buf; int count; do { count = read(fd, &buf, 1); } while (count != 1 && errno == EAGAIN); assert(count == 1); close(fd); fd_passer_destroy(fdp); assert(buf == '2'); } struct fd_passer_listener double_fd_passer_listener = { double_pre_fd, double_fd, }; static void double_zombie_fd_handle_globals(void *data, struct wl_registry *registry, uint32_t id, const char *intf, uint32_t ver) { struct fd_passer *fdp1, *fdp2; if (!strcmp(intf, "fd_passer")) { fdp1 = wl_registry_bind(registry, id, &fd_passer_interface, 2); fd_passer_add_listener(fdp1, &double_fd_passer_listener, NULL); fdp2 = wl_registry_bind(registry, id, &fd_passer_interface, 2); fd_passer_add_listener(fdp2, &double_fd_passer_listener, NULL); fd_passer_conjoin(fdp1, fdp2); fd_passer_destroy(fdp1); } } static const struct wl_registry_listener double_zombie_fd_registry_listener = { double_zombie_fd_handle_globals, NULL }; static void double_zombie_client(void *data) { struct client *c = client_connect(); struct wl_registry *registry; registry = wl_display_get_registry(c->wl_display); wl_registry_add_listener(registry, &double_zombie_fd_registry_listener, NULL); /* Gets the registry */ wl_display_roundtrip(c->wl_display); /* One more so server can respond to conjoin+destroy */ wl_display_roundtrip(c->wl_display); /* And finally push out our last fd_passer.destroy */ wl_display_roundtrip(c->wl_display); wl_registry_destroy(registry); client_disconnect_nocheck(c); } TEST(zombie_fd_errant_consumption) { struct display *d; struct wl_global *g; d = display_create(); g = wl_global_create(d->wl_display, &fd_passer_interface, 2, d, bind_fd_passer); client_create_noarg(d, double_zombie_client); display_run(d); wl_global_destroy(g); display_destroy(d); } static void registry_bind_interface_mismatch_handle_global(void *data, struct wl_registry *registry, uint32_t id, const char *intf, uint32_t ver) { uint32_t *seat_id_ptr = data; if (strcmp(intf, wl_seat_interface.name) == 0) { *seat_id_ptr = id; } } static const struct wl_registry_listener bind_interface_mismatch_registry_listener = { registry_bind_interface_mismatch_handle_global, NULL }; static void registry_bind_interface_mismatch_client(void *data) { struct client *c = client_connect(); struct wl_registry *registry; uint32_t seat_id = 0; void *ptr; int ret; registry = wl_display_get_registry(c->wl_display); wl_registry_add_listener(registry, &bind_interface_mismatch_registry_listener, &seat_id); ret = wl_display_roundtrip(c->wl_display); assert(ret >= 0); assert(seat_id != 0); /* Bind with a different interface */ ptr = wl_registry_bind(registry, seat_id, &wl_output_interface, 1); ret = wl_display_roundtrip(c->wl_display); assert(ret < 0); check_bind_error(c); wl_proxy_destroy((struct wl_proxy *) ptr); wl_registry_destroy(registry); client_disconnect_nocheck(c); } TEST(registry_bind_interface_mismatch) { struct display *d; struct wl_global *seat_global; d = display_create(); seat_global = wl_global_create(d->wl_display, &wl_seat_interface, 1, NULL, NULL); client_create_noarg(d, registry_bind_interface_mismatch_client); display_run(d); wl_global_destroy(seat_global); display_destroy(d); } static void send_overflow_client(void *data) { struct client *c = client_connect(); int i, err = 0; int *pipes = data; char tmp = '\0'; int sock, optval = 16384; /* By default, client buffers are now unbounded, set a limit to cause * an overflow, otherwise the client buffers will grow indefinitely. */ wl_display_set_max_buffer_size(c->wl_display, 4096); /* Limit the send buffer size for the display socket to guarantee * that the test will cause an overflow. */ sock = wl_display_get_fd(c->wl_display); assert(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &optval, sizeof(optval)) == 0); /* Request to break out of 'display_run' in the main process */ assert(stop_display(c, 1) >= 0); /* On Linux, the actual socket data + metadata space is twice `optval`; * since each noop request requires 8 bytes, the buffer should overflow * within <=4096 iterations. */ for (i = 0; i < 1000000; i++) { noop_request(c); fprintf(stderr, "Send loop %i\n", i); err = wl_display_get_error(c->wl_display); if (err) break; } /* Do not close the pipe file descriptors afterwards, because the leak * check verifies that the initial/final FD counts are the same */ assert(write(pipes[1], &tmp, sizeof(tmp)) == (ssize_t)sizeof(tmp)); /* Expect an error - ring_buffer_ensure_space() returns E2BIG */ fprintf(stderr, "Send loop failed on try %d, err = %d, %s\n", i, err, strerror(err)); assert(err == EAGAIN || err == E2BIG); client_disconnect_nocheck(c); } TEST(send_overflow_disconnection) { struct display *d; char tmp; int rpipe[2]; ssize_t ret; assert(pipe(rpipe) != -1); d = display_create(); (void) client_create(d, send_overflow_client, &rpipe); /* Close write end of the pipe, so that the later read() call gets * interrupted if the client dies */ close(rpipe[1]); /* Run the display until the client sends a `stop_display`, then * send a resume message but don't actually look at new messages */ display_run(d); display_post_resume_events(d); wl_display_flush_clients(d->wl_display); /* Wait until all noop requests have been sent (read returns 1), or * until client process aborts (read returns 0) */ do { ret = read(rpipe[0], &tmp, sizeof(tmp)); } while (ret == -1 && errno == EINTR); assert(ret != -1); close(rpipe[0]); /* For a clean shutdown */ display_run(d); display_destroy(d); } static void registry_global_remove_before_handle_global(void *data, struct wl_registry *registry, uint32_t id, const char *intf, uint32_t ver) { uint32_t *id_ptr = data; if (strcmp(intf, wl_seat_interface.name) == 0) { assert(*id_ptr == 0); *id_ptr = id; } } static void registry_global_remove_before_handle_global_remove(void *data, struct wl_registry *registry, uint32_t id) { uint32_t *id_ptr = data; if (*id_ptr == id) { *id_ptr = 0; } } /* This listener expects a uint32_t user data pointer, sets it to the wl_seat * global ID when receiving a "global" event, and sets it to zero when receiving * a "global_remove" event. */ static const struct wl_registry_listener global_remove_before_registry_listener = { registry_global_remove_before_handle_global, registry_global_remove_before_handle_global_remove, }; static void global_remove_before_client(void *data) { struct client *c = client_connect(); struct wl_registry *registry; uint32_t global_id = 0, saved_global_id; struct wl_seat *seat; int ret; registry = wl_display_get_registry(c->wl_display); wl_registry_add_listener(registry, &global_remove_before_registry_listener, &global_id); ret = wl_display_roundtrip(c->wl_display); assert(ret >= 0); assert(global_id != 0); saved_global_id = global_id; /* Wait for the compositor to remove the global */ assert(stop_display(c, 1) >= 0); /* Check binding still works after the global has been removed. Also * check we get the global_remove event. */ seat = wl_registry_bind(registry, saved_global_id, &wl_seat_interface, 1); ret = wl_display_roundtrip(c->wl_display); assert(ret >= 0); assert(global_id == 0); wl_seat_destroy(seat); wl_registry_destroy(registry); client_disconnect(c); } static void registry_global_remove_after_handle_global(void *data, struct wl_registry *registry, uint32_t id, const char *intf, uint32_t ver) { /* Make sure the global isn't advertised anymore after being removed */ assert(strcmp(intf, wl_seat_interface.name) != 0); } static const struct wl_registry_listener global_remove_after_registry_listener = { registry_global_remove_after_handle_global, NULL, }; static void global_remove_after_client(void *data) { struct client *c = client_connect(); struct wl_registry *registry; uint32_t global_id = 0; int ret; registry = wl_display_get_registry(c->wl_display); wl_registry_add_listener(registry, &global_remove_after_registry_listener, &global_id); ret = wl_display_roundtrip(c->wl_display); assert(ret >= 0); wl_registry_destroy(registry); client_disconnect(c); } TEST(global_remove) { struct display *d; struct wl_global *global; d = display_create(); global = wl_global_create(d->wl_display, &wl_seat_interface, 1, d, bind_seat); /* Create a client before removing the global */ client_create_noarg(d, global_remove_before_client); display_run(d); wl_global_remove(global); /* Create another client after removing the global */ client_create_noarg(d, global_remove_after_client); display_resume(d); wl_global_destroy(global); display_destroy(d); } static void terminate_display(void *arg) { struct wl_display *wl_display = arg; wl_display_terminate(wl_display); } TEST(no_source_terminate) { struct display *d; struct wl_event_loop *loop; d = display_create(); loop = wl_display_get_event_loop(d->wl_display); wl_event_loop_add_idle(loop, terminate_display, d->wl_display); display_run(d); display_destroy(d); } wayland-1.23.1/tests/enum-validator-test.c000066400000000000000000000020061466237767300204720ustar00rootroot00000000000000#include #include "data/small-server-core.h" int main(int argc, char *argv[]) { assert(intf_A_foo_is_valid(INTF_A_FOO_FIRST, 1)); assert(intf_A_foo_is_valid(INTF_A_FOO_FIRST, 2)); assert(!intf_A_foo_is_valid(INTF_A_FOO_THIRD, 1)); assert(intf_A_foo_is_valid(INTF_A_FOO_THIRD, 2)); assert(intf_A_foo_is_valid(INTF_A_FOO_NEGATIVE, 2)); assert(intf_A_bar_is_valid(INTF_A_BAR_FIRST, 1)); assert(intf_A_bar_is_valid(INTF_A_BAR_FIRST, 2)); assert(intf_A_bar_is_valid(INTF_A_BAR_SECOND, 1)); assert(intf_A_bar_is_valid(INTF_A_BAR_SECOND, 2)); assert(intf_A_bar_is_valid(INTF_A_BAR_FIRST | INTF_A_BAR_SECOND, 1)); assert(intf_A_bar_is_valid(INTF_A_BAR_FIRST | INTF_A_BAR_SECOND, 2)); assert(!intf_A_bar_is_valid(INTF_A_BAR_THIRD, 1)); assert(!intf_A_bar_is_valid(INTF_A_BAR_FIRST | INTF_A_BAR_THIRD, 1)); assert(intf_A_bar_is_valid(INTF_A_BAR_THIRD, 2)); assert(intf_A_bar_is_valid(INTF_A_BAR_FIRST | INTF_A_BAR_THIRD, 2)); assert(!intf_A_bar_is_valid(0xFF, 1)); assert(!intf_A_bar_is_valid(0xFF, 2)); } wayland-1.23.1/tests/event-loop-test.c000066400000000000000000000356151466237767300176470ustar00rootroot00000000000000/* * Copyright © 2012 Intel Corporation * Copyright © 2012 Jason Ekstrand * * 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. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "wayland-private.h" #include "wayland-server.h" #include "test-runner.h" static int fd_dispatch(int fd, uint32_t mask, void *data) { int *p = data; assert(mask == 0); ++(*p); return 0; } TEST(event_loop_post_dispatch_check) { struct wl_event_loop *loop = wl_event_loop_create(); struct wl_event_source *source; int dispatch_ran = 0; int p[2]; assert(loop); assert(pipe(p) == 0); source = wl_event_loop_add_fd(loop, p[0], WL_EVENT_READABLE, fd_dispatch, &dispatch_ran); assert(source); wl_event_source_check(source); wl_event_loop_dispatch(loop, 0); assert(dispatch_ran == 1); assert(close(p[0]) == 0); assert(close(p[1]) == 0); wl_event_source_remove(source); wl_event_loop_destroy(loop); } struct free_source_context { struct wl_event_source *source1, *source2; int p1[2], p2[2]; int count; }; static int free_source_callback(int fd, uint32_t mask, void *data) { struct free_source_context *context = data; context->count++; /* Remove other source */ if (fd == context->p1[0]) { wl_event_source_remove(context->source2); context->source2 = NULL; } else if (fd == context->p2[0]) { wl_event_source_remove(context->source1); context->source1 = NULL; } else { assert(0); } return 1; } TEST(event_loop_free_source_with_data) { struct wl_event_loop *loop = wl_event_loop_create(); struct free_source_context context; int data; /* This test is a little tricky to get right, since we don't * have any guarantee from the event loop (ie epoll) on the * order of which it reports events. We want to have one * source free the other, but we don't know which one is going * to run first. So we add two fd sources with a callback * that frees the other source and check that only one of them * run (and that we don't crash, of course). */ assert(loop); context.count = 0; assert(pipe(context.p1) == 0); assert(pipe(context.p2) == 0); context.source1 = wl_event_loop_add_fd(loop, context.p1[0], WL_EVENT_READABLE, free_source_callback, &context); assert(context.source1); context.source2 = wl_event_loop_add_fd(loop, context.p2[0], WL_EVENT_READABLE, free_source_callback, &context); assert(context.source2); data = 5; assert(write(context.p1[1], &data, sizeof data) == sizeof data); assert(write(context.p2[1], &data, sizeof data) == sizeof data); wl_event_loop_dispatch(loop, 0); assert(context.count == 1); if (context.source1) wl_event_source_remove(context.source1); if (context.source2) wl_event_source_remove(context.source2); wl_event_loop_destroy(loop); assert(close(context.p1[0]) == 0); assert(close(context.p1[1]) == 0); assert(close(context.p2[0]) == 0); assert(close(context.p2[1]) == 0); } static int signal_callback(int signal_number, void *data) { int *got_it = data; assert(signal_number == SIGUSR1); ++(*got_it); return 1; } TEST(event_loop_signal) { struct wl_event_loop *loop = wl_event_loop_create(); struct wl_event_source *source; int got_it = 0; source = wl_event_loop_add_signal(loop, SIGUSR1, signal_callback, &got_it); assert(source); assert(wl_event_loop_dispatch(loop, 0) == 0); assert(!got_it); assert(kill(getpid(), SIGUSR1) == 0); /* * On Linux the signal will be immediately visible in the epoll_wait() * call. However, on FreeBSD we may need a small delay between kill() * call and the signal being visible to the kevent() call. This * sometimes happens when the signal processing and kevent processing * runs on different CPUs, so becomes more likely when the system is * under load (e.g. running all tests in parallel). * See https://github.com/jiixyj/epoll-shim/pull/32 * Passing 1ms as the timeout appears to avoid this race condition in * all cases tested so far, but to be safe we use 1000ms which should * be enough time even on a really slow (or emulated) system. */ assert(wl_event_loop_dispatch(loop, 1000) == 0); assert(got_it == 1); wl_event_source_remove(source); wl_event_loop_destroy(loop); } TEST(event_loop_multiple_same_signals) { struct wl_event_loop *loop = wl_event_loop_create(); struct wl_event_source *s1, *s2; int calls_no = 0; int i; s1 = wl_event_loop_add_signal(loop, SIGUSR1, signal_callback, &calls_no); assert(s1); s2 = wl_event_loop_add_signal(loop, SIGUSR1, signal_callback, &calls_no); assert(s2); assert(wl_event_loop_dispatch(loop, 0) == 0); assert(!calls_no); /* Try it more times */ for (i = 0; i < 5; ++i) { calls_no = 0; assert(kill(getpid(), SIGUSR1) == 0); /* * We need a non-zero timeout here to allow the test to pass * on non-Linux systems (see comment in event_loop_signal). */ assert(wl_event_loop_dispatch(loop, 1000) == 0); assert(calls_no == 2); } wl_event_source_remove(s1); /* Try it again with one source */ calls_no = 0; assert(kill(getpid(), SIGUSR1) == 0); /* * We need a non-zero timeout here to allow the test to pass * on non-Linux systems (see comment in event_loop_signal). */ assert(wl_event_loop_dispatch(loop, 1000) == 0); assert(calls_no == 1); wl_event_source_remove(s2); wl_event_loop_destroy(loop); } static int timer_callback(void *data) { int *got_it = data; ++(*got_it); return 1; } TEST(event_loop_timer) { struct wl_event_loop *loop = wl_event_loop_create(); struct wl_event_source *source1, *source2; int got_it = 0; source1 = wl_event_loop_add_timer(loop, timer_callback, &got_it); assert(source1); wl_event_source_timer_update(source1, 20); source2 = wl_event_loop_add_timer(loop, timer_callback, &got_it); assert(source2); wl_event_source_timer_update(source2, 100); /* Check that the timer marked for 20 msec from now fires within 30 * msec, and that the timer marked for 100 msec is expected to fire * within an additional 90 msec. (Some extra wait time is provided to * account for reasonable code execution / thread preemption delays.) */ wl_event_loop_dispatch(loop, 0); assert(got_it == 0); wl_event_loop_dispatch(loop, 30); assert(got_it == 1); wl_event_loop_dispatch(loop, 0); assert(got_it == 1); wl_event_loop_dispatch(loop, 90); assert(got_it == 2); wl_event_source_remove(source1); wl_event_source_remove(source2); wl_event_loop_destroy(loop); } #define MSEC_TO_USEC(msec) ((msec) * 1000) struct timer_update_context { struct wl_event_source *source1, *source2; int count; }; static int timer_update_callback_1(void *data) { struct timer_update_context *context = data; context->count++; wl_event_source_timer_update(context->source2, 1000); return 1; } static int timer_update_callback_2(void *data) { struct timer_update_context *context = data; context->count++; wl_event_source_timer_update(context->source1, 1000); return 1; } TEST(event_loop_timer_updates) { struct wl_event_loop *loop = wl_event_loop_create(); struct timer_update_context context; struct timeval start_time, end_time, interval; /* Create two timers that should expire at the same time (after 10ms). * The first timer to receive its expiry callback updates the other timer * with a much larger timeout (1s). This highlights a bug where * wl_event_source_timer_dispatch would block for this larger timeout * when reading from the timer fd, before calling the second timer's * callback. */ context.source1 = wl_event_loop_add_timer(loop, timer_update_callback_1, &context); assert(context.source1); assert(wl_event_source_timer_update(context.source1, 10) == 0); context.source2 = wl_event_loop_add_timer(loop, timer_update_callback_2, &context); assert(context.source2); assert(wl_event_source_timer_update(context.source2, 10) == 0); context.count = 0; /* Since calling the functions between source2's update and * wl_event_loop_dispatch() takes some time, it may happen * that only one timer expires until we call epoll_wait. * This naturally means that only one source is dispatched * and the test fails. To fix that, sleep 15 ms before * calling wl_event_loop_dispatch(). That should be enough * for the second timer to expire. * * https://bugs.freedesktop.org/show_bug.cgi?id=80594 */ usleep(MSEC_TO_USEC(15)); gettimeofday(&start_time, NULL); wl_event_loop_dispatch(loop, 20); gettimeofday(&end_time, NULL); assert(context.count == 2); /* Dispatching the events should not have taken much more than 20ms, * since this is the timeout passed to wl_event_loop_dispatch. If it * blocked, then it will have taken over 1s. * Of course, it could take over 1s anyway on a very slow or heavily * loaded system, so this test isn't 100% perfect. */ timersub(&end_time, &start_time, &interval); assert(interval.tv_sec < 1); wl_event_source_remove(context.source1); wl_event_source_remove(context.source2); wl_event_loop_destroy(loop); } struct timer_order_data { struct wl_event_source *source; int *last_number; int number; }; static int timer_order_callback(void *data) { struct timer_order_data *tod = data; /* Check that the timers have the correct sequence */ assert(tod->number == *tod->last_number + 2); *tod->last_number = tod->number; return 0; } TEST(event_loop_timer_order) { struct wl_event_loop *loop = wl_event_loop_create(); struct timer_order_data order[20]; int i, j; int last = -1; /* Configure a set of timers so that only timers 1, 3, 5, ..., 19 * (in that order) will be dispatched when the event loop is run */ for (i = 0; i < 20; i++) { order[i].number = i; order[i].last_number = &last; order[i].source = wl_event_loop_add_timer(loop, timer_order_callback, &order[i]); assert(order[i].source); assert(wl_event_source_timer_update(order[i].source, 10) == 0); } for (i = 0; i < 20; i++) { /* Permute the order in which timers are updated, so as to * more exhaustively test the underlying priority queue code */ j = ((i + 3) * 17) % 20; assert(wl_event_source_timer_update(order[j].source, j) == 0); } for (i = 0; i < 20; i += 2) { assert(wl_event_source_timer_update(order[i].source, 0) == 0); } /* Wait until all timers are due */ usleep(MSEC_TO_USEC(21)); wl_event_loop_dispatch(loop, 0); assert(last == 19); for (i = 0; i < 20; i++) { wl_event_source_remove(order[i].source); } wl_event_loop_destroy(loop); } struct timer_cancel_context { struct wl_event_source *timers[4]; struct timer_cancel_context *back_refs[4]; int order[4]; int called, first; }; static int timer_cancel_callback(void *data) { struct timer_cancel_context **context_ref = data; struct timer_cancel_context *context = *context_ref; int i = (int)(context_ref - context->back_refs); context->called++; context->order[i] = context->called; if (context->called == 1) { context->first = i; /* Removing a timer always prevents its callback from * being called ... */ wl_event_source_remove(context->timers[(i + 1) % 4]); /* ... but disarming or rescheduling a timer does not, * (in the case where the modified timers had already expired * as of when `wl_event_loop_dispatch` was called.) */ assert(wl_event_source_timer_update(context->timers[(i + 2) % 4], 0) == 0); assert(wl_event_source_timer_update(context->timers[(i + 3) % 4], 2000000000) == 0); } return 0; } TEST(event_loop_timer_cancellation) { struct wl_event_loop *loop = wl_event_loop_create(); struct timer_cancel_context context; int i; memset(&context, 0, sizeof(context)); /* Test that when multiple timers are dispatched in a single call * of `wl_event_loop_dispatch`, that having some timers run code * to modify the other timers only actually prevents the other timers * from running their callbacks when the those timers are removed, not * when they are disarmed or rescheduled. */ for (i = 0; i < 4; i++) { context.back_refs[i] = &context; context.timers[i] = wl_event_loop_add_timer(loop, timer_cancel_callback, &context.back_refs[i]); assert(context.timers[i]); assert(wl_event_source_timer_update(context.timers[i], 1) == 0); } usleep(MSEC_TO_USEC(2)); assert(wl_event_loop_dispatch(loop, 0) == 0); /* Tracking which timer was first makes this test independent of the * actual timer dispatch order, which is not guaranteed by the docs */ assert(context.order[context.first] == 1); assert(context.order[(context.first + 1) % 4] == 0); assert(context.order[(context.first + 2) % 4] > 1); assert(context.order[(context.first + 3) % 4] > 1); wl_event_source_remove(context.timers[context.first]); wl_event_source_remove(context.timers[(context.first + 2) % 4]); wl_event_source_remove(context.timers[(context.first + 3) % 4]); wl_event_loop_destroy(loop); } struct event_loop_destroy_listener { struct wl_listener listener; int done; }; static void event_loop_destroy_notify(struct wl_listener *l, void *data) { struct event_loop_destroy_listener *listener = wl_container_of(l, listener, listener); listener->done = 1; } TEST(event_loop_destroy) { struct wl_event_loop *loop; struct wl_display * display; struct event_loop_destroy_listener a, b; loop = wl_event_loop_create(); assert(loop); a.listener.notify = &event_loop_destroy_notify; a.done = 0; wl_event_loop_add_destroy_listener(loop, &a.listener); assert(wl_event_loop_get_destroy_listener(loop, event_loop_destroy_notify) == &a.listener); b.listener.notify = &event_loop_destroy_notify; b.done = 0; wl_event_loop_add_destroy_listener(loop, &b.listener); wl_list_remove(&a.listener.link); wl_event_loop_destroy(loop); assert(!a.done); assert(b.done); /* Test to make sure it gets fired on display destruction */ display = wl_display_create(); assert(display); loop = wl_display_get_event_loop(display); assert(loop); a.done = 0; wl_event_loop_add_destroy_listener(loop, &a.listener); wl_display_destroy(display); assert(a.done); } wayland-1.23.1/tests/exec-fd-leak-checker.c000066400000000000000000000040231466237767300204160ustar00rootroot00000000000000/* * Copyright © 2012 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 #include #include #include #include "test-runner.h" static int parse_count(const char *str, int *value) { char *end; long v; errno = 0; v = strtol(str, &end, 10); if ((errno == ERANGE && (v == LONG_MAX || v == LONG_MIN)) || (errno != 0 && v == 0) || (end == str) || (*end != '\0')) { return -1; } if (v < 0 || v > INT_MAX) { return -1; } *value = v; return 0; } int main(int argc, char *argv[]) { int expected; if (argc != 2) goto help_out; if (parse_count(argv[1], &expected) < 0) goto help_out; if (count_open_fds() == expected) return EXIT_SUCCESS; else return EXIT_FAILURE; help_out: fprintf(stderr, "Usage: %s N\n" "where N is the expected number of open file descriptors.\n" "This program exits with a failure if the number " "does not match exactly.\n", argv[0]); return EXIT_FAILURE; } wayland-1.23.1/tests/fixed-test.c000066400000000000000000000047201466237767300166470ustar00rootroot00000000000000/* * Copyright © 2012 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. */ #define _GNU_SOURCE #include #include #include #include "wayland-private.h" #include "test-runner.h" TEST(fixed_double_conversions) { wl_fixed_t f; double d; d = 62.125; f = wl_fixed_from_double(d); fprintf(stderr, "double %lf to fixed %x\n", d, f); assert(f == 0x3e20); d = -1200.625; f = wl_fixed_from_double(d); fprintf(stderr, "double %lf to fixed %x\n", d, f); assert(f == -0x4b0a0); f = random(); d = wl_fixed_to_double(f); fprintf(stderr, "fixed %x to double %lf\n", f, d); assert(d == f / 256.0); f = 0x012030; d = wl_fixed_to_double(f); fprintf(stderr, "fixed %x to double %lf\n", f, d); assert(d == 288.1875); f = 0x70000000; d = wl_fixed_to_double(f); fprintf(stderr, "fixed %x to double %lf\n", f, d); assert(d == f / 256); f = -0x012030; d = wl_fixed_to_double(f); fprintf(stderr, "fixed %x to double %lf\n", f, d); assert(d == -288.1875); f = 0x80000000; d = wl_fixed_to_double(f); fprintf(stderr, "fixed %x to double %lf\n", f, d); assert(d == f / 256); } TEST(fixed_int_conversions) { wl_fixed_t f; int i; i = 62; f = wl_fixed_from_int(i); assert(f == 62 * 256); i = -2080; f = wl_fixed_from_int(i); assert(f == -2080 * 256); f = 0x277013; i = wl_fixed_to_int(f); assert(i == 0x2770); f = -0x5044; i = wl_fixed_to_int(f); assert(i == -0x50); } wayland-1.23.1/tests/headers-protocol-core-test.c000066400000000000000000000032521466237767300217470ustar00rootroot00000000000000/* * Copyright © 2015 Giulio Camuffo * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "wayland-client-protocol-core.h" #include "wayland-server-protocol-core.h" #ifndef WAYLAND_CLIENT_CORE_H #error including wayland-client-protocol-core.h did not include wayland-client-core.h! #endif #ifndef WAYLAND_SERVER_CORE_H #error including wayland-server-protocol-core.h did not include wayland-server-core.h! #endif #ifdef WAYLAND_CLIENT_H #error including wayland-client-protocol-core.h included wayland-client.h! #endif #ifdef WAYLAND_SERVER_H #error including wayland-server-protocol-core.h included wayland-server.h! #endif wayland-1.23.1/tests/headers-protocol-test.c000066400000000000000000000026551466237767300210270ustar00rootroot00000000000000/* * Copyright © 2015 Giulio Camuffo * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "wayland-client-protocol.h" #include "wayland-server-protocol.h" #ifndef WAYLAND_CLIENT_H #error including wayland-client-protocol.h did not include wayland-client.h! #endif #ifndef WAYLAND_SERVER_H #error including wayland-server-protocol.h did not include wayland-server.h! #endif wayland-1.23.1/tests/headers-test.c000066400000000000000000000036031466237767300171620ustar00rootroot00000000000000/* * Copyright © 2015 Giulio Camuffo * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "wayland-client-core.h" #include "wayland-server-core.h" #ifdef WL_DISPLAY_SYNC #error including wayland-client-core.h imported protocol symbols! #endif #ifdef WL_DISPLAY_ERROR #error including wayland-server-core.h imported protocol symbols! #endif #ifdef WAYLAND_CLIENT_H #error including wayland-client-core.h included the non-core header! #endif #ifdef WAYLAND_SERVER_H #error including wayland-server-core.h included the non-core header! #endif #include "wayland-client.h" #include "wayland-server.h" #ifndef WL_DISPLAY_SYNC #error including wayland-client.h did not import protocol symbols! #endif #ifndef WL_DISPLAY_ERROR #error including wayland-server.h did not import protocol symbols! #endif int main(int argc, char **argv) { return 0; } wayland-1.23.1/tests/interface-test.c000066400000000000000000000034361466237767300175130ustar00rootroot00000000000000/* * Copyright © 2016 Yong Bakos * * 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 #include "wayland-client.h" #include "wayland-private.h" #include "test-runner.h" TEST(interface_equal) { const struct wl_interface fake = { "fake", 1, 0, NULL, 0, NULL }; const struct wl_interface fake_registry = { "wl_registry", 1, 0, NULL, 0, NULL }; const struct wl_interface copy = wl_registry_interface; assert(&wl_registry_interface != ©); assert(wl_interface_equal(&wl_registry_interface, &wl_registry_interface)); assert(wl_interface_equal(&wl_registry_interface, ©)); assert(wl_interface_equal(&wl_registry_interface, &fake_registry)); assert(!wl_interface_equal(&wl_registry_interface, &fake)); } wayland-1.23.1/tests/list-test.c000066400000000000000000000103511466237767300165200ustar00rootroot00000000000000/* * Copyright © 2012 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 #include #include #include "wayland-private.h" #include "test-runner.h" TEST(list_init) { struct wl_list list; wl_list_init(&list); assert(list.next == &list); assert(list.prev == &list); assert(wl_list_empty(&list)); } struct element { int i; struct wl_list link; }; TEST(list_insert) { struct wl_list list; struct element e; wl_list_init(&list); wl_list_insert(&list, &e.link); assert(list.next == &e.link); assert(list.prev == &e.link); assert(e.link.next == &list); assert(e.link.prev == &list); } TEST(list_length) { struct wl_list list; struct element e; wl_list_init(&list); assert(wl_list_length(&list) == 0); wl_list_insert(&list, &e.link); assert(wl_list_length(&list) == 1); wl_list_remove(&e.link); assert(wl_list_length(&list) == 0); } TEST(list_iterator) { struct wl_list list; struct element e1, e2, e3, e4, *e; int reference[] = { 708090, 102030, 5588, 12 }; unsigned int i; e1.i = 708090; e2.i = 102030; e3.i = 5588; e4.i = 12; wl_list_init(&list); wl_list_insert(list.prev, &e1.link); wl_list_insert(list.prev, &e2.link); wl_list_insert(list.prev, &e3.link); wl_list_insert(list.prev, &e4.link); i = 0; wl_list_for_each(e, &list, link) { assert(i < ARRAY_LENGTH(reference)); assert(e->i == reference[i]); i++; } assert(i == ARRAY_LENGTH(reference)); i = 0; wl_list_for_each_reverse(e, &list, link) { assert(i < ARRAY_LENGTH(reference)); assert(e->i == reference[ARRAY_LENGTH(reference) - i - 1]); i++; } assert(i == ARRAY_LENGTH(reference)); } static int validate_list(struct wl_list *list, int *reference, int length) { struct element *e; int i; i = 0; wl_list_for_each(e, list, link) { if (i >= length) return 0; if (e->i != reference[i]) return 0; i++; } if (i != length) return 0; return 1; } TEST(list_remove) { struct wl_list list; struct element e1, e2, e3; int reference1[] = { 17, 8888, 1000 }, reference2[] = { 17, 1000 }; e1.i = 17; e2.i = 8888; e3.i = 1000; wl_list_init(&list); wl_list_insert(&list, &e1.link); wl_list_insert(list.prev, &e2.link); wl_list_insert(list.prev, &e3.link); assert(validate_list(&list, reference1, ARRAY_LENGTH(reference1))); wl_list_remove(&e2.link); assert(validate_list(&list, reference2, ARRAY_LENGTH(reference2))); } TEST(list_insert_list) { struct wl_list list, other; struct element e1, e2, e3, e4, e5, e6; int reference1[] = { 17, 8888, 1000 }; int reference2[] = { 76543, 1, -500 }; int reference3[] = { 17, 76543, 1, -500, 8888, 1000 }; e1.i = 17; e2.i = 8888; e3.i = 1000; wl_list_init(&list); wl_list_insert(&list, &e1.link); wl_list_insert(list.prev, &e2.link); wl_list_insert(list.prev, &e3.link); assert(validate_list(&list, reference1, ARRAY_LENGTH(reference1))); e4.i = 76543; e5.i = 1; e6.i = -500; wl_list_init(&other); wl_list_insert(&other, &e4.link); wl_list_insert(other.prev, &e5.link); wl_list_insert(other.prev, &e6.link); assert(validate_list(&other, reference2, ARRAY_LENGTH(reference2))); wl_list_insert_list(list.next, &other); assert(validate_list(&list, reference3, ARRAY_LENGTH(reference3))); } wayland-1.23.1/tests/map-test.c000066400000000000000000000073421466237767300163300ustar00rootroot00000000000000/* * Copyright © 2012 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 #include #include #include #include "wayland-private.h" #include "test-runner.h" TEST(map_insert_new) { struct wl_map map; uint32_t i, j, k, a, b, c; wl_map_init(&map, WL_MAP_SERVER_SIDE); i = wl_map_insert_new(&map, 0, &a); j = wl_map_insert_new(&map, 0, &b); k = wl_map_insert_new(&map, 0, &c); assert(i == WL_SERVER_ID_START); assert(j == WL_SERVER_ID_START + 1); assert(k == WL_SERVER_ID_START + 2); assert(wl_map_lookup(&map, i) == &a); assert(wl_map_lookup(&map, j) == &b); assert(wl_map_lookup(&map, k) == &c); wl_map_release(&map); wl_map_init(&map, WL_MAP_CLIENT_SIDE); i = wl_map_insert_new(&map, 0, &a); assert(i == 0); assert(wl_map_lookup(&map, i) == &a); wl_map_release(&map); } TEST(map_insert_at) { struct wl_map map; uint32_t a, b, c; wl_map_init(&map, WL_MAP_CLIENT_SIDE); assert(wl_map_insert_at(&map, 0, WL_SERVER_ID_START, &a) == 0); assert(wl_map_insert_at(&map, 0, WL_SERVER_ID_START + 3, &b) == -1); assert(wl_map_insert_at(&map, 0, WL_SERVER_ID_START + 1, &c) == 0); assert(wl_map_lookup(&map, WL_SERVER_ID_START) == &a); assert(wl_map_lookup(&map, WL_SERVER_ID_START + 1) == &c); wl_map_release(&map); } TEST(map_remove) { struct wl_map map; uint32_t i, j, k, l, a, b, c, d; wl_map_init(&map, WL_MAP_SERVER_SIDE); i = wl_map_insert_new(&map, 0, &a); j = wl_map_insert_new(&map, 0, &b); k = wl_map_insert_new(&map, 0, &c); assert(i == WL_SERVER_ID_START); assert(j == WL_SERVER_ID_START + 1); assert(k == WL_SERVER_ID_START + 2); assert(wl_map_lookup(&map, i) == &a); assert(wl_map_lookup(&map, j) == &b); assert(wl_map_lookup(&map, k) == &c); wl_map_remove(&map, j); assert(wl_map_lookup(&map, j) == NULL); /* Verify that we insert d at the hole left by removing b */ l = wl_map_insert_new(&map, 0, &d); assert(l == WL_SERVER_ID_START + 1); assert(wl_map_lookup(&map, l) == &d); wl_map_release(&map); } TEST(map_flags) { struct wl_map map; uint32_t i, j, a, b; wl_map_init(&map, WL_MAP_SERVER_SIDE); i = wl_map_insert_new(&map, 0, &a); j = wl_map_insert_new(&map, 1, &b); assert(i == WL_SERVER_ID_START); assert(j == WL_SERVER_ID_START + 1); assert(wl_map_lookup(&map, i) == &a); assert(wl_map_lookup(&map, j) == &b); assert(wl_map_lookup_flags(&map, i) == 0); assert(wl_map_lookup_flags(&map, j) == 1); wl_map_release(&map); } static enum wl_iterator_result never_run(void *element, void *data, uint32_t flags) { assert(0); } TEST(map_iter_empty) { struct wl_map map; wl_map_init(&map, WL_MAP_SERVER_SIDE); wl_map_for_each(&map, never_run, NULL); wl_map_release(&map); } wayland-1.23.1/tests/meson.build000066400000000000000000000100551466237767300165670ustar00rootroot00000000000000if not get_option('libraries') error('-Dtests=true requires -Dlibraries=true') endif test_runner = static_library( 'test-runner', sources: [ 'test-runner.c', 'test-helpers.c', 'test-compositor.c' ], include_directories: [ root_inc, src_inc ], dependencies: [ cc.find_library('dl', required: false), dependency('threads'), epoll_dep, ffi_dep, wayland_util_dep, wayland_private_dep, wayland_client_dep, wayland_server_dep ] ) test_runner_dep = declare_dependency( link_with: test_runner, include_directories: [ src_inc ], dependencies: [ dependency('threads'), cc.find_library('dl', required: false) ] ) tests_protocol_xml = files('../protocol/tests.xml') tests_server_protocol_h = custom_target( 'test server protocol header', command: [ wayland_scanner_for_build, '-s', 'server-header', '@INPUT@', '@OUTPUT@' ], input: tests_protocol_xml, output: 'tests-server-protocol.h' ) tests_client_protocol_c = custom_target( 'test client protocol header', command: [ wayland_scanner_for_build, '-s', 'client-header', '@INPUT@', '@OUTPUT@' ], input: tests_protocol_xml, output: 'tests-client-protocol.h' ) tests_protocol_c = custom_target( 'test protocol source', command: [ wayland_scanner_for_build, '-s', 'public-code', '@INPUT@', '@OUTPUT@' ], input: tests_protocol_xml, output: 'tests-protocol.c' ) executable( 'exec-fd-leak-checker', 'exec-fd-leak-checker.c', dependencies: test_runner_dep ) if add_languages('cpp', native: false) test( 'cpp-compile-test', executable( 'cpp-compile-test', 'cpp-compile-test.cpp', wayland_server_protocol_h, include_directories: src_inc ) ) endif sed_path = find_program('sed').full_path() if get_option('scanner') scanner_test_env = [ 'TEST_DATA_DIR=@0@/data'.format(meson.current_source_dir()), 'TEST_OUTPUT_DIR=@0@/output'.format(meson.current_build_dir()), 'SED=@0@'.format(sed_path), 'WAYLAND_SCANNER=@0@'.format(wayland_scanner.full_path()), ] test( 'scanner-test', find_program('scanner-test.sh'), env: scanner_test_env, ) run_target( 'gen-scanner-test', command: find_program('scanner-test-gen.sh'), env: scanner_test_env, ) endif tests = { 'array-test': [], 'client-test': [ wayland_server_protocol_h ], 'display-test': [ wayland_client_protocol_h, wayland_server_protocol_h, tests_server_protocol_h, tests_client_protocol_c, tests_protocol_c, ], 'connection-test': [ wayland_client_protocol_h, wayland_server_protocol_h, ], 'event-loop-test': [ wayland_server_protocol_h ], 'fixed-test': [], 'interface-test': [ wayland_client_protocol_h ], 'list-test': [], 'map-test': [], 'sanity-test' : [ wayland_client_protocol_h, wayland_server_protocol_h, ], 'socket-test': [ wayland_client_protocol_h, wayland_server_protocol_h, ], 'queue-test': [ wayland_client_protocol_h, wayland_server_protocol_h, ], 'signal-test': [ wayland_server_protocol_h ], 'newsignal-test': [ # wayland-server.c is needed here to access wl_priv_* functions files('../src/wayland-server.c'), wayland_server_protocol_h, ], 'resources-test': [ wayland_server_protocol_h ], 'message-test': [ wayland_client_protocol_h, wayland_server_protocol_h, ], 'compositor-introspection-test': [ wayland_client_protocol_h, wayland_server_protocol_h, ], 'protocol-logger-test': [ wayland_client_protocol_h, wayland_server_protocol_h, ], 'headers-test': [ wayland_client_protocol_h, wayland_server_protocol_h, 'headers-protocol-test.c', wayland_client_protocol_core_h, wayland_server_protocol_core_h, 'headers-protocol-core-test.c', ], 'os-wrappers-test': [], 'proxy-test': [ wayland_client_protocol_h, wayland_server_protocol_h, ], 'enum-validator-test': [], } foreach test_name, test_extra_sources: tests test_sources = [ test_name + '.c' ] + test_extra_sources test_deps = [test_runner_dep, epoll_dep] bin = executable(test_name, test_sources, dependencies: test_deps) test( test_name, bin, env: [ 'TEST_SRC_DIR=@0@'.format(meson.current_source_dir()), 'TEST_BUILD_DIR=@0@'.format(meson.current_build_dir()), ], ) endforeach wayland-1.23.1/tests/message-test.c000066400000000000000000000060051466237767300171720ustar00rootroot00000000000000/* * Copyright © 2014 Jonas Ådahl * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include "wayland-client.h" #include "wayland-private.h" #include "wayland-server.h" #include "test-runner.h" TEST(message_version) { unsigned int i; const struct { const struct wl_message *message; int expected_version; } messages[] = { { &wl_pointer_interface.events[WL_POINTER_ENTER], 1 }, { &wl_surface_interface.events[WL_SURFACE_ENTER], 1 }, { &wl_pointer_interface.methods[WL_POINTER_SET_CURSOR], 1 }, { &wl_pointer_interface.methods[WL_POINTER_RELEASE], 3 }, { &wl_surface_interface.methods[WL_SURFACE_DESTROY], 1 }, { &wl_surface_interface.methods[WL_SURFACE_SET_BUFFER_TRANSFORM], 2 }, { &wl_surface_interface.methods[WL_SURFACE_SET_BUFFER_SCALE], 3 }, }; for (i = 0; i < ARRAY_LENGTH(messages); ++i) { assert(wl_message_get_since(messages[i].message) == messages[i].expected_version); } } TEST(message_count_arrays) { unsigned int i; struct wl_message fake_messages[] = { { "empty", "", NULL }, { "non_present", "iufsonh", NULL }, { "leading", "aiufsonh", NULL}, { "trailing", "iufsonha", NULL }, { "middle", "iufasonh", NULL }, { "multiple", "aaiufaasonhaa", NULL }, { "leading_version", "2aaiufaasonhaa", NULL }, { "among_nullables", "iufsa?oa?sah", NULL }, { "all_mixed", "2aiufas?oa?sa", NULL }, }; const struct { const struct wl_message *message; int expected_array_count; } messages[] = { { &wl_pointer_interface.events[WL_POINTER_ENTER], 0 }, { &wl_keyboard_interface.events[WL_KEYBOARD_ENTER], 1 }, { &fake_messages[0], 0 }, { &fake_messages[1], 0 }, { &fake_messages[2], 1 }, { &fake_messages[3], 1 }, { &fake_messages[4], 1 }, { &fake_messages[5], 6 }, { &fake_messages[6], 6 }, { &fake_messages[7], 3 }, { &fake_messages[8], 4 }, }; for (i = 0; i < ARRAY_LENGTH(messages); ++i) { assert(wl_message_count_arrays(messages[i].message) == messages[i].expected_array_count); } } wayland-1.23.1/tests/newsignal-test.c000066400000000000000000000207131466237767300175370ustar00rootroot00000000000000/* * Copyright © 2013 Marek Chalupa * * 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 #include "test-runner.h" #include "wayland-server-private.h" static void signal_notify(struct wl_listener *listener, void *data) { /* only increase counter*/ ++(*((int *) data)); } TEST(signal_init) { struct wl_priv_signal signal; wl_priv_signal_init(&signal); /* Test if listeners' list is initialized */ assert(&signal.listener_list == signal.listener_list.next && "Maybe wl_priv_signal implementation changed?"); assert(signal.listener_list.next == signal.listener_list.prev && "Maybe wl_priv_signal implementation changed?"); } TEST(signal_add_get) { struct wl_priv_signal signal; /* we just need different values of notify */ struct wl_listener l1 = {.notify = (wl_notify_func_t) 0x1}; struct wl_listener l2 = {.notify = (wl_notify_func_t) 0x2}; struct wl_listener l3 = {.notify = (wl_notify_func_t) 0x3}; /* one real, why not */ struct wl_listener l4 = {.notify = signal_notify}; wl_priv_signal_init(&signal); wl_priv_signal_add(&signal, &l1); wl_priv_signal_add(&signal, &l2); wl_priv_signal_add(&signal, &l3); wl_priv_signal_add(&signal, &l4); assert(wl_priv_signal_get(&signal, signal_notify) == &l4); assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x3) == &l3); assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x2) == &l2); assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x1) == &l1); /* get should not be destructive */ assert(wl_priv_signal_get(&signal, signal_notify) == &l4); assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x3) == &l3); assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x2) == &l2); assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x1) == &l1); } TEST(signal_emit_to_one_listener) { int count = 0; int counter; struct wl_priv_signal signal; struct wl_listener l1 = {.notify = signal_notify}; wl_priv_signal_init(&signal); wl_priv_signal_add(&signal, &l1); for (counter = 0; counter < 100; counter++) wl_priv_signal_emit(&signal, &count); assert(counter == count); } TEST(signal_emit_to_more_listeners) { int count = 0; int counter; struct wl_priv_signal signal; struct wl_listener l1 = {.notify = signal_notify}; struct wl_listener l2 = {.notify = signal_notify}; struct wl_listener l3 = {.notify = signal_notify}; wl_priv_signal_init(&signal); wl_priv_signal_add(&signal, &l1); wl_priv_signal_add(&signal, &l2); wl_priv_signal_add(&signal, &l3); for (counter = 0; counter < 100; counter++) wl_priv_signal_emit(&signal, &count); assert(3 * counter == count); } struct signal { struct wl_priv_signal signal; struct wl_listener l1, l2, l3; int count; struct wl_listener *current; }; static void notify_remove(struct wl_listener *l, void *data) { struct signal *sig = data; wl_list_remove(&sig->current->link); wl_list_init(&sig->current->link); sig->count++; } #define INIT \ wl_priv_signal_init(&signal.signal); \ wl_list_init(&signal.l1.link); \ wl_list_init(&signal.l2.link); \ wl_list_init(&signal.l3.link); #define CHECK_EMIT(expected) \ signal.count = 0; \ wl_priv_signal_emit(&signal.signal, &signal); \ assert(signal.count == expected); TEST(signal_remove_listener) { test_set_timeout(4); struct signal signal; signal.l1.notify = notify_remove; signal.l2.notify = notify_remove; signal.l3.notify = notify_remove; INIT wl_priv_signal_add(&signal.signal, &signal.l1); signal.current = &signal.l1; CHECK_EMIT(1) CHECK_EMIT(0) INIT wl_priv_signal_add(&signal.signal, &signal.l1); wl_priv_signal_add(&signal.signal, &signal.l2); CHECK_EMIT(2) CHECK_EMIT(1) INIT wl_priv_signal_add(&signal.signal, &signal.l1); wl_priv_signal_add(&signal.signal, &signal.l2); signal.current = &signal.l2; CHECK_EMIT(1) CHECK_EMIT(1) INIT wl_priv_signal_add(&signal.signal, &signal.l1); wl_priv_signal_add(&signal.signal, &signal.l2); wl_priv_signal_add(&signal.signal, &signal.l3); signal.current = &signal.l1; CHECK_EMIT(3) CHECK_EMIT(2) INIT wl_priv_signal_add(&signal.signal, &signal.l1); wl_priv_signal_add(&signal.signal, &signal.l2); wl_priv_signal_add(&signal.signal, &signal.l3); signal.current = &signal.l2; CHECK_EMIT(2) CHECK_EMIT(2) INIT wl_priv_signal_add(&signal.signal, &signal.l1); wl_priv_signal_add(&signal.signal, &signal.l2); wl_priv_signal_add(&signal.signal, &signal.l3); signal.current = &signal.l3; CHECK_EMIT(2) CHECK_EMIT(2) } static void notify_readd(struct wl_listener *l, void *data) { struct signal *signal = data; if (signal->current) { wl_list_remove(&signal->current->link); wl_list_init(&signal->current->link); wl_priv_signal_add(&signal->signal, signal->current); } signal->count++; } static void notify_empty(struct wl_listener *l, void *data) { struct signal *signal = data; signal->count++; } TEST(signal_readd_listener) { /* Readding a listener is supported, that is it doesn't trigger an * infinite loop or other weird things, but if in a listener you * re-add another listener, that will not be fired in the current * signal emission. */ test_set_timeout(4); struct signal signal; signal.l1.notify = notify_readd; signal.l2.notify = notify_readd; INIT wl_priv_signal_add(&signal.signal, &signal.l1); signal.current = &signal.l1; CHECK_EMIT(1) CHECK_EMIT(1) INIT wl_priv_signal_add(&signal.signal, &signal.l1); signal.current = &signal.l2; CHECK_EMIT(1) signal.current = NULL; CHECK_EMIT(2) INIT wl_priv_signal_add(&signal.signal, &signal.l2); signal.current = &signal.l1; CHECK_EMIT(1) /* l2 was added before l1, so l2 is fired first, which by readding l1 * removes it from the current list that is being fired, so 1 is correct */ CHECK_EMIT(1) INIT wl_priv_signal_add(&signal.signal, &signal.l1); wl_priv_signal_add(&signal.signal, &signal.l2); signal.l1.notify = notify_empty; signal.current = &signal.l2; CHECK_EMIT(2) CHECK_EMIT(2) INIT wl_priv_signal_add(&signal.signal, &signal.l1); wl_priv_signal_add(&signal.signal, &signal.l2); signal.l1.notify = notify_empty; signal.current = &signal.l1; CHECK_EMIT(2) /* same as before, by readding l1 in the first emit, it now is fired * after l2, so on the second emit it is not fired at all. */ CHECK_EMIT(1) } static void notify_addandget(struct wl_listener *l, void *data) { struct signal *signal = data; wl_list_remove(&signal->current->link); wl_list_init(&signal->current->link); wl_priv_signal_add(&signal->signal, signal->current); assert(wl_priv_signal_get(&signal->signal, signal->current->notify) != NULL); signal->count++; } static void notify_get(struct wl_listener *l, void *data) { struct signal *signal = data; assert(wl_priv_signal_get(&signal->signal, signal->current->notify) == signal->current); signal->count++; } TEST(signal_get_listener) { test_set_timeout(4); struct signal signal; signal.l1.notify = notify_addandget; signal.l2.notify = notify_get; INIT wl_priv_signal_add(&signal.signal, &signal.l1); signal.current = &signal.l2; CHECK_EMIT(1) INIT wl_priv_signal_add(&signal.signal, &signal.l2); signal.current = &signal.l2; CHECK_EMIT(1) INIT signal.l1.notify = notify_get; signal.l2.notify = notify_empty; wl_priv_signal_add(&signal.signal, &signal.l1); wl_priv_signal_add(&signal.signal, &signal.l2); CHECK_EMIT(2) INIT signal.l1.notify = notify_empty; signal.l2.notify = notify_get; wl_priv_signal_add(&signal.signal, &signal.l1); wl_priv_signal_add(&signal.signal, &signal.l2); signal.current = &signal.l1; CHECK_EMIT(2) } wayland-1.23.1/tests/os-wrappers-test.c000066400000000000000000000212461466237767300200340ustar00rootroot00000000000000/* * Copyright © 2012 Collabora, Ltd. * Copyright © 2012 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" #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include "wayland-private.h" #include "test-runner.h" #include "wayland-os.h" extern int (*wl_socket)(int domain, int type, int protocol); extern int (*wl_fcntl)(int fildes, int cmd, ...); extern ssize_t (*wl_recvmsg)(int socket, struct msghdr *message, int flags); extern int (*wl_epoll_create1)(int flags); static int fall_back; static int wrapped_calls_socket = 0; static int wrapped_calls_fcntl = 0; static int wrapped_calls_recvmsg = 0; static int wrapped_calls_epoll_create1 = 0; static int socket_wrapper(int domain, int type, int protocol) { wrapped_calls_socket++; if (fall_back && (type & SOCK_CLOEXEC)) { errno = EINVAL; return -1; } return socket(domain, type, protocol); } static int fcntl_wrapper(int fd, int cmd, ...) { va_list ap; int arg; int has_arg; wrapped_calls_fcntl++; if (fall_back && (cmd == F_DUPFD_CLOEXEC)) { errno = EINVAL; return -1; } switch (cmd) { case F_DUPFD_CLOEXEC: case F_DUPFD: case F_SETFD: va_start(ap, cmd); arg = va_arg(ap, int); has_arg = 1; va_end(ap); break; case F_GETFD: has_arg = 0; break; default: fprintf(stderr, "Unexpected fctnl cmd %d\n", cmd); abort(); } if (has_arg) { return fcntl(fd, cmd, arg); } return fcntl(fd, cmd); } static ssize_t recvmsg_wrapper(int sockfd, struct msghdr *msg, int flags) { wrapped_calls_recvmsg++; if (fall_back && (flags & MSG_CMSG_CLOEXEC)) { errno = EINVAL; return -1; } return recvmsg(sockfd, msg, flags); } static int epoll_create1_wrapper(int flags) { wrapped_calls_epoll_create1++; if (fall_back) { wrapped_calls_epoll_create1++; /* epoll_create() not wrapped */ errno = EINVAL; return -1; } return epoll_create1(flags); } static void init_fallbacks(int do_fallbacks) { fall_back = do_fallbacks; wl_fcntl = fcntl_wrapper; wl_socket = socket_wrapper; wl_recvmsg = recvmsg_wrapper; wl_epoll_create1 = epoll_create1_wrapper; } static void do_os_wrappers_socket_cloexec(int n) { int fd; int nr_fds; nr_fds = count_open_fds(); /* simply create a socket that closes on exec */ fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0); assert(fd >= 0); /* * Must have 2 calls if falling back, but must also allow * falling back without a forced fallback. */ assert(wrapped_calls_socket > n); exec_fd_leak_check(nr_fds); } TEST(os_wrappers_socket_cloexec) { /* normal case */ init_fallbacks(0); do_os_wrappers_socket_cloexec(0); } TEST(os_wrappers_socket_cloexec_fallback) { /* forced fallback */ init_fallbacks(1); do_os_wrappers_socket_cloexec(1); } static void do_os_wrappers_dupfd_cloexec(int n) { int base_fd; int fd; int nr_fds; nr_fds = count_open_fds(); base_fd = socket(PF_LOCAL, SOCK_STREAM, 0); assert(base_fd >= 0); fd = wl_os_dupfd_cloexec(base_fd, 13); assert(fd >= 13); close(base_fd); /* * Must have 4 calls if falling back, but must also allow * falling back without a forced fallback. */ assert(wrapped_calls_fcntl > n); exec_fd_leak_check(nr_fds); } TEST(os_wrappers_dupfd_cloexec) { init_fallbacks(0); do_os_wrappers_dupfd_cloexec(0); } TEST(os_wrappers_dupfd_cloexec_fallback) { init_fallbacks(1); do_os_wrappers_dupfd_cloexec(3); } struct marshal_data { struct wl_connection *read_connection; struct wl_connection *write_connection; int s[2]; uint32_t read_mask; uint32_t write_mask; union { int h[3]; } value; int nr_fds_begin; int nr_fds_conn; int wrapped_calls; }; static void setup_marshal_data(struct marshal_data *data) { assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, data->s) == 0); data->read_connection = wl_connection_create(data->s[0], WL_BUFFER_DEFAULT_MAX_SIZE); assert(data->read_connection); data->write_connection = wl_connection_create(data->s[1], WL_BUFFER_DEFAULT_MAX_SIZE); assert(data->write_connection); } static void marshal_demarshal(struct marshal_data *data, void (*func)(void), int size, const char *format, ...) { struct wl_closure *closure; static const int opcode = 4444; static struct wl_object sender = { NULL, NULL, 1234 }; struct wl_message message = { "test", format, NULL }; struct wl_map objects; struct wl_object object = { NULL, &func, 1234 }; va_list ap; uint32_t msg[1] = { 1234 }; va_start(ap, format); closure = wl_closure_vmarshal(&sender, opcode, ap, &message); va_end(ap); assert(closure); assert(wl_closure_send(closure, data->write_connection) == 0); wl_closure_destroy(closure); assert(wl_connection_flush(data->write_connection) == size); assert(wl_connection_read(data->read_connection) == size); wl_map_init(&objects, WL_MAP_SERVER_SIDE); object.id = msg[0]; closure = wl_connection_demarshal(data->read_connection, size, &objects, &message); assert(closure); wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, data); wl_closure_destroy(closure); } static void validate_recvmsg_h(struct marshal_data *data, struct wl_object *object, int fd1, int fd2, int fd3) { struct stat buf1, buf2; assert(fd1 >= 0); assert(fd2 >= 0); assert(fd3 >= 0); assert(fd1 != data->value.h[0]); assert(fd2 != data->value.h[1]); assert(fd3 != data->value.h[2]); assert(fstat(fd3, &buf1) == 0); assert(fstat(data->value.h[2], &buf2) == 0); assert(buf1.st_dev == buf2.st_dev); assert(buf1.st_ino == buf2.st_ino); /* close the original file descriptors */ close(data->value.h[0]); close(data->value.h[1]); close(data->value.h[2]); /* the dup'd (received) fds should still be open */ assert(count_open_fds() == data->nr_fds_conn + 3); /* * Must have 2 calls if falling back, but must also allow * falling back without a forced fallback. */ assert(wrapped_calls_recvmsg > data->wrapped_calls); if (data->wrapped_calls == 0 && wrapped_calls_recvmsg > 1) printf("recvmsg fell back unforced.\n"); /* all fds opened during the test in any way should be gone on exec */ exec_fd_leak_check(data->nr_fds_begin); } static void do_os_wrappers_recvmsg_cloexec(int n) { struct marshal_data data; data.nr_fds_begin = count_open_fds(); #if HAVE_BROKEN_MSG_CMSG_CLOEXEC /* We call the fallback directly on FreeBSD versions with a broken * MSG_CMSG_CLOEXEC, so we don't call the local recvmsg() wrapper. */ data.wrapped_calls = 0; #else data.wrapped_calls = n; #endif setup_marshal_data(&data); data.nr_fds_conn = count_open_fds(); assert(pipe(data.value.h) >= 0); data.value.h[2] = open("/dev/zero", O_RDONLY); assert(data.value.h[2] >= 0); marshal_demarshal(&data, (void *) validate_recvmsg_h, 8, "hhh", data.value.h[0], data.value.h[1], data.value.h[2]); } TEST(os_wrappers_recvmsg_cloexec) { init_fallbacks(0); do_os_wrappers_recvmsg_cloexec(0); } TEST(os_wrappers_recvmsg_cloexec_fallback) { init_fallbacks(1); do_os_wrappers_recvmsg_cloexec(1); } static void do_os_wrappers_epoll_create_cloexec(int n) { int fd; int nr_fds; nr_fds = count_open_fds(); fd = wl_os_epoll_create_cloexec(); assert(fd >= 0); #ifdef EPOLL_CLOEXEC assert(wrapped_calls_epoll_create1 == n); #else printf("No epoll_create1.\n"); #endif exec_fd_leak_check(nr_fds); } TEST(os_wrappers_epoll_create_cloexec) { init_fallbacks(0); do_os_wrappers_epoll_create_cloexec(1); } TEST(os_wrappers_epoll_create_cloexec_fallback) { init_fallbacks(1); do_os_wrappers_epoll_create_cloexec(2); } /* FIXME: add tests for wl_os_accept_cloexec() */ wayland-1.23.1/tests/protocol-logger-test.c000066400000000000000000000100321466237767300206570ustar00rootroot00000000000000/* * Copyright © 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com * * 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 #include #include #include #include #include #include #include "wayland-client.h" #include "wayland-server.h" #include "test-runner.h" /* Ensure the connection doesn't fail due to lack of XDG_RUNTIME_DIR. */ static const char * require_xdg_runtime_dir(void) { char *val = getenv("XDG_RUNTIME_DIR"); assert(val && val[0] == '/' && "set $XDG_RUNTIME_DIR to run this test"); return val; } struct compositor { struct wl_display *display; struct wl_event_loop *loop; int message; struct wl_client *client; }; struct message { enum wl_protocol_logger_type type; const char *class; int opcode; const char *message_name; int args_count; } messages[] = { { .type = WL_PROTOCOL_LOGGER_REQUEST, .class = "wl_display", .opcode = 0, .message_name = "sync", .args_count = 1, }, { .type = WL_PROTOCOL_LOGGER_EVENT, .class = "wl_callback", .opcode = 0, .message_name = "done", .args_count = 1, }, { .type = WL_PROTOCOL_LOGGER_EVENT, .class = "wl_display", .opcode = 1, .message_name = "delete_id", .args_count = 1, }, }; static void logger_func(void *user_data, enum wl_protocol_logger_type type, const struct wl_protocol_logger_message *message) { struct compositor *c = user_data; struct message *msg = &messages[c->message++]; assert(msg->type == type); assert(strcmp(msg->class, wl_resource_get_class(message->resource)) == 0); assert(msg->opcode == message->message_opcode); assert(strcmp(msg->message_name, message->message->name) == 0); assert(msg->args_count == message->arguments_count); c->client = wl_resource_get_client(message->resource); } static void callback_done(void *data, struct wl_callback *cb, uint32_t time) { wl_callback_destroy(cb); } static const struct wl_callback_listener callback_listener = { callback_done, }; TEST(logger) { test_set_timeout(1); const char *socket; struct compositor compositor = { 0 }; struct { struct wl_display *display; struct wl_callback *cb; } client; struct wl_protocol_logger *logger; require_xdg_runtime_dir(); compositor.display = wl_display_create(); compositor.loop = wl_display_get_event_loop(compositor.display); socket = wl_display_add_socket_auto(compositor.display); logger = wl_display_add_protocol_logger(compositor.display, logger_func, &compositor); client.display = wl_display_connect(socket); client.cb = wl_display_sync(client.display); wl_callback_add_listener(client.cb, &callback_listener, NULL); wl_display_flush(client.display); while (compositor.message < 3) { wl_event_loop_dispatch(compositor.loop, -1); wl_display_flush_clients(compositor.display); } wl_display_dispatch(client.display); wl_display_disconnect(client.display); wl_client_destroy(compositor.client); wl_protocol_logger_destroy(logger); wl_display_destroy(compositor.display); } wayland-1.23.1/tests/proxy-test.c000066400000000000000000000074451466237767300167400ustar00rootroot00000000000000/* * Copyright (c) 2019 Red Hat, Inc. * * 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 #include #include "wayland-server.h" #include "wayland-client.h" #include "test-runner.h" static struct { struct wl_display *display; struct wl_event_loop *loop; int sync_count; } server; static struct { struct wl_display *display; struct wl_callback *callback_a; struct wl_callback *callback_b; int callback_count; } client; static const char *tag_a = "tag"; static const char *tag_b = "tag"; static void callback_done(void *data, struct wl_callback *cb, uint32_t time) { const char * const *expected_tag; const char * const *tag; if (cb == client.callback_a) expected_tag = &tag_a; else if (cb == client.callback_b) expected_tag = &tag_b; else assert(!"unexpected callback"); tag = wl_proxy_get_tag((struct wl_proxy *) cb); assert(tag == expected_tag); assert(strcmp(*tag, "tag") == 0); wl_callback_destroy(cb); client.callback_count++; } static const struct wl_callback_listener callback_listener = { callback_done, }; static void logger_func(void *user_data, enum wl_protocol_logger_type type, const struct wl_protocol_logger_message *message) { if (type != WL_PROTOCOL_LOGGER_REQUEST) return; assert(strcmp(wl_resource_get_class(message->resource), "wl_display") == 0); assert(strcmp(message->message->name, "sync") == 0); server.sync_count++; } TEST(proxy_tag) { const char *socket; struct wl_protocol_logger *logger; assert(&tag_a != &tag_b); server.display = wl_display_create(); assert(server.display); server.loop = wl_display_get_event_loop(server.display); assert(server.loop); socket = wl_display_add_socket_auto(server.display); assert(socket); logger = wl_display_add_protocol_logger(server.display, logger_func, NULL); assert(logger); client.display = wl_display_connect(socket); assert(client.display); client.callback_a = wl_display_sync(client.display); wl_callback_add_listener(client.callback_a, &callback_listener, NULL); wl_proxy_set_tag((struct wl_proxy *) client.callback_a, &tag_a); client.callback_b = wl_display_sync(client.display); wl_callback_add_listener(client.callback_b, &callback_listener, NULL); wl_proxy_set_tag((struct wl_proxy *) client.callback_b, &tag_b); assert(wl_proxy_get_display((struct wl_proxy *) client.callback_b) == client.display); wl_display_flush(client.display); while (server.sync_count < 2) { wl_event_loop_dispatch(server.loop, -1); wl_display_flush_clients(server.display); } wl_display_dispatch(client.display); assert(client.callback_count == 2); wl_protocol_logger_destroy(logger); wl_display_disconnect(client.display); wl_event_loop_dispatch(server.loop, 100); wl_display_destroy(server.display); } wayland-1.23.1/tests/queue-test.c000066400000000000000000000444711466237767300167030ustar00rootroot00000000000000/* * Copyright © 2012 Jonas Ådahl * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #define _GNU_SOURCE /* For memrchr */ #include #include #include #include #include #include #include #include #include #include #include #include "wayland-client.h" #include "wayland-server.h" #include "test-runner.h" #include "test-compositor.h" #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version) { int *pcounter = data; (*pcounter)++; assert(*pcounter == 1); wl_registry_destroy(registry); } static const struct wl_registry_listener registry_listener = { registry_handle_global, NULL }; /* Test that destroying a proxy object doesn't result in any more * callback being invoked, even though were many queued. */ static void client_test_proxy_destroy(void) { struct wl_display *display; struct wl_registry *registry; int counter = 0; display = wl_display_connect(NULL); assert(display); registry = wl_display_get_registry(display); assert(registry != NULL); wl_registry_add_listener(registry, ®istry_listener, &counter); assert(wl_display_roundtrip(display) != -1); assert(counter == 1); /* don't destroy the registry, we have already destroyed them * in the global handler */ wl_display_disconnect(display); } struct multiple_queues_state { struct wl_display *display; struct wl_callback* callback2; bool done; }; static void sync_callback(void *data, struct wl_callback *callback, uint32_t serial) { struct multiple_queues_state *state = data; state->done = true; wl_callback_destroy(callback); wl_display_dispatch_pending(state->display); wl_callback_destroy(state->callback2); } static const struct wl_callback_listener sync_listener = { sync_callback }; /* Test that when receiving the first of two synchronization * callback events, destroying the second one doesn't cause any * errors even if the delete_id event is handled out of order. */ static void client_test_multiple_queues(void) { struct wl_event_queue *queue; struct wl_callback *callback1; struct multiple_queues_state state; int ret = 0; state.display = wl_display_connect(NULL); assert(state.display); queue = wl_display_create_queue(state.display); assert(queue); state.done = false; callback1 = wl_display_sync(state.display); assert(callback1 != NULL); wl_callback_add_listener(callback1, &sync_listener, &state); wl_proxy_set_queue((struct wl_proxy *) callback1, queue); state.callback2 = wl_display_sync(state.display); assert(state.callback2 != NULL); wl_callback_add_listener(state.callback2, &sync_listener, NULL); wl_proxy_set_queue((struct wl_proxy *) state.callback2, queue); wl_display_flush(state.display); while (!state.done && !ret) ret = wl_display_dispatch_queue(state.display, queue); wl_event_queue_destroy(queue); wl_display_disconnect(state.display); exit(ret == -1 ? -1 : 0); } static void sync_callback_roundtrip(void *data, struct wl_callback *callback, uint32_t serial) { bool *done = data; *done = true; } static const struct wl_callback_listener sync_listener_roundtrip = { sync_callback_roundtrip }; /* Test that doing a roundtrip on a queue only the events on that * queue get dispatched. */ static void client_test_queue_roundtrip(void) { struct wl_event_queue *queue; struct wl_callback *callback1; struct wl_callback *callback2; struct wl_display *display; bool done1 = false; bool done2 = false; display = wl_display_connect(NULL); assert(display); queue = wl_display_create_queue(display); assert(queue); /* arm a callback on the default queue */ callback1 = wl_display_sync(display); assert(callback1 != NULL); wl_callback_add_listener(callback1, &sync_listener_roundtrip, &done1); /* arm a callback on the other queue */ callback2 = wl_display_sync(display); assert(callback2 != NULL); wl_callback_add_listener(callback2, &sync_listener_roundtrip, &done2); wl_proxy_set_queue((struct wl_proxy *) callback2, queue); /* roundtrip on default queue must not dispatch the other queue. */ wl_display_roundtrip(display); assert(done1 == true); assert(done2 == false); /* re-arm the sync callback on the default queue, so we see that * wl_display_roundtrip_queue() does not dispatch the default queue. */ wl_callback_destroy(callback1); done1 = false; callback1 = wl_display_sync(display); assert(callback1 != NULL); wl_callback_add_listener(callback1, &sync_listener_roundtrip, &done1); wl_display_roundtrip_queue(display, queue); assert(done1 == false); assert(done2 == true); wl_callback_destroy(callback1); wl_callback_destroy(callback2); wl_event_queue_destroy(queue); wl_display_disconnect(display); } static void client_test_queue_proxy_wrapper(void) { struct wl_event_queue *queue; struct wl_display *display; struct wl_display *display_wrapper; struct wl_callback *callback; bool done = false; /* * For an illustration of what usage would normally fail without using * proxy wrappers, see the `client_test_queue_set_queue_race' test case. */ display = wl_display_connect(NULL); assert(display); /* Pretend we are in a separate thread where a thread-local queue is * used. */ queue = wl_display_create_queue(display); assert(queue); display_wrapper = wl_proxy_create_wrapper(display); assert(display_wrapper); wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue); callback = wl_display_sync(display_wrapper); wl_proxy_wrapper_destroy(display_wrapper); assert(callback != NULL); /* Pretend we are now another thread and dispatch the dispatch the main * queue while also knowing our callback is read and queued. */ wl_display_roundtrip(display); /* Make sure that the pretend-to-be main thread didn't dispatch our * callback, behind our back. */ wl_callback_add_listener(callback, &sync_listener_roundtrip, &done); wl_display_flush(display); assert(!done); /* Make sure that we eventually end up dispatching our callback. */ while (!done) assert(wl_display_dispatch_queue(display, queue) != -1); wl_callback_destroy(callback); wl_event_queue_destroy(queue); wl_display_disconnect(display); } static void client_test_queue_set_queue_race(void) { struct wl_event_queue *queue; struct wl_display *display; struct wl_callback *callback; bool done = false; /* * This test illustrates the multi threading scenario which would fail * without doing what is done in the `client_test_queue_proxy_wrapper' * test. */ display = wl_display_connect(NULL); assert(display); /* Pretend we are in a separate thread where a thread-local queue is * used. */ queue = wl_display_create_queue(display); assert(queue); callback = wl_display_sync(display); assert(callback != NULL); /* Pretend we are now another thread and dispatch the dispatch the main * queue while also knowing our callback is read, queued on the wrong * queue, and dispatched. */ wl_display_roundtrip(display); /* Pretend we are back in the separate thread, and continue with setting * up our callback. */ wl_callback_add_listener(callback, &sync_listener_roundtrip, &done); wl_proxy_set_queue((struct wl_proxy *) callback, queue); /* Roundtrip our separate thread queue to make sure any events are * dispatched. */ wl_display_roundtrip_queue(display, queue); /* Verify that the callback has indeed been dropped. */ assert(!done); wl_callback_destroy(callback); wl_event_queue_destroy(queue); wl_display_disconnect(display); } static char * maybe_map_file(int fd, size_t *len) { char *data; *len = lseek(fd, 0, SEEK_END); data = mmap(0, *len, PROT_READ, MAP_PRIVATE, fd, 0); return data; } static char * map_file(int fd, size_t *len) { char *data; data = maybe_map_file(fd, len); assert(data != MAP_FAILED && "Failed to mmap file"); return data; } static char * last_line_of(char *s) { size_t len = strlen(s); char *last; last = memrchr(s, '\n', len); /* If we found a newline at end of string, find the previous one. */ if (last && last[1] == 0) last = memrchr(s, '\n', len - 1); /* If we have a newline, the last line starts after the newline. * Otherwise, the whole string is the last line. */ if (last) last += 1; else last = s; return last; } static void client_test_queue_destroy_with_attached_proxies(void) { struct wl_event_queue *queue; struct wl_display *display; struct wl_display *display_wrapper; struct wl_callback *callback; char *log; size_t log_len; char callback_name[24]; int ret; display = wl_display_connect(NULL); assert(display); /* Pretend we are in a separate thread where a thread-local queue is * used. */ queue = wl_display_create_queue(display); assert(queue); /* Create a sync dispatching events on the thread-local queue. */ display_wrapper = wl_proxy_create_wrapper(display); assert(display_wrapper); wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue); callback = wl_display_sync(display_wrapper); wl_proxy_wrapper_destroy(display_wrapper); assert(callback != NULL); /* Destroy the queue before the attached object. */ wl_event_queue_destroy(queue); /* Check that the log contains some information about the attached * wl_callback proxy. */ log = map_file(client_log_fd, &log_len); ret = snprintf(callback_name, sizeof(callback_name), "wl_callback#%u", wl_proxy_get_id((struct wl_proxy *) callback)); assert(ret > 0 && ret < (int)sizeof(callback_name) && "callback name creation failed (possibly truncated)"); assert(strstr(last_line_of(log), callback_name)); munmap(log, log_len); wl_callback_destroy(callback); wl_display_disconnect(display); } static void client_test_queue_proxy_event_to_destroyed_queue(void) { struct wl_event_queue *queue; struct wl_display *display; struct wl_display *display_wrapper; struct wl_callback *callback; display = wl_display_connect(NULL); assert(display); /* Pretend we are in a separate thread where a thread-local queue is * used. */ queue = wl_display_create_queue(display); assert(queue); /* Create a sync dispatching events on the thread-local queue. */ display_wrapper = wl_proxy_create_wrapper(display); assert(display_wrapper); wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue); callback = wl_display_sync(display_wrapper); wl_proxy_wrapper_destroy(display_wrapper); assert(callback != NULL); wl_display_flush(display); /* Destroy the queue before the attached object. */ wl_event_queue_destroy(queue); /* During this roundtrip we should receive the done event on 'callback', * try to queue it to the destroyed queue, and abort. */ wl_display_roundtrip(display); wl_callback_destroy(callback); wl_display_disconnect(display); } static void client_test_queue_destroy_default_with_attached_proxies(void) { struct wl_display *display; struct wl_callback *callback; char *log; size_t log_len; char callback_name[24]; int ret; display = wl_display_connect(NULL); assert(display); /* Create a sync dispatching events on the default queue. */ callback = wl_display_sync(display); assert(callback != NULL); /* Destroy the default queue (by disconnecting) before the attached * object. */ wl_display_disconnect(display); /* Check that the log does not contain any warning about the attached * wl_callback proxy. */ log = maybe_map_file(client_log_fd, &log_len); ret = snprintf(callback_name, sizeof(callback_name), "wl_callback#%u", wl_proxy_get_id((struct wl_proxy *) callback)); assert(ret > 0 && ret < (int)sizeof(callback_name) && "callback name creation failed (possibly truncated)"); assert(log == MAP_FAILED || strstr(log, callback_name) == NULL); if (log != MAP_FAILED) munmap(log, log_len); /* HACK: Directly free the memory of the wl_callback proxy to appease * ASan. We would normally use wl_callback_destroy(), but since we have * destroyed the associated wl_display, using this function would lead * to memory errors. */ free(callback); } static void check_queue_name(struct wl_proxy *proxy, const char *name) { struct wl_event_queue *queue; const char *queue_name; queue = wl_proxy_get_queue(proxy); queue_name = wl_event_queue_get_name(queue); if (!name) assert(!queue_name); else assert(strcmp(queue_name, name) == 0); } static struct wl_callback * roundtrip_named_queue_nonblock(struct wl_display *display, struct wl_event_queue *queue, const char *name) { struct wl_callback *callback; struct wl_display *wrapped_display = NULL; if (queue) { wrapped_display = wl_proxy_create_wrapper(display); assert(wrapped_display); wl_proxy_set_queue((struct wl_proxy *) wrapped_display, queue); check_queue_name((struct wl_proxy *) wrapped_display, name); callback = wl_display_sync(wrapped_display); } else callback = wl_display_sync(display); check_queue_name((struct wl_proxy *) callback, name); if (wrapped_display) wl_proxy_wrapper_destroy(wrapped_display); assert(callback != NULL); return callback; } static void client_test_queue_names(void) { struct wl_event_queue *queue1, *queue2, *queue3; struct wl_display *display; struct wl_callback *callback1, *callback2, *callback3, *callback4; struct wl_event_queue *default_queue; char *log; size_t log_len; const char *default_queue_name; display = wl_display_connect(NULL); assert(display); default_queue = wl_proxy_get_queue((struct wl_proxy *) display); default_queue_name = wl_event_queue_get_name(default_queue); assert(strcmp(default_queue_name, "Default Queue") == 0); /* Create some event queues both with and without names. */ queue1 = wl_display_create_queue_with_name(display, "First"); assert(queue1); queue2 = wl_display_create_queue_with_name(display, "Second"); assert(queue2); queue3 = wl_display_create_queue(display); assert(queue3); /* Create some requests and ensure their queues have the expected * names. */ callback1 = roundtrip_named_queue_nonblock(display, queue1, "First"); callback2 = roundtrip_named_queue_nonblock(display, queue2, "Second"); callback3 = roundtrip_named_queue_nonblock(display, queue3, NULL); callback4 = roundtrip_named_queue_nonblock(display, NULL, "Default Queue"); /* Destroy one queue with proxies still attached so we can verify * that the queue name is in the log message. */ wl_event_queue_destroy(queue2); log = map_file(client_log_fd, &log_len); assert(strstr(log, "Second")); /* There's no reason for the First queue name to be present. */ assert(!strstr(log, "First")); munmap(log, log_len); wl_callback_destroy(callback1); wl_callback_destroy(callback2); wl_callback_destroy(callback3); wl_callback_destroy(callback4); wl_event_queue_destroy(queue1); wl_event_queue_destroy(queue3); wl_display_disconnect(display); } static void dummy_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { } TEST(queue_proxy_destroy) { struct display *d; const struct wl_interface *dummy_interfaces[] = { &wl_seat_interface, &wl_pointer_interface, &wl_keyboard_interface, &wl_surface_interface }; unsigned int i; d = display_create(); for (i = 0; i < ARRAY_LENGTH(dummy_interfaces); i++) wl_global_create(d->wl_display, dummy_interfaces[i], dummy_interfaces[i]->version, NULL, dummy_bind); test_set_timeout(2); client_create_noarg(d, client_test_proxy_destroy); display_run(d); display_destroy(d); } TEST(queue_multiple_queues) { struct display *d = display_create(); test_set_timeout(2); client_create_noarg(d, client_test_multiple_queues); display_run(d); display_destroy(d); } TEST(queue_roundtrip) { struct display *d = display_create(); test_set_timeout(2); client_create_noarg(d, client_test_queue_roundtrip); display_run(d); display_destroy(d); } TEST(queue_set_queue_proxy_wrapper) { struct display *d = display_create(); test_set_timeout(2); client_create_noarg(d, client_test_queue_proxy_wrapper); display_run(d); display_destroy(d); } TEST(queue_set_queue_race) { struct display *d = display_create(); test_set_timeout(2); client_create_noarg(d, client_test_queue_set_queue_race); display_run(d); display_destroy(d); } TEST(queue_destroy_with_attached_proxies) { struct display *d = display_create(); test_set_timeout(2); client_create_noarg(d, client_test_queue_destroy_with_attached_proxies); display_run(d); display_destroy(d); } TEST(queue_proxy_event_to_destroyed_queue) { struct display *d = display_create(); struct client_info *ci; char *client_log; size_t client_log_len; test_set_timeout(2); ci = client_create_noarg(d, client_test_queue_proxy_event_to_destroyed_queue); display_run(d); /* Check that the final line in the log mentions the expected reason * for the abort. */ client_log = map_file(ci->log_fd, &client_log_len); assert(!strcmp(last_line_of(client_log), "Tried to add event to destroyed queue\n")); munmap(client_log, client_log_len); /* Check that the client aborted. */ display_destroy_expect_signal(d, SIGABRT); } TEST(queue_destroy_default_with_attached_proxies) { struct display *d = display_create(); test_set_timeout(2); client_create_noarg(d, client_test_queue_destroy_default_with_attached_proxies); display_run(d); display_destroy(d); } TEST(queue_names) { struct display *d = display_create(); test_set_timeout(2); client_create_noarg(d, client_test_queue_names); display_run(d); display_destroy(d); } wayland-1.23.1/tests/resources-test.c000066400000000000000000000162061466237767300175640ustar00rootroot00000000000000/* * Copyright © 2013 Marek Chalupa * * 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 #include #include #include #include "wayland-server.h" #include "test-runner.h" TEST(create_resource_tst) { struct wl_display *display; struct wl_client *client; struct wl_resource *res; struct wl_list *link; int s[2]; uint32_t id; assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); display = wl_display_create(); assert(display); client = wl_client_create(display, s[0]); assert(client); res = wl_resource_create(client, &wl_seat_interface, 4, 0); assert(res); /* setters/getters */ assert(wl_resource_get_version(res) == 4); assert(client == wl_resource_get_client(res)); id = wl_resource_get_id(res); assert(wl_client_get_object(client, id) == res); link = wl_resource_get_link(res); assert(link); assert(wl_resource_from_link(link) == res); wl_resource_set_user_data(res, (void *) 0xbee); assert(wl_resource_get_user_data(res) == (void *) 0xbee); wl_resource_destroy(res); wl_client_destroy(client); wl_display_destroy(display); close(s[1]); } static void res_destroy_func(struct wl_resource *res) { assert(res); _Bool *destr = wl_resource_get_user_data(res); *destr = 1; } static _Bool notify_called = 0; static void destroy_notify(struct wl_listener *l, void *data) { assert(l && data); notify_called = 1; /* In real code it's common to free the structure holding the * listener at this point, but not to remove it from the list. * * That's fine since this is a destruction notification and * it's the last time this signal can fire. We set these * to NULL so we can check them later to ensure no write after * "free" occurred. */ l->link.prev = NULL; l->link.next = NULL; } TEST(destroy_res_tst) { struct wl_display *display; struct wl_client *client; struct wl_resource *res; int s[2]; unsigned id; struct wl_list *link; _Bool destroyed = 0; struct wl_listener destroy_listener = { .notify = &destroy_notify }; assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); display = wl_display_create(); assert(display); client = wl_client_create(display, s[0]); assert(client); res = wl_resource_create(client, &wl_seat_interface, 4, 0); assert(res); wl_resource_set_implementation(res, NULL, &destroyed, res_destroy_func); wl_resource_add_destroy_listener(res, &destroy_listener); id = wl_resource_get_id(res); link = wl_resource_get_link(res); assert(link); wl_resource_destroy(res); assert(destroyed); assert(notify_called); /* check if signal was emitted */ assert(wl_client_get_object(client, id) == NULL); assert(destroy_listener.link.prev == NULL); assert(destroy_listener.link.next == NULL); res = wl_resource_create(client, &wl_seat_interface, 2, 0); assert(res); destroyed = 0; notify_called = 0; wl_resource_set_destructor(res, res_destroy_func); wl_resource_set_user_data(res, &destroyed); wl_resource_add_destroy_listener(res, &destroy_listener); /* client should destroy the resource upon its destruction */ wl_client_destroy(client); assert(destroyed); assert(notify_called); assert(destroy_listener.link.prev == NULL); assert(destroy_listener.link.next == NULL); wl_display_destroy(display); close(s[1]); } TEST(create_resource_with_same_id) { struct wl_display *display; struct wl_client *client; struct wl_resource *res, *res2; int s[2]; uint32_t id; assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); display = wl_display_create(); assert(display); client = wl_client_create(display, s[0]); assert(client); res = wl_resource_create(client, &wl_seat_interface, 2, 0); assert(res); id = wl_resource_get_id(res); assert(wl_client_get_object(client, id) == res); /* this one should replace the old one */ res2 = wl_resource_create(client, &wl_seat_interface, 1, id); assert(res2 != NULL); assert(wl_client_get_object(client, id) == res2); wl_resource_destroy(res2); wl_resource_destroy(res); wl_client_destroy(client); wl_display_destroy(display); close(s[1]); } static void display_destroy_notify(struct wl_listener *l, void *data) { l->link.prev = l->link.next = NULL; } TEST(free_without_remove) { struct wl_display *display; struct wl_listener a, b; display = wl_display_create(); a.notify = display_destroy_notify; b.notify = display_destroy_notify; wl_display_add_destroy_listener(display, &a); wl_display_add_destroy_listener(display, &b); wl_display_destroy(display); assert(a.link.next == a.link.prev && a.link.next == NULL); assert(b.link.next == b.link.prev && b.link.next == NULL); } static enum wl_iterator_result client_resource_check(struct wl_resource* resource, void* data) { /* Ensure there is no iteration over already freed resources. */ assert(!wl_resource_get_user_data(resource)); return WL_ITERATOR_CONTINUE; } static void resource_destroy_notify(struct wl_listener *l, void *data) { struct wl_resource* resource = data; struct wl_client* client = resource->client; wl_client_for_each_resource(client, client_resource_check, NULL); /* Set user data to flag the resource has been deleted. The resource should * not be accessible from this point forward. */ wl_resource_set_user_data(resource, client); } TEST(resource_destroy_iteration) { struct wl_display *display; struct wl_client *client; struct wl_resource *resource1; struct wl_resource *resource2; int s[2]; struct wl_listener destroy_listener1 = { .notify = &resource_destroy_notify }; struct wl_listener destroy_listener2 = { .notify = &resource_destroy_notify }; assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); display = wl_display_create(); assert(display); client = wl_client_create(display, s[0]); assert(client); resource1 = wl_resource_create(client, &wl_callback_interface, 1, 0); resource2 = wl_resource_create(client, &wl_callback_interface, 1, 0); assert(resource1); assert(resource2); wl_resource_add_destroy_listener(resource1, &destroy_listener1); wl_resource_add_destroy_listener(resource2, &destroy_listener2); wl_client_destroy(client); close(s[0]); close(s[1]); wl_display_destroy(display); } wayland-1.23.1/tests/sanity-test.c000066400000000000000000000143451466237767300170630ustar00rootroot00000000000000/* * Copyright © 2012 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 #include #include #include #include #include #include #include "test-runner.h" #include "wayland-util.h" #include "wayland-private.h" #include "test-compositor.h" extern int fd_leak_check_enabled; TEST(empty) { } TEST(exit_success) { exit(EXIT_SUCCESS); } FAIL_TEST(exit_failure) { exit(EXIT_FAILURE); } FAIL_TEST(fail_abort) { test_disable_coredumps(); abort(); } FAIL_TEST(fail_wl_abort) { test_disable_coredumps(); wl_abort("Abort the program\n"); } FAIL_TEST(fail_kill) { kill(getpid(), SIGTERM); } FAIL_TEST(fail_segv) { char * volatile *null = 0; test_disable_coredumps(); *null = "Goodbye, world"; } FAIL_TEST(sanity_assert) { test_disable_coredumps(); /* must fail */ assert(0); } FAIL_TEST(sanity_fd_leak) { int fd[2]; assert(fd_leak_check_enabled); /* leak 2 file descriptors */ if (pipe(fd) < 0) exit(EXIT_SUCCESS); /* failed to fail */ test_disable_coredumps(); } FAIL_TEST(sanity_fd_leak_exec) { int fd[2]; int nr_fds = count_open_fds(); /* leak 2 file descriptors */ if (pipe(fd) < 0) exit(EXIT_SUCCESS); /* failed to fail */ test_disable_coredumps(); exec_fd_leak_check(nr_fds); } TEST(sanity_fd_exec) { int fd[2]; int nr_fds = count_open_fds(); /* create 2 file descriptors, that should pass over exec */ assert(pipe(fd) >= 0); exec_fd_leak_check(nr_fds + 2); } static void sanity_fd_no_leak(void) { int fd[2]; assert(fd_leak_check_enabled); /* leak 2 file descriptors */ if (pipe(fd) < 0) exit(EXIT_SUCCESS); /* failed to fail */ close(fd[0]); close(fd[1]); } static void sanity_client_no_leak(void) { struct wl_display *display = wl_display_connect(NULL); assert(display); wl_display_disconnect(display); } TEST(tc_client_no_fd_leaks) { struct display *d = display_create(); /* Client which does not consume the WAYLAND_DISPLAY socket. */ client_create_noarg(d, sanity_fd_no_leak); display_run(d); /* Client which does consume the WAYLAND_DISPLAY socket. */ client_create_noarg(d, sanity_client_no_leak); display_run(d); display_destroy(d); } FAIL_TEST(tc_client_fd_leaks) { struct display *d = display_create(); client_create_noarg(d, sanity_fd_leak); display_run(d); test_disable_coredumps(); display_destroy(d); } FAIL_TEST(tc_client_fd_leaks_exec) { struct display *d = display_create(); client_create_noarg(d, sanity_fd_leak_exec); display_run(d); test_disable_coredumps(); display_destroy(d); } static char * map_file(int fd, size_t *len) { char *data; *len = lseek(fd, 0, SEEK_END); data = mmap(0, *len, PROT_READ, MAP_PRIVATE, fd, 0); assert(data != MAP_FAILED && "Failed to mmap file"); return data; } static void sanity_client_log(void) { char *log; size_t log_len; char *wayland_socket = strdup(getenv("WAYLAND_SOCKET")); char *xdg_runtime_dir = strdup(getenv("XDG_RUNTIME_DIR")); unsetenv("WAYLAND_SOCKET"); unsetenv("XDG_RUNTIME_DIR"); /* Try to connect to the default wayland display, which should fail since * we have neither WAYLAND_SOCKET nor XDG_RUNTIME_DIR. */ assert(!wl_display_connect(NULL)); /* Check that the client log contains some mention of XDG_RUNTIME_DIR. */ log = map_file(client_log_fd, &log_len); assert(strstr(log, "XDG_RUNTIME_DIR")); munmap(log, log_len); /* Reset the environment variables we unset for the test. The test harness * leak checker cares about the value of WAYLAND_SOCKET during teardown for * correct fd accounting. */ setenv("XDG_RUNTIME_DIR", xdg_runtime_dir, 0); setenv("WAYLAND_SOCKET", wayland_socket, 0); free(xdg_runtime_dir); free(wayland_socket); } TEST(tc_client_log) { struct display *d = display_create(); struct client_info *ci; char *log; size_t log_len; ci = client_create_noarg(d, sanity_client_log); display_run(d); /* Check that the client log contains some mention of XDG_RUNTIME_DIR. */ log = map_file(ci->log_fd, &log_len); assert(strstr(log, "XDG_RUNTIME_DIR")); munmap(log, log_len); display_destroy(d); } FAIL_TEST(timeout_tst) { test_set_timeout(1); test_disable_coredumps(); /* test should reach timeout */ test_sleep(2); } TEST(timeout2_tst) { /* the test should end before reaching timeout, * thus it should pass */ test_set_timeout(1); /* 200 000 microsec = 0.2 sec */ test_usleep(200000); } FAIL_TEST(timeout_reset_tst) { test_set_timeout(5); test_set_timeout(10); test_set_timeout(1); test_disable_coredumps(); /* test should fail on timeout */ test_sleep(2); } TEST(timeout_turnoff) { test_set_timeout(1); test_set_timeout(0); test_usleep(2); } /* test timeouts with test-compositor */ FAIL_TEST(tc_timeout_tst) { struct display *d = display_create(); client_create_noarg(d, timeout_tst); display_run(d); test_disable_coredumps(); display_destroy(d); } FAIL_TEST(tc_timeout2_tst) { struct display *d = display_create(); client_create_noarg(d, timeout_reset_tst); display_run(d); test_disable_coredumps(); display_destroy(d); } TEST(tc_timeout3_tst) { struct display *d = display_create(); client_create_noarg(d, timeout2_tst); display_run(d); client_create_noarg(d, timeout_turnoff); display_run(d); display_destroy(d); } wayland-1.23.1/tests/scanner-test-gen.sh000077500000000000000000000016641466237767300201470ustar00rootroot00000000000000#!/bin/sh -eu generate() { "$WAYLAND_SCANNER" $1 < "$TEST_DATA_DIR/$2" > "$TEST_DATA_DIR/$3" "$SED" -i -e 's/Generated by wayland-scanner [0-9.]*/SCANNER TEST/' \ "$TEST_DATA_DIR/$3" } generate "code" "example.xml" "example-code.c" generate "client-header" "example.xml" "example-client.h" generate "server-header" "example.xml" "example-server.h" generate "enum-header" "example.xml" "example-enum.h" generate "code" "small.xml" "small-code.c" generate "client-header" "small.xml" "small-client.h" generate "server-header" "small.xml" "small-server.h" generate "-c code" "small.xml" "small-code-core.c" generate "-c client-header" "small.xml" "small-client-core.h" generate "-c server-header" "small.xml" "small-server-core.h" generate "private-code" "small.xml" "small-private-code.c" generate "code" "empty.xml" "empty-code.c" generate "client-header" "empty.xml" "empty-client.h" generate "server-header" "empty.xml" "empty-server.h" wayland-1.23.1/tests/scanner-test.sh000077500000000000000000000053631466237767300174000ustar00rootroot00000000000000#!/bin/sh echo "srcdir: $srcdir" echo "scanner: $WAYLAND_SCANNER" echo "test_data_dir: $TEST_DATA_DIR" echo "test_output_dir: $TEST_OUTPUT_DIR" echo "pwd: $PWD" echo "sed: $SED" RETCODE=0 hard_fail() { echo "$@" "ERROR" exit 99 } fail() { echo "$@" "FAIL" RETCODE=1 } mkdir -p "$TEST_OUTPUT_DIR" || hard_fail "setup" generate_and_compare() { echo echo "Testing $1 generation: $2 -> $3" "$WAYLAND_SCANNER" $1 < "$TEST_DATA_DIR/$2" > "$TEST_OUTPUT_DIR/$3" || \ hard_fail "$2 -> $3" "$SED" -i -e 's/Generated by wayland-scanner [0-9.]*/SCANNER TEST/' \ "$TEST_OUTPUT_DIR/$3" || hard_fail "$2 -> $3" diff -q "$TEST_DATA_DIR/$3" "$TEST_OUTPUT_DIR/$3" && \ echo "$2 -> $3 PASS" || \ fail "$2 -> $3" } verify_error() { echo echo "Checking that reading $1 gives an error on line $3" [ -f "$TEST_DATA_DIR/$1" ] || hard_fail "$1 not present" # Confirm failure error code "$WAYLAND_SCANNER" server-header < "$TEST_DATA_DIR/$1" >/dev/null 2>"$TEST_OUTPUT_DIR/$2" && \ fail "$1 return code check" # Verify that an error is produced at the correct line grep -q ":$3: error:" "$TEST_OUTPUT_DIR/$2" && echo "$1 PASS" || fail "$1 line number check" } generate_and_compare "code" "example.xml" "example-code.c" generate_and_compare "client-header" "example.xml" "example-client.h" generate_and_compare "server-header" "example.xml" "example-server.h" generate_and_compare "enum-header" "example.xml" "example-enum.h" generate_and_compare "code" "small.xml" "small-code.c" generate_and_compare "client-header" "small.xml" "small-client.h" generate_and_compare "server-header" "small.xml" "small-server.h" generate_and_compare "-c code" "small.xml" "small-code-core.c" generate_and_compare "-c client-header" "small.xml" "small-client-core.h" generate_and_compare "-c server-header" "small.xml" "small-server-core.h" # The existing "code" must produce result identical to "public-code" generate_and_compare "code" "small.xml" "small-code.c" generate_and_compare "public-code" "small.xml" "small-code.c" generate_and_compare "private-code" "small.xml" "small-private-code.c" generate_and_compare "code" "empty.xml" "empty-code.c" generate_and_compare "client-header" "empty.xml" "empty-client.h" generate_and_compare "server-header" "empty.xml" "empty-server.h" verify_error "bad-identifier-arg.xml" "bad-identifier-arg.log" 7 verify_error "bad-identifier-entry.xml" "bad-identifier-entry.log" 8 verify_error "bad-identifier-enum.xml" "bad-identifier-enum.log" 6 verify_error "bad-identifier-event.xml" "bad-identifier-event.log" 6 verify_error "bad-identifier-interface.xml" "bad-identifier-interface.log" 3 verify_error "bad-identifier-protocol.xml" "bad-identifier-protocol.log" 2 verify_error "bad-identifier-request.xml" "bad-identifier-request.log" 6 exit $RETCODE wayland-1.23.1/tests/signal-test.c000066400000000000000000000107411466237767300170250ustar00rootroot00000000000000/* * Copyright © 2013 Marek Chalupa * * 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 #include "wayland-server.h" #include "test-runner.h" static void signal_notify(struct wl_listener *listener, void *data) { /* only increase counter*/ ++(*((int *) data)); } TEST(signal_init) { struct wl_signal signal; wl_signal_init(&signal); /* Test if listeners' list is initialized */ assert(&signal.listener_list == signal.listener_list.next && "Maybe wl_signal implementation changed?"); assert(signal.listener_list.next == signal.listener_list.prev && "Maybe wl_signal implementation changed?"); } TEST(signal_add_get) { struct wl_signal signal; /* we just need different values of notify */ struct wl_listener l1 = {.notify = (wl_notify_func_t) 0x1}; struct wl_listener l2 = {.notify = (wl_notify_func_t) 0x2}; struct wl_listener l3 = {.notify = (wl_notify_func_t) 0x3}; /* one real, why not */ struct wl_listener l4 = {.notify = signal_notify}; wl_signal_init(&signal); wl_signal_add(&signal, &l1); wl_signal_add(&signal, &l2); wl_signal_add(&signal, &l3); wl_signal_add(&signal, &l4); assert(wl_signal_get(&signal, signal_notify) == &l4); assert(wl_signal_get(&signal, (wl_notify_func_t) 0x3) == &l3); assert(wl_signal_get(&signal, (wl_notify_func_t) 0x2) == &l2); assert(wl_signal_get(&signal, (wl_notify_func_t) 0x1) == &l1); /* get should not be destructive */ assert(wl_signal_get(&signal, signal_notify) == &l4); assert(wl_signal_get(&signal, (wl_notify_func_t) 0x3) == &l3); assert(wl_signal_get(&signal, (wl_notify_func_t) 0x2) == &l2); assert(wl_signal_get(&signal, (wl_notify_func_t) 0x1) == &l1); } TEST(signal_emit_to_one_listener) { int count = 0; int counter; struct wl_signal signal; struct wl_listener l1 = {.notify = signal_notify}; wl_signal_init(&signal); wl_signal_add(&signal, &l1); for (counter = 0; counter < 100; counter++) wl_signal_emit(&signal, &count); assert(counter == count); } TEST(signal_emit_to_more_listeners) { int count = 0; int counter; struct wl_signal signal; struct wl_listener l1 = {.notify = signal_notify}; struct wl_listener l2 = {.notify = signal_notify}; struct wl_listener l3 = {.notify = signal_notify}; wl_signal_init(&signal); wl_signal_add(&signal, &l1); wl_signal_add(&signal, &l2); wl_signal_add(&signal, &l3); for (counter = 0; counter < 100; counter++) wl_signal_emit(&signal, &count); assert(3 * counter == count); } struct signal_emit_mutable_data { int count; struct wl_listener *remove_listener; }; static void signal_notify_mutable(struct wl_listener *listener, void *data) { struct signal_emit_mutable_data *test_data = data; test_data->count++; } static void signal_notify_and_remove_mutable(struct wl_listener *listener, void *data) { struct signal_emit_mutable_data *test_data = data; signal_notify_mutable(listener, test_data); wl_list_remove(&test_data->remove_listener->link); } TEST(signal_emit_mutable) { struct signal_emit_mutable_data data = {0}; /* l2 will remove l3 before l3 is notified */ struct wl_signal signal; struct wl_listener l1 = {.notify = signal_notify_mutable}; struct wl_listener l2 = {.notify = signal_notify_and_remove_mutable}; struct wl_listener l3 = {.notify = signal_notify_mutable}; wl_signal_init(&signal); wl_signal_add(&signal, &l1); wl_signal_add(&signal, &l2); wl_signal_add(&signal, &l3); data.remove_listener = &l3; wl_signal_emit_mutable(&signal, &data); assert(data.count == 2); } wayland-1.23.1/tests/socket-test.c000066400000000000000000000200301466237767300170300ustar00rootroot00000000000000/* * 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 #include #include #include #include #include #include #include #include #include #include "wayland-client.h" #include "wayland-os.h" #include "wayland-server.h" #include "test-runner.h" /* Paths longer than what the .sun_path array can contain must be rejected. * This is a hard limitation of assigning a name to AF_UNIX/AF_LOCAL sockets. * See `man 7 unix`. */ static struct sockaddr_un example_sockaddr_un; #define TOO_LONG (1 + sizeof example_sockaddr_un.sun_path) /* Ensure the connection doesn't fail due to lack of XDG_RUNTIME_DIR. */ static const char * require_xdg_runtime_dir(void) { char *val = getenv("XDG_RUNTIME_DIR"); assert(val && val[0] == '/' && "set $XDG_RUNTIME_DIR to run this test"); return val; } TEST(socket_path_overflow_client_connect) { char path[TOO_LONG]; struct wl_display *d; require_xdg_runtime_dir(); memset(path, 'a', sizeof path); path[sizeof path - 1] = '\0'; d = wl_display_connect(path); assert(d == NULL); assert(errno == ENAMETOOLONG); /* This is useless, but prevents a warning about example_sockaddr_un * being discarded from the compilation unit. */ strcpy(example_sockaddr_un.sun_path, "happy now clang?"); assert(example_sockaddr_un.sun_path[0] != '\0'); } TEST(socket_path_overflow_server_create) { char path[TOO_LONG]; struct wl_display *d; int ret; require_xdg_runtime_dir(); memset(path, 'a', sizeof path); path[sizeof path - 1] = '\0'; d = wl_display_create(); assert(d != NULL); ret = wl_display_add_socket(d, path); assert(ret < 0); assert(errno == ENAMETOOLONG); wl_display_destroy(d); } TEST(add_existing_socket) { char path[sizeof example_sockaddr_un.sun_path]; const char *name = "wayland-test-0"; const char *xdg_runtime_dir; struct wl_display *d; int ret; size_t len; xdg_runtime_dir = require_xdg_runtime_dir(); d = wl_display_create(); assert(d != NULL); /* this one should be OK */ ret = wl_display_add_socket(d, name); assert(ret == 0); /* this one should fail */ ret = wl_display_add_socket(d, name); assert(ret < 0); /* the original socket should still exist. * this was a bug introduced in e2c0d47b0c77f18cd90e9c6eabb358c4d89681c8 */ len = snprintf(path, sizeof example_sockaddr_un.sun_path, "%s/%s", xdg_runtime_dir, name); assert(len < sizeof example_sockaddr_un.sun_path && "Bug in test. Path too long"); assert(access(path, F_OK) != -1); /* the original socket should still exist */ ret = wl_display_add_socket(d, name); assert(ret < 0); wl_display_destroy(d); } TEST(add_socket_auto) { /* the number of auto sockets is currently 32, * set in wayland-server.c. */ const int MAX_SOCKETS = 32; char path[sizeof example_sockaddr_un.sun_path]; const char *name; const char *xdg_runtime_dir; struct wl_display *d; int i; size_t len; xdg_runtime_dir = require_xdg_runtime_dir(); d = wl_display_create(); assert(d != NULL); for (i = 0; i <= MAX_SOCKETS; ++i) { name = wl_display_add_socket_auto(d); assert(name != NULL); len = snprintf(path, sizeof example_sockaddr_un.sun_path, "%s/%s", xdg_runtime_dir, name); assert(len < sizeof example_sockaddr_un.sun_path && "Bug in test. Path too long"); /* was the socket created correctly? */ assert(access(path, F_OK) != -1); /* is the name sequential? */ len = snprintf(path, sizeof example_sockaddr_un.sun_path, "wayland-%d", i); assert(strcmp(name, path) == 0); } /* next addition should return NULL */ name = wl_display_add_socket_auto(d); assert(name == NULL); /* check if the socket was not deleted the last time */ name = wl_display_add_socket_auto(d); assert(name == NULL); wl_display_destroy(d); } struct client_create_listener { struct wl_listener listener; struct wl_display *display; }; struct client_destroy_listener { struct wl_listener listener; struct wl_display *display; }; static void client_destroy_notify(struct wl_listener *l, void *data) { struct client_destroy_listener *listener = wl_container_of(l, listener, listener); wl_display_terminate(listener->display); free(listener); } static void client_create_notify(struct wl_listener *l, void *data) { struct wl_client *client = data; struct client_create_listener *listener = wl_container_of(l, listener, listener); struct client_destroy_listener *destroy_listener = (struct client_destroy_listener *)malloc(sizeof *destroy_listener); assert(destroy_listener != NULL); destroy_listener->display = listener->display; destroy_listener->listener.notify = client_destroy_notify; wl_client_add_destroy_listener(client, &destroy_listener->listener); } TEST(absolute_socket_path) { struct wl_display *display; struct client_create_listener client_create_listener; struct sockaddr_un addr; int fd; socklen_t size; const char *xdg_runtime_dir; size_t len; int ret; pid_t pid; /* It's a little weird that this test about absolute socket paths * uses XDG_RUNTIME_DIR, but that's the only location guaranteed * by test-runner to be both writable and unique. This isn't * really a problem; we'll just take care that the leaf-level * filename used for the socket isn't anything that would * accidentally be generated by a default usage of wl_display_connect(). */ xdg_runtime_dir = require_xdg_runtime_dir(); memset(&addr, 0, sizeof addr); len = snprintf(addr.sun_path, sizeof addr.sun_path, "%s/%s", xdg_runtime_dir, "wayland-absolute-0"); assert(len < sizeof addr.sun_path && "Bug in test. Path too long"); /* The path must not exist prior to binding. */ assert(access(addr.sun_path, F_OK) == -1); size = offsetof (struct sockaddr_un, sun_path) + strlen(addr.sun_path); addr.sun_family = AF_LOCAL; fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0); assert(fd >= 0 ); ret = bind(fd, (struct sockaddr *) &addr, size); assert(ret >= 0); ret = listen(fd, 128); assert(ret >= 0); /* Start server display. Be careful (by avoiding wl_display_add_socket_auto() * to offer only the absolutely qualified socket made above. */ display = wl_display_create(); assert(display != NULL); client_create_listener.listener.notify = client_create_notify; client_create_listener.display = display; wl_display_add_client_created_listener(display, &client_create_listener.listener); ret = wl_display_add_socket_fd(display, fd); assert(ret == 0); /* Execute client that connects to the absolutely qualified server socket path. */ pid = fork(); assert(pid != -1); if (pid == 0) { ret = setenv("WAYLAND_DISPLAY", addr.sun_path, 1); assert(ret == 0); struct wl_display *client_display = wl_display_connect(NULL); assert(client_display != NULL); ret = wl_display_roundtrip(client_display); assert(ret != -1); wl_display_disconnect(client_display); exit(0); assert(false); } wl_display_run(display); ret = waitpid(pid, NULL, 0); assert(ret == pid); wl_display_destroy(display); ret = unlink(addr.sun_path); assert(ret == 0); } wayland-1.23.1/tests/test-compositor.c000066400000000000000000000325401466237767300177470ustar00rootroot00000000000000/* * Copyright (c) 2014 Red Hat, Inc. * * 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 #include #include #include #include #include #include #include #include #include #include #define WL_HIDE_DEPRECATED #include "test-runner.h" #include "test-compositor.h" int client_log_fd = -1; /* --- Protocol --- */ struct test_compositor; static const struct wl_message tc_requests[] = { /* this request serves as a barrier for synchronizing*/ { "stop_display", "u", NULL }, { "noop", "", NULL }, }; static const struct wl_message tc_events[] = { { "display_resumed", "", NULL } }; const struct wl_interface test_compositor_interface = { "test", 1, 2, tc_requests, 1, tc_events }; struct test_compositor_interface { void (*stop_display)(struct wl_client *client, struct wl_resource *resource, uint32_t num); void (*noop)(struct wl_client *client, struct wl_resource *resource); }; struct test_compositor_listener { void (*display_resumed)(void *data, struct test_compositor *tc); }; enum { STOP_DISPLAY = 0, TEST_NOOP = 1 }; enum { DISPLAY_RESUMED = 0 }; /* Since tests can run parallelly, we need unique socket names * for each test, otherwise the test can fail on wl_display_add_socket. */ static const char * get_socket_name(void) { struct timeval tv; static char retval[64]; gettimeofday(&tv, NULL); snprintf(retval, sizeof retval, "wayland-test-%d-%ld%ld", getpid(), tv.tv_sec, tv.tv_usec); return retval; } static void handle_client_destroy(void *data) { struct client_info *ci = data; struct display *d; int status; d = ci->display; assert(waitpid(ci->pid, &status, 0) != -1); if (WIFSIGNALED(status)) { fprintf(stderr, "Client '%s' was killed by signal %d\n", ci->name, WTERMSIG(status)); ci->kill_code = WTERMSIG(status); } else if (WIFEXITED(status)) { if (WEXITSTATUS(status) != EXIT_SUCCESS) fprintf(stderr, "Client '%s' exited with code %d\n", ci->name, WEXITSTATUS(status)); ci->exit_code = WEXITSTATUS(status); } ++d->clients_terminated_no; if (d->clients_no == d->clients_terminated_no) { wl_display_terminate(d->wl_display); } /* the clients are not removed from the list, because * at the end of the test we check the exit codes of all * clients. In the case that the test would go through * the clients list manually, zero out the wl_client as a sign * that the client is not running anymore */ } /** * Check client's state and terminate display when all clients exited */ static void client_destroyed(struct wl_listener *listener, void *data) { struct client_info *ci; struct display *d; struct wl_event_loop *loop; /* Wait for client in an idle handler to avoid blocking the actual * client destruction (fd close etc. */ ci = wl_container_of(listener, ci, destroy_listener); d = ci->display; loop = wl_display_get_event_loop(d->wl_display); wl_event_loop_add_idle(loop, handle_client_destroy, ci); ci->wl_client = NULL; } static void client_log_handler(const char *fmt, va_list arg) { va_list arg_copy; va_copy(arg_copy, arg); vdprintf(client_log_fd, fmt, arg_copy); va_end(arg_copy); vfprintf(stderr, fmt, arg); } static void run_client(void (*client_main)(void *data), void *data, int wayland_sock, int client_pipe, int log_fd) { char s[8]; int cur_fds; int can_continue = 0; /* Wait until display signals that client can continue */ assert(read(client_pipe, &can_continue, sizeof(int)) == sizeof(int)); if (can_continue == 0) abort(); /* error in parent */ /* for wl_display_connect() */ snprintf(s, sizeof s, "%d", wayland_sock); setenv("WAYLAND_SOCKET", s, 0); /* Capture the log to the specified file descriptor. */ client_log_fd = log_fd; wl_log_set_handler_client(client_log_handler); cur_fds = count_open_fds(); client_main(data); /* Clients using wl_display_connect() will end up closing the socket * passed in through the WAYLAND_SOCKET environment variable. When * doing this, it clears the environment variable, so if it's been * unset, then we assume the client consumed the file descriptor and * do not count it towards leak checking. */ if (!getenv("WAYLAND_SOCKET")) cur_fds--; check_fd_leaks(cur_fds); } static int create_log_fd(void) { char logname[] = "/tmp/wayland-tests-log-XXXXXX"; int log_fd = mkstemp(logname); if (log_fd >= 0) unlink(logname); return log_fd; } static struct client_info * display_create_client(struct display *d, void (*client_main)(void *data), void *data, const char *name) { int pipe_cli[2]; int sock_wayl[2]; pid_t pid; int can_continue = 0; struct client_info *cl; int log_fd; assert(pipe(pipe_cli) == 0 && "Failed creating pipe"); assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_wayl) == 0 && "Failed creating socket pair"); log_fd = create_log_fd(); assert(log_fd >= 0 && "Failed to create log fd"); pid = fork(); assert(pid != -1 && "Fork failed"); if (pid == 0) { close(sock_wayl[1]); close(pipe_cli[1]); run_client(client_main, data, sock_wayl[0], pipe_cli[0], log_fd); close(sock_wayl[0]); close(pipe_cli[0]); close(log_fd); exit(0); } close(sock_wayl[0]); close(pipe_cli[0]); cl = calloc(1, sizeof(struct client_info)); assert(cl && "Out of memory"); wl_list_insert(&d->clients, &cl->link); cl->display = d; cl->name = name; cl->pid = pid; cl->pipe = pipe_cli[1]; cl->log_fd = log_fd; cl->destroy_listener.notify = &client_destroyed; cl->wl_client = wl_client_create(d->wl_display, sock_wayl[1]); if (!cl->wl_client) { int ret; /* abort the client */ ret = write(cl->pipe, &can_continue, sizeof(int)); assert(ret == sizeof(int) && "aborting the client failed"); assert(0 && "Couldn't create wayland client"); } wl_client_add_destroy_listener(cl->wl_client, &cl->destroy_listener); ++d->clients_no; return cl; } struct client_info * client_create_with_name(struct display *d, void (*client_main)(void *data), void *data, const char *name) { int can_continue = 1; struct client_info *cl = display_create_client(d, client_main, data, name); /* let the show begin! */ assert(write(cl->pipe, &can_continue, sizeof(int)) == sizeof(int)); return cl; } /* wfr = waiting for resume */ struct wfr { struct wl_resource *resource; struct wl_list link; }; static void handle_stop_display(struct wl_client *client, struct wl_resource *resource, uint32_t num) { struct display *d = wl_resource_get_user_data(resource); struct wfr *wfr; assert(d->wfr_num < num && "test error: Too many clients sent stop_display request"); ++d->wfr_num; wfr = malloc(sizeof *wfr); if (!wfr) { wl_client_post_no_memory(client); assert(0 && "Out of memory"); } wfr->resource = resource; wl_list_insert(&d->waiting_for_resume, &wfr->link); if (d->wfr_num == num) wl_display_terminate(d->wl_display); } static void handle_noop(struct wl_client *client, struct wl_resource *resource) { (void)client; (void)resource; } static const struct test_compositor_interface tc_implementation = { handle_stop_display, handle_noop, }; static void tc_bind(struct wl_client *client, void *data, uint32_t ver, uint32_t id) { struct wl_resource *res; res = wl_resource_create(client, &test_compositor_interface, ver, id); if (!res) { wl_client_post_no_memory(client); assert(0 && "Out of memory"); } wl_resource_set_implementation(res, &tc_implementation, data, NULL); } struct display * display_create(void) { struct display *d = NULL; const char *socket_name; int stat = 0; d = calloc(1, sizeof *d); assert(d && "Out of memory"); d->wl_display = wl_display_create(); assert(d->wl_display && "Creating display failed"); /* hope the path won't be longer than 108 ... */ socket_name = get_socket_name(); stat = wl_display_add_socket(d->wl_display, socket_name); assert(stat == 0 && "Failed adding socket"); wl_list_init(&d->clients); d->clients_no = d->clients_terminated_no = 0; wl_list_init(&d->waiting_for_resume); d->wfr_num = 0; d->test_global = wl_global_create(d->wl_display, &test_compositor_interface, 1, d, tc_bind); assert(d->test_global && "Creating test global failed"); return d; } void display_run(struct display *d) { assert(d->wfr_num == 0 && "test error: Have waiting clients. Use display_resume."); wl_display_run(d->wl_display); } void display_post_resume_events(struct display *d) { struct wfr *wfr, *next; assert(d->wfr_num > 0 && "test error: No clients waiting."); wl_list_for_each_safe(wfr, next, &d->waiting_for_resume, link) { wl_resource_post_event(wfr->resource, DISPLAY_RESUMED); wl_list_remove(&wfr->link); free(wfr); } assert(wl_list_empty(&d->waiting_for_resume)); d->wfr_num = 0; } void display_resume(struct display *d) { display_post_resume_events(d); wl_display_run(d->wl_display); } /* If signum is 0, expect a successful client exit, otherwise * expect the client to have been killed by that signal. */ void display_destroy_expect_signal(struct display *d, int signum) { struct client_info *cl, *next; int failed = 0; assert(d->wfr_num == 0 && "test error: Didn't you forget to call display_resume?"); wl_list_for_each_safe(cl, next, &d->clients, link) { assert(cl->wl_client == NULL); if (signum != 0 && cl->kill_code != signum) { ++failed; fprintf(stderr, "Client '%s' failed, expecting signal %d, " "got %d\n", cl->name, signum, cl->kill_code); } else if (signum == 0 && (cl->kill_code != 0 || cl->exit_code != 0)) { ++failed; fprintf(stderr, "Client '%s' failed\n", cl->name); } close(cl->pipe); close(cl->log_fd); free(cl); } wl_global_destroy(d->test_global); wl_display_destroy(d->wl_display); free(d); if (failed) { fprintf(stderr, "%d child(ren) failed\n", failed); abort(); } } void display_destroy(struct display *d) { display_destroy_expect_signal(d, 0); } /* * --- Client helper functions --- */ static void handle_display_resumed(void *data, struct test_compositor *tc) { struct client *c = data; c->display_stopped = 0; } static const struct test_compositor_listener tc_listener = { handle_display_resumed }; static void registry_handle_globals(void *data, struct wl_registry *registry, uint32_t id, const char *intf, uint32_t ver) { struct client *c = data; if (strcmp(intf, "test") != 0) return; c->tc = wl_registry_bind(registry, id, &test_compositor_interface, ver); assert(c->tc && "Failed binding to registry"); wl_proxy_add_listener((struct wl_proxy *) c->tc, (void *) &tc_listener, c); } static const struct wl_registry_listener registry_listener = { registry_handle_globals, NULL }; struct client *client_connect() { struct wl_registry *reg; struct client *c = calloc(1, sizeof *c); assert(c && "Out of memory"); c->wl_display = wl_display_connect(NULL); assert(c->wl_display && "Failed connecting to display"); /* create test_compositor proxy. Do it with temporary * registry so that client can define it's own listener later */ reg = wl_display_get_registry(c->wl_display); assert(reg); wl_registry_add_listener(reg, ®istry_listener, c); wl_display_roundtrip(c->wl_display); assert(c->tc); wl_registry_destroy(reg); return c; } static void check_error(struct wl_display *display) { uint32_t ec, id; const struct wl_interface *intf; int err; err = wl_display_get_error(display); /* write out message about protocol error */ if (err == EPROTO) { ec = wl_display_get_protocol_error(display, &intf, &id); fprintf(stderr, "Client: Got protocol error %u on interface %s" " (object %u)\n", ec, intf->name, id); } if (err) { fprintf(stderr, "Client error: %s\n", strerror(err)); abort(); } } void client_disconnect(struct client *c) { /* check for errors */ check_error(c->wl_display); wl_proxy_destroy((struct wl_proxy *) c->tc); wl_display_disconnect(c->wl_display); free(c); } /* num is number of clients that requests to stop display. * Display is stopped after it receives num STOP_DISPLAY requests */ int stop_display(struct client *c, int num) { int n = 0; c->display_stopped = 1; wl_proxy_marshal((struct wl_proxy *) c->tc, STOP_DISPLAY, num); while (c->display_stopped && n >= 0) { n = wl_display_dispatch(c->wl_display); } return n; } void noop_request(struct client *c) { wl_proxy_marshal((struct wl_proxy *) c->tc, TEST_NOOP); } wayland-1.23.1/tests/test-compositor.h000066400000000000000000000074531466237767300177610ustar00rootroot00000000000000/* * Copyright (c) 2014 Red Hat, Inc. * * 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 #include #include #include "wayland-server.h" #include "wayland-client.h" /* info about a client on server side */ struct client_info { struct display *display; struct wl_client *wl_client; struct wl_listener destroy_listener; const char *name; /* for debugging */ int pipe; pid_t pid; int exit_code; int kill_code; struct wl_list link; void *data; /* for arbitrary use */ int log_fd; }; struct display { struct wl_display *wl_display; struct wl_global *test_global; struct wl_list clients; uint32_t clients_no; uint32_t clients_terminated_no; /* list of clients waiting for display_resumed event */ struct wl_list waiting_for_resume; uint32_t wfr_num; }; /* This is a helper structure for clients. * Instead of calling wl_display_connect() and all the other stuff, * client can use client_connect and it will return this structure * filled. */ struct client { struct wl_display *wl_display; struct test_compositor *tc; atomic_bool display_stopped; }; struct client *client_connect(void); void client_disconnect(struct client *); int stop_display(struct client *, int); void noop_request(struct client *); /** * Usual workflow: * * d = display_create(); * * wl_global_create(d->wl_display, ...); * ... other setups ... * * client_create(d, client_main, data); * client_create(d, client_main2, data); * * display_run(d); * display_destroy(d); */ struct display *display_create(void); void display_destroy(struct display *d); void display_destroy_expect_signal(struct display *d, int signum); void display_run(struct display *d); /* This function posts the display_resumed event to all waiting clients, * so that after flushing events the clients will stop waiting and continue. * * (Calling `display_run` after this function will resume the display loop.) */ void display_post_resume_events(struct display *d); /* After n clients called stop_display(..., n), the display * is stopped and can process the code after display_run(). * * This function posts the display_resumed event to the waiting * clients, so that the clients will stop waiting and continue; * it then reruns the display. */ void display_resume(struct display *d); /* The file descriptor containing the client log. This is only valid in the * test client processes. */ extern int client_log_fd; struct client_info *client_create_with_name(struct display *d, void (*client_main)(void *data), void *data, const char *name); #define client_create(d, c, data) client_create_with_name((d), (c), data, (#c)) #define client_create_noarg(d, c) \ client_create_with_name((d), (void(*)(void *)) (c), NULL, (#c)) wayland-1.23.1/tests/test-helpers.c000066400000000000000000000112011466237767300172020ustar00rootroot00000000000000/* * Copyright © 2012 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 #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_PRCTL_H #include #endif #include "test-runner.h" #if defined(__FreeBSD__) #include /* * On FreeBSD, get file descriptor information using sysctl() since that does * not depend on a mounted fdescfs (which provides /dev/fd/N for N > 2). */ int count_open_fds(void) { int error; int nfds; int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_NFDS, 0 }; size_t len; len = sizeof(nfds); error = sysctl(mib, 4, &nfds, &len, NULL, 0); assert(error == 0 && "sysctl KERN_PROC_NFDS failed."); return nfds; } #elif defined(__OpenBSD__) #include /* * On OpenBSD, get file descriptor information using sysctl() */ int count_open_fds(void) { int error; int mib[6]; size_t size; mib[0] = CTL_KERN; mib[1] = KERN_FILE; mib[2] = KERN_FILE_BYPID; mib[3] = getpid(); mib[4] = sizeof(struct kinfo_file); mib[5] = 0; /* find the size required to store all the entries */ error = sysctl(mib, 6, NULL, &size, NULL, 0); assert(error != -1 && "sysctl KERN_FILE_BYPID failed."); /* return the current number of entries */ return size / sizeof(struct kinfo_file); } #else int count_open_fds(void) { DIR *dir; struct dirent *ent; int count = 0; /* * Using /dev/fd instead of /proc/self/fd should allow this code to * work on non-Linux operating systems. */ dir = opendir("/dev/fd"); assert(dir && "opening /dev/fd failed."); errno = 0; while ((ent = readdir(dir))) { const char *s = ent->d_name; if (s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) continue; count++; } assert(errno == 0 && "reading /dev/fd failed."); closedir(dir); return count; } #endif void exec_fd_leak_check(int nr_expected_fds) { const char *exe = "exec-fd-leak-checker"; char number[16] = { 0 }; const char *test_build_dir = getenv("TEST_BUILD_DIR"); char exe_path[256] = { 0 }; if (test_build_dir == NULL || test_build_dir[0] == 0) { test_build_dir = "."; } snprintf(exe_path, sizeof exe_path - 1, "%s/%s", test_build_dir, exe); snprintf(number, sizeof number - 1, "%d", nr_expected_fds); execl(exe_path, exe, number, (char *)NULL); assert(0 && "execing fd leak checker failed"); } #define USEC_TO_NSEC(n) (1000 * (n)) /* our implementation of usleep and sleep functions that are safe to use with * timeouts (timeouts are implemented using alarm(), so it is not safe use * usleep and sleep. See man pages of these functions) */ void test_usleep(useconds_t usec) { struct timespec ts = { .tv_sec = 0, .tv_nsec = USEC_TO_NSEC(usec) }; assert(nanosleep(&ts, NULL) == 0); } /* we must write the whole function instead of * wrapping test_usleep, because useconds_t may not * be able to contain such a big number of microseconds */ void test_sleep(unsigned int sec) { struct timespec ts = { .tv_sec = sec, .tv_nsec = 0 }; assert(nanosleep(&ts, NULL) == 0); } /** Try to disable coredumps * * Useful for tests that crash on purpose, to avoid creating a core file * or launching an application crash handler service or cluttering coredumpctl. * * NOTE: Calling this may make the process undebuggable. */ void test_disable_coredumps(void) { struct rlimit r; if (getrlimit(RLIMIT_CORE, &r) == 0) { r.rlim_cur = 0; setrlimit(RLIMIT_CORE, &r); } #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); #endif } wayland-1.23.1/tests/test-runner.c000066400000000000000000000224401466237767300170600ustar00rootroot00000000000000/* * Copyright © 2012 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" #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_PROCCTL_H #include #elif defined(HAVE_SYS_PRCTL_H) #include #ifndef PR_SET_PTRACER # define PR_SET_PTRACER 0x59616d61 #endif #endif #include "test-runner.h" /* when set to 1, check if tests are not leaking opened files. * It is turned on by default. It can be turned off by * WAYLAND_TEST_NO_LEAK_CHECK environment variable. */ int fd_leak_check_enabled; /* when this var is set to 0, every call to test_set_timeout() is * suppressed - handy when debugging the test. Can be set by * WAYLAND_TEST_NO_TIMEOUTS environment variable. */ static int timeouts_enabled = 1; /* set to one if the output goes to the terminal */ static int is_atty = 0; extern const struct test __start_test_section, __stop_test_section; static const struct test * find_test(const char *name) { const struct test *t; for (t = &__start_test_section; t < &__stop_test_section; t++) if (strcmp(t->name, name) == 0) return t; return NULL; } static void usage(const char *name, int status) { const struct test *t; fprintf(stderr, "Usage: %s [TEST]\n\n" "With no arguments, run all test. Specify test case to run\n" "only that test without forking. Available tests:\n\n", name); for (t = &__start_test_section; t < &__stop_test_section; t++) fprintf(stderr, " %s\n", t->name); fprintf(stderr, "\n"); exit(status); } void test_set_timeout(unsigned int to) { int re; if (!timeouts_enabled) { fprintf(stderr, "Timeouts suppressed.\n"); return; } re = alarm(to); fprintf(stderr, "Timeout was %sset", re ? "re-" : ""); if (to != 0) fprintf(stderr, " to %d second%s from now.\n", to, to > 1 ? "s" : ""); else fprintf(stderr, " off.\n"); } static void sigalrm_handler(int signum) { fprintf(stderr, "Test timed out.\n"); abort(); } void check_fd_leaks(int supposed_fds) { int num_fds; if (fd_leak_check_enabled) { num_fds = count_open_fds(); if (supposed_fds != num_fds) { fprintf(stderr, "fd leak detected in test. " "Opened %d files, unclosed %d\n", num_fds, num_fds - supposed_fds); abort(); } } else { fprintf(stderr, "FD leak checks disabled\n"); } } static void run_test(const struct test *t) { int cur_fds; struct sigaction sa; if (timeouts_enabled) { sa.sa_handler = sigalrm_handler; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); assert(sigaction(SIGALRM, &sa, NULL) == 0); } //cur_alloc = get_current_alloc_num(); cur_fds = count_open_fds(); t->run(); /* turn off timeout (if any) after test completion */ if (timeouts_enabled) alarm(0); check_fd_leaks(cur_fds); exit(EXIT_SUCCESS); } #ifndef PATH_MAX #define PATH_MAX 256 #endif static void set_xdg_runtime_dir(void) { char xdg_runtime_dir[PATH_MAX]; const char *xrd_env; xrd_env = getenv("XDG_RUNTIME_DIR"); /* if XDG_RUNTIME_DIR is not set in environ, fallback to /tmp */ assert((snprintf(xdg_runtime_dir, PATH_MAX, "%s/wayland-tests-XXXXXX", (xrd_env && xrd_env[0] == '/') ? xrd_env : "/tmp") < PATH_MAX) && "test error: XDG_RUNTIME_DIR too long"); assert(mkdtemp(xdg_runtime_dir) && "test error: mkdtemp failed"); if (mkdir(xdg_runtime_dir, 0700) == -1) if (errno != EEXIST) { perror("Creating XDG_RUNTIME_DIR"); abort(); } if (setenv("XDG_RUNTIME_DIR", xdg_runtime_dir, 1) == -1) { perror("Setting XDG_RUNTIME_DIR"); abort(); } } static void rmdir_xdg_runtime_dir(void) { const char *xrd_env = getenv("XDG_RUNTIME_DIR"); assert(xrd_env && xrd_env[0] == '/' && "No XDG_RUNTIME_DIR set"); /* rmdir may fail if some test didn't do clean up */ if (rmdir(xrd_env) == -1) perror("Cleaning XDG_RUNTIME_DIR"); } #define RED "\033[31m" #define GREEN "\033[32m" static void stderr_set_color(const char *color) { /* use colors only when the output is connected to * the terminal */ if (is_atty) fprintf(stderr, "%s", color); } static void stderr_reset_color(void) { if (is_atty) fprintf(stderr, "\033[0m"); } /* this function is taken from libinput/test/litest.c * (rev 028513a0a723e97941c39) * * Returns: 1 if a debugger is confirmed present; 0 if no debugger is * present or if it can't be determined. */ #if defined(HAVE_SYS_PROCCTL_H) && defined(PROC_TRACE_STATUS) static int is_debugger_attached(void) { int rc; int status; rc = procctl(P_PID, getpid(), PROC_TRACE_STATUS, &status); if (rc == -1) { perror("procctl"); return 0; } /* -1=tracing disabled, 0=no debugger attached, >0=pid of debugger. */ return status > 0; } #elif defined(HAVE_SYS_PRCTL_H) static int is_debugger_attached(void) { int status; int rc; pid_t pid; int pipefd[2]; if (pipe(pipefd) == -1) { perror("pipe"); return 0; } pid = fork(); if (pid == -1) { perror("fork"); close(pipefd[0]); close(pipefd[1]); return 0; } else if (pid == 0) { char buf; pid_t ppid = getppid(); /* Wait until parent is ready */ close(pipefd[1]); /* Close unused write end */ read(pipefd[0], &buf, 1); close(pipefd[0]); if (buf == '-') _exit(1); if (ptrace(PTRACE_ATTACH, ppid, NULL, NULL) != 0) _exit(1); if (!waitpid(-1, NULL, 0)) _exit(1); ptrace(PTRACE_CONT, NULL, NULL); ptrace(PTRACE_DETACH, ppid, NULL, NULL); _exit(0); } else { close(pipefd[0]); /* Enable child to ptrace the parent process */ rc = prctl(PR_SET_PTRACER, pid); if (rc != 0 && errno != EINVAL) { /* An error prevents us from telling if a debugger is attached. * Instead of propagating the error, assume no debugger present. * But note the error to the log as a clue for troubleshooting. * Then flag the error state to the client by sending '-'. */ perror("prctl"); write(pipefd[1], "-", 1); } else { /* Signal to client that parent is ready by passing '+' */ write(pipefd[1], "+", 1); } close(pipefd[1]); waitpid(pid, &status, 0); rc = WEXITSTATUS(status); } return rc; } #else static int is_debugger_attached(void) { /* 0=debugger can't be determined */ return 0; } #endif int main(int argc, char *argv[]) { const struct test *t; pid_t pid; int total, pass; int info; if (isatty(fileno(stderr))) is_atty = 1; if (is_debugger_attached()) { fd_leak_check_enabled = 0; timeouts_enabled = 0; } else { fd_leak_check_enabled = !getenv("WAYLAND_TEST_NO_LEAK_CHECK"); timeouts_enabled = !getenv("WAYLAND_TEST_NO_TIMEOUTS"); } if (argc == 2 && strcmp(argv[1], "--help") == 0) usage(argv[0], EXIT_SUCCESS); if (argc == 2) { t = find_test(argv[1]); if (t == NULL) { fprintf(stderr, "unknown test: \"%s\"\n", argv[1]); usage(argv[0], EXIT_FAILURE); } set_xdg_runtime_dir(); /* run_test calls exit() */ assert(atexit(rmdir_xdg_runtime_dir) == 0); run_test(t); } /* set our own XDG_RUNTIME_DIR */ set_xdg_runtime_dir(); pass = 0; for (t = &__start_test_section; t < &__stop_test_section; t++) { int success = 0; pid = fork(); assert(pid >= 0); if (pid == 0) run_test(t); /* never returns */ if (waitpid(pid, &info, 0) == -1) { stderr_set_color(RED); fprintf(stderr, "waitpid failed: %s\n", strerror(errno)); stderr_reset_color(); abort(); } if (WIFEXITED(info)) { if (WEXITSTATUS(info) == EXIT_SUCCESS) success = !t->must_fail; else success = t->must_fail; stderr_set_color(success ? GREEN : RED); fprintf(stderr, "test \"%s\":\texit status %d", t->name, WEXITSTATUS(info)); } else if (WIFSIGNALED(info)) { if (t->must_fail) success = 1; stderr_set_color(success ? GREEN : RED); fprintf(stderr, "test \"%s\":\tsignal %d", t->name, WTERMSIG(info)); } if (success) { pass++; fprintf(stderr, ", pass.\n"); } else fprintf(stderr, ", fail.\n"); stderr_reset_color(); /* print separator line */ fprintf(stderr, "----------------------------------------\n"); } total = &__stop_test_section - &__start_test_section; fprintf(stderr, "%d tests, %d pass, %d fail\n", total, pass, total - pass); /* cleaning */ rmdir_xdg_runtime_dir(); return pass == total ? EXIT_SUCCESS : EXIT_FAILURE; } wayland-1.23.1/tests/test-runner.h000066400000000000000000000051051466237767300170640ustar00rootroot00000000000000/* * Copyright © 2012 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. */ #ifndef _TEST_RUNNER_H_ #define _TEST_RUNNER_H_ #ifdef NDEBUG #error "Tests must not be built with NDEBUG defined, they rely on assert()." #endif #include struct test { const char *name; void (*run)(void); int must_fail; } __attribute__ ((aligned (16))); #define TEST(name) \ static void name(void); \ \ const struct test test##name \ __attribute__ ((used, section ("test_section"))) = { \ #name, name, 0 \ }; \ \ static void name(void) #define FAIL_TEST(name) \ static void name(void); \ \ const struct test test##name \ __attribute__ ((used, section ("test_section"))) = { \ #name, name, 1 \ }; \ \ static void name(void) int count_open_fds(void); void exec_fd_leak_check(int nr_expected_fds); /* never returns */ void check_fd_leaks(int supposed_fds); /* * set/reset the timeout in seconds. The timeout starts * at the point of invoking this function */ void test_set_timeout(unsigned int); /* test-runner uses alarm() and SIGALRM, so we can not * use usleep and sleep functions in tests (see 'man usleep' * or 'man sleep', respectively). Following functions are safe * to use in tests */ void test_usleep(useconds_t); void test_sleep(unsigned int); void test_disable_coredumps(void); #define DISABLE_LEAK_CHECKS \ do { \ extern int fd_leak_check_enabled; \ fd_leak_check_enabled = 0; \ } while (0); #endif wayland-1.23.1/wayland-scanner.m4000066400000000000000000000006541466237767300166170ustar00rootroot00000000000000AC_DEFUN([WAYLAND_SCANNER_RULES], [ PKG_PROG_PKG_CONFIG PKG_CHECK_MODULES([WAYLAND_SCANNER], [wayland-scanner >= 1.14.0]) wayland_scanner=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner` AC_SUBST([wayland_scanner]) wayland_scanner_rules=`$PKG_CONFIG --variable=pkgdatadir wayland-scanner`/wayland-scanner.mk AC_SUBST_FILE([wayland_scanner_rules]) AC_SUBST([wayland_protocoldir], [$1]) ]) wayland-1.23.1/wayland-scanner.mk000066400000000000000000000004441466237767300167030ustar00rootroot00000000000000%-protocol.c : $(wayland_protocoldir)/%.xml $(AM_V_GEN)$(wayland_scanner) code $< $@ %-server-protocol.h : $(wayland_protocoldir)/%.xml $(AM_V_GEN)$(wayland_scanner) server-header $< $@ %-client-protocol.h : $(wayland_protocoldir)/%.xml $(AM_V_GEN)$(wayland_scanner) client-header $< $@