├── .github ├── .jira_sync_config.yaml ├── CODEOWNERS └── workflows │ ├── ppa-upload.yml │ ├── spread.yml │ ├── tarball.yml │ └── tics.yaml ├── .gitignore ├── CMakeLists.txt ├── COPYING.GPL2 ├── COPYING.GPL3 ├── README.rst ├── SECURITY.md ├── cmake ├── FindGtestGmock.cmake └── JoinPaths.cmake ├── debian ├── changelog ├── compat ├── control ├── copyright ├── rules ├── source │ └── format ├── upstream │ └── signing-key.asc └── watch ├── example └── mir_integration.cpp ├── include ├── active_listeners.h ├── data_device.h ├── expect_protocol_error.h ├── geometry │ ├── dimensions.h │ ├── displacement.h │ ├── forward.h │ ├── point.h │ ├── rectangle.h │ └── size.h ├── gtest_helpers.h ├── gtk_primary_selection.h ├── helpers.h ├── in_process_server.h ├── input_method.h ├── layer_shell_v1.h ├── method_event_impl.h ├── mock_input_method_v1.h ├── mock_input_method_v2.h ├── mock_text_input_v2.h ├── mock_text_input_v3.h ├── mutex.h ├── pointer_constraints_unstable_v1.h ├── primary_selection.h ├── relative_pointer_unstable_v1.h ├── shared_library.h ├── surface_builder.h ├── version_specifier.h ├── wl_handle.h ├── wl_interface_descriptor.h ├── wlcs │ ├── display_server.h │ ├── pointer.h │ └── touch.h ├── xdg_decoration_unstable_v1.h ├── xdg_output_v1.h ├── xdg_shell_stable.h └── xdg_shell_v6.h ├── renovate.json ├── spread.yaml ├── spread └── build │ ├── alpine │ └── task.yaml │ ├── archlinux │ └── task.yaml │ ├── fedora │ └── task.yaml │ └── ubuntu │ └── task.yaml ├── src ├── data_device.cpp ├── gtk_primary_selection.cpp ├── helpers.cpp ├── in_process_server.cpp ├── input_method.cpp ├── layer_shell_v1.cpp ├── main.cpp ├── pointer_constraints_unstable_v1.cpp ├── primary_selection.cpp ├── protocol │ ├── fractional-scale-v1.xml │ ├── gtk-primary-selection.xml │ ├── input-method-unstable-v1.xml │ ├── input-method-unstable-v2.xml │ ├── pointer-constraints-unstable-v1.xml │ ├── primary-selection-unstable-v1.xml │ ├── relative-pointer-unstable-v1.xml │ ├── text-input-unstable-v2.xml │ ├── text-input-unstable-v3.xml │ ├── viewporter.xml │ ├── wayland.xml │ ├── wlr-foreign-toplevel-management-unstable-v1.xml │ ├── wlr-layer-shell-unstable-v1.xml │ ├── wlr-virtual-pointer-unstable-v1.xml │ ├── xdg-decoration-unstable-v1.xml │ ├── xdg-output-unstable-v1.xml │ ├── xdg-shell-unstable-v6.xml │ └── xdg-shell.xml ├── relative_pointer_unstable_v1.cpp ├── shared_library.cpp ├── surface_builder.cpp ├── termcolor.hpp ├── test_c_compile.c ├── thread_proxy.h ├── version_specifier.cpp ├── xdg_decoration_unstable_v1.cpp ├── xdg_output_v1.cpp ├── xdg_shell_stable.cpp ├── xdg_shell_v6.cpp ├── xfail_supporting_test_listener.cpp └── xfail_supporting_test_listener.h ├── tests ├── copy_cut_paste.cpp ├── fractional_scale_v1.cpp ├── frame_submission.cpp ├── gtk_primary_selection.cpp ├── pointer_constraints.cpp ├── primary_selection.cpp ├── relative_pointer.cpp ├── self_test.cpp ├── subsurfaces.cpp ├── surface_input_regions.cpp ├── test_bad_buffer.cpp ├── test_surface_events.cpp ├── text_input_v2_with_input_method_v1.cpp ├── text_input_v3_with_input_method_v2.cpp ├── touches.cpp ├── wl_output.cpp ├── wlr_foreign_toplevel_management_v1.cpp ├── wlr_layer_shell_v1.cpp ├── wlr_virtual_pointer_v1.cpp ├── wp_viewporter.cpp ├── xdg_decoration_v1.cpp ├── xdg_output_v1.cpp ├── xdg_popup.cpp ├── xdg_surface_stable.cpp ├── xdg_surface_v6.cpp ├── xdg_toplevel_stable.cpp └── xdg_toplevel_v6.cpp ├── tools ├── make_release_tarball └── ppa-upload.sh └── wlcs.pc.in /.github/.jira_sync_config.yaml: -------------------------------------------------------------------------------- 1 | settings: 2 | jira_project_key: MIRENG 3 | # Only act on issues labeled "triaged" 4 | labels: 5 | - triaged 6 | status_mapping: 7 | opened: Triaged 8 | closed: Done 9 | components: 10 | - Testing 11 | label_mapping: 12 | enhancement: Story 13 | 14 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | 2 | # These owners will be the default owners for everything in 3 | # the repo. Unless a later match takes precedence, 4 | * @canonical/mir 5 | -------------------------------------------------------------------------------- /.github/workflows/ppa-upload.yml: -------------------------------------------------------------------------------- 1 | name: PPA Upload 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - release/[0-9]+.[0-9]+ 8 | tags: 9 | - v[0-9]+.[0-9]+.[0-9]+ 10 | 11 | jobs: 12 | PPAUpload: 13 | strategy: 14 | fail-fast: true 15 | matrix: 16 | release: 17 | - "24.04" 18 | - "24.10" 19 | - "devel" 20 | 21 | runs-on: ubuntu-latest 22 | 23 | env: 24 | DEBFULLNAME: "Mir CI Bot" 25 | DEBEMAIL: "mir-ci-bot@canonical.com" 26 | 27 | steps: 28 | - name: Import GPG key 29 | uses: crazy-max/ghaction-import-gpg@v6 30 | with: 31 | gpg_private_key: ${{ secrets.MIR_BOT_GPG_PRIVATE_KEY }} 32 | 33 | - name: Check out code 34 | uses: actions/checkout@v4 35 | with: 36 | # Need full history for version determination 37 | fetch-depth: 0 38 | 39 | - name: Install dependencies 40 | run: | 41 | sudo apt-get install --no-install-recommends --yes \ 42 | debhelper \ 43 | devscripts \ 44 | dput \ 45 | dh-python \ 46 | python3-launchpadlib 47 | 48 | - name: Set up Launchpad credentials 49 | uses: DamianReeves/write-file-action@v1.3 50 | with: 51 | path: ${{ github.workspace }}/../lp_credentials 52 | contents: ${{ secrets.LAUNCHPAD_CREDENTIALS }} 53 | 54 | - name: Upload to PPA 55 | env: 56 | RELEASE: ${{ matrix.release }} 57 | run: tools/ppa-upload.sh ${{ github.workspace }}/../lp_credentials 58 | 59 | - if: ${{ failure() && runner.debug }} 60 | name: Setup upterm session 61 | uses: mxschmitt/action-tmate@v3 62 | with: 63 | limit-access-to-actor: true 64 | -------------------------------------------------------------------------------- /.github/workflows/spread.yml: -------------------------------------------------------------------------------- 1 | name: Spread 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.event.number && format('pr{0}', github.event.number) || github.run_id }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | push: 9 | branches: 10 | - main 11 | - release/[0-9]+.[0-9]+ 12 | tags: 13 | - v[0-9]+[0-9]+.[0-9]+ 14 | merge_group: 15 | types: [checks_requested] 16 | pull_request: 17 | types: [opened, synchronize, reopened, ready_for_review] 18 | 19 | jobs: 20 | BuildAndTest: 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | spread-task: 25 | - lxd:ubuntu-24.04:...:gcc 26 | - lxd:ubuntu-24.10:...:gcc 27 | - lxd:ubuntu-25.04:...:gcc 28 | - lxd:ubuntu-25.04:...:clang 29 | - lxd:fedora-41:...:gcc 30 | - lxd:fedora-42:...:gcc 31 | - lxd:fedora-rawhide:...:gcc 32 | - lxd:alpine-3.20:...:gcc 33 | - lxd:alpine-3.21:...:gcc 34 | - lxd:ubuntu-devel:...:gcc 35 | - lxd:ubuntu-devel:...:clang 36 | - lxd:alpine-edge:...:gcc 37 | - lxd:archlinux-cloud:...:gcc 38 | 39 | runs-on: ubuntu-latest 40 | 41 | env: 42 | DEBFULLNAME: "Mir CI Bot" 43 | DEBEMAIL: "mir-ci-bot@canonical.com" 44 | 45 | steps: 46 | - name: Set up LXD 47 | uses: canonical/setup-lxd@main 48 | 49 | - name: Set up Spread 50 | run: | 51 | set -euo pipefail 52 | sudo snap install spread-mir-ci 53 | sudo snap run lxd init --auto 54 | 55 | - name: Check out code 56 | uses: actions/checkout@v4 57 | 58 | - name: Run Spread task 59 | run: snap run spread-mir-ci.spread -v ${{ matrix.spread-task }} 60 | -------------------------------------------------------------------------------- /.github/workflows/tarball.yml: -------------------------------------------------------------------------------- 1 | name: Build a tarball 2 | 3 | on: 4 | push: 5 | tags: 6 | - v[0-9]+.[0-9]+.[0-9]+ 7 | workflow_dispatch: 8 | inputs: 9 | version: 10 | description: The version to build the tarball for 11 | required: true 12 | 13 | jobs: 14 | BuildTarball: 15 | 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - name: Determine version to build 20 | id: get-version 21 | run: | 22 | if ${{ github.event_name == 'push' }}; then 23 | version="$( echo '${{ github.ref }}' | sed 's@^refs/tags/v@@' )" 24 | else 25 | version='${{ inputs.version }}' 26 | fi 27 | 28 | # assert it's a version number 29 | set -x 30 | [[ ${version} =~ ^[0-9]+.[0-9]+.[0-9]+$ ]] && echo "version=${version}" >> $GITHUB_OUTPUT 31 | 32 | - name: Import GPG key 33 | uses: crazy-max/ghaction-import-gpg@v6 34 | with: 35 | gpg_private_key: ${{ secrets.MIR_BOT_GPG_PRIVATE_KEY }} 36 | 37 | - name: Check out code 38 | uses: actions/checkout@v4 39 | with: 40 | ref: v${{ steps.get-version.outputs.version }} 41 | 42 | - name: Build the tarball 43 | run: | 44 | ./tools/make_release_tarball --skip-checks 45 | gpg --detach-sig --sign --output wlcs-${{ steps.get-version.outputs.version }}.tar.xz.asc wlcs-${{ steps.get-version.outputs.version }}.tar.xz 46 | 47 | - name: Store the tarball and signature 48 | uses: actions/upload-artifact@v4 49 | with: 50 | name: wlcs-${{ steps.get-version.outputs.version }} 51 | path: | 52 | wlcs-${{ steps.get-version.outputs.version }}.tar.xz 53 | wlcs-${{ steps.get-version.outputs.version }}.tar.xz.asc 54 | -------------------------------------------------------------------------------- /.github/workflows/tics.yaml: -------------------------------------------------------------------------------- 1 | name: TICS 2 | 3 | on: 4 | # push: 5 | # branches: 6 | # - main 7 | schedule: 8 | # 5:04 on a Wednesday 9 | - cron: 5 4 * * 3 10 | workflow_dispatch: 11 | 12 | jobs: 13 | CI: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v4 18 | 19 | - name: Install dependencies 20 | run: | 21 | sudo add-apt-repository --yes ppa:mir-team/dev 22 | sudo apt install --yes \ 23 | build-essential \ 24 | cmake \ 25 | google-mock \ 26 | libboost-dev \ 27 | libgtest-dev \ 28 | libwayland-dev \ 29 | ninja-build \ 30 | pkg-config 31 | 32 | - name: Run TICS analysis 33 | uses: tiobe/tics-github-action@v3 34 | with: 35 | mode: qserver 36 | project: wlcs 37 | viewerUrl: https://canonical.tiobe.com/tiobeweb/TICS/api/cfg?name=default 38 | ticsAuthToken: ${{ secrets.TICSAUTHTOKEN }} 39 | installTics: true 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | /build/ 3 | /cmake-build-debug/ 4 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | Wayland Conformance Test Suite 3 | ============================== 4 | 5 | ``wlcs`` aspires to be a protocol-conformance-verifying test suite usable by 6 | Wayland compositor implementors. 7 | 8 | It is growing out of porting the existing Weston test suite to be run 9 | in `Mir's `_ test suite, 10 | but it is designed to be usable by any compositor. 11 | 12 | There have been a number of previous attempts at a Wayland compositor test 13 | suite - the `Wayland Functional Integration Test Suite `_, 14 | and the `Weston test suite `_ 15 | are a couple of examples. 16 | 17 | What sets ``wlcs`` apart from the graveyard of existing test suites is its 18 | integration method. 19 | 20 | Previous test suites have used a Wayland protocol extension 21 | to interrogate the compositor state. This obviously requires that compositors 22 | implement that protocol, means that tests only have access to information 23 | provided by that protocol, and the IPC means that there isn't a canonical 24 | happens-before ordering available. 25 | 26 | Instead, ``wlcs`` relies on compositors providing an integration module, 27 | providing ``wlcs`` with API hooks to start a compositor, connect a client, 28 | move a window, and so on. This makes both writing and debugging tests easier - 29 | the tests are (generally) in the same address space as the compositor, so there 30 | is a consistent global clock available, it's easier to poke around in 31 | compositor internals, and standard debugging tools can follow control flow from 32 | the test client to the compositor and back again. 33 | 34 | Usage 35 | ----- 36 | 37 | In order for ``wlcs`` to test your compositor you need to provide an 38 | integration module. This needs to implement the interfaces found in 39 | ``include/wlcs``. If your integration module is 40 | ``awesome_compositor_wlcs_integration.so``, then running ``wlcs 41 | awesome_compositor_wlcs_integration.so`` will load and run all the tests. 42 | 43 | Development 44 | ----------- 45 | 46 | ``wlcs`` requires a small number of hooks into your compositor to drive the 47 | tests - it needs to know how to start and stop the mainloop, to get an fd to 48 | connect a client to, and so on. 49 | 50 | To access these hooks, ``wlcs`` looks for a symbol ``wlcs_server_integration`` 51 | of type ``struct WlcsServerIntegration const`` (defined in 52 | ``include/wlcs/display_server.h``) in your integration module. 53 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | To report a security issue, file a [Private Security Report](https://github.com/canonical/mir/security/advisories/new) with a description of the issue, the steps you took to create the issue, affected versions, and, if known, mitigations for the issue. 2 | The [Ubuntu Security disclosure and embargo policy](https://ubuntu.com/security/disclosure-policy) contains more information about what you can expect when you contact us and what we expect from you. 3 | -------------------------------------------------------------------------------- /cmake/FindGtestGmock.cmake: -------------------------------------------------------------------------------- 1 | include(FindPackageHandleStandardArgs) 2 | 3 | find_package(GTest) 4 | 5 | if (NOT GTEST_FOUND) 6 | include(ExternalProject) 7 | 8 | find_path(GTEST_ROOT 9 | NAMES CMakeLists.txt 10 | PATHS /usr/src/gtest /usr/src/googletest/googletest/ 11 | DOC "Path to GTest CMake project") 12 | 13 | ExternalProject_Add(GTest PREFIX ./gtest 14 | SOURCE_DIR ${GTEST_ROOT} 15 | CMAKE_ARGS 16 | -DCMAKE_CXX_COMPILER_WORKS=1 17 | -DCMAKE_CXX_FLAGS='${CMAKE_CXX_FLAGS}' 18 | -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} 19 | INSTALL_COMMAND true 20 | BUILD_BYPRODUCTS 21 | ${CMAKE_CURRENT_BINARY_DIR}/gtest/src/GTest-build/libgtest.a 22 | ${CMAKE_CURRENT_BINARY_DIR}/gtest/src/GTest-build/libgtest_main.a 23 | ${CMAKE_CURRENT_BINARY_DIR}/gtest/src/GMock-build/libgmock.a) 24 | 25 | ExternalProject_Get_Property(GTest binary_dir) 26 | 27 | add_library(gtest UNKNOWN IMPORTED) 28 | set_target_properties(gtest PROPERTIES IMPORTED_LOCATION ${binary_dir}/libgtest.a) 29 | add_dependencies(gtest GTest) 30 | set(GTEST_LIBRARY "gtest") 31 | 32 | add_library(gtest_main UNKNOWN IMPORTED) 33 | set_target_properties(gtest_main PROPERTIES IMPORTED_LOCATION ${binary_dir}/libgtest_main.a) 34 | add_dependencies(gtest_main GTest) 35 | set(GTEST_MAIN_LIBRARY "gtest_main") 36 | 37 | set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARY} ${GTEST_MAIN_LIBRARY}) 38 | find_path(GTEST_INCLUDE_DIRS NAMES gtest/gtest.h) 39 | find_package_handle_standard_args(GTest GTEST_LIBRARY GTEST_BOTH_LIBRARIES GTEST_INCLUDE_DIRS) 40 | endif() 41 | 42 | # Upstream GTestConfig.cmake doesn't provide GTEST_LIBRARY but GTEST_LIBRARIES 43 | # CMake 3.20+ uses the upstream gtest config if possible. 44 | if (NOT DEFINED GTEST_LIBRARY) 45 | set(GTEST_LIBRARY ${GTEST_LIBRARIES}) 46 | endif() 47 | 48 | find_file(GMOCK_SOURCE 49 | NAMES gmock-all.cc 50 | DOC "GMock source" 51 | PATHS /usr/src/googletest/googlemock/src/ /usr/src/gmock/ /usr/src/gmock/src) 52 | 53 | if (EXISTS ${GMOCK_SOURCE}) 54 | find_path(GMOCK_INCLUDE_DIR gmock/gmock.h PATHS /usr/src/googletest/googlemock/include) 55 | 56 | add_library(GMock STATIC ${GMOCK_SOURCE}) 57 | 58 | if (EXISTS /usr/src/googletest/googlemock/src) 59 | set_source_files_properties(${GMOCK_SOURCE} PROPERTIES COMPILE_FLAGS "-I/usr/src/googletest/googlemock") 60 | endif() 61 | 62 | if (EXISTS /usr/src/gmock/src) 63 | set_source_files_properties(${GMOCK_SOURCE} PROPERTIES COMPILE_FLAGS "-I/usr/src/gmock") 64 | endif() 65 | 66 | find_package_handle_standard_args(GMock DEFAULT_MSG GMOCK_INCLUDE_DIR) 67 | 68 | set(GMOCK_LIBRARY GMock) 69 | else() 70 | # Assume gmock is no longer source, we'll find out soon enough if that's wrong 71 | add_custom_target(GMock) 72 | string(REPLACE gtest gmock GMOCK_LIBRARY ${GTEST_LIBRARY}) 73 | endif() 74 | 75 | set(GMOCK_LIBRARIES ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY}) 76 | -------------------------------------------------------------------------------- /cmake/JoinPaths.cmake: -------------------------------------------------------------------------------- 1 | # This module provides function for joining paths 2 | # known from most languages 3 | # 4 | # SPDX-License-Identifier: (MIT OR CC0-1.0) 5 | # Copyright 2020 Jan Tojnar 6 | # https://github.com/jtojnar/cmake-snips 7 | # 8 | # Modelled after Python’s os.path.join 9 | # https://docs.python.org/3.7/library/os.path.html#os.path.join 10 | # Windows not supported 11 | function(join_paths joined_path first_path_segment) 12 | set(temp_path "${first_path_segment}") 13 | foreach(current_segment IN LISTS ARGN) 14 | if(NOT ("${current_segment}" STREQUAL "")) 15 | if(IS_ABSOLUTE "${current_segment}") 16 | set(temp_path "${current_segment}") 17 | else() 18 | set(temp_path "${temp_path}/${current_segment}") 19 | endif() 20 | endif() 21 | endforeach() 22 | set(${joined_path} "${temp_path}" PARENT_SCOPE) 23 | endfunction() 24 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | wlcs (1.7.0-0ubuntu0) UNRELEASED; urgency=medium 2 | 3 | * New upstream release. Notable changes: 4 | + New tests for input-method-v1 (#302) 5 | + Handle incomplete logical pointer/touch events better (#313) 6 | + XdgToplevelStable: Fix race in .configure handling (#318) 7 | + helpers: avoid triggering a kernel warning (#320) 8 | + InProcessServer: Fix xdg_shell window construction (#324) 9 | + XdgSurfaceStable: Fix configure event logic 10 | 11 | -- Michał Sawicz Tue, 05 Dec 2023 13:52:28 +0100 12 | 13 | wlcs (1.6.1-0ubuntu0) UNRELEASED; urgency=medium 14 | 15 | * Bump project version in CMakeLists.txt 16 | 17 | -- Michał Sawicz Tue, 10 Oct 2023 12:14:27 +0200 18 | 19 | wlcs (1.6.0-0ubuntu0) UNRELEASED; urgency=medium 20 | 21 | * New upstream release. Notable changes: 22 | + Update wayland.xml to latest 23 | + XDG stable: use mock methods instead of notification lists 24 | + Test popup constraint_adjustment 25 | + Tests for XDG shell (stable) version 5 26 | + Test that text input is entered after child window is closed 27 | + Copy geometry headers from Mir 28 | + Test popups are dismissed in the correct order 29 | + Test buffer can be deleted after it's attached 30 | + Less flaky synchronization for VirtualPointerV1Test (#297, #294) 31 | + VirtualPointerV1Test: no-events-sent test fails if events are sent (#296) 32 | + Fix various frame-event misunderstandings 33 | + Change remaining std::experimental::optionals to std::optional 34 | 35 | -- Alan Griffiths Mon, 17 Jul 2023 13:12:00 +0100 36 | 37 | wlcs (1.5.0-0ubuntu0) UNRELEASED; urgency=medium 38 | 39 | * New upstream release. Notable changes: 40 | + Tests for zwlr_virtual_pointer_v1 41 | + Use maximum shared version when binding globals (Fixes #234) 42 | + Make zxdg_shell_v6 ExpectedlyNotSupported if not in supported_extensions 43 | (Fixes #237) 44 | + Destroy xdg_toplevel before xdg_surface on cleanup 45 | + Fixup CMakeLists.txt so tests can use MOCK_METHOD 46 | + c++20 47 | + Fix BadBufferTest.test_truncated_shm_file protocol error 48 | + Fix CMake install dir usage in pkgconfig, honour CMAKE_INSTALL_INCLUDEDIR 49 | 50 | -- Alan Griffiths Fri, 6 Jan 2023 11:40:13 +0000 51 | 52 | wlcs (1.4.0-0ubuntu0) UNRELEASED; urgency=medium 53 | 54 | * New upstream release. Notable changes: 55 | + Add tests for zwp_text_input_unstable_v3 56 | + Add tests for zwp_input_method_unstable_v2 57 | + Add tests for zwlr_layer_shell_v1 version 4 58 | + Drop requriement for compositors to implement wl_shell. Tests which 59 | require an arbitrary "visible surface" should now only require one 60 | of xdg_shell, xdg_shell_unstable_v6, or wl_shell. 61 | + Fix expectations of keyboard focus for xdg_popup tests to match the 62 | protocol. NOTE: These tests will fail on many compositors, including 63 | Weston, as is is common to not follow the protocol correctly here. 64 | 65 | -- Christopher James Halse Rogers Fri, 25 Feb 2022 15:33:24 +1100 66 | 67 | wlcs (1.3.0-0ubuntu0) groovy; urgency=medium 68 | 69 | * New upstream release. Notable changes: 70 | + Check Cursor movement is not propagating to clients correctly when 71 | zwp_relative_pointer_manager_v1 is enabled 72 | + Support getting the latest serial sent from the compositor (useful for 73 | popup grabs, and possibly other things in the future). Adding `wl_keyboard` 74 | makes sure new surfaces have a serial once they're focused, and provides 75 | access to keyboard focus 76 | + Test that correct input event is used for interactive move 77 | + Fix FindGtestGmock.cmake for new cmake (Fixes the build on Alpine Linux) 78 | + Test that layer surfaces are correctly reconfigured 79 | + Add tests for popup done event 80 | + Test surfaces get enter/leave events 81 | + Test version 2 and 3 features of zwlr_layer_shell_v1 82 | + Destroy subsurfaces 83 | + Show surface type names in paramaterized touch tests 84 | 85 | -- Alan Griffiths Thu, 27 May 2021 13:13:13 +0100 86 | 87 | wlcs (1.2.1-0ubuntu0) groovy; urgency=medium 88 | 89 | * New upstream release. Notable changes: 90 | + Fix cut & paste test 91 | 92 | -- Alan Griffiths Fri, 19 Feb 2021 11:11:11 +0000 93 | 94 | wlcs (1.2.0-0ubuntu0) groovy; urgency=medium 95 | 96 | * New upstream release. Notable changes: 97 | + Add tests for wlr_layer_shell_unstable_v1 98 | + Build fixes for Musl libc; WLCS now builds on Alpine. Thanks, Luca Weiss 99 | + More XDG Shell tests, particularly around protocol errors, 100 | window-geometry, and input edge-cases. 101 | + Add tests for wlr_foreign_toplevel_management_unstable_v1 102 | + Many improvements to wl_subsurface tests. Notably this fixes a 103 | misinterpretation of the protocol which lead to testing incorrect 104 | behaviour. 105 | 106 | -- Christopher James Halse Rogers Mon, 31 Aug 2020 16:39:21 +1000 107 | 108 | wlcs (1.1.0-0ubuntu0) eoan; urgency=medium 109 | 110 | * New upstream release. Relevant upstream changes: 111 | + Document the compositor-integration version macros 112 | + Add tests for the wl_output protocol 113 | + More tests for XDG Shell, particularly around popups and window movement 114 | + Add tests for wp_primary_selection_unstable_v1 protocol 115 | + Add tests for gdk_primary_selection protocol 116 | + Lots of build fixes for !Ubuntu systems. Thanks, Neal Gompa! 117 | 118 | -- Christopher James Halse Rogers Tue, 23 Jul 2019 10:37:52 +1000 119 | 120 | wlcs (1.0-0ubuntu0) disco; urgency=medium 121 | 122 | * Initial release 123 | 124 | -- Christopher James Halse Rogers Tue, 08 Jan 2019 11:32:06 +1100 125 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: wlcs 2 | Priority: optional 3 | Maintainer: Christopher James Halse Rogers 4 | Build-Depends: 5 | debhelper (>= 9), 6 | cmake, 7 | libboost-dev, 8 | libgtest-dev, 9 | libwayland-dev, 10 | pkg-config, 11 | google-mock 12 | Standards-Version: 4.1.3 13 | Section: devel 14 | Homepage: https://github.com/MirServer/wlcs 15 | Vcs-Browser: https://salsa.debian.org/mir-server-team/wlcs 16 | Vcs-Git: https://salsa.debian.org/mir-server-team/wlcs.git 17 | 18 | Package: wlcs 19 | Section: devel 20 | Architecture: any 21 | Multi-Arch: same 22 | Depends: ${misc:Depends}, ${shlibs:Depends} 23 | Description: Wayland Conformance Suite's 24 | wlcs aspires to be a protocol-conformance-verifying test suite usable by 25 | Wayland compositor implementations. 26 | . 27 | This package contains the headers necessary for a Wayland compositor to 28 | provide the integration module needed to run wlcs tests, and the test 29 | runner binary needed to run the tests against the compositor. 30 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: wlcs 3 | Source: https://github.com/MirServer/wlcs 4 | 5 | Files: * 6 | Copyright: 2017-2019 Canonical, Ltd 7 | License: GPL-3 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License version 3 as 10 | published by the Free Software Foundation. 11 | . 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | . 17 | On Debian systems, the full text of the GNU General Public 18 | License version 3 can be found in the file 19 | `/usr/share/common-licenses/GPL-3'. 20 | 21 | Files: tests/test_bad_buffer.cpp 22 | tests/test_surface_events.cpp 23 | xdg_popup_stable.cpp 24 | xdg_popup_v6.cpp 25 | xdg_surface_stable.cpp 26 | xdg_surface_v6.cpp 27 | xdg_toplevel_stable.cpp 28 | xdg_toplevel_v6.cpp 29 | Copyright: 2012 Intel Corporation 30 | 2013 Collabora, Ltd. 31 | 2017-2018 Canonical Ltd. 32 | License: Expat 33 | Permission is hereby granted, free of charge, to any person obtaining 34 | a copy of this software and associated documentation files (the 35 | "Software"), to deal in the Software without restriction, including 36 | without limitation the rights to use, copy, modify, merge, publish, 37 | distribute, sublicense, and/or sell copies of the Software, and to 38 | permit persons to whom the Software is furnished to do so, subject to 39 | the following conditions: 40 | . 41 | The above copyright notice and this permission notice (including the 42 | next paragraph) shall be included in all copies or substantial 43 | portions of the Software. 44 | . 45 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 46 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 47 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 48 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 49 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 50 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 51 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 52 | SOFTWARE. 53 | 54 | 55 | Files: debian/* 56 | Copyright: 2019 Christopher James Halse Rogers 57 | License: GPL-2+ 58 | This package is free software; you can redistribute it and/or modify 59 | it under the terms of the GNU General Public License as published by 60 | the Free Software Foundation; either version 2 of the License, or 61 | (at your option) any later version. 62 | . 63 | This package is distributed in the hope that it will be useful, 64 | but WITHOUT ANY WARRANTY; without even the implied warranty of 65 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 66 | GNU General Public License for more details. 67 | . 68 | You should have received a copy of the GNU General Public License 69 | along with this program. If not, see 70 | . 71 | On Debian systems, the complete text of the GNU General 72 | Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". 73 | 74 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | include /usr/share/dpkg/default.mk 4 | 5 | # see FEATURE AREAS in dpkg-buildflags(1) 6 | export DEB_BUILD_MAINT_OPTIONS = hardening=+all 7 | 8 | COMMON_CONFIGURE_OPTIONS =\ 9 | -DWLCS_BUILD_ASAN=ON \ 10 | -DWLCS_BUILD_UBSAN=ON \ 11 | -DWLCS_BUILD_TSAN=ON 12 | 13 | ifneq ($(filter i386 armhf, $(DEB_HOST_ARCH)),) 14 | # i386 and armhf do not have tsan 15 | COMMON_CONFIGURE_OPTIONS += -DWLCS_BUILD_TSAN=OFF 16 | endif 17 | 18 | ifeq ($(DEB_HOST_ARCH), riscv64) 19 | # riscv64 does not have sanitizers 20 | ifeq ($(DEB_DISTRIBUTION), focal) 21 | COMMON_CONFIGURE_OPTIONS += -DWLCS_BUILD_ASAN=OFF 22 | endif 23 | COMMON_CONFIGURE_OPTIONS += -DWLCS_BUILD_UBSAN=OFF 24 | COMMON_CONFIGURE_OPTIONS += -DWLCS_BUILD_TSAN=OFF 25 | endif 26 | 27 | # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105329 28 | ifeq ($(DEB_HOST_ARCH), ppc64el) 29 | ifneq ($(shell gcc --version | grep '1[34].[[:digit:]]\+.[[:digit:]]\+$$'),) 30 | export DEB_CFLAGS_MAINT_APPEND = -O2 31 | export DEB_CXXFLAGS_MAINT_APPEND = -O2 32 | export DEB_FCFLAGS_MAINT_APPEND = -O2 33 | export DEB_FFLAGS_MAINT_APPEND = -O2 34 | endif 35 | endif 36 | 37 | # Disable LTO on broken binutils 38 | # https://bugs.launchpad.net/ubuntu/+source/binutils/+bug/2070302 39 | ifneq ($(shell ld --version | grep '2.43.1$$'),) 40 | DEB_BUILD_MAINT_OPTIONS += optimize=-lto 41 | endif 42 | 43 | override_dh_auto_configure: 44 | dh_auto_configure -- $(COMMON_CONFIGURE_OPTIONS) 45 | 46 | %: 47 | dh $@ 48 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 1.0 2 | -------------------------------------------------------------------------------- /debian/watch: -------------------------------------------------------------------------------- 1 | # Compulsory line, this is a version 4 file 2 | version=4 3 | 4 | version=4 5 | opts="pgpsigurlmangle=s/$/.asc/" \ 6 | https://github.com/MirServer/wlcs/releases/latest .*/wlcs-(\d\S+)\.tar\.xz 7 | -------------------------------------------------------------------------------- /include/active_listeners.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Alan Griffiths 17 | */ 18 | 19 | #ifndef WLCS_ACTIVE_LISTENERS_H 20 | #define WLCS_ACTIVE_LISTENERS_H 21 | 22 | #include 23 | #include 24 | 25 | namespace wlcs 26 | { 27 | class ActiveListeners 28 | { 29 | public: 30 | void add(void* listener) 31 | { 32 | std::lock_guard lock{mutex}; 33 | listeners.insert(listener); 34 | } 35 | 36 | void del(void* listener) 37 | { 38 | std::lock_guard lock{mutex}; 39 | listeners.erase(listener); 40 | } 41 | 42 | bool includes(void* listener) const 43 | { 44 | std::lock_guard lock{mutex}; 45 | return listeners.find(listener) != end(listeners); 46 | } 47 | 48 | private: 49 | std::mutex mutable mutex; 50 | std::set listeners; 51 | }; 52 | } 53 | 54 | #endif //WLCS_ACTIVE_LISTENERS_H 55 | -------------------------------------------------------------------------------- /include/expect_protocol_error.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2017-Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #ifndef WLCS_EXPECT_PROTOCOL_ERROR_H_ 18 | #define WLCS_EXPECT_PROTOCOL_ERROR_H_ 19 | 20 | #include 21 | #include 22 | 23 | #define EXPECT_PROTOCOL_ERROR(block, iface, err_code) \ 24 | try { \ 25 | block \ 26 | FAIL() << "Expected protocol error not raised"; \ 27 | } catch (wlcs::ProtocolError const& err) {\ 28 | EXPECT_THAT(err.interface(), Eq(iface));\ 29 | EXPECT_THAT(err.error_code(), Eq(err_code));\ 30 | } 31 | 32 | #endif // WLCS_EXPECT_PROTOCOL_ERROR_H_ 33 | -------------------------------------------------------------------------------- /include/geometry/displacement.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License version 2 or 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU Lesser General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #ifndef WLCS_GEOMETRY_DISPLACEMENT_H_ 18 | #define WLCS_GEOMETRY_DISPLACEMENT_H_ 19 | 20 | #include "forward.h" 21 | #include "dimensions.h" 22 | #include "point.h" 23 | #include 24 | 25 | namespace wlcs 26 | { 27 | namespace generic 28 | { 29 | template 30 | struct Point; 31 | 32 | template 33 | struct Size; 34 | 35 | template 36 | struct Displacement 37 | { 38 | using ValueType = T; 39 | 40 | constexpr Displacement() {} 41 | constexpr Displacement(Displacement const&) = default; 42 | Displacement& operator=(Displacement const&) = default; 43 | 44 | template 45 | explicit constexpr Displacement(Displacement const& other) noexcept 46 | : dx{DeltaX{other.dx}}, 47 | dy{DeltaY{other.dy}} 48 | { 49 | } 50 | 51 | template 52 | constexpr Displacement(DeltaXType&& dx, DeltaYType&& dy) : dx{dx}, dy{dy} {} 53 | 54 | template 55 | constexpr typename std::enable_if::value, long long>::type length_squared() const 56 | { 57 | long long x = dx.as_value(), y = dy.as_value(); 58 | return x * x + y * y; 59 | } 60 | 61 | template 62 | constexpr typename std::enable_if::value, T>::type length_squared() const 63 | { 64 | T x = dx.as_value(), y = dy.as_value(); 65 | return x * x + y * y; 66 | } 67 | 68 | DeltaX dx; 69 | DeltaY dy; 70 | }; 71 | 72 | template 73 | inline constexpr bool operator==(Displacement const& lhs, Displacement const& rhs) 74 | { 75 | return lhs.dx == rhs.dx && lhs.dy == rhs.dy; 76 | } 77 | 78 | template 79 | inline constexpr bool operator!=(Displacement const& lhs, Displacement const& rhs) 80 | { 81 | return lhs.dx != rhs.dx || lhs.dy != rhs.dy; 82 | } 83 | 84 | template 85 | std::ostream& operator<<(std::ostream& out, Displacement const& value) 86 | { 87 | out << '(' << value.dx << ", " << value.dy << ')'; 88 | return out; 89 | } 90 | 91 | template 92 | inline constexpr Displacement operator+(Displacement const& lhs, Displacement const& rhs) 93 | { 94 | return Displacement{lhs.dx + rhs.dx, lhs.dy + rhs.dy}; 95 | } 96 | 97 | template 98 | inline constexpr Displacement operator-(Displacement const& lhs, Displacement const& rhs) 99 | { 100 | return Displacement{lhs.dx - rhs.dx, lhs.dy - rhs.dy}; 101 | } 102 | 103 | template 104 | inline constexpr Displacement operator-(Displacement const& rhs) 105 | { 106 | return Displacement{-rhs.dx, -rhs.dy}; 107 | } 108 | 109 | template 110 | inline constexpr Point operator+(Point const& lhs, Displacement const& rhs) 111 | { 112 | return Point{lhs.x + rhs.dx, lhs.y + rhs.dy}; 113 | } 114 | 115 | template 116 | inline constexpr Point operator+(Displacement const& lhs, Point const& rhs) 117 | { 118 | return Point{rhs.x + lhs.dx, rhs.y + lhs.dy}; 119 | } 120 | 121 | template 122 | inline constexpr Point operator-(Point const& lhs, Displacement const& rhs) 123 | { 124 | return Point{lhs.x - rhs.dx, lhs.y - rhs.dy}; 125 | } 126 | 127 | template 128 | inline constexpr Displacement operator-(Point const& lhs, Point const& rhs) 129 | { 130 | return Displacement{lhs.x - rhs.x, lhs.y - rhs.y}; 131 | } 132 | 133 | template 134 | inline constexpr Point& operator+=(Point& lhs, Displacement const& rhs) 135 | { 136 | return lhs = lhs + rhs; 137 | } 138 | 139 | template 140 | inline constexpr Point& operator-=(Point& lhs, Displacement const& rhs) 141 | { 142 | return lhs = lhs - rhs; 143 | } 144 | 145 | template 146 | inline bool operator<(Displacement const& lhs, Displacement const& rhs) 147 | { 148 | return lhs.length_squared() < rhs.length_squared(); 149 | } 150 | 151 | template 152 | inline constexpr Displacement operator*(Scalar scale, Displacement const& disp) 153 | { 154 | return Displacement{scale*disp.dx, scale*disp.dy}; 155 | } 156 | 157 | template 158 | inline constexpr Displacement operator*(Displacement const& disp, Scalar scale) 159 | { 160 | return scale*disp; 161 | } 162 | 163 | template 164 | inline constexpr Displacement as_displacement(Size const& size) 165 | { 166 | return Displacement{size.width.as_value(), size.height.as_value()}; 167 | } 168 | 169 | template 170 | inline constexpr Size as_size(Displacement const& disp) 171 | { 172 | return Size{disp.dx.as_value(), disp.dy.as_value()}; 173 | } 174 | 175 | template 176 | inline constexpr Displacement as_displacement(Point const& point) 177 | { 178 | return Displacement{point.x.as_value(), point.y.as_value()}; 179 | } 180 | 181 | template 182 | inline constexpr Point as_point(Displacement const& disp) 183 | { 184 | return Point{disp.dx.as_value(), disp.dy.as_value()}; 185 | } 186 | } 187 | } 188 | 189 | #endif // WLCS_GEOMETRY_DISPLACEMENT_H_ 190 | -------------------------------------------------------------------------------- /include/geometry/forward.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License version 2 or 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU Lesser General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #ifndef WLCS_GEOMETRY_FORWARD_H_ 18 | #define WLCS_GEOMETRY_FORWARD_H_ 19 | 20 | namespace wlcs 21 | { 22 | /// These tag types determine what type of dimension a value holds and what operations are possible with it. They are 23 | /// only used as template parameters, are never instantiated and should only require forward declarations, but some 24 | /// compiler versions seem to fail if they aren't given real declarations. 25 | /// @{ 26 | struct WidthTag{}; 27 | struct HeightTag{}; 28 | struct XTag{}; 29 | struct YTag{}; 30 | struct DeltaXTag{}; 31 | struct DeltaYTag{}; 32 | struct StrideTag{}; 33 | /// @} 34 | 35 | namespace generic 36 | { 37 | template 38 | struct Value; 39 | 40 | template 41 | struct Point; 42 | 43 | template 44 | struct Size; 45 | 46 | template 47 | struct Displacement; 48 | 49 | template 50 | struct Rectangle; 51 | 52 | template using Width = Value; 53 | template using Height = Value; 54 | template using X = Value; 55 | template using Y = Value; 56 | template using DeltaX = Value; 57 | template using DeltaY = Value; 58 | } 59 | 60 | using Width = generic::Width; 61 | using Height = generic::Height; 62 | using X = generic::X; 63 | using Y = generic::Y; 64 | using DeltaX = generic::DeltaX; 65 | using DeltaY = generic::DeltaY; 66 | 67 | using WidthF = generic::Width; 68 | using HeightF = generic::Height; 69 | using XF = generic::X; 70 | using YF = generic::Y; 71 | using DeltaXF = generic::DeltaX; 72 | using DeltaYF = generic::DeltaY; 73 | 74 | // Just to be clear, mir::geometry::Stride is the stride of the buffer in bytes 75 | using Stride = generic::Value; 76 | 77 | using Point = generic::Point; 78 | using Size = generic::Size; 79 | using Displacement = generic::Displacement; 80 | using Rectangle = generic::Rectangle; 81 | 82 | using PointF = generic::Point; 83 | using SizeF = generic::Size; 84 | using DisplacementF = generic::Displacement; 85 | using RectangleF = generic::Rectangle; 86 | } 87 | 88 | #endif // WLCS_GEOMETRY_FORWARD_H_ 89 | -------------------------------------------------------------------------------- /include/geometry/point.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License version 2 or 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU Lesser General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #ifndef WLCS_GEOMETRY_POINT_H_ 18 | #define WLCS_GEOMETRY_POINT_H_ 19 | 20 | #include "forward.h" 21 | #include "dimensions.h" 22 | #include 23 | 24 | namespace wlcs 25 | { 26 | namespace generic 27 | { 28 | template 29 | struct Size; 30 | template 31 | struct Displacement; 32 | 33 | template 34 | struct Point 35 | { 36 | using ValueType = T; 37 | 38 | constexpr Point() = default; 39 | constexpr Point(Point const&) = default; 40 | Point& operator=(Point const&) = default; 41 | 42 | template 43 | explicit constexpr Point(Point const& other) noexcept 44 | : x{X{other.x}}, 45 | y{Y{other.y}} 46 | { 47 | } 48 | 49 | template 50 | constexpr Point(XType&& x, YType&& y) : x(x), y(y) {} 51 | 52 | X x; 53 | Y y; 54 | }; 55 | 56 | template 57 | inline constexpr bool operator == (Point const& lhs, Point const& rhs) 58 | { 59 | return lhs.x == rhs.x && lhs.y == rhs.y; 60 | } 61 | 62 | template 63 | inline constexpr bool operator != (Point const& lhs, Point const& rhs) 64 | { 65 | return lhs.x != rhs.x || lhs.y != rhs.y; 66 | } 67 | 68 | template 69 | inline constexpr Point operator+(Point lhs, DeltaX rhs) { return{lhs.x + rhs, lhs.y}; } 70 | template 71 | inline constexpr Point operator+(Point lhs, DeltaY rhs) { return{lhs.x, lhs.y + rhs}; } 72 | 73 | template 74 | inline constexpr Point operator-(Point lhs, DeltaX rhs) { return{lhs.x - rhs, lhs.y}; } 75 | template 76 | inline constexpr Point operator-(Point lhs, DeltaY rhs) { return{lhs.x, lhs.y - rhs}; } 77 | 78 | template 79 | inline Point& operator+=(Point& lhs, DeltaX rhs) { lhs.x += rhs; return lhs; } 80 | template 81 | inline Point& operator+=(Point& lhs, DeltaY rhs) { lhs.y += rhs; return lhs; } 82 | 83 | template 84 | inline Point& operator-=(Point& lhs, DeltaX rhs) { lhs.x -= rhs; return lhs; } 85 | template 86 | inline Point& operator-=(Point& lhs, DeltaY rhs) { lhs.y -= rhs; return lhs; } 87 | 88 | template 89 | std::ostream& operator<<(std::ostream& out, Point const& value) 90 | { 91 | out << value.x << ", " << value.y; 92 | return out; 93 | } 94 | 95 | } 96 | } 97 | 98 | #endif // WLCS_GEOMETRY_POINT_H_ 99 | -------------------------------------------------------------------------------- /include/geometry/rectangle.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License version 2 or 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU Lesser General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #ifndef WLCS_GEOMETRY_RECTANGLE_H_ 18 | #define WLCS_GEOMETRY_RECTANGLE_H_ 19 | 20 | #include "forward.h" 21 | #include "point.h" 22 | #include "size.h" 23 | #include "displacement.h" 24 | 25 | #include 26 | 27 | namespace wlcs 28 | { 29 | namespace generic 30 | { 31 | template 32 | struct Rectangle 33 | { 34 | constexpr Rectangle() = default; 35 | 36 | constexpr Rectangle(Point const& top_left, Size const& size) 37 | : top_left{top_left}, size{size} 38 | { 39 | } 40 | 41 | /** 42 | * The bottom right boundary point of the rectangle. 43 | * 44 | * Note that the returned point is *not* included in the rectangle 45 | * area, that is, the rectangle is represented as [top_left,bottom_right). 46 | */ 47 | Point bottom_right() const 48 | { 49 | return top_left + as_displacement(size); 50 | } 51 | 52 | Point top_right() const 53 | { 54 | return top_left + as_delta(size.width); 55 | } 56 | 57 | Point bottom_left() const 58 | { 59 | return top_left + as_delta(size.height); 60 | } 61 | 62 | bool contains(Point const& p) const 63 | { 64 | if (size.width == decltype(size.width){} || size.height == decltype(size.height){}) 65 | return false; 66 | 67 | auto br = bottom_right(); 68 | return p.x >= left() && p.x < br.x && 69 | p.y >= top() && p.y < br.y; 70 | } 71 | 72 | /** 73 | * Test if the rectangle contains another. 74 | * 75 | * Note that an empty rectangle can still contain other empty rectangles, 76 | * which are treated as points or lines of thickness zero. 77 | */ 78 | bool contains(Rectangle const& r) const 79 | { 80 | return r.left() >= left() && 81 | r.left() + as_delta(r.size.width) <= left() + as_delta(size.width) && 82 | r.top() >= top() && 83 | r.top() + as_delta(r.size.height) <= top() + as_delta(size.height); 84 | } 85 | 86 | bool overlaps(Rectangle const& r) const 87 | { 88 | bool disjoint = r.left() >= right() 89 | || r.right() <= left() 90 | || r.top() >= bottom() 91 | || r.bottom() <= top() 92 | || size.width == decltype(size.width){} 93 | || size.height == decltype(size.height){} 94 | || r.size.width == decltype(r.size.width){} 95 | || r.size.height == decltype(r.size.height){}; 96 | return !disjoint; 97 | } 98 | 99 | X left() const { return top_left.x; } 100 | X right() const { return bottom_right().x; } 101 | Y top() const { return top_left.y; } 102 | Y bottom() const { return bottom_right().y; } 103 | 104 | Point top_left; 105 | Size size; 106 | }; 107 | 108 | template 109 | Rectangle intersection_of(Rectangle const& a, Rectangle const& b) 110 | { 111 | auto const max_left = std::max(a.left(), b.left()); 112 | auto const min_right = std::min(a.right(), b.right()); 113 | auto const max_top = std::max(a.top(), b.top()); 114 | auto const min_bottom = std::min(a.bottom(), b.bottom()); 115 | 116 | if (max_left < min_right && max_top < min_bottom) 117 | return {{max_left, max_top}, 118 | {(min_right - max_left).as_value(), 119 | (min_bottom - max_top).as_value()}}; 120 | else 121 | return {}; 122 | } 123 | 124 | template 125 | inline constexpr bool operator == (Rectangle const& lhs, Rectangle const& rhs) 126 | { 127 | return lhs.top_left == rhs.top_left && lhs.size == rhs.size; 128 | } 129 | 130 | template 131 | inline constexpr bool operator != (Rectangle const& lhs, Rectangle const& rhs) 132 | { 133 | return lhs.top_left != rhs.top_left || lhs.size != rhs.size; 134 | } 135 | 136 | template 137 | std::ostream& operator<<(std::ostream& out, Rectangle const& value) 138 | { 139 | out << '(' << value.top_left << ", " << value.size << ')'; 140 | return out; 141 | } 142 | } 143 | } 144 | 145 | #endif // WLCS_GEOMETRY_RECTANGLE_H_ 146 | -------------------------------------------------------------------------------- /include/geometry/size.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License version 2 or 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU Lesser General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #ifndef WLCS_GEOMETRY_SIZE_H_ 18 | #define WLCS_GEOMETRY_SIZE_H_ 19 | 20 | #include "forward.h" 21 | #include "dimensions.h" 22 | #include 23 | 24 | namespace wlcs 25 | { 26 | namespace generic 27 | { 28 | template 29 | struct Point; 30 | template 31 | struct Displacement; 32 | 33 | template 34 | struct Size 35 | { 36 | using ValueType = T; 37 | 38 | constexpr Size() noexcept {} 39 | constexpr Size(Size const&) noexcept = default; 40 | Size& operator=(Size const&) noexcept = default; 41 | 42 | template 43 | explicit constexpr Size(Size const& other) noexcept 44 | : width{Width{other.width}}, 45 | height{Height{other.height}} 46 | { 47 | } 48 | 49 | template 50 | constexpr Size(WidthType&& width, HeightType&& height) noexcept : width(width), height(height) {} 51 | 52 | Width width; 53 | Height height; 54 | }; 55 | 56 | template 57 | inline constexpr bool operator == (Size const& lhs, Size const& rhs) 58 | { 59 | return lhs.width == rhs.width && lhs.height == rhs.height; 60 | } 61 | 62 | template 63 | inline constexpr bool operator != (Size const& lhs, Size const& rhs) 64 | { 65 | return lhs.width != rhs.width || lhs.height != rhs.height; 66 | } 67 | 68 | template 69 | std::ostream& operator<<(std::ostream& out, Size const& value) 70 | { 71 | out << '(' << value.width << ", " << value.height << ')'; 72 | return out; 73 | } 74 | 75 | template 76 | inline constexpr Size operator*(Scalar scale, Size const& size) 77 | { 78 | return Size{scale*size.width, scale*size.height}; 79 | } 80 | 81 | template 82 | inline constexpr Size operator*(Size const& size, Scalar scale) 83 | { 84 | return scale*size; 85 | } 86 | 87 | template 88 | inline constexpr Size operator/(Size const& size, Scalar scale) 89 | { 90 | return Size{size.width / scale, size.height / scale}; 91 | } 92 | 93 | template 94 | inline constexpr Size as_size(Point const& point) 95 | { 96 | return Size{point.x.as_value(), point.y.as_value()}; 97 | } 98 | 99 | template 100 | inline constexpr Point as_point(Size const& size) 101 | { 102 | return Point{size.width.as_value(), size.height.as_value()}; 103 | } 104 | } 105 | } 106 | 107 | #endif // WLCS_GEOMETRY_SIZE_H_ 108 | -------------------------------------------------------------------------------- /include/gtest_helpers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Christopher James Halse Rogers 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | namespace std 24 | { 25 | namespace chrono 26 | { 27 | /// GTest helper to pretty-print time-points 28 | template 29 | void PrintTo(time_point const& time, ostream* os) 30 | { 31 | auto remainder = time.time_since_epoch(); 32 | auto const hours = duration_cast(remainder); 33 | remainder -= hours; 34 | auto const minutes = duration_cast(remainder); 35 | remainder -= minutes; 36 | auto const seconds = duration_cast(remainder); 37 | remainder -= seconds; 38 | auto const nsec = duration_cast(remainder); 39 | (*os) 40 | << hours.count() 41 | << ":" << setw(2) << setfill('0') << minutes.count() 42 | << ":" << setw(2) << setfill('0') << seconds.count() 43 | << "." << setw(9) << setfill('0') << nsec.count(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /include/helpers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2017 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Christopher James Halse Rogers 17 | */ 18 | 19 | #ifndef WLCS_HELPERS_H_ 20 | #define WLCS_HELPERS_H_ 21 | 22 | #include 23 | #include 24 | 25 | struct WlcsServerIntegration; 26 | 27 | namespace wlcs 28 | { 29 | namespace helpers 30 | { 31 | int create_anonymous_file(size_t size); 32 | 33 | void set_command_line(int argc, char const** argv); 34 | 35 | int get_argc(); 36 | char const** get_argv(); 37 | 38 | void set_entry_point(std::shared_ptr const& entry_point); 39 | 40 | std::shared_ptr get_test_hooks(); 41 | } 42 | } 43 | 44 | #endif //WLCS_HELPERS_H_ 45 | -------------------------------------------------------------------------------- /include/input_method.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | 19 | #ifndef WLCS_INPUT_METHOD_H_ 20 | #define WLCS_INPUT_METHOD_H_ 21 | 22 | #include 23 | #include 24 | #include "in_process_server.h" 25 | 26 | namespace wlcs 27 | { 28 | 29 | struct InputMethod 30 | { 31 | InputMethod(std::string const& name) : name{name} {} 32 | virtual ~InputMethod() = default; 33 | 34 | struct Device 35 | { 36 | virtual ~Device() = default; 37 | /// Can only be called while decice is up 38 | virtual void down_at(std::pair position) = 0; 39 | /// Can only be called while device is down 40 | virtual void move_to(std::pair position) = 0; 41 | /// Can only be called while device is down 42 | virtual void up() = 0; 43 | }; 44 | 45 | virtual auto create_device(wlcs::Server& server) -> std::unique_ptr = 0; 46 | virtual auto current_surface(wlcs::Client const& client) -> wl_surface* = 0; 47 | virtual auto position_on_surface(wlcs::Client const& client) -> std::pair = 0; 48 | 49 | static auto all_input_methods() -> std::vector>; 50 | 51 | std::string const name; 52 | }; 53 | 54 | struct PointerInputMethod : InputMethod 55 | { 56 | PointerInputMethod() : InputMethod{"pointer"} {} 57 | 58 | struct Pointer; 59 | 60 | auto create_device(wlcs::Server& server) -> std::unique_ptr override; 61 | auto current_surface(wlcs::Client const& client) -> wl_surface* override; 62 | auto position_on_surface(wlcs::Client const& client) -> std::pair override; 63 | }; 64 | 65 | struct TouchInputMethod : InputMethod 66 | { 67 | TouchInputMethod() : InputMethod{"touch"} {} 68 | 69 | struct Touch; 70 | 71 | auto create_device(wlcs::Server& server) -> std::unique_ptr override; 72 | auto current_surface(wlcs::Client const& client) -> wl_surface* override; 73 | auto position_on_surface(wlcs::Client const& client) -> std::pair override; 74 | }; 75 | 76 | } 77 | 78 | namespace std 79 | { 80 | std::ostream& operator<<(std::ostream& out, std::shared_ptr const& param); 81 | } 82 | 83 | #endif // WLCS_INPUT_METHOD_H_ 84 | -------------------------------------------------------------------------------- /include/layer_shell_v1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2018-2019 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | 19 | #ifndef WLCS_LAYER_SHELL_V1_H 20 | #define WLCS_LAYER_SHELL_V1_H 21 | 22 | #include "in_process_server.h" 23 | #include "wl_handle.h" 24 | #include "geometry/size.h" 25 | 26 | // Because _someone_ *cough*ddevault*cough* thought it would be a great idea to name an argument "namespace" 27 | #ifdef __clang__ 28 | #pragma clang diagnostic push 29 | #pragma clang diagnostic ignored "-Wkeyword-macro" 30 | #endif 31 | #define namespace _namespace 32 | #include "generated/wlr-layer-shell-unstable-v1-client.h" 33 | #undef namespace 34 | #ifdef __clang__ 35 | #pragma clang diagnostic pop 36 | #endif 37 | 38 | namespace wlcs 39 | { 40 | 41 | // We need to use a custom destructor as .destroyed() changed in v3 42 | namespace 43 | { 44 | void send_destroy_if_supported(zwlr_layer_shell_v1* to_destroy) 45 | { 46 | if (zwlr_layer_shell_v1_get_version(to_destroy) >= ZWLR_LAYER_SHELL_V1_DESTROY_SINCE_VERSION) 47 | { 48 | zwlr_layer_shell_v1_destroy(to_destroy); 49 | } 50 | else 51 | { 52 | wl_proxy_destroy(reinterpret_cast(to_destroy)); 53 | } 54 | } 55 | } 56 | template<> 57 | struct WlInterfaceDescriptor 58 | { 59 | static constexpr bool const has_specialisation = true; 60 | static constexpr wl_interface const* const interface = &zwlr_layer_shell_v1_interface; 61 | static constexpr void (* const destructor)(zwlr_layer_shell_v1*) = &send_destroy_if_supported; 62 | }; 63 | 64 | WLCS_CREATE_INTERFACE_DESCRIPTOR(zwlr_layer_surface_v1) 65 | 66 | class LayerSurfaceV1 67 | { 68 | public: 69 | LayerSurfaceV1( 70 | wlcs::Client& client, 71 | wlcs::Surface& surface, 72 | zwlr_layer_shell_v1_layer layer = ZWLR_LAYER_SHELL_V1_LAYER_TOP, 73 | wl_output* output = NULL, 74 | const char *_namespace = "wlcs"); 75 | LayerSurfaceV1(LayerSurfaceV1 const&) = delete; 76 | LayerSurfaceV1& operator=(LayerSurfaceV1 const&) = delete; 77 | 78 | operator zwlr_layer_surface_v1*() const { return layer_surface; } 79 | operator zwlr_layer_shell_v1*() const { return layer_shell; } 80 | 81 | void dispatch_until_configure(); 82 | auto last_size() const -> wlcs::Size { return last_size_; } 83 | 84 | private: 85 | wlcs::Client& client; 86 | WlHandle layer_shell; 87 | WlHandle layer_surface; 88 | Size last_size_ = {-1, -1}; 89 | int configure_count = 0; 90 | }; 91 | 92 | } 93 | 94 | #endif // WLCS_LAYER_SHELL_V1_H 95 | -------------------------------------------------------------------------------- /include/method_event_impl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | 19 | #ifndef WLCS_METHOD_EVENT_IMPL_H_ 20 | #define WLCS_METHOD_EVENT_IMPL_H_ 21 | 22 | #include "wl_handle.h" 23 | 24 | namespace wlcs 25 | { 26 | namespace detail 27 | { 28 | template 29 | struct MemberFunctionClass; 30 | 31 | template 32 | struct MemberFunctionClass { 33 | using type = T; 34 | }; 35 | } 36 | 37 | /// Can be used to easily implement Wayland listeners using methods, including gmock methods 38 | template 39 | void method_event_impl(void* data, WlType*, Args... args) 40 | { 41 | auto self = static_cast::type*>(data); 42 | (self->*member_fn)(args...); 43 | } 44 | 45 | } 46 | 47 | #endif // WLCS_METHOD_EVENT_IMPL_H_ 48 | -------------------------------------------------------------------------------- /include/mock_input_method_v1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #ifndef MOCK_INPUT_METHOD_V1_H 18 | #define MOCK_INPUT_METHOD_V1_H 19 | 20 | #include "generated/wayland-client.h" 21 | #include "generated/input-method-unstable-v1-client.h" 22 | 23 | #include "in_process_server.h" 24 | #include "wl_interface_descriptor.h" 25 | #include "wl_handle.h" 26 | #include "method_event_impl.h" 27 | 28 | #include 29 | #include 30 | 31 | namespace wlcs 32 | { 33 | WLCS_CREATE_INTERFACE_DESCRIPTOR(zwp_input_method_v1) 34 | WLCS_CREATE_INTERFACE_DESCRIPTOR(zwp_input_method_context_v1) 35 | WLCS_CREATE_INTERFACE_DESCRIPTOR(zwp_input_panel_v1) 36 | WLCS_CREATE_INTERFACE_DESCRIPTOR(zwp_input_panel_surface_v1) 37 | 38 | class MockInputMethodContextV1 : public WlHandle 39 | { 40 | public: 41 | MockInputMethodContextV1(zwp_input_method_context_v1* proxy) 42 | : WlHandle{proxy} 43 | { 44 | zwp_input_method_context_v1_add_listener(proxy, &listener, this); 45 | } 46 | 47 | MOCK_METHOD3(surrounding_text, void(std::string const&, uint32_t, uint32_t)); 48 | MOCK_METHOD0(reset, void()); 49 | MOCK_METHOD2(content_type, void(uint32_t, uint32_t)); 50 | MOCK_METHOD2(invoke_action, void(uint32_t, uint32_t)); 51 | MOCK_METHOD1(preferred_language, void(std::string const&)); 52 | 53 | void commit_state(uint32_t in_serial) 54 | { 55 | serial = in_serial; 56 | } 57 | 58 | static zwp_input_method_context_v1_listener constexpr listener { 59 | method_event_impl<&MockInputMethodContextV1::surrounding_text>, 60 | method_event_impl<&MockInputMethodContextV1::reset>, 61 | method_event_impl<&MockInputMethodContextV1::content_type>, 62 | method_event_impl<&MockInputMethodContextV1::invoke_action>, 63 | method_event_impl<&MockInputMethodContextV1::commit_state>, 64 | method_event_impl<&MockInputMethodContextV1::preferred_language> 65 | }; 66 | 67 | uint32_t serial = 0; 68 | }; 69 | 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /include/mock_input_method_v2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | 19 | #ifndef MOCK_INPUT_METHOD_V2 20 | #define MOCK_INPUT_METHOD_V2 21 | 22 | #include "generated/wayland-client.h" 23 | #include "generated/input-method-unstable-v2-client.h" 24 | 25 | #include "in_process_server.h" 26 | #include "wl_interface_descriptor.h" 27 | #include "wl_handle.h" 28 | #include "method_event_impl.h" 29 | 30 | #include 31 | 32 | namespace wlcs 33 | { 34 | WLCS_CREATE_INTERFACE_DESCRIPTOR(zwp_input_method_manager_v2) 35 | WLCS_CREATE_INTERFACE_DESCRIPTOR(zwp_input_method_v2) 36 | 37 | class MockInputMethodV2 : public WlHandle 38 | { 39 | private: 40 | void done_wrapper() 41 | { 42 | done_count_++; 43 | done(); 44 | } 45 | 46 | public: 47 | MockInputMethodV2(zwp_input_method_v2* proxy) 48 | : WlHandle{proxy} 49 | { 50 | zwp_input_method_v2_add_listener(proxy, &listener, this); 51 | } 52 | 53 | MOCK_METHOD0(activate, void()); 54 | MOCK_METHOD0(deactivate, void()); 55 | MOCK_METHOD3(surrounding_text, void(std::string const&, uint32_t, uint32_t)); 56 | MOCK_METHOD1(text_change_cause, void(uint32_t)); 57 | MOCK_METHOD2(content_type, void(uint32_t, uint32_t)); 58 | MOCK_METHOD0(done, void()); 59 | MOCK_METHOD0(unavailable, void()); 60 | 61 | auto done_count() -> uint32_t { return done_count_; } 62 | 63 | static zwp_input_method_v2_listener constexpr listener { 64 | method_event_impl<&MockInputMethodV2::activate>, 65 | method_event_impl<&MockInputMethodV2::deactivate>, 66 | method_event_impl<&MockInputMethodV2::surrounding_text>, 67 | method_event_impl<&MockInputMethodV2::text_change_cause>, 68 | method_event_impl<&MockInputMethodV2::content_type>, 69 | method_event_impl<&MockInputMethodV2::done_wrapper>, 70 | method_event_impl<&MockInputMethodV2::unavailable>, 71 | }; 72 | 73 | private: 74 | uint32_t done_count_{0}; 75 | }; 76 | } 77 | 78 | #endif // MOCK_INPUT_METHOD_V2 79 | -------------------------------------------------------------------------------- /include/mock_text_input_v2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #ifndef MOCK_TEXT_INPUT_V2_H 18 | #define MOCK_TEXT_INPUT_V2_H 19 | 20 | #include "generated/wayland-client.h" 21 | #include "generated/text-input-unstable-v2-client.h" 22 | #include "wl_handle.h" 23 | #include "wl_interface_descriptor.h" 24 | #include "method_event_impl.h" 25 | #include 26 | 27 | namespace wlcs 28 | { 29 | 30 | WLCS_CREATE_INTERFACE_DESCRIPTOR(zwp_text_input_manager_v2) 31 | WLCS_CREATE_INTERFACE_DESCRIPTOR(zwp_text_input_v2) 32 | 33 | class MockTextInputV2 : public WlHandle 34 | { 35 | public: 36 | MockTextInputV2(zwp_text_input_v2* proxy) 37 | : WlHandle{proxy} 38 | { 39 | zwp_text_input_v2_add_listener(proxy, &listener, this); 40 | } 41 | 42 | MOCK_METHOD2(on_enter, void(uint32_t, wl_surface*)); 43 | MOCK_METHOD2(on_leave, void(uint32_t, wl_surface*)); 44 | void enter(uint32_t in_serial, wl_surface* surface) 45 | { 46 | serial = in_serial; 47 | on_enter(in_serial, surface); 48 | } 49 | void leave(uint32_t in_serial, wl_surface* surface) 50 | { 51 | serial = in_serial; 52 | on_leave(in_serial, surface); 53 | } 54 | MOCK_METHOD5(input_panel_state, void(uint32_t, int32_t, int32_t, int32_t, int32_t)); 55 | MOCK_METHOD2(preedit_string, void(std::string const&, std::string const&)); 56 | MOCK_METHOD3(predit_styling, void(uint32_t, uint32_t, uint32_t)); 57 | MOCK_METHOD1(preedit_cursor, void(int32_t)); 58 | MOCK_METHOD1(commit_string, void(std::string const&)); 59 | MOCK_METHOD2(cursor_position, void(int32_t, int32_t)); 60 | MOCK_METHOD2(delete_surrounding_text, void(uint32_t, uint32_t)); 61 | MOCK_METHOD1(modifiers_map, void(wl_array*)); 62 | MOCK_METHOD4(keysym, void(uint32_t, uint32_t, uint32_t, uint32_t)); 63 | MOCK_METHOD1(language, void(std::string const&)); 64 | MOCK_METHOD1(text_direction, void(uint32_t)); 65 | MOCK_METHOD2(configure_surrounding_text, void(int32_t, int32_t)); 66 | MOCK_METHOD2(on_input_method_changed, void(uint32_t, uint32_t)); 67 | void input_method_changed(uint32_t in_serial, uint32_t reason) 68 | { 69 | serial = in_serial; 70 | on_input_method_changed(in_serial, reason); 71 | } 72 | 73 | static zwp_text_input_v2_listener constexpr listener { 74 | method_event_impl<&MockTextInputV2::enter>, 75 | method_event_impl<&MockTextInputV2::leave>, 76 | method_event_impl<&MockTextInputV2::input_panel_state>, 77 | method_event_impl<&MockTextInputV2::preedit_string>, 78 | method_event_impl<&MockTextInputV2::predit_styling>, 79 | method_event_impl<&MockTextInputV2::preedit_cursor>, 80 | method_event_impl<&MockTextInputV2::commit_string>, 81 | method_event_impl<&MockTextInputV2::cursor_position>, 82 | method_event_impl<&MockTextInputV2::delete_surrounding_text>, 83 | method_event_impl<&MockTextInputV2::modifiers_map>, 84 | method_event_impl<&MockTextInputV2::keysym>, 85 | method_event_impl<&MockTextInputV2::language>, 86 | method_event_impl<&MockTextInputV2::text_direction>, 87 | method_event_impl<&MockTextInputV2::configure_surrounding_text>, 88 | method_event_impl<&MockTextInputV2::input_method_changed> 89 | }; 90 | 91 | uint32_t serial; 92 | }; 93 | 94 | } 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /include/mock_text_input_v3.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | 19 | #ifndef MOCK_TEXT_INPUT_V3_H 20 | #define MOCK_TEXT_INPUT_V3_H 21 | 22 | #include "generated/wayland-client.h" 23 | #include "generated/text-input-unstable-v3-client.h" 24 | 25 | #include "in_process_server.h" 26 | #include "wl_interface_descriptor.h" 27 | #include "wl_handle.h" 28 | #include "method_event_impl.h" 29 | 30 | #include 31 | #include 32 | 33 | namespace wlcs 34 | { 35 | WLCS_CREATE_INTERFACE_DESCRIPTOR(zwp_text_input_manager_v3) 36 | WLCS_CREATE_INTERFACE_DESCRIPTOR(zwp_text_input_v3) 37 | 38 | class MockTextInputV3 : public WlHandle 39 | { 40 | public: 41 | MockTextInputV3(zwp_text_input_v3* proxy) 42 | : WlHandle{proxy} 43 | { 44 | zwp_text_input_v3_add_listener(proxy, &listener, this); 45 | } 46 | 47 | MOCK_METHOD1(enter, void(wl_surface *)); 48 | MOCK_METHOD1(leave, void(wl_surface *)); 49 | MOCK_METHOD3(preedit_string, void(std::string const&, int32_t, int32_t)); 50 | MOCK_METHOD1(commit_string, void(std::string const&)); 51 | MOCK_METHOD2(delete_surrounding_text, void(int32_t, int32_t)); 52 | MOCK_METHOD1(done, void(int32_t)); 53 | 54 | static zwp_text_input_v3_listener constexpr listener { 55 | method_event_impl<&MockTextInputV3::enter>, 56 | method_event_impl<&MockTextInputV3::leave>, 57 | method_event_impl<&MockTextInputV3::preedit_string>, 58 | method_event_impl<&MockTextInputV3::commit_string>, 59 | method_event_impl<&MockTextInputV3::delete_surrounding_text>, 60 | method_event_impl<&MockTextInputV3::done>, 61 | }; 62 | }; 63 | } 64 | 65 | #endif // MOCK_TEXT_INPUT_V3_H 66 | -------------------------------------------------------------------------------- /include/mutex.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2017 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License version 2 or 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU Lesser General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Christopher James Halse Rogers 17 | */ 18 | 19 | #ifndef WLCS_MUTEX_H_ 20 | #define WLCS_MUTEX_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | namespace wlcs 27 | { 28 | /** 29 | * Smart-pointer-esque accessor for Mutex<> protected data. 30 | * 31 | * Ensures exclusive access to the referenced data. 32 | * 33 | * \tparam Guarded Type of data guarded by the mutex. 34 | */ 35 | template 36 | class MutexGuard 37 | { 38 | public: 39 | MutexGuard(std::unique_lock&& lock, Guarded& value) 40 | : value{value}, 41 | lock{std::move(lock)} 42 | { 43 | } 44 | MutexGuard(MutexGuard&& from) = default; 45 | ~MutexGuard() noexcept(false) 46 | { 47 | if (lock.owns_lock()) 48 | { 49 | lock.unlock(); 50 | } 51 | } 52 | 53 | Guarded& operator*() 54 | { 55 | return value; 56 | } 57 | Guarded* operator->() 58 | { 59 | return &value; 60 | } 61 | private: 62 | Guarded& value; 63 | std::unique_lock lock; 64 | }; 65 | 66 | /** 67 | * A data-locking mutex 68 | * 69 | * This is a mutex which owns the data it guards, and can give out a 70 | * smart-pointer-esque lock to lock and access it. 71 | * 72 | * \tparam Guarded The type of data guarded by the mutex 73 | */ 74 | template 75 | class Mutex 76 | { 77 | public: 78 | Mutex() = default; 79 | Mutex(Guarded&& initial_value) 80 | : value{std::move(initial_value)} 81 | { 82 | } 83 | 84 | Mutex(Mutex const&) = delete; 85 | Mutex& operator=(Mutex const&) = delete; 86 | 87 | /** 88 | * Lock the mutex and return an accessor for the protected data. 89 | * 90 | * \return A smart-pointer-esque accessor for the contained data. 91 | * While code has access to the MutexGuard it is guaranteed to have exclusive 92 | * access to the contained data. 93 | */ 94 | MutexGuard lock() 95 | { 96 | return MutexGuard{std::unique_lock{mutex}, value}; 97 | } 98 | 99 | protected: 100 | std::mutex mutex; 101 | Guarded value; 102 | }; 103 | 104 | template 105 | class WaitableMutex : public Mutex 106 | { 107 | public: 108 | using Mutex::Mutex; 109 | 110 | template 111 | MutexGuard wait_for(Predicate predicate, std::chrono::duration timeout) 112 | { 113 | std::unique_lock lock{this->mutex}; 114 | if (!notifier.wait_for(lock, timeout, [this, &predicate]() { return predicate(this->value); })) 115 | { 116 | BOOST_THROW_EXCEPTION((std::runtime_error{"Notification timeout"})); 117 | } 118 | return MutexGuard{std::move(lock), this->value}; 119 | } 120 | 121 | void notify_all() 122 | { 123 | notifier.notify_all(); 124 | } 125 | private: 126 | std::condition_variable notifier; 127 | }; 128 | 129 | 130 | } 131 | 132 | #endif //WLCS_MUTEX_H_ 133 | -------------------------------------------------------------------------------- /include/pointer_constraints_unstable_v1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Alan Griffiths 17 | */ 18 | 19 | #ifndef WLCS_POINTER_CONSTRAINTS_UNSTABLE_V1_H 20 | #define WLCS_POINTER_CONSTRAINTS_UNSTABLE_V1_H 21 | 22 | #include "generated/pointer-constraints-unstable-v1-client.h" 23 | #include "wl_interface_descriptor.h" 24 | #include "wl_handle.h" 25 | 26 | #include 27 | 28 | #include 29 | 30 | struct wl_pointer; 31 | 32 | namespace wlcs 33 | { 34 | WLCS_CREATE_INTERFACE_DESCRIPTOR(zwp_pointer_constraints_v1) 35 | 36 | class Client; 37 | 38 | class ZwpPointerConstraintsV1 39 | { 40 | public: 41 | ZwpPointerConstraintsV1(Client& client); 42 | ~ZwpPointerConstraintsV1(); 43 | 44 | operator zwp_pointer_constraints_v1*() const; 45 | 46 | friend void zwp_pointer_constraints_v1_destroy(ZwpPointerConstraintsV1 const&) = delete; 47 | 48 | private: 49 | WlHandle const manager; 50 | }; 51 | 52 | class ZwpConfinedPointerV1 53 | { 54 | public: 55 | ZwpConfinedPointerV1( 56 | ZwpPointerConstraintsV1& manager, 57 | wl_surface* surface, 58 | wl_pointer* pointer, 59 | wl_region* region, 60 | uint32_t lifetime); 61 | 62 | ~ZwpConfinedPointerV1(); 63 | 64 | MOCK_METHOD0(confined, void()); 65 | MOCK_METHOD0(unconfined, void()); 66 | 67 | operator zwp_confined_pointer_v1*() const; 68 | 69 | friend void zwp_confined_pointer_v1_destroy(ZwpConfinedPointerV1 const&) = delete; 70 | 71 | private: 72 | zwp_confined_pointer_v1* const relative_pointer; 73 | uint32_t const version; 74 | static zwp_confined_pointer_v1_listener const listener; 75 | }; 76 | 77 | class ZwpLockedPointerV1 78 | { 79 | public: 80 | ZwpLockedPointerV1( 81 | ZwpPointerConstraintsV1& manager, 82 | wl_surface* surface, 83 | wl_pointer* pointer, 84 | wl_region* region, 85 | uint32_t lifetime); 86 | 87 | ~ZwpLockedPointerV1(); 88 | 89 | MOCK_METHOD0(locked, void()); 90 | MOCK_METHOD0(unlocked, void()); 91 | 92 | operator zwp_locked_pointer_v1*() const; 93 | 94 | friend void zwp_locked_pointer_v1_destroy(ZwpLockedPointerV1 const&) = delete; 95 | 96 | private: 97 | zwp_locked_pointer_v1* const locked_pointer; 98 | uint32_t const version; 99 | static zwp_locked_pointer_v1_listener const listener; 100 | }; 101 | 102 | } 103 | 104 | #endif //WLCS_POINTER_CONSTRAINTS_UNSTABLE_V1_H 105 | -------------------------------------------------------------------------------- /include/relative_pointer_unstable_v1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Alan Griffiths 17 | */ 18 | 19 | #ifndef WLCS_RELATIVE_POINTER_UNSTABLE_V1_H 20 | #define WLCS_RELATIVE_POINTER_UNSTABLE_V1_H 21 | 22 | #include "generated/relative-pointer-unstable-v1-client.h" 23 | #include "wl_interface_descriptor.h" 24 | #include "wl_handle.h" 25 | 26 | #include 27 | 28 | #include 29 | 30 | struct wl_pointer; 31 | 32 | namespace wlcs 33 | { 34 | WLCS_CREATE_INTERFACE_DESCRIPTOR(zwp_relative_pointer_manager_v1) 35 | 36 | class Client; 37 | 38 | class ZwpRelativePointerManagerV1 39 | { 40 | public: 41 | ZwpRelativePointerManagerV1(Client& client); 42 | ~ZwpRelativePointerManagerV1(); 43 | 44 | operator zwp_relative_pointer_manager_v1*() const; 45 | 46 | friend void zwp_relative_pointer_manager_v1_destroy(ZwpRelativePointerManagerV1 const&) = delete; 47 | 48 | private: 49 | WlHandle manager; 50 | }; 51 | 52 | class ZwpRelativePointerV1 53 | { 54 | public: 55 | ZwpRelativePointerV1(ZwpRelativePointerManagerV1& manager, wl_pointer* pointer); 56 | ~ZwpRelativePointerV1(); 57 | 58 | MOCK_METHOD6(relative_motion, 59 | void(uint32_t utime_hi, uint32_t utime_lo, 60 | wl_fixed_t dx, wl_fixed_t dy, 61 | wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel)); 62 | 63 | operator zwp_relative_pointer_v1*() const; 64 | 65 | friend void zwp_relative_pointer_v1_destroy(ZwpRelativePointerV1 const&) = delete; 66 | 67 | private: 68 | zwp_relative_pointer_v1* const relative_pointer; 69 | uint32_t const version; 70 | static zwp_relative_pointer_v1_listener const listener; 71 | }; 72 | 73 | } 74 | 75 | #endif //WLCS_RELATIVE_POINTER_UNSTABLE_V1_H 76 | -------------------------------------------------------------------------------- /include/shared_library.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License version 2 or 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU Lesser General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Alan Griffiths 17 | */ 18 | 19 | #ifndef MIR_SHARED_LIBRARY_H_ 20 | #define MIR_SHARED_LIBRARY_H_ 21 | 22 | #include 23 | 24 | namespace wlcs 25 | { 26 | class SharedLibrary 27 | { 28 | public: 29 | explicit SharedLibrary(char const* library_name); 30 | explicit SharedLibrary(std::string const& library_name); 31 | ~SharedLibrary() noexcept; 32 | 33 | template 34 | FunctionPtr load_function(char const* function_name) const 35 | { 36 | FunctionPtr result{}; 37 | (void*&)result = load_symbol(function_name); 38 | return result; 39 | } 40 | 41 | template 42 | FunctionPtr load_function(std::string const& function_name) const 43 | { 44 | return load_function(function_name.c_str()); 45 | } 46 | private: 47 | void* const so; 48 | void* load_symbol(char const* function_name) const; 49 | SharedLibrary(SharedLibrary const&) = delete; 50 | SharedLibrary& operator=(SharedLibrary const&) = delete; 51 | }; 52 | } 53 | 54 | 55 | #endif /* MIR_SHARED_LIBRARY_H_ */ 56 | -------------------------------------------------------------------------------- /include/surface_builder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | 19 | #ifndef WLCS_SURFACE_BUILDER_H_ 20 | #define WLCS_SURFACE_BUILDER_H_ 21 | 22 | #include 23 | #include 24 | #include "in_process_server.h" 25 | 26 | namespace wlcs 27 | { 28 | 29 | struct SurfaceBuilder 30 | { 31 | SurfaceBuilder(std::string const& name) : name{name} {} 32 | virtual ~SurfaceBuilder() = default; 33 | 34 | virtual auto build( 35 | wlcs::Server& server, 36 | wlcs::Client& client, 37 | std::pair position, 38 | std::pair size) const -> std::unique_ptr = 0; 39 | 40 | std::string const name; 41 | 42 | static auto all_surface_types() -> std::vector>; 43 | static auto toplevel_surface_types() -> std::vector>; 44 | 45 | static auto surface_builder_to_string( 46 | testing::TestParamInfo> builder) -> std::string; 47 | }; 48 | 49 | struct WlShellSurfaceBuilder : SurfaceBuilder 50 | { 51 | WlShellSurfaceBuilder() : SurfaceBuilder{"wl_shell_surface"} {} 52 | 53 | auto build( 54 | wlcs::Server& server, 55 | wlcs::Client& client, 56 | std::pair position, 57 | std::pair size) const -> std::unique_ptr override; 58 | }; 59 | 60 | struct XdgV6SurfaceBuilder : SurfaceBuilder 61 | { 62 | XdgV6SurfaceBuilder() : SurfaceBuilder{"zxdg_surface_v6"} {} 63 | 64 | auto build( 65 | wlcs::Server& server, 66 | wlcs::Client& client, 67 | std::pair position, 68 | std::pair size) const -> std::unique_ptr override; 69 | }; 70 | 71 | struct XdgStableSurfaceBuilder : SurfaceBuilder 72 | { 73 | XdgStableSurfaceBuilder(int left_offset, int top_offset, int right_offset, int bottom_offset); 74 | 75 | auto build( 76 | wlcs::Server& server, 77 | wlcs::Client& client, 78 | std::pair position, 79 | std::pair size) const -> std::unique_ptr override; 80 | 81 | int left_offset, top_offset, right_offset, bottom_offset; 82 | }; 83 | 84 | struct SubsurfaceBuilder : SurfaceBuilder 85 | { 86 | SubsurfaceBuilder(std::pair offset); 87 | 88 | auto build( 89 | wlcs::Server& server, 90 | wlcs::Client& client, 91 | std::pair position, 92 | std::pair size) const -> std::unique_ptr override; 93 | 94 | std::pair offset; 95 | }; 96 | 97 | // TODO: popup surfaces 98 | } 99 | 100 | namespace std 101 | { 102 | std::ostream& operator<<(std::ostream& out, std::shared_ptr const& param); 103 | } 104 | 105 | #endif // WLCS_SURFACE_BUILDER_H_ 106 | -------------------------------------------------------------------------------- /include/version_specifier.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Christopher James Halse Rogers 17 | */ 18 | 19 | #ifndef WLCS_VERSION_SPECIFIER_H_ 20 | #define WLCS_VERSION_SPECIFIER_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | namespace wlcs 27 | { 28 | class VersionSpecifier 29 | { 30 | public: 31 | VersionSpecifier() = default; 32 | virtual ~VersionSpecifier() = default; 33 | 34 | virtual auto select_version( 35 | uint32_t max_available_version, 36 | uint32_t max_supported_version) const -> std::optional = 0; 37 | virtual auto describe() const -> std::string = 0; 38 | }; 39 | 40 | class ExactlyVersion : public VersionSpecifier 41 | { 42 | public: 43 | explicit ExactlyVersion(uint32_t version) noexcept; 44 | 45 | auto select_version( 46 | uint32_t max_available_version, 47 | uint32_t max_supported_version) const -> std::optional override; 48 | auto describe() const -> std::string override; 49 | private: 50 | uint32_t const version; 51 | }; 52 | 53 | class AtLeastVersion : public VersionSpecifier 54 | { 55 | public: 56 | explicit AtLeastVersion(uint32_t version) noexcept; 57 | 58 | auto select_version( 59 | uint32_t max_available_version, 60 | uint32_t max_supported_version) const -> std::optional override; 61 | auto describe() const -> std::string override; 62 | private: 63 | uint32_t const version; 64 | }; 65 | 66 | extern VersionSpecifier const& AnyVersion; 67 | } 68 | 69 | #endif //WLCS_VERSION_SPECIFIER_H_ 70 | -------------------------------------------------------------------------------- /include/wl_handle.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Christopher James Halse Rogers 17 | * William Wold 18 | */ 19 | 20 | #ifndef WLCS_WL_PROXY_H_ 21 | #define WLCS_WL_PROXY_H_ 22 | 23 | #include "wl_interface_descriptor.h" 24 | #include "boost/throw_exception.hpp" 25 | #include "boost/current_function.hpp" 26 | 27 | #include 28 | #include 29 | 30 | struct wl_proxy; 31 | 32 | namespace wlcs 33 | { 34 | template 35 | class WlHandle 36 | { 37 | public: 38 | explicit WlHandle(T* const proxy) 39 | : proxy{proxy}, 40 | owns_wl_object{true} 41 | { 42 | static_assert( 43 | WlInterfaceDescriptor::has_specialisation, 44 | "Missing specialisation for WlInterfaceDescriptor"); 45 | if (proxy == nullptr) 46 | { 47 | BOOST_THROW_EXCEPTION((std::logic_error{"Attempt to construct a WlHandle from null Wayland object"})); 48 | } 49 | } 50 | 51 | ~WlHandle() 52 | { 53 | if (owns_wl_object) 54 | { 55 | (*WlInterfaceDescriptor::destructor)(proxy); 56 | } 57 | } 58 | 59 | WlHandle(WlHandle&& from) 60 | : WlHandle(from.proxy) 61 | { 62 | from.owns_wl_object = false; 63 | } 64 | 65 | WlHandle(WlHandle const&) = delete; 66 | 67 | auto operator=(WlHandle&&) -> WlHandle& = delete; 68 | auto operator=(WlHandle const&) -> bool = delete; 69 | 70 | operator T*() const 71 | { 72 | // This is a precondition failure, but as this is a test-suite let's be generous and make it fail hard and fast 73 | if (!owns_wl_object) 74 | { 75 | std::abort(); 76 | } 77 | return proxy; 78 | } 79 | 80 | auto wl_proxy() const -> struct wl_proxy* 81 | { 82 | // This is a precondition failure, but as this is a test-suite let's be generous and make it fail hard and fast 83 | if (!owns_wl_object) 84 | { 85 | std::abort(); 86 | } 87 | return static_cast(proxy); 88 | } 89 | 90 | private: 91 | T* const proxy; 92 | bool owns_wl_object; 93 | }; 94 | 95 | template 96 | auto wrap_wl_object(WlType* proxy) -> WlHandle 97 | { 98 | return WlHandle{proxy}; 99 | } 100 | 101 | } 102 | 103 | #endif // WLCS_WL_PROXY_H_ 104 | -------------------------------------------------------------------------------- /include/wl_interface_descriptor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Christopher James Halse Rogers 17 | */ 18 | 19 | #ifndef WLCS_WL_INTERFACE_DESCRIPTOR_H 20 | #define WLCS_WL_INTERFACE_DESCRIPTOR_H 21 | 22 | struct wl_interface; 23 | 24 | namespace wlcs 25 | { 26 | /*** 27 | * A specialisable struct containing the constants and types associated with a Wayland protocol 28 | * 29 | * \tparam WlType The base Wayland object type (eg; wl_surface, xdg_wm_base, etc) 30 | */ 31 | template 32 | struct WlInterfaceDescriptor 33 | { 34 | // Needed because apparently GCC < 10 can't compare a constexpr wl_interface const* const to nullptr in constexpr context?! 35 | static constexpr bool const has_specialisation = false; 36 | static constexpr wl_interface const* const interface = nullptr; 37 | static constexpr void (* const destructor)(WlType*) = nullptr; 38 | }; 39 | } 40 | 41 | /*** 42 | * Declare a specialisation of WlInterfaceDescriptor for \param name 43 | * 44 | * This will use the standard Wayland conventions of 45 | * name - name_interface - name_destroy 46 | * (eg: wl_surface - wl_surface_interface - wl_surface_destroy) 47 | * 48 | * If an interface requires special handling, a manual specialisation can be 49 | * provided (for example, see wl_output handling in in_process_server.h) 50 | */ 51 | #define WLCS_CREATE_INTERFACE_DESCRIPTOR(name) \ 52 | template<> \ 53 | struct WlInterfaceDescriptor \ 54 | { \ 55 | static constexpr bool const has_specialisation = true; \ 56 | static constexpr wl_interface const* const interface = &name##_interface; \ 57 | static constexpr void(* const destructor)(name*) = &name##_destroy; \ 58 | }; 59 | 60 | 61 | #endif //WLCS_WL_INTERFACE_DESCRIPTOR_H 62 | -------------------------------------------------------------------------------- /include/wlcs/pointer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2017 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Christopher James Halse Rogers 17 | */ 18 | #ifndef WLCS_POINTER_H_ 19 | #define WLCS_POINTER_H_ 20 | 21 | #include 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | /** 28 | * Maximum version of WlcsPointer this header provides a definition for 29 | */ 30 | #define WLCS_POINTER_VERSION 1 31 | 32 | typedef struct WlcsPointer WlcsPointer; 33 | /** 34 | * An object to manipulate the server's pointer state 35 | */ 36 | struct WlcsPointer 37 | { 38 | uint32_t version; /**< Version of the struct this instance provides */ 39 | 40 | /** 41 | * Move the pointer to the specified location, in compositor coördinate space 42 | */ 43 | void (*move_absolute)(WlcsPointer* pointer, wl_fixed_t x, wl_fixed_t y); 44 | /** 45 | * Move the pointer by the specified amount, in compositor coördinates. 46 | */ 47 | void (*move_relative)(WlcsPointer* pointer, wl_fixed_t dx, wl_fixed_t dy); 48 | 49 | /** 50 | * Generate a button-up event 51 | * 52 | * \param button Button code (as per wl_pointer. eg: BTN_LEFT) 53 | */ 54 | void (*button_up)(WlcsPointer* pointer, int button); 55 | /** 56 | * Generate a button-down event 57 | * 58 | * \param button Button code (as per wl_pointer. eg: BTN_LEFT) 59 | */ 60 | void (*button_down)(WlcsPointer* pointer, int button); 61 | 62 | /** 63 | * Destroy this pointer, freeing any resources. 64 | */ 65 | void (*destroy)(WlcsPointer* pointer); 66 | }; 67 | 68 | #ifdef __cplusplus 69 | } 70 | #endif 71 | 72 | #endif //WLCS_SERVER_H_ 73 | -------------------------------------------------------------------------------- /include/wlcs/touch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2018 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | #ifndef WLCS_TOUCH_H_ 19 | #define WLCS_TOUCH_H_ 20 | 21 | #include 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | /** 28 | * Maximum version of WlcsTouch this header provides a definition for 29 | */ 30 | #define WLCS_TOUCH_VERSION 1 31 | 32 | typedef struct WlcsTouch WlcsTouch; 33 | struct WlcsTouch 34 | { 35 | uint32_t version; /**< Version of the struct this instance provides */ 36 | 37 | void (*touch_down)(WlcsTouch* touch, wl_fixed_t x, wl_fixed_t y); 38 | void (*touch_move)(WlcsTouch* touch, wl_fixed_t x, wl_fixed_t y); 39 | void (*touch_up)(WlcsTouch* touch); 40 | 41 | void (*destroy)(WlcsTouch* touch); 42 | }; 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | 48 | #endif //WLCS_TOUCH_H_ 49 | -------------------------------------------------------------------------------- /include/xdg_decoration_unstable_v1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #ifndef WLCS_XDG_DECORATION_UNSTABLE_V1_H 18 | #define WLCS_XDG_DECORATION_UNSTABLE_V1_H 19 | 20 | #include "generated/xdg-decoration-unstable-v1-client.h" 21 | #include "wl_handle.h" 22 | #include "wl_interface_descriptor.h" 23 | #include "gmock/gmock.h" 24 | 25 | namespace wlcs 26 | { 27 | WLCS_CREATE_INTERFACE_DESCRIPTOR(zxdg_decoration_manager_v1); 28 | 29 | class Client; 30 | 31 | class ZxdgDecorationManagerV1 32 | { 33 | public: 34 | ZxdgDecorationManagerV1(Client& client); 35 | ~ZxdgDecorationManagerV1(); 36 | 37 | operator zxdg_decoration_manager_v1*() const; 38 | friend void zxdg_decoration_manager_v1_destroy(ZxdgDecorationManagerV1 const&) = delete; 39 | 40 | private: 41 | WlHandle manager; 42 | }; 43 | 44 | class ZxdgToplevelDecorationV1 45 | { 46 | public: 47 | ZxdgToplevelDecorationV1(ZxdgDecorationManagerV1& manager, xdg_toplevel* toplevel); 48 | ~ZxdgToplevelDecorationV1(); 49 | 50 | MOCK_METHOD(void, configure, (uint32_t mode), ()); 51 | 52 | 53 | operator zxdg_toplevel_decoration_v1*() const; 54 | friend void zxdg_toplevel_manager_v1_destroy(ZxdgToplevelDecorationV1 const&) = delete; 55 | 56 | private: 57 | uint32_t const version; 58 | zxdg_toplevel_decoration_v1* const toplevel_decoration; 59 | 60 | static zxdg_toplevel_decoration_v1_listener const listener; 61 | }; 62 | } 63 | 64 | #endif // WLCS_XDG_DECORATION_UNSTABLE_V1_H 65 | -------------------------------------------------------------------------------- /include/xdg_output_v1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | 19 | #ifndef XDG_OUTPUT_V1_H 20 | #define XDG_OUTPUT_V1_H 21 | 22 | #include "generated/wayland-client.h" 23 | #include "generated/xdg-output-unstable-v1-client.h" 24 | 25 | #include "in_process_server.h" 26 | #include "wl_interface_descriptor.h" 27 | #include "wl_handle.h" 28 | 29 | #include 30 | #include 31 | 32 | namespace wlcs 33 | { 34 | WLCS_CREATE_INTERFACE_DESCRIPTOR(zxdg_output_manager_v1) 35 | 36 | class XdgOutputManagerV1 37 | { 38 | public: 39 | XdgOutputManagerV1(Client& client); 40 | ~XdgOutputManagerV1(); 41 | 42 | operator zxdg_output_manager_v1*() const; 43 | auto client() const -> Client&; 44 | 45 | private: 46 | struct Impl; 47 | std::unique_ptr const impl; 48 | }; 49 | 50 | class XdgOutputV1 51 | { 52 | public: 53 | struct State 54 | { 55 | std::optional> logical_position; 56 | std::optional> logical_size; 57 | std::optional name; 58 | std::optional description; 59 | }; 60 | 61 | XdgOutputV1(XdgOutputManagerV1& manager, size_t output_index); 62 | 63 | XdgOutputV1(XdgOutputV1 const&) = delete; 64 | XdgOutputV1 const& operator=(XdgOutputV1 const&) = delete; 65 | 66 | operator zxdg_output_v1*() const; 67 | auto state() -> State const&; 68 | 69 | private: 70 | struct Impl; 71 | std::shared_ptr const impl; // shared instead of unique because interally a weak is needed 72 | }; 73 | 74 | } 75 | 76 | #endif // XDG_OUTPUT_V1_H 77 | -------------------------------------------------------------------------------- /include/xdg_shell_stable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2018 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | 19 | #ifndef WLCS_XDG_SHELL_STABLE_H 20 | #define WLCS_XDG_SHELL_STABLE_H 21 | 22 | #include "in_process_server.h" 23 | #include "generated/xdg-shell-client.h" 24 | #include "wl_interface_descriptor.h" 25 | #include "wl_handle.h" 26 | 27 | #include 28 | 29 | namespace wlcs 30 | { 31 | WLCS_CREATE_INTERFACE_DESCRIPTOR(xdg_wm_base) 32 | 33 | class XdgSurfaceStable 34 | { 35 | public: 36 | XdgSurfaceStable(wlcs::Client& client, wlcs::Surface& surface); 37 | XdgSurfaceStable(XdgSurfaceStable const&) = delete; 38 | XdgSurfaceStable& operator=(XdgSurfaceStable const&) = delete; 39 | ~XdgSurfaceStable(); 40 | 41 | MOCK_METHOD(void, configure, (uint32_t serial)); 42 | 43 | operator xdg_surface*() const {return shell_surface;} 44 | 45 | private: 46 | xdg_surface* shell_surface; 47 | }; 48 | 49 | class XdgToplevelStable 50 | { 51 | public: 52 | struct State 53 | { 54 | State(int32_t width, int32_t height, struct wl_array *states); 55 | 56 | int width; 57 | int height; 58 | 59 | bool maximized; 60 | bool fullscreen; 61 | bool resizing; 62 | bool activated; 63 | }; 64 | 65 | XdgToplevelStable(XdgSurfaceStable& shell_surface_); 66 | XdgToplevelStable(XdgToplevelStable const&) = delete; 67 | XdgToplevelStable& operator=(XdgToplevelStable const&) = delete; 68 | ~XdgToplevelStable(); 69 | 70 | MOCK_METHOD(void, configure, (int32_t width, int32_t height, wl_array* states)); 71 | MOCK_METHOD(void, close, ()); 72 | MOCK_METHOD(void, configure_bounds, (int32_t width, int32_t height)); 73 | MOCK_METHOD(void, wm_capabilities, (wl_array* capabilities)); 74 | 75 | operator xdg_toplevel*() const {return toplevel;} 76 | 77 | XdgSurfaceStable* const shell_surface; 78 | xdg_toplevel* toplevel; 79 | }; 80 | 81 | class XdgPositionerStable 82 | { 83 | public: 84 | XdgPositionerStable(wlcs::Client& client); 85 | ~XdgPositionerStable(); 86 | operator xdg_positioner*() const {return positioner;} 87 | auto setup_default(std::pair size) -> XdgPositionerStable&; 88 | 89 | private: 90 | xdg_positioner* const positioner; 91 | }; 92 | 93 | class XdgPopupStable 94 | { 95 | public: 96 | XdgPopupStable( 97 | XdgSurfaceStable& shell_surface_, 98 | std::optional parent, 99 | XdgPositionerStable& positioner); 100 | XdgPopupStable(XdgPopupStable const&) = delete; 101 | XdgPopupStable& operator=(XdgPopupStable const&) = delete; 102 | ~XdgPopupStable(); 103 | 104 | MOCK_METHOD(void, configure, (int32_t x, int32_t y, int32_t width, int32_t height)); 105 | MOCK_METHOD(void, done, ()); 106 | MOCK_METHOD(void, repositioned, (uint32_t token)); 107 | 108 | operator xdg_popup*() const {return popup;} 109 | 110 | XdgSurfaceStable* const shell_surface; 111 | xdg_popup* const popup; 112 | 113 | std::vector> configure_notifiers; 114 | std::vector> popup_done_notifiers; 115 | }; 116 | 117 | } 118 | 119 | #endif // WLCS_XDG_SHELL_STABLE_H 120 | -------------------------------------------------------------------------------- /include/xdg_shell_v6.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2018 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | 19 | #ifndef WLCS_XDG_SHELL_V6_ 20 | #define WLCS_XDG_SHELL_V6_ 21 | 22 | #include "in_process_server.h" 23 | #include "generated/xdg-shell-unstable-v6-client.h" 24 | 25 | #include 26 | 27 | namespace wlcs 28 | { 29 | 30 | class XdgSurfaceV6 31 | { 32 | public: 33 | XdgSurfaceV6(wlcs::Client& client, wlcs::Surface& surface); 34 | XdgSurfaceV6(XdgSurfaceV6 const&) = delete; 35 | XdgSurfaceV6& operator=(XdgSurfaceV6 const&) = delete; 36 | ~XdgSurfaceV6(); 37 | 38 | MOCK_METHOD(void, configure, (uint32_t serial)); 39 | 40 | operator zxdg_surface_v6*() const {return shell_surface;} 41 | 42 | private: 43 | zxdg_surface_v6* shell_surface; 44 | }; 45 | 46 | class XdgToplevelV6 47 | { 48 | public: 49 | struct State 50 | { 51 | State(int32_t width, int32_t height, struct wl_array *states); 52 | 53 | int width; 54 | int height; 55 | 56 | bool maximized; 57 | bool fullscreen; 58 | bool resizing; 59 | bool activated; 60 | }; 61 | 62 | XdgToplevelV6(XdgSurfaceV6& shell_surface_); 63 | XdgToplevelV6(XdgToplevelV6 const&) = delete; 64 | XdgToplevelV6& operator=(XdgToplevelV6 const&) = delete; 65 | ~XdgToplevelV6(); 66 | 67 | MOCK_METHOD(void, configure, (int32_t width, int32_t height, wl_array* states)); 68 | MOCK_METHOD(void, close, ()); 69 | 70 | operator zxdg_toplevel_v6*() const {return toplevel;} 71 | 72 | XdgSurfaceV6* const shell_surface; 73 | zxdg_toplevel_v6* toplevel; 74 | }; 75 | 76 | class XdgPositionerV6 77 | { 78 | public: 79 | XdgPositionerV6(wlcs::Client& client); 80 | ~XdgPositionerV6(); 81 | operator zxdg_positioner_v6*() const {return positioner;} 82 | 83 | private: 84 | zxdg_positioner_v6* const positioner; 85 | }; 86 | 87 | class XdgPopupV6 88 | { 89 | public: 90 | XdgPopupV6(XdgSurfaceV6& shell_surface_, XdgSurfaceV6& parent, XdgPositionerV6& positioner); 91 | XdgPopupV6(XdgPopupV6 const&) = delete; 92 | XdgPopupV6& operator=(XdgPopupV6 const&) = delete; 93 | ~XdgPopupV6(); 94 | 95 | MOCK_METHOD(void, configure, (int32_t x, int32_t y, int32_t width, int32_t height)); 96 | MOCK_METHOD(void, done, ()); 97 | 98 | operator zxdg_popup_v6*() const {return popup;} 99 | 100 | XdgSurfaceV6* const shell_surface; 101 | zxdg_popup_v6* const popup; 102 | }; 103 | 104 | } 105 | 106 | #endif // WLCS_XDG_SHELL_V6_ 107 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /spread.yaml: -------------------------------------------------------------------------------- 1 | project: wlcs 2 | 3 | kill-timeout: 50m 4 | 5 | backends: 6 | lxd: 7 | systems: 8 | - ubuntu-24.04 9 | - ubuntu-24.10 10 | - ubuntu-25.04 11 | - ubuntu-devel: 12 | image: ubuntu-daily:devel/amd64 13 | - fedora-41 14 | - fedora-42 15 | - fedora-rawhide: 16 | image: images:fedora/42 17 | - alpine-3.20 18 | - alpine-3.21 19 | - alpine-edge 20 | - archlinux-cloud 21 | 22 | suites: 23 | spread/build/: 24 | summary: Build wlcs 25 | environment: 26 | CC/gcc: gcc 27 | CXX/gcc: g++ 28 | CC/clang: clang 29 | CXX/clang: clang++ 30 | 31 | path: 32 | /spread/wlcs 33 | 34 | exclude: 35 | - .git 36 | -------------------------------------------------------------------------------- /spread/build/alpine/task.yaml: -------------------------------------------------------------------------------- 1 | summary: Build (on Alpine Linux) 2 | systems: [alpine-*] 3 | 4 | execute: | 5 | apk add \ 6 | coreutils \ 7 | make \ 8 | g++ \ 9 | wayland-dev \ 10 | cmake \ 11 | boost-dev \ 12 | gtest-dev 13 | 14 | cd $SPREAD_PATH 15 | cd $(mktemp --directory) 16 | # Alpine doesn't build gcc's libsanitizer 17 | cmake $SPREAD_PATH \ 18 | -DWLCS_BUILD_ASAN=False \ 19 | -DWLCS_BUILD_TSAN=False \ 20 | -DWLCS_BUILD_UBSAN=False 21 | make -j$(nproc) 22 | 23 | -------------------------------------------------------------------------------- /spread/build/archlinux/task.yaml: -------------------------------------------------------------------------------- 1 | summary: Build (on Arch Linux) 2 | systems: [archlinux-*] 3 | 4 | execute: | 5 | pacman --noconfirm --sync \ 6 | base-devel \ 7 | cmake \ 8 | boost \ 9 | wayland \ 10 | wayland-protocols \ 11 | gtest 12 | 13 | cd $SPREAD_PATH 14 | cd $(mktemp --directory) 15 | cmake $SPREAD_PATH 16 | make -j$(nproc) 17 | 18 | -------------------------------------------------------------------------------- /spread/build/fedora/task.yaml: -------------------------------------------------------------------------------- 1 | summary: Build (on Fedora) 2 | systems: [fedora-*] 3 | 4 | execute: | 5 | if [[ "${SPREAD_SYSTEM}" == "fedora-rawhide" ]]; then 6 | dnf --refresh --assumeyes upgrade 7 | dnf --assumeyes install fedora-repos-rawhide 8 | dnf --refresh --assumeyes --enablerepo=rawhide distro-sync 9 | fi 10 | 11 | dnf install --assumeyes \ 12 | wayland-devel \ 13 | cmake \ 14 | make \ 15 | clang \ 16 | gcc-c++ \ 17 | libasan.x86_64 \ 18 | libtsan.x86_64 \ 19 | libubsan.x86_64 \ 20 | pkg-config \ 21 | boost-devel \ 22 | gtest-devel \ 23 | gmock-devel 24 | 25 | cd $SPREAD_PATH 26 | cd $(mktemp --directory) 27 | cmake $SPREAD_PATH 28 | make -j$(nproc) 29 | 30 | -------------------------------------------------------------------------------- /spread/build/ubuntu/task.yaml: -------------------------------------------------------------------------------- 1 | summary: Build (on Ubuntu) 2 | systems: [ubuntu-*] 3 | 4 | execute: | 5 | # Grab builds of Mir git master 6 | add-apt-repository ppa:mir-team/dev 7 | 8 | apt-get install --yes \ 9 | dpkg-dev \ 10 | libwayland-dev \ 11 | cmake \ 12 | clang \ 13 | g++ \ 14 | pkg-config \ 15 | libgtest-dev \ 16 | google-mock \ 17 | libboost-dev \ 18 | mir-test-tools 19 | 20 | # Check that we build… 21 | cd $SPREAD_PATH 22 | cd $(mktemp --directory) 23 | cmake \ 24 | -DCMAKE_C_FLAGS="-D_FORTIFY_SOURCE=2" \ 25 | -DCMAKE_CXX_FLAGS="-D_FORTIFY_SOURCE=2" \ 26 | $SPREAD_PATH 27 | make -j$(nproc) 28 | 29 | # …and run the Mir tests, but don't fail on them, unless we fail with a signal 30 | # TODO: Store the set of passing tests in the Travis cache, and fail if a test which 31 | # previously passed now fails. 32 | ./wlcs /usr/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/mir/miral_wlcs_integration.so || { 33 | test $? -lt 128 -o $? -gt 165 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/data_device.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2018 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Alan Griffiths 17 | */ 18 | 19 | #include "data_device.h" 20 | 21 | wlcs::ActiveListeners wlcs::DataDeviceListener::active_listeners; 22 | constexpr wl_data_device_listener wlcs::DataDeviceListener::thunks; 23 | 24 | 25 | void wlcs::DataDeviceListener::data_offer(void* data, struct wl_data_device* wl_data_device, struct wl_data_offer* id) 26 | { 27 | if (active_listeners.includes(data)) 28 | static_cast(data)->data_offer(wl_data_device, id); 29 | } 30 | 31 | void wlcs::DataDeviceListener::enter( 32 | void* data, 33 | struct wl_data_device* wl_data_device, 34 | uint32_t serial, 35 | struct wl_surface* surface, 36 | wl_fixed_t x, 37 | wl_fixed_t y, 38 | struct wl_data_offer* id) 39 | { 40 | if (active_listeners.includes(data)) 41 | static_cast(data)->enter(wl_data_device, serial, surface, x, y, id); 42 | } 43 | 44 | void wlcs::DataDeviceListener::leave(void* data, struct wl_data_device* wl_data_device) 45 | { 46 | if (active_listeners.includes(data)) 47 | static_cast(data)->leave(wl_data_device); 48 | } 49 | 50 | void wlcs::DataDeviceListener::motion( 51 | void* data, 52 | struct wl_data_device* wl_data_device, 53 | uint32_t time, 54 | wl_fixed_t x, 55 | wl_fixed_t y) 56 | { 57 | if (active_listeners.includes(data)) 58 | static_cast(data)->motion(wl_data_device, time, x, y); 59 | } 60 | 61 | void wlcs::DataDeviceListener::drop(void* data, struct wl_data_device* wl_data_device) 62 | { 63 | if (active_listeners.includes(data)) 64 | static_cast(data)->drop(wl_data_device); 65 | } 66 | 67 | void wlcs::DataDeviceListener::selection( 68 | void* data, 69 | struct wl_data_device* wl_data_device, 70 | struct wl_data_offer* id) 71 | { 72 | if (active_listeners.includes(data)) 73 | static_cast(data)->selection(wl_data_device, wl_data_device, id); 74 | } 75 | 76 | void wlcs::DataDeviceListener::data_offer(struct wl_data_device* /*wl_data_device*/, struct wl_data_offer* /*id*/) 77 | { 78 | } 79 | 80 | void wlcs::DataDeviceListener::enter( 81 | struct wl_data_device* /*wl_data_device*/, 82 | uint32_t /*serial*/, 83 | struct wl_surface* /*surface*/, 84 | wl_fixed_t /*x*/, 85 | wl_fixed_t /*y*/, 86 | struct wl_data_offer* /*id*/) 87 | { 88 | } 89 | 90 | void wlcs::DataDeviceListener::leave(struct wl_data_device* /*wl_data_device*/) 91 | { 92 | } 93 | 94 | void wlcs::DataDeviceListener::motion( 95 | struct wl_data_device* /*wl_data_device*/, 96 | uint32_t /*time*/, 97 | wl_fixed_t /*x*/, 98 | wl_fixed_t /*y*/) 99 | { 100 | } 101 | 102 | void wlcs::DataDeviceListener::drop(struct wl_data_device* /*wl_data_device*/) 103 | { 104 | } 105 | 106 | void wlcs::DataDeviceListener::selection( 107 | struct wl_data_device* /*wl_data_device*/, 108 | struct wl_data_offer* /*id*/) 109 | { 110 | } 111 | 112 | 113 | wlcs::ActiveListeners wlcs::DataOfferListener::active_listeners; 114 | constexpr wl_data_offer_listener wlcs::DataOfferListener::thunks; 115 | 116 | void wlcs::DataOfferListener::offer(void* data, struct wl_data_offer* data_offer, char const* mime_type) 117 | { 118 | if (active_listeners.includes(data)) 119 | static_cast(data)->offer(data_offer, mime_type); 120 | } 121 | 122 | void wlcs::DataOfferListener::source_actions(void* data, struct wl_data_offer* data_offer, uint32_t dnd_actions) 123 | { 124 | if (active_listeners.includes(data)) 125 | static_cast(data)->source_actions(data_offer, dnd_actions); 126 | } 127 | 128 | void wlcs::DataOfferListener::action(void* data, struct wl_data_offer* data_offer, uint32_t dnd_action) 129 | { 130 | if (active_listeners.includes(data)) 131 | static_cast(data)->action(data_offer, dnd_action); 132 | } 133 | 134 | void wlcs::DataOfferListener::offer(struct wl_data_offer* /*data_offer*/, char const* /*mime_type*/) 135 | { 136 | } 137 | 138 | void wlcs::DataOfferListener::source_actions(struct wl_data_offer* /*data_offer*/, uint32_t /*dnd_actions*/) 139 | { 140 | } 141 | 142 | void wlcs::DataOfferListener::action(struct wl_data_offer* /*data_offer*/, uint32_t /*dnd_action*/) 143 | { 144 | } 145 | -------------------------------------------------------------------------------- /src/gtk_primary_selection.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Alan Griffiths 17 | */ 18 | 19 | #include "gtk_primary_selection.h" 20 | 21 | #include 22 | 23 | wlcs::ActiveListeners wlcs::GtkPrimarySelectionDeviceListener::active_listeners; 24 | constexpr gtk_primary_selection_device_listener wlcs::GtkPrimarySelectionDeviceListener::thunks; 25 | 26 | wlcs::ActiveListeners wlcs::GtkPrimarySelectionOfferListener::active_listeners; 27 | constexpr gtk_primary_selection_offer_listener wlcs::GtkPrimarySelectionOfferListener::thunks; 28 | 29 | wlcs::ActiveListeners wlcs::GtkPrimarySelectionSourceListener::active_listeners; 30 | constexpr gtk_primary_selection_source_listener wlcs::GtkPrimarySelectionSourceListener::thunks; 31 | 32 | 33 | void wlcs::GtkPrimarySelectionDeviceListener::data_offer( 34 | void* data, 35 | gtk_primary_selection_device* device, 36 | gtk_primary_selection_offer* offer) 37 | { 38 | if (active_listeners.includes(data)) 39 | static_cast(data)->data_offer(device, offer); 40 | } 41 | 42 | void wlcs::GtkPrimarySelectionDeviceListener::data_offer(gtk_primary_selection_device*, gtk_primary_selection_offer*) 43 | { 44 | } 45 | 46 | void wlcs::GtkPrimarySelectionDeviceListener::selection(gtk_primary_selection_device*, gtk_primary_selection_offer*) 47 | { 48 | } 49 | 50 | void wlcs::GtkPrimarySelectionDeviceListener::selection( 51 | void* data, 52 | gtk_primary_selection_device* device, 53 | gtk_primary_selection_offer* offer) 54 | { 55 | if (active_listeners.includes(data)) 56 | static_cast(data)->selection(device, offer); 57 | } 58 | 59 | void wlcs::GtkPrimarySelectionOfferListener::offer(gtk_primary_selection_offer*, const char*) 60 | { 61 | } 62 | 63 | void wlcs::GtkPrimarySelectionOfferListener::offer( 64 | void* data, gtk_primary_selection_offer* offer, const char* mime_type) 65 | { 66 | if (active_listeners.includes(data)) 67 | static_cast(data)->offer(offer, mime_type); 68 | } 69 | 70 | void wlcs::GtkPrimarySelectionSourceListener::send(gtk_primary_selection_source*, const char*, int32_t fd) 71 | { 72 | close(fd); 73 | } 74 | 75 | void wlcs::GtkPrimarySelectionSourceListener::cancelled(gtk_primary_selection_source*) 76 | { 77 | } 78 | 79 | void wlcs::GtkPrimarySelectionSourceListener::send( 80 | void* data, gtk_primary_selection_source* source, const char* mime_type, int32_t fd) 81 | { 82 | if (active_listeners.includes(data)) 83 | static_cast(data)->send(source, mime_type, fd); 84 | } 85 | 86 | void wlcs::GtkPrimarySelectionSourceListener::cancelled(void* data, gtk_primary_selection_source* source) 87 | { 88 | if (active_listeners.includes(data)) 89 | static_cast(data)->cancelled(source); 90 | } 91 | -------------------------------------------------------------------------------- /src/helpers.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License version 2 or 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU Lesser General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: 17 | * Alexandros Frantzis 18 | */ 19 | 20 | #include "helpers.h" 21 | #include "shared_library.h" 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | /* Since kernel 6.3 it generates a warning to construct a memfd without one of 31 | * MFD_EXEC (to mark the memfd as executable) or MFD_NOEXEC_SEAL (to permanently 32 | * prevent the memfd from being marked as executable). 33 | * 34 | * Since we don't need execution from our shm buffers, we can mark them as 35 | * MFD_NOEXEC_SEAL. Since this is only silencing a warning in dmesg we can safely 36 | * null it out if we're building against too-old headers. 37 | */ 38 | #ifndef MFD_NOEXEC_SEAL 39 | #define MFD_NOEXEC_SEAL 0 40 | #endif 41 | 42 | namespace 43 | { 44 | 45 | bool error_indicates_tmpfile_not_supported(int error) 46 | { 47 | return 48 | error == EISDIR || // Directory exists, but no support for O_TMPFILE 49 | error == ENOENT || // Directory doesn't exist, and no support for O_TMPFILE 50 | error == EOPNOTSUPP || // Filesystem that directory resides on does not support O_TMPFILE 51 | error == EINVAL; // There apparently exists at least one development board that has a kernel 52 | // that incorrectly returns EINVAL. Yay. 53 | } 54 | 55 | int memfd_create(char const* name, unsigned int flags) 56 | { 57 | return static_cast(syscall(SYS_memfd_create, name, flags)); 58 | } 59 | } 60 | 61 | int wlcs::helpers::create_anonymous_file(size_t size) 62 | { 63 | 64 | int fd = memfd_create("wlcs-unnamed", MFD_CLOEXEC | MFD_NOEXEC_SEAL); 65 | if (fd == -1 && errno == EINVAL) 66 | { 67 | // Maybe we're running on a kernel prior to MFD_NOEXEC_SEAL? 68 | fd = memfd_create("wlcs-unnamed", MFD_CLOEXEC); 69 | } 70 | if (fd == -1 && errno == ENOSYS) 71 | { 72 | fd = open("/dev/shm", O_TMPFILE | O_RDWR | O_EXCL | O_CLOEXEC, S_IRWXU); 73 | 74 | // Workaround for filesystems that don't support O_TMPFILE 75 | if (fd == -1 && error_indicates_tmpfile_not_supported(errno)) 76 | { 77 | char template_filename[] = "/dev/shm/wlcs-buffer-XXXXXX"; 78 | fd = mkostemp(template_filename, O_CLOEXEC); 79 | if (fd != -1) 80 | { 81 | if (unlink(template_filename) < 0) 82 | { 83 | close(fd); 84 | fd = -1; 85 | } 86 | } 87 | } 88 | } 89 | 90 | if (fd == -1) 91 | { 92 | BOOST_THROW_EXCEPTION( 93 | std::system_error(errno, std::system_category(), "Failed to open temporary file")); 94 | } 95 | 96 | if (ftruncate(fd, size) == -1) 97 | { 98 | close(fd); 99 | BOOST_THROW_EXCEPTION( 100 | std::system_error(errno, std::system_category(), "Failed to resize temporary file")); 101 | } 102 | 103 | return fd; 104 | } 105 | 106 | namespace 107 | { 108 | static int argc; 109 | static char const** argv; 110 | 111 | std::shared_ptr entry_point; 112 | } 113 | 114 | void wlcs::helpers::set_command_line(int argc, char const** argv) 115 | { 116 | ::argc = argc; 117 | ::argv = argv; 118 | } 119 | 120 | int wlcs::helpers::get_argc() 121 | { 122 | return ::argc; 123 | } 124 | 125 | char const** wlcs::helpers::get_argv() 126 | { 127 | return ::argv; 128 | } 129 | 130 | void wlcs::helpers::set_entry_point(std::shared_ptr const& entry_point) 131 | { 132 | ::entry_point = entry_point; 133 | } 134 | 135 | std::shared_ptr wlcs::helpers::get_test_hooks() 136 | { 137 | return ::entry_point; 138 | } 139 | -------------------------------------------------------------------------------- /src/input_method.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | 19 | #include "input_method.h" 20 | #include 21 | 22 | auto wlcs::InputMethod::all_input_methods() -> std::vector> 23 | { 24 | return { 25 | std::make_shared(), 26 | std::make_shared()}; 27 | } 28 | 29 | struct wlcs::PointerInputMethod::Pointer : Device 30 | { 31 | Pointer(wlcs::Server& server) 32 | : pointer{server.create_pointer()} 33 | { 34 | } 35 | 36 | void down_at(std::pair position) override 37 | { 38 | ASSERT_THAT(button_down, testing::Eq(false)) << "Called down_at() with pointer already down"; 39 | pointer.move_to(position.first, position.second); 40 | pointer.left_button_down(); 41 | button_down = true; 42 | } 43 | 44 | void move_to(std::pair position) override 45 | { 46 | ASSERT_THAT(button_down, testing::Eq(true)) << "Called move_to() with pointer up"; 47 | pointer.move_to(position.first, position.second); 48 | } 49 | 50 | void up() override 51 | { 52 | ASSERT_THAT(button_down, testing::Eq(true)) << "Called up() with pointer already up"; 53 | pointer.left_button_up(); 54 | button_down = false; 55 | } 56 | 57 | wlcs::Pointer pointer; 58 | bool button_down = false; 59 | }; 60 | 61 | auto wlcs::PointerInputMethod::create_device(wlcs::Server& server) -> std::unique_ptr 62 | { 63 | return std::make_unique(server); 64 | } 65 | 66 | auto wlcs::PointerInputMethod::current_surface(wlcs::Client const& client) -> wl_surface* 67 | { 68 | return client.window_under_cursor(); 69 | } 70 | 71 | auto wlcs::PointerInputMethod::position_on_surface(wlcs::Client const& client) -> std::pair 72 | { 73 | auto const wl_fixed_position = client.pointer_position(); 74 | return { 75 | wl_fixed_to_int(wl_fixed_position.first), 76 | wl_fixed_to_int(wl_fixed_position.second)}; 77 | } 78 | 79 | struct wlcs::TouchInputMethod::Touch : Device 80 | { 81 | Touch(wlcs::Server& server) 82 | : touch{server.create_touch()} 83 | { 84 | } 85 | 86 | void down_at(std::pair position) override 87 | { 88 | ASSERT_THAT(is_down, testing::Eq(false)) << "Called down_at() with touch already down"; 89 | touch.down_at(position.first, position.second); 90 | is_down = true; 91 | } 92 | 93 | void move_to(std::pair position) override 94 | { 95 | ASSERT_THAT(is_down, testing::Eq(true)) << "Called move_to() with touch up"; 96 | touch.move_to(position.first, position.second); 97 | } 98 | 99 | void up() override 100 | { 101 | ASSERT_THAT(is_down, testing::Eq(true)) << "Called up() with touch already up"; 102 | touch.up(); 103 | is_down = false; 104 | } 105 | 106 | wlcs::Touch touch; 107 | bool is_down = false; 108 | }; 109 | 110 | auto wlcs::TouchInputMethod::create_device(wlcs::Server& server) -> std::unique_ptr 111 | { 112 | return std::make_unique(server); 113 | } 114 | 115 | auto wlcs::TouchInputMethod::current_surface(wlcs::Client const& client) -> wl_surface* 116 | { 117 | return client.touched_window(); 118 | } 119 | 120 | auto wlcs::TouchInputMethod::position_on_surface(wlcs::Client const& client) -> std::pair 121 | { 122 | auto const wl_fixed_position = client.touch_position(); 123 | return { 124 | wl_fixed_to_int(wl_fixed_position.first), 125 | wl_fixed_to_int(wl_fixed_position.second)}; 126 | } 127 | 128 | std::ostream& std::operator<<(std::ostream& out, std::shared_ptr const& param) 129 | { 130 | return out << param->name; 131 | } 132 | -------------------------------------------------------------------------------- /src/layer_shell_v1.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2018-2019 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | 19 | #include "layer_shell_v1.h" 20 | #include "in_process_server.h" 21 | #include "version_specifier.h" 22 | 23 | wlcs::LayerSurfaceV1::LayerSurfaceV1( 24 | wlcs::Client& client, 25 | wlcs::Surface& surface, 26 | zwlr_layer_shell_v1_layer layer, 27 | wl_output* output, 28 | const char *_namespace) 29 | : client{client}, 30 | layer_shell{client.bind_if_supported(AnyVersion)}, 31 | layer_surface{wrap_wl_object( 32 | zwlr_layer_shell_v1_get_layer_surface( 33 | layer_shell, 34 | surface, 35 | output, 36 | layer, 37 | _namespace))} 38 | { 39 | static struct zwlr_layer_surface_v1_listener const listener { 40 | [](void* data, 41 | struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, 42 | uint32_t serial, 43 | uint32_t width, 44 | uint32_t height) 45 | { 46 | auto self = static_cast(data); 47 | self->last_size_ = {width, height}; 48 | self->configure_count++; 49 | (void)zwlr_layer_surface_v1; 50 | (void)serial; 51 | zwlr_layer_surface_v1_ack_configure(zwlr_layer_surface_v1, serial); 52 | }, 53 | [](void* /*data*/, 54 | struct zwlr_layer_surface_v1 */*zwlr_layer_surface_v1*/) 55 | { 56 | } 57 | }; 58 | zwlr_layer_surface_v1_add_listener(layer_surface, &listener, this); 59 | } 60 | 61 | void wlcs::LayerSurfaceV1::dispatch_until_configure() 62 | { 63 | client.dispatch_until([prev_config_count = configure_count, ¤t_config_count = configure_count] 64 | { 65 | return current_config_count > prev_config_count; 66 | }); 67 | } 68 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2017 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Christopher James Halse Rogers 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include "xfail_supporting_test_listener.h" 26 | #include "shared_library.h" 27 | #include "wlcs/display_server.h" 28 | 29 | #include "helpers.h" 30 | 31 | 32 | int main(int argc, char** argv) 33 | { 34 | ::testing::InitGoogleTest(&argc, argv); 35 | 36 | if (argc < 2 || !argv[1] || std::string{"--help"} == argv[1]) 37 | { 38 | std::cerr 39 | << "WayLand Conformance Suite test runner" << std::endl 40 | << "Usage: " << argv[0] << " COMPOSITOR_INTEGRATION_MODULE [GTEST OPTIONS]... [COMPOSITOR_OPTIONS]..." << std::endl; 41 | return 1; 42 | } 43 | 44 | auto const integration_filename = argv[1]; 45 | 46 | // Shuffle the integration module argument out of argv 47 | for (auto i = 1 ; i < (argc - 1) ; ++i) 48 | { 49 | argv[i] = argv[i + 1]; 50 | } 51 | wlcs::helpers::set_command_line(argc - 1, const_cast(argv)); 52 | 53 | std::shared_ptr dso; 54 | try 55 | { 56 | dso = std::make_shared(integration_filename); 57 | } 58 | catch (std::exception const& err) 59 | { 60 | std::cerr 61 | << "Failed to load compositor integration module " << integration_filename << ": " << err.what() << std::endl; 62 | return 1; 63 | } 64 | 65 | std::shared_ptr entry_point; 66 | try 67 | { 68 | entry_point = std::shared_ptr{ 69 | dso, 70 | dso->load_function("wlcs_server_integration") 71 | }; 72 | } 73 | catch (std::exception const& err) 74 | { 75 | std::cerr 76 | << "Failed to load compositor entry point: " << err.what() << std::endl; 77 | return 1; 78 | } 79 | 80 | wlcs::helpers::set_entry_point(entry_point); 81 | 82 | auto& listeners = ::testing::UnitTest::GetInstance()->listeners(); 83 | auto wrapping_listener = new testing::XFailSupportingTestListenerWrapper{ 84 | std::unique_ptr<::testing::TestEventListener>{ 85 | listeners.Release(listeners.default_result_printer())}}; 86 | listeners.Append(wrapping_listener); 87 | 88 | /* (void)! is apparently the magical incantation required to get GCC to 89 | * *actually* silently ignore the return value of a function declared with 90 | * __attribute__(("warn_unused_result")) 91 | * cf: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 92 | */ 93 | (void)!RUN_ALL_TESTS(); 94 | if (wrapping_listener->failed()) 95 | { 96 | return EXIT_FAILURE; 97 | } 98 | return EXIT_SUCCESS; 99 | } 100 | 101 | -------------------------------------------------------------------------------- /src/pointer_constraints_unstable_v1.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Alan Griffiths 17 | */ 18 | 19 | #include "pointer_constraints_unstable_v1.h" 20 | 21 | #include "in_process_server.h" 22 | #include 23 | 24 | wlcs::ZwpPointerConstraintsV1::ZwpPointerConstraintsV1(Client& client) : 25 | manager{client.bind_if_supported(AnyVersion)} 26 | { 27 | } 28 | 29 | wlcs::ZwpPointerConstraintsV1::~ZwpPointerConstraintsV1() = default; 30 | 31 | wlcs::ZwpPointerConstraintsV1::operator zwp_pointer_constraints_v1*() const 32 | { 33 | return manager; 34 | } 35 | 36 | wlcs::ZwpConfinedPointerV1::ZwpConfinedPointerV1( 37 | ZwpPointerConstraintsV1& manager, 38 | wl_surface* surface, 39 | wl_pointer* pointer, 40 | wl_region* region, 41 | uint32_t lifetime) : 42 | relative_pointer{zwp_pointer_constraints_v1_confine_pointer(manager, surface, pointer, region, lifetime)}, 43 | version{zwp_confined_pointer_v1_get_version(relative_pointer)} 44 | { 45 | zwp_confined_pointer_v1_set_user_data(relative_pointer, this); 46 | zwp_confined_pointer_v1_add_listener(relative_pointer, &listener, this); 47 | } 48 | 49 | wlcs::ZwpConfinedPointerV1::~ZwpConfinedPointerV1() 50 | { 51 | zwp_confined_pointer_v1_destroy(relative_pointer); 52 | } 53 | 54 | wlcs::ZwpConfinedPointerV1::operator zwp_confined_pointer_v1*() const 55 | { 56 | return relative_pointer; 57 | } 58 | 59 | zwp_confined_pointer_v1_listener const wlcs::ZwpConfinedPointerV1::listener = 60 | { 61 | [](void* self, auto*) { static_cast(self)->confined(); }, 62 | [](void* self, auto*) { static_cast(self)->unconfined(); }, 63 | }; 64 | 65 | 66 | wlcs::ZwpLockedPointerV1::ZwpLockedPointerV1( 67 | ZwpPointerConstraintsV1& manager, 68 | wl_surface* surface, 69 | wl_pointer* pointer, 70 | wl_region* region, 71 | uint32_t lifetime) : 72 | locked_pointer{zwp_pointer_constraints_v1_lock_pointer(manager, surface, pointer, region, lifetime)}, 73 | version{zwp_locked_pointer_v1_get_version(locked_pointer)} 74 | { 75 | zwp_locked_pointer_v1_set_user_data(locked_pointer, this); 76 | zwp_locked_pointer_v1_add_listener(locked_pointer, &listener, this); 77 | } 78 | 79 | wlcs::ZwpLockedPointerV1::~ZwpLockedPointerV1() 80 | { 81 | zwp_locked_pointer_v1_destroy(locked_pointer); 82 | } 83 | 84 | wlcs::ZwpLockedPointerV1::operator zwp_locked_pointer_v1*() const 85 | { 86 | return locked_pointer; 87 | } 88 | 89 | zwp_locked_pointer_v1_listener const wlcs::ZwpLockedPointerV1::listener = 90 | { 91 | [](void* self, auto*) { static_cast(self)->locked(); }, 92 | [](void* self, auto*) { static_cast(self)->unlocked(); }, 93 | }; 94 | -------------------------------------------------------------------------------- /src/primary_selection.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Alan Griffiths 17 | */ 18 | 19 | #include "primary_selection.h" 20 | 21 | #include 22 | 23 | wlcs::ActiveListeners wlcs::PrimarySelectionDeviceListener::active_listeners; 24 | constexpr zwp_primary_selection_device_v1_listener wlcs::PrimarySelectionDeviceListener::thunks; 25 | 26 | wlcs::ActiveListeners wlcs::PrimarySelectionOfferListener::active_listeners; 27 | constexpr zwp_primary_selection_offer_v1_listener wlcs::PrimarySelectionOfferListener::thunks; 28 | 29 | wlcs::ActiveListeners wlcs::PrimarySelectionSourceListener::active_listeners; 30 | constexpr zwp_primary_selection_source_v1_listener wlcs::PrimarySelectionSourceListener::thunks; 31 | 32 | 33 | void wlcs::PrimarySelectionDeviceListener::data_offer( 34 | void* data, 35 | zwp_primary_selection_device_v1* device, 36 | zwp_primary_selection_offer_v1* offer) 37 | { 38 | if (active_listeners.includes(data)) 39 | static_cast(data)->data_offer(device, offer); 40 | } 41 | 42 | void wlcs::PrimarySelectionDeviceListener::data_offer(zwp_primary_selection_device_v1*, zwp_primary_selection_offer_v1*) 43 | { 44 | } 45 | 46 | void wlcs::PrimarySelectionDeviceListener::selection(zwp_primary_selection_device_v1*, zwp_primary_selection_offer_v1*) 47 | { 48 | } 49 | 50 | void wlcs::PrimarySelectionDeviceListener::selection( 51 | void* data, 52 | zwp_primary_selection_device_v1* device, 53 | zwp_primary_selection_offer_v1* offer) 54 | { 55 | if (active_listeners.includes(data)) 56 | static_cast(data)->selection(device, offer); 57 | } 58 | 59 | void wlcs::PrimarySelectionOfferListener::offer(zwp_primary_selection_offer_v1*, const char*) 60 | { 61 | } 62 | 63 | void wlcs::PrimarySelectionOfferListener::offer( 64 | void* data, zwp_primary_selection_offer_v1* offer, const char* mime_type) 65 | { 66 | if (active_listeners.includes(data)) 67 | static_cast(data)->offer(offer, mime_type); 68 | } 69 | 70 | void wlcs::PrimarySelectionSourceListener::send(zwp_primary_selection_source_v1*, const char*, int32_t fd) 71 | { 72 | close(fd); 73 | } 74 | 75 | void wlcs::PrimarySelectionSourceListener::cancelled(zwp_primary_selection_source_v1*) 76 | { 77 | } 78 | 79 | void wlcs::PrimarySelectionSourceListener::send( 80 | void* data, zwp_primary_selection_source_v1* source, const char* mime_type, int32_t fd) 81 | { 82 | if (active_listeners.includes(data)) 83 | static_cast(data)->send(source, mime_type, fd); 84 | } 85 | 86 | void wlcs::PrimarySelectionSourceListener::cancelled(void* data, zwp_primary_selection_source_v1* source) 87 | { 88 | if (active_listeners.includes(data)) 89 | static_cast(data)->cancelled(source); 90 | } 91 | -------------------------------------------------------------------------------- /src/protocol/fractional-scale-v1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Copyright © 2022 Kenny Levinsen 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the "Software"), 8 | to deal in the Software without restriction, including without limitation 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice (including the next 14 | paragraph) shall be included in all copies or substantial portions of the 15 | Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | 25 | 26 | 27 | This protocol allows a compositor to suggest for surfaces to render at 28 | fractional scales. 29 | 30 | A client can submit scaled content by utilizing wp_viewport. This is done by 31 | creating a wp_viewport object for the surface and setting the destination 32 | rectangle to the surface size before the scale factor is applied. 33 | 34 | The buffer size is calculated by multiplying the surface size by the 35 | intended scale. 36 | 37 | The wl_surface buffer scale should remain set to 1. 38 | 39 | If a surface has a surface-local size of 100 px by 50 px and wishes to 40 | submit buffers with a scale of 1.5, then a buffer of 150px by 75 px should 41 | be used and the wp_viewport destination rectangle should be 100 px by 50 px. 42 | 43 | For toplevel surfaces, the size is rounded halfway away from zero. The 44 | rounding algorithm for subsurface position and size is not defined. 45 | 46 | 47 | 48 | 49 | A global interface for requesting surfaces to use fractional scales. 50 | 51 | 52 | 53 | 54 | Informs the server that the client will not be using this protocol 55 | object anymore. This does not affect any other objects, 56 | wp_fractional_scale_v1 objects included. 57 | 58 | 59 | 60 | 61 | 63 | 64 | 65 | 66 | 67 | Create an add-on object for the the wl_surface to let the compositor 68 | request fractional scales. If the given wl_surface already has a 69 | wp_fractional_scale_v1 object associated, the fractional_scale_exists 70 | protocol error is raised. 71 | 72 | 74 | 76 | 77 | 78 | 79 | 80 | 81 | An additional interface to a wl_surface object which allows the compositor 82 | to inform the client of the preferred scale. 83 | 84 | 85 | 86 | 87 | Destroy the fractional scale object. When this object is destroyed, 88 | preferred_scale events will no longer be sent. 89 | 90 | 91 | 92 | 93 | 94 | Notification of a new preferred scale for this surface that the 95 | compositor suggests that the client should use. 96 | 97 | The sent scale is the numerator of a fraction with a denominator of 120. 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /src/relative_pointer_unstable_v1.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Alan Griffiths 17 | */ 18 | 19 | #include "relative_pointer_unstable_v1.h" 20 | 21 | #include "in_process_server.h" 22 | #include 23 | 24 | wlcs::ZwpRelativePointerManagerV1::ZwpRelativePointerManagerV1(Client& client) : 25 | manager{client.bind_if_supported(AnyVersion)} 26 | { 27 | 28 | } 29 | 30 | wlcs::ZwpRelativePointerManagerV1::~ZwpRelativePointerManagerV1() = default; 31 | 32 | wlcs::ZwpRelativePointerManagerV1::operator zwp_relative_pointer_manager_v1*() const 33 | { 34 | return manager; 35 | } 36 | 37 | wlcs::ZwpRelativePointerV1::ZwpRelativePointerV1(wlcs::ZwpRelativePointerManagerV1& manager, wl_pointer* pointer) : 38 | relative_pointer{zwp_relative_pointer_manager_v1_get_relative_pointer(manager, pointer)}, 39 | version{zwp_relative_pointer_v1_get_version(relative_pointer)} 40 | { 41 | zwp_relative_pointer_v1_set_user_data(relative_pointer, this); 42 | zwp_relative_pointer_v1_add_listener(relative_pointer, &listener, this); 43 | } 44 | 45 | wlcs::ZwpRelativePointerV1::~ZwpRelativePointerV1() 46 | { 47 | zwp_relative_pointer_v1_destroy(relative_pointer); 48 | } 49 | 50 | wlcs::ZwpRelativePointerV1::operator zwp_relative_pointer_v1*() const 51 | { 52 | return relative_pointer; 53 | } 54 | 55 | zwp_relative_pointer_v1_listener const wlcs::ZwpRelativePointerV1::listener = 56 | { 57 | [](void* self, auto*, auto... args) { static_cast(self)->relative_motion(args...); } 58 | }; 59 | -------------------------------------------------------------------------------- /src/shared_library.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2013 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License version 2 or 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU Lesser General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Alan Griffiths 17 | */ 18 | 19 | #include "shared_library.h" 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | 28 | wlcs::SharedLibrary::SharedLibrary(char const* library_name) : 29 | so(dlopen(library_name, RTLD_NOW | RTLD_LOCAL)) 30 | { 31 | if (!so) 32 | { 33 | BOOST_THROW_EXCEPTION(std::runtime_error(dlerror())); 34 | } 35 | } 36 | 37 | wlcs::SharedLibrary::SharedLibrary(std::string const& library_name) : 38 | SharedLibrary(library_name.c_str()) {} 39 | 40 | wlcs::SharedLibrary::~SharedLibrary() noexcept 41 | { 42 | dlclose(so); 43 | } 44 | 45 | void* wlcs::SharedLibrary::load_symbol(char const* function_name) const 46 | { 47 | if (void* result = dlsym(so, function_name)) 48 | { 49 | return result; 50 | } 51 | else 52 | { 53 | BOOST_THROW_EXCEPTION(std::runtime_error(dlerror())); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/surface_builder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | 19 | #include "surface_builder.h" 20 | #include "xdg_shell_stable.h" 21 | 22 | auto wlcs::SurfaceBuilder::all_surface_types() -> std::vector> 23 | { 24 | return { 25 | std::make_shared(), 26 | std::make_shared(), 27 | std::make_shared(0, 0, 0, 0), 28 | std::make_shared(12, 5, 20, 6), 29 | std::make_shared(std::make_pair(0, 0)), 30 | std::make_shared(std::make_pair(7, 12))}; 31 | } 32 | 33 | auto wlcs::SurfaceBuilder::toplevel_surface_types() -> std::vector> 34 | { 35 | return { 36 | std::make_shared(), 37 | std::make_shared(), 38 | std::make_shared(0, 0, 0, 0)}; 39 | } 40 | 41 | auto wlcs::SurfaceBuilder::surface_builder_to_string( 42 | testing::TestParamInfo> builder) -> std::string 43 | { 44 | return builder.param->name; 45 | } 46 | 47 | auto wlcs::WlShellSurfaceBuilder::build( 48 | wlcs::Server& server, 49 | wlcs::Client& client, 50 | std::pair position, 51 | std::pair size) const -> std::unique_ptr 52 | { 53 | auto surface = std::make_unique( 54 | client.create_wl_shell_surface(size.first, size.second)); 55 | server.move_surface_to(*surface, position.first, position.second); 56 | return surface; 57 | } 58 | 59 | auto wlcs::XdgV6SurfaceBuilder::build( 60 | wlcs::Server& server, 61 | wlcs::Client& client, 62 | std::pair position, 63 | std::pair size) const -> std::unique_ptr 64 | { 65 | auto surface = std::make_unique( 66 | client.create_xdg_shell_v6_surface(size.first, size.second)); 67 | server.move_surface_to(*surface, position.first, position.second); 68 | return surface; 69 | } 70 | 71 | wlcs::XdgStableSurfaceBuilder::XdgStableSurfaceBuilder(int left_offset, int top_offset, int right_offset, int bottom_offset) 72 | : SurfaceBuilder{"xdg_surface_stable" + 73 | ((left_offset || top_offset || right_offset || bottom_offset) ? ("_" + 74 | std::to_string(left_offset) + "_" + 75 | std::to_string(top_offset) + "_" + 76 | std::to_string(right_offset) + "_" + 77 | std::to_string(bottom_offset)) : "")}, 78 | left_offset{left_offset}, 79 | top_offset{top_offset}, 80 | right_offset{right_offset}, 81 | bottom_offset{bottom_offset} 82 | { 83 | } 84 | 85 | auto wlcs::XdgStableSurfaceBuilder::build( 86 | wlcs::Server& server, 87 | wlcs::Client& client, 88 | std::pair position, 89 | std::pair size) const -> std::unique_ptr 90 | { 91 | auto surface = std::make_unique(client); 92 | auto xdg_surface = std::make_shared(client, *surface); 93 | auto xdg_toplevel = std::make_shared(*xdg_surface); 94 | // The logical window will be shrunk and moved based on the offset, but the underlying surface will not 95 | xdg_surface_set_window_geometry( 96 | *xdg_surface, 97 | left_offset, top_offset, 98 | size.first - left_offset - right_offset, size.second -bottom_offset - top_offset); 99 | surface->attach_visible_buffer(size.first, size.second); 100 | surface->run_on_destruction( 101 | [xdg_surface, xdg_toplevel]() mutable 102 | { 103 | xdg_toplevel.reset(); 104 | xdg_surface.reset(); 105 | }); 106 | server.move_surface_to(*surface, position.first + left_offset, position.second + top_offset); 107 | return surface; 108 | } 109 | 110 | wlcs::SubsurfaceBuilder::SubsurfaceBuilder(std::pair offset) 111 | : SurfaceBuilder{ 112 | "subsurface_at_x" + 113 | std::to_string(offset.first) + 114 | "_y" + 115 | std::to_string(offset.second)}, 116 | offset{offset} 117 | { 118 | } 119 | 120 | auto wlcs::SubsurfaceBuilder::build( 121 | wlcs::Server& server, 122 | wlcs::Client& client, 123 | std::pair position, 124 | std::pair size) const -> std::unique_ptr 125 | { 126 | auto main_surface = std::make_shared( 127 | client.create_visible_surface(80, 50)); 128 | server.move_surface_to( 129 | *main_surface, 130 | position.first - offset.first, 131 | position.second - offset.second); 132 | client.run_on_destruction( 133 | [main_surface]() mutable 134 | { 135 | main_surface.reset(); 136 | }); 137 | auto subsurface = std::make_unique(wlcs::Subsurface::create_visible( 138 | *main_surface, 139 | offset.first, offset.second, 140 | size.first, size.second)); 141 | // if subsurface is sync, tests would have to commit the parent to modify it 142 | // this is inconvenient to do in a generic way, so we make it desync 143 | wl_subsurface_set_desync(*subsurface); 144 | return subsurface; 145 | } 146 | 147 | std::ostream& std::operator<<(std::ostream& out, std::shared_ptr const& param) 148 | { 149 | return out << param->name; 150 | } 151 | -------------------------------------------------------------------------------- /src/test_c_compile.c: -------------------------------------------------------------------------------- 1 | #include "wlcs/display_server.h" 2 | #include "wlcs/pointer.h" 3 | #include "wlcs/touch.h" 4 | 5 | WlcsServerIntegration server_integration; 6 | WlcsPointer pointer; 7 | WlcsTouch touch; 8 | -------------------------------------------------------------------------------- /src/version_specifier.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Christopher James Halse Rogers 17 | */ 18 | 19 | #include "version_specifier.h" 20 | #include "boost/throw_exception.hpp" 21 | #include 22 | 23 | wlcs::ExactlyVersion::ExactlyVersion(uint32_t version) noexcept 24 | : version{version} 25 | { 26 | } 27 | 28 | auto wlcs::ExactlyVersion::select_version( 29 | uint32_t max_available_version, 30 | uint32_t max_supported_version) const -> std::optional 31 | { 32 | if (version > max_supported_version) 33 | { 34 | BOOST_THROW_EXCEPTION(std::logic_error( 35 | "Required version " + 36 | std::to_string(version) + 37 | " is higher than the highest version supported by WLCS (" + 38 | std::to_string(max_supported_version) + 39 | ")")); 40 | } 41 | else if (version > max_available_version) 42 | { 43 | return {}; 44 | } 45 | else 46 | { 47 | return {version}; 48 | } 49 | } 50 | 51 | auto wlcs::ExactlyVersion::describe() const -> std::string 52 | { 53 | return std::string{"= "} + std::to_string(version); 54 | } 55 | 56 | wlcs::AtLeastVersion::AtLeastVersion(uint32_t version) noexcept 57 | : version{version} 58 | { 59 | } 60 | 61 | auto wlcs::AtLeastVersion::select_version( 62 | uint32_t max_available_version, 63 | uint32_t max_supported_version) const -> std::optional 64 | { 65 | if (version > max_supported_version) 66 | { 67 | BOOST_THROW_EXCEPTION(std::logic_error( 68 | "Required version " + 69 | std::to_string(version) + 70 | " is higher than the highest version supported by WLCS (" + 71 | std::to_string(max_supported_version) + 72 | ")")); 73 | } 74 | else if (version > max_available_version) 75 | { 76 | return {}; 77 | } 78 | else 79 | { 80 | return {std::min(max_available_version, max_supported_version)}; 81 | } 82 | } 83 | 84 | auto wlcs::AtLeastVersion::describe() const -> std::string 85 | { 86 | return std::string{">= "} + std::to_string(version); 87 | } 88 | 89 | wlcs::VersionSpecifier const& wlcs::AnyVersion = wlcs::AtLeastVersion{1}; 90 | -------------------------------------------------------------------------------- /src/xdg_decoration_unstable_v1.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #include "xdg_decoration_unstable_v1.h" 18 | 19 | #include "generated/xdg-decoration-unstable-v1-client.h" 20 | #include "in_process_server.h" 21 | #include "version_specifier.h" 22 | 23 | wlcs::ZxdgDecorationManagerV1::ZxdgDecorationManagerV1(Client& client) : 24 | manager{client.bind_if_supported(AnyVersion)} 25 | { 26 | } 27 | 28 | wlcs::ZxdgDecorationManagerV1::~ZxdgDecorationManagerV1() = default; 29 | 30 | wlcs::ZxdgDecorationManagerV1::operator zxdg_decoration_manager_v1*() const 31 | { 32 | return manager; 33 | } 34 | 35 | wlcs::ZxdgToplevelDecorationV1::ZxdgToplevelDecorationV1(ZxdgDecorationManagerV1& manager, xdg_toplevel* toplevel) : 36 | version{zxdg_decoration_manager_v1_get_version(manager)}, 37 | toplevel_decoration{zxdg_decoration_manager_v1_get_toplevel_decoration(manager, toplevel)} 38 | { 39 | zxdg_toplevel_decoration_v1_set_user_data(toplevel_decoration, this); 40 | zxdg_toplevel_decoration_v1_add_listener(toplevel_decoration, &listener, this); 41 | } 42 | 43 | wlcs::ZxdgToplevelDecorationV1::~ZxdgToplevelDecorationV1() { zxdg_toplevel_decoration_v1_destroy(toplevel_decoration); } 44 | 45 | wlcs::ZxdgToplevelDecorationV1::operator zxdg_toplevel_decoration_v1*() const 46 | { 47 | return toplevel_decoration; 48 | } 49 | 50 | zxdg_toplevel_decoration_v1_listener const wlcs::ZxdgToplevelDecorationV1::listener = { 51 | [](void* self, auto*, auto... args) 52 | { 53 | static_cast(self)->configure(args...); 54 | }}; 55 | -------------------------------------------------------------------------------- /src/xdg_output_v1.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | 19 | #include "xdg_output_v1.h" 20 | #include "wl_handle.h" 21 | #include "version_specifier.h" 22 | #include 23 | 24 | struct wlcs::XdgOutputManagerV1::Impl 25 | { 26 | Impl(Client& client) 27 | : client{client}, 28 | manager{client.bind_if_supported(AnyVersion)} 29 | { 30 | } 31 | 32 | Client& client; 33 | WlHandle const manager; 34 | }; 35 | 36 | wlcs::XdgOutputManagerV1::XdgOutputManagerV1(Client& client) 37 | : impl{std::make_unique(client)} 38 | { 39 | } 40 | 41 | wlcs::XdgOutputManagerV1::~XdgOutputManagerV1() = default; 42 | 43 | wlcs::XdgOutputManagerV1::operator zxdg_output_manager_v1*() const 44 | { 45 | return impl->manager; 46 | } 47 | 48 | auto wlcs::XdgOutputManagerV1::client() const -> Client& 49 | { 50 | return impl->client; 51 | } 52 | 53 | struct wlcs::XdgOutputV1::Impl 54 | { 55 | Impl(XdgOutputManagerV1& manager, size_t output_index) 56 | : output{zxdg_output_manager_v1_get_xdg_output( 57 | manager, 58 | manager.client().output_state(output_index).output)}, 59 | version{zxdg_output_v1_get_version(output)} 60 | { 61 | zxdg_output_v1_add_listener(output, &Impl::listener, this); 62 | } 63 | 64 | ~Impl() 65 | { 66 | zxdg_output_v1_destroy(output); 67 | } 68 | 69 | zxdg_output_v1* const output; 70 | uint32_t const version; 71 | bool dirty{false}; 72 | State _state; 73 | 74 | static zxdg_output_v1_listener const listener; 75 | }; 76 | 77 | zxdg_output_v1_listener const wlcs::XdgOutputV1::Impl::listener = { 78 | [] /* logical_position */ (void *data, zxdg_output_v1 *, int32_t x, int32_t y) 79 | { 80 | auto const impl = static_cast(data); 81 | impl->_state.logical_position = std::make_pair(x, y); 82 | impl->dirty = true; 83 | }, 84 | 85 | [] /* logical_size */ (void *data, zxdg_output_v1 *, int32_t width, int32_t height) 86 | { 87 | auto const impl = static_cast(data); 88 | impl->_state.logical_size = std::make_pair(width, height); 89 | impl->dirty = true; 90 | }, 91 | 92 | [] /* done */ (void *data, zxdg_output_v1 *) 93 | { 94 | auto const impl = static_cast(data); 95 | if (impl->version < 3) 96 | impl->dirty = false; 97 | }, 98 | 99 | [] /* name */ (void *data, zxdg_output_v1 *, const char *name) 100 | { 101 | auto const impl = static_cast(data); 102 | std::string str{name}; 103 | impl->_state.name = str; 104 | impl->dirty = true; 105 | }, 106 | 107 | [] /* description */ (void *data, zxdg_output_v1 *, const char *description) 108 | { 109 | auto const impl = static_cast(data); 110 | impl->_state.description = std::string{description}; 111 | impl->dirty = true; 112 | }, 113 | }; 114 | 115 | wlcs::XdgOutputV1::XdgOutputV1(XdgOutputManagerV1& manager, size_t output_index) 116 | : impl{std::make_shared(manager, output_index)} 117 | { 118 | if (impl->version >= 3) 119 | { 120 | manager.client().add_output_done_notifier(output_index, [weak = std::weak_ptr(impl)]() 121 | { 122 | if (auto const impl = weak.lock()) 123 | { 124 | impl->dirty = false; 125 | } 126 | }); 127 | } 128 | } 129 | 130 | wlcs::XdgOutputV1::operator zxdg_output_v1*() const 131 | { 132 | return impl->output; 133 | } 134 | 135 | auto wlcs::XdgOutputV1::state() -> State const& 136 | { 137 | if (impl->dirty) 138 | { 139 | std::string done_event = (impl->version >= 3 ? "wl_output.done" : "zxdg_output_v1.done"); 140 | BOOST_THROW_EXCEPTION(std::logic_error("State change was not finished with a " + done_event + " event")); 141 | } 142 | 143 | return impl->_state; 144 | } 145 | -------------------------------------------------------------------------------- /src/xdg_shell_stable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2018 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | 19 | #include "xdg_shell_stable.h" 20 | 21 | using namespace testing; 22 | 23 | // XdgSurfaceStable 24 | 25 | wlcs::XdgSurfaceStable::XdgSurfaceStable(wlcs::Client& client, wlcs::Surface& surface) 26 | { 27 | EXPECT_CALL(*this, configure).Times(AnyNumber()); 28 | if (!client.xdg_shell_stable()) 29 | throw std::runtime_error("XDG shell stable not supported by compositor"); 30 | shell_surface = xdg_wm_base_get_xdg_surface(client.xdg_shell_stable(), surface); 31 | static struct xdg_surface_listener const listener = { 32 | [](void* data, auto, auto... args) { static_cast(data)->configure(args...); }}; 33 | xdg_surface_add_listener(shell_surface, &listener, this); 34 | } 35 | 36 | wlcs::XdgSurfaceStable::~XdgSurfaceStable() 37 | { 38 | xdg_surface_destroy(shell_surface); 39 | } 40 | 41 | // XdgToplevelStable 42 | 43 | wlcs::XdgToplevelStable::State::State(int32_t width, int32_t height, struct wl_array *states) 44 | : width{width}, 45 | height{height}, 46 | maximized{false}, 47 | fullscreen{false}, 48 | resizing{false}, 49 | activated{false} 50 | { 51 | if (!states) 52 | return; 53 | xdg_toplevel_state* item; 54 | for (item = static_cast(states->data); 55 | (char*)item < static_cast(states->data) + states->size; 56 | item++) 57 | { 58 | switch (*item) 59 | { 60 | case XDG_TOPLEVEL_STATE_MAXIMIZED: 61 | maximized = true; 62 | break; 63 | case XDG_TOPLEVEL_STATE_FULLSCREEN: 64 | fullscreen = true; 65 | break; 66 | case XDG_TOPLEVEL_STATE_RESIZING: 67 | resizing = true; 68 | break; 69 | case XDG_TOPLEVEL_STATE_ACTIVATED: 70 | activated = true; 71 | case XDG_TOPLEVEL_STATE_TILED_LEFT: 72 | case XDG_TOPLEVEL_STATE_TILED_RIGHT: 73 | case XDG_TOPLEVEL_STATE_TILED_BOTTOM: 74 | case XDG_TOPLEVEL_STATE_TILED_TOP: 75 | break; 76 | } 77 | } 78 | } 79 | 80 | wlcs::XdgToplevelStable::XdgToplevelStable(XdgSurfaceStable& shell_surface_) 81 | : shell_surface{&shell_surface_} 82 | { 83 | EXPECT_CALL(*this, configure).Times(AnyNumber()); 84 | EXPECT_CALL(*this, close).Times(AnyNumber()); 85 | EXPECT_CALL(*this, configure_bounds).Times(AnyNumber()); 86 | EXPECT_CALL(*this, wm_capabilities).Times(AnyNumber()); 87 | toplevel = xdg_surface_get_toplevel(*shell_surface); 88 | static struct xdg_toplevel_listener const listener = { 89 | [](void* data, auto, auto... args) { static_cast(data)->configure(args...); }, 90 | [](void* data, auto, auto... args) { static_cast(data)->close(args...); }, 91 | [](void* data, auto, auto... args) { static_cast(data)->configure_bounds(args...); }, 92 | [](void* data, auto, auto... args) { static_cast(data)->wm_capabilities(args...); }}; 93 | xdg_toplevel_add_listener(toplevel, &listener, this); 94 | } 95 | 96 | wlcs::XdgToplevelStable::~XdgToplevelStable() 97 | { 98 | xdg_toplevel_destroy(toplevel); 99 | } 100 | 101 | wlcs::XdgPositionerStable::XdgPositionerStable(wlcs::Client& client) 102 | : positioner{xdg_wm_base_create_positioner(client.xdg_shell_stable())} 103 | { 104 | } 105 | 106 | wlcs::XdgPositionerStable::~XdgPositionerStable() 107 | { 108 | xdg_positioner_destroy(positioner); 109 | } 110 | 111 | auto wlcs::XdgPositionerStable::setup_default(std::pair size) -> XdgPositionerStable& 112 | { 113 | xdg_positioner_set_size(positioner, size.first, size.second); 114 | xdg_positioner_set_anchor_rect(positioner, 0, 0, 1, 1); 115 | xdg_positioner_set_anchor(positioner, XDG_POSITIONER_ANCHOR_TOP_LEFT); 116 | xdg_positioner_set_gravity(positioner, XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT); 117 | return *this; 118 | } 119 | 120 | wlcs::XdgPopupStable::XdgPopupStable( 121 | XdgSurfaceStable& shell_surface_, 122 | std::optional parent, 123 | XdgPositionerStable& positioner) 124 | : shell_surface{&shell_surface_}, 125 | popup{xdg_surface_get_popup( 126 | *shell_surface, 127 | parent ? *parent.value() : (xdg_surface*)nullptr, 128 | positioner)} 129 | { 130 | EXPECT_CALL(*this, configure).Times(AnyNumber()); 131 | EXPECT_CALL(*this, done).Times(AnyNumber()); 132 | EXPECT_CALL(*this, repositioned).Times(AnyNumber()); 133 | static struct xdg_popup_listener const listener = { 134 | [](void* data, auto, auto... args) { static_cast(data)->configure(args...); }, 135 | [](void* data, auto, auto... args) { static_cast(data)->done(args...); }, 136 | [](void* data, auto, auto... args) { static_cast(data)->repositioned(args...); }}; 137 | xdg_popup_add_listener(popup, &listener, this); 138 | } 139 | 140 | wlcs::XdgPopupStable::~XdgPopupStable() 141 | { 142 | xdg_popup_destroy(popup); 143 | } 144 | -------------------------------------------------------------------------------- /src/xdg_shell_v6.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2018 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | 19 | #include "xdg_shell_v6.h" 20 | 21 | using namespace testing; 22 | 23 | // XdgSurfaceV6 24 | 25 | wlcs::XdgSurfaceV6::XdgSurfaceV6(wlcs::Client& client, wlcs::Surface& surface) 26 | { 27 | EXPECT_CALL(*this, configure).Times(AnyNumber()); 28 | if (!client.xdg_shell_v6()) 29 | throw std::runtime_error("XDG shell unstable V6 not supported by compositor"); 30 | shell_surface = zxdg_shell_v6_get_xdg_surface(client.xdg_shell_v6(), surface); 31 | static struct zxdg_surface_v6_listener const listener = { 32 | [](void* data, auto, auto... args) { static_cast(data)->configure(args...); }}; 33 | zxdg_surface_v6_add_listener(shell_surface, &listener, this); 34 | } 35 | 36 | wlcs::XdgSurfaceV6::~XdgSurfaceV6() 37 | { 38 | zxdg_surface_v6_destroy(shell_surface); 39 | } 40 | 41 | // XdgToplevelV6 42 | 43 | wlcs::XdgToplevelV6::State::State(int32_t width, int32_t height, struct wl_array *states) 44 | : width{width}, 45 | height{height}, 46 | maximized{false}, 47 | fullscreen{false}, 48 | resizing{false}, 49 | activated{false} 50 | { 51 | if (!states) 52 | return; 53 | zxdg_toplevel_v6_state* item; 54 | for (item = static_cast(states->data); 55 | (char*)item < static_cast(states->data) + states->size; 56 | item++) 57 | { 58 | switch (*item) 59 | { 60 | case ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED: 61 | maximized = true; 62 | break; 63 | case ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN: 64 | fullscreen = true; 65 | break; 66 | case ZXDG_TOPLEVEL_V6_STATE_RESIZING: 67 | resizing = true; 68 | break; 69 | case ZXDG_TOPLEVEL_V6_STATE_ACTIVATED: 70 | activated = true; 71 | break; 72 | } 73 | } 74 | } 75 | 76 | wlcs::XdgToplevelV6::XdgToplevelV6(XdgSurfaceV6& shell_surface_) 77 | : shell_surface{&shell_surface_} 78 | { 79 | EXPECT_CALL(*this, configure).Times(AnyNumber()); 80 | EXPECT_CALL(*this, close).Times(AnyNumber()); 81 | toplevel = zxdg_surface_v6_get_toplevel(*shell_surface); 82 | static struct zxdg_toplevel_v6_listener const listener = { 83 | [](void* data, auto, auto... args) { static_cast(data)->configure(args...); }, 84 | [](void* data, auto, auto... args) { static_cast(data)->close(args...); }}; 85 | zxdg_toplevel_v6_add_listener(toplevel, &listener, this); 86 | } 87 | 88 | wlcs::XdgToplevelV6::~XdgToplevelV6() 89 | { 90 | zxdg_toplevel_v6_destroy(toplevel); 91 | } 92 | 93 | wlcs::XdgPositionerV6::XdgPositionerV6(wlcs::Client& client) 94 | : positioner{zxdg_shell_v6_create_positioner(client.xdg_shell_v6())} 95 | { 96 | } 97 | 98 | wlcs::XdgPositionerV6::~XdgPositionerV6() 99 | { 100 | zxdg_positioner_v6_destroy(positioner); 101 | } 102 | 103 | wlcs::XdgPopupV6::XdgPopupV6(XdgSurfaceV6& shell_surface_, XdgSurfaceV6& parent, XdgPositionerV6& positioner) 104 | : shell_surface{&shell_surface_}, 105 | popup{zxdg_surface_v6_get_popup(*shell_surface, parent, positioner)} 106 | { 107 | EXPECT_CALL(*this, configure).Times(AnyNumber()); 108 | EXPECT_CALL(*this, done).Times(AnyNumber()); 109 | static struct zxdg_popup_v6_listener const listener = { 110 | [](void* data, auto, auto... args) { static_cast(data)->configure(args...); }, 111 | [](void* data, auto, auto... args) { static_cast(data)->done(args...); }}; 112 | zxdg_popup_v6_add_listener(popup, &listener, this); 113 | } 114 | 115 | wlcs::XdgPopupV6::~XdgPopupV6() 116 | { 117 | zxdg_popup_v6_destroy(popup); 118 | } 119 | -------------------------------------------------------------------------------- /src/xfail_supporting_test_listener.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Christopher James Halse Rogers 17 | */ 18 | 19 | #ifndef WLCS_XFAIL_SUPPORTING_TEST_LISTENER_H_ 20 | #define WLCS_XFAIL_SUPPORTING_TEST_LISTENER_H_ 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | namespace testing 31 | { 32 | class XFailSupportingTestListenerWrapper : public testing::TestEventListener 33 | { 34 | public: 35 | explicit XFailSupportingTestListenerWrapper(std::unique_ptr&& wrapped); 36 | 37 | void OnTestProgramStart(testing::UnitTest const& unit_test) override; 38 | 39 | void OnTestIterationStart(testing::UnitTest const& unit_test, int iteration) override; 40 | 41 | void OnEnvironmentsSetUpStart(testing::UnitTest const& unit_test) override; 42 | 43 | void OnEnvironmentsSetUpEnd(testing::UnitTest const& unit_test) override; 44 | 45 | void OnTestCaseStart(testing::TestCase const& test_case) override; 46 | 47 | void OnTestStart(testing::TestInfo const& test_info) override; 48 | 49 | void OnTestPartResult(testing::TestPartResult const& test_part_result) override; 50 | 51 | void OnTestEnd(testing::TestInfo const& test_info) override; 52 | void OnTestCaseEnd(testing::TestCase const& test_case) override; 53 | 54 | void OnEnvironmentsTearDownStart(testing::UnitTest const& unit_test) override; 55 | 56 | void OnEnvironmentsTearDownEnd(testing::UnitTest const& unit_test) override; 57 | 58 | void OnTestIterationEnd(testing::UnitTest const& unit_test, int iteration) override; 59 | 60 | void OnTestProgramEnd(testing::UnitTest const& unit_test) override; 61 | 62 | bool failed() const; 63 | private: 64 | std::unique_ptr const delegate; 65 | 66 | std::chrono::steady_clock::time_point current_test_start; 67 | ::testing::TestInfo const* current_test_info; 68 | std::optional> current_skip_reasons; 69 | 70 | std::unordered_set failed_test_names; 71 | std::unordered_set skipped_test_names; 72 | 73 | bool failed_{false}; 74 | }; 75 | 76 | } 77 | 78 | #endif //WLCS_XFAIL_SUPPORTING_TEST_LISTENER_H_ 79 | -------------------------------------------------------------------------------- /tests/copy_cut_paste.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2018 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Alan Griffiths 17 | */ 18 | 19 | #include "data_device.h" 20 | #include "helpers.h" 21 | #include "in_process_server.h" 22 | #include "wl_handle.h" 23 | #include "version_specifier.h" 24 | 25 | #include 26 | 27 | #include 28 | 29 | using namespace testing; 30 | using namespace wlcs; 31 | 32 | namespace 33 | { 34 | 35 | auto static const any_width = 100; 36 | auto static const any_height = 100; 37 | auto static const any_mime_type = "AnyMimeType"; 38 | 39 | struct CCnPSource : Client 40 | { 41 | using Client::Client; 42 | 43 | Surface const surface{create_visible_surface(any_width, any_height)}; 44 | WlHandle const manager{ 45 | this->bind_if_supported(AnyVersion)}; 46 | DataDevice data_device{wl_data_device_manager_get_data_device(manager,seat())}; 47 | DataSource data{wl_data_device_manager_create_data_source(manager)}; 48 | 49 | void offer(char const* mime_type) 50 | { 51 | wl_data_source_offer(data, mime_type); 52 | // TODO: collect a serial from the "event that triggered" the selection 53 | // (This works while Mir fails to validate the serial) 54 | uint32_t const serial = 0; 55 | wl_data_device_set_selection(data_device, data, serial); 56 | roundtrip(); 57 | } 58 | }; 59 | 60 | struct MockDataDeviceListener : DataDeviceListener 61 | { 62 | using DataDeviceListener::DataDeviceListener; 63 | 64 | MOCK_METHOD2(data_offer, void(struct wl_data_device* wl_data_device, struct wl_data_offer* id)); 65 | }; 66 | 67 | struct MockDataOfferListener : DataOfferListener 68 | { 69 | using DataOfferListener::DataOfferListener; 70 | 71 | MOCK_METHOD2(offer, void(struct wl_data_offer* data_offer, char const* MimeType)); 72 | }; 73 | 74 | struct CCnPSink : Client 75 | { 76 | using Client::Client; 77 | 78 | WlHandle const manager{ 79 | this->bind_if_supported(AnyVersion)}; 80 | DataDevice sink_data{wl_data_device_manager_get_data_device(manager, seat())}; 81 | MockDataDeviceListener listener{sink_data}; 82 | 83 | Surface create_surface_with_focus() 84 | { 85 | return Surface{create_visible_surface(any_width, any_height)}; 86 | } 87 | }; 88 | 89 | struct CopyCutPaste : StartedInProcessServer 90 | { 91 | CCnPSource source{the_server()}; 92 | CCnPSink sink{the_server()}; 93 | 94 | MockDataOfferListener mdol; 95 | 96 | void TearDown() override 97 | { 98 | source.roundtrip(); 99 | sink.roundtrip(); 100 | StartedInProcessServer::TearDown(); 101 | } 102 | }; 103 | } 104 | 105 | TEST_F(CopyCutPaste, given_source_has_offered_when_sink_gets_focus_it_sees_offer) 106 | { 107 | source.offer(any_mime_type); 108 | 109 | EXPECT_CALL(mdol, offer(_, StrEq(any_mime_type))); 110 | EXPECT_CALL(sink.listener, data_offer(_,_)) 111 | .WillOnce(Invoke([&](struct wl_data_device*, struct wl_data_offer* id) 112 | { mdol.listen_to(id); })); 113 | 114 | sink.create_surface_with_focus(); 115 | } 116 | 117 | TEST_F(CopyCutPaste, given_sink_has_focus_when_source_makes_offer_sink_sees_offer) 118 | { 119 | auto sink_surface_with_focus = sink.create_surface_with_focus(); 120 | 121 | EXPECT_CALL(mdol, offer(_, StrEq(any_mime_type))); 122 | EXPECT_CALL(sink.listener, data_offer(_,_)) 123 | .WillOnce(Invoke([&](struct wl_data_device*, struct wl_data_offer* id) 124 | { mdol.listen_to(id); })); 125 | 126 | source.offer(any_mime_type); 127 | } 128 | -------------------------------------------------------------------------------- /tests/fractional_scale_v1.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #include "expect_protocol_error.h" 18 | #include "generated/fractional-scale-v1-client.h" 19 | #include "in_process_server.h" 20 | #include "version_specifier.h" 21 | 22 | using namespace wlcs; 23 | using testing::Eq; 24 | 25 | namespace wlcs { 26 | WLCS_CREATE_INTERFACE_DESCRIPTOR(wp_fractional_scale_manager_v1) 27 | WLCS_CREATE_INTERFACE_DESCRIPTOR(wp_fractional_scale_v1) 28 | } 29 | 30 | class FractionalScaleV1Test : public wlcs::StartedInProcessServer 31 | { 32 | public: 33 | Client a_client{the_server()}; 34 | Surface a_surface{a_client}; 35 | WlHandle fractional_scale_manager{ 36 | a_client.bind_if_supported(AnyVersion)}; 37 | }; 38 | 39 | TEST_F(FractionalScaleV1Test, fractional_scale_creation_does_not_throw) 40 | { 41 | auto fractional_scale = 42 | wrap_wl_object(wp_fractional_scale_manager_v1_get_fractional_scale(fractional_scale_manager, a_surface)); 43 | 44 | EXPECT_NO_THROW(a_client.roundtrip()); 45 | } 46 | 47 | TEST_F(FractionalScaleV1Test, duplicate_fractional_scales_throw_fractional_scale_exists) 48 | { 49 | auto fractional_scale1 = 50 | wrap_wl_object(wp_fractional_scale_manager_v1_get_fractional_scale(fractional_scale_manager, a_surface)); 51 | auto fractional_scale2 = 52 | wrap_wl_object(wp_fractional_scale_manager_v1_get_fractional_scale(fractional_scale_manager, a_surface)); 53 | 54 | EXPECT_PROTOCOL_ERROR( 55 | { a_client.roundtrip(); }, 56 | &wp_fractional_scale_manager_v1_interface, 57 | WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS); 58 | } 59 | -------------------------------------------------------------------------------- /tests/frame_submission.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2018 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Alan Griffiths 17 | */ 18 | 19 | #include "helpers.h" 20 | #include "in_process_server.h" 21 | 22 | #include 23 | 24 | using namespace testing; 25 | using namespace wlcs; 26 | 27 | namespace 28 | { 29 | 30 | struct FrameSubmission : StartedInProcessServer 31 | { 32 | Client client{the_server()}; 33 | Surface surface{client.create_visible_surface(200, 200)}; 34 | 35 | void submit_frame(bool& frame_consumed); 36 | 37 | void wait_for_frame(bool const& frame_consumed); 38 | }; 39 | 40 | void FrameSubmission::submit_frame(bool& consumed_flag) 41 | { 42 | static wl_callback_listener const frame_listener 43 | { 44 | [](void *data, struct wl_callback* callback, uint32_t /*callback_data*/) 45 | { 46 | *static_cast(data) = true; 47 | wl_callback_destroy(callback); 48 | } 49 | }; 50 | 51 | consumed_flag = false; 52 | wl_callback_add_listener(wl_surface_frame(surface), &frame_listener, &consumed_flag); 53 | auto buffer = std::make_shared(client, 200, 200); 54 | wl_surface_attach(surface, *buffer, 0, 0); 55 | wl_surface_commit(surface); 56 | } 57 | 58 | void FrameSubmission::wait_for_frame(bool const& consumed_flag) 59 | { 60 | // TODO timeout 61 | client.dispatch_until([&consumed_flag]() { return consumed_flag; }); 62 | } 63 | } 64 | 65 | TEST_F(FrameSubmission, post_one_frame_at_a_time) 66 | { 67 | for (auto i = 0; i != 10; ++i) 68 | { 69 | auto frame_consumed = false; 70 | 71 | submit_frame(frame_consumed); 72 | wait_for_frame(frame_consumed); 73 | 74 | EXPECT_THAT(frame_consumed, Eq(true)); 75 | } 76 | } 77 | 78 | // Regression test for https://github.com/MirServer/mir/issues/2960 79 | TEST_F(FrameSubmission, test_buffer_can_be_deleted_after_attached) 80 | { 81 | using namespace testing; 82 | 83 | wlcs::Client client{the_server()}; 84 | auto surface = client.create_visible_surface(200, 200); 85 | 86 | auto buffer = std::make_shared(client, 200, 200); 87 | wl_surface_attach(surface, *buffer, 0, 0); 88 | buffer.reset(); 89 | /* Check that the destroyed buffer doesn't crash the server 90 | * It's not clear what the *correct* behaviour is in this case: 91 | * Weston treats this as committing a null buffer, wlroots appears to 92 | * treat this as committing the content of the buffer before deletion. 93 | * 94 | * *Whatever* the correct behaviour is, "crash" is *definitely* 95 | * incorrect. 96 | */ 97 | wl_surface_commit(surface); 98 | 99 | // Roundtrip to ensure the server has processed our weirdness 100 | client.roundtrip(); 101 | } 102 | 103 | /* Firefox has a lovely habit of sending an endless stream of 104 | * wl_surface.frame() requests (maybe it's trying to estimate vsync?!) 105 | * 106 | * If a compositor responds immediately to the frame on commit, Firefox 107 | * ends up looping endlessly. If the compositor *doesn't* respond to the frame 108 | * request, Firefox decides not to draw anything. 🤷‍♀️ 109 | */ 110 | TEST_F(FrameSubmission, when_client_endlessly_requests_frame_then_callbacks_are_throttled) 111 | { 112 | using namespace testing; 113 | using namespace std::chrono_literals; 114 | 115 | wlcs::Client annoying_client{the_server()}; 116 | auto surface = client.create_visible_surface(200, 200); 117 | 118 | bool frame_callback_called{false}; 119 | 120 | wl_callback_listener const listener = { 121 | .done = [](void* data, struct wl_callback* callback, [[maybe_unused]]uint32_t timestamp) 122 | { 123 | wl_callback_destroy(callback); 124 | 125 | auto callback_called = static_cast(data); 126 | *callback_called = true; 127 | } 128 | }; 129 | 130 | auto const timeout = std::chrono::steady_clock::now() + 10s; 131 | 132 | do 133 | { 134 | frame_callback_called = false; 135 | wl_callback_add_listener(wl_surface_frame(surface), &listener, &frame_callback_called); 136 | wl_surface_commit(surface); 137 | client.roundtrip(); 138 | /* This roundtrip ensures the server has processed everything prior. 139 | * In particular, if the server sends the frame callback in response to wl_surface.commit, that frame callback 140 | * will have been processed by now. 141 | */ 142 | } 143 | while (frame_callback_called && std::chrono::steady_clock::now() < timeout); 144 | 145 | EXPECT_THAT(std::chrono::steady_clock::now(), Lt(timeout)) << "Timed out looping in frame callback storm"; 146 | } 147 | -------------------------------------------------------------------------------- /tests/relative_pointer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: Alan Griffiths 17 | */ 18 | 19 | #include "relative_pointer_unstable_v1.h" 20 | #include "helpers.h" 21 | #include "in_process_server.h" 22 | 23 | #include 24 | 25 | using testing::AnyNumber; 26 | using testing::IsTrue; 27 | using testing::NotNull; 28 | using testing::_; 29 | 30 | using namespace wlcs; 31 | 32 | namespace 33 | { 34 | auto const any_width = 300; 35 | auto const any_height = 300; 36 | auto const nw_middle_x = any_width / 2; 37 | auto const nw_middle_y = any_height / 2; 38 | 39 | struct RelativePointer : StartedInProcessServer 40 | { 41 | // Create a client with a surface and a cursor centered on the surface 42 | Client a_client{the_server()}; 43 | Surface a_surface{a_client.create_visible_surface(any_width, any_height)}; 44 | Pointer cursor = the_server().create_pointer(); 45 | 46 | ZwpRelativePointerManagerV1 manager{a_client}; 47 | ZwpRelativePointerV1 pointer{manager, a_client.the_pointer()}; 48 | 49 | void SetUp() override 50 | { 51 | StartedInProcessServer::SetUp(); 52 | 53 | // Get the surface in a known position with the cursor over it 54 | the_server().move_surface_to(a_surface, 0, 0); 55 | cursor.move_to(nw_middle_x, nw_middle_y); 56 | } 57 | 58 | void TearDown() override 59 | { 60 | a_client.roundtrip(); 61 | StartedInProcessServer::TearDown(); 62 | } 63 | }; 64 | } 65 | 66 | TEST_F(RelativePointer, can_get_relative_pointer) 67 | { 68 | EXPECT_THAT(pointer, NotNull()); 69 | } 70 | 71 | TEST_F(RelativePointer, relative_pointer_gets_movement) 72 | { 73 | auto const move_x = any_width/6; 74 | auto const move_y = any_height/6; 75 | 76 | EXPECT_CALL(pointer, relative_motion(_, _, 77 | wl_fixed_from_int(move_x), wl_fixed_from_int(move_y), 78 | wl_fixed_from_int(move_x), wl_fixed_from_int(move_y))).Times(1); 79 | 80 | cursor.move_by(move_x, move_y); 81 | } 82 | 83 | // #1959 84 | TEST_F(RelativePointer, default_pointer_still_gets_movement) 85 | { 86 | auto const move_x = any_width/6; 87 | auto const move_y = any_height/6; 88 | EXPECT_CALL(pointer, relative_motion(_, _, _, _, _, _)).Times(AnyNumber()); 89 | 90 | bool moved = false; 91 | a_client.add_pointer_motion_notification([&](auto...) { moved = true; return true; }); 92 | 93 | cursor.move_by(move_x, move_y); 94 | 95 | a_client.roundtrip(); 96 | EXPECT_THAT(moved, IsTrue()); 97 | } 98 | -------------------------------------------------------------------------------- /tests/test_bad_buffer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2012 Intel Corporation 3 | * Copyright © 2013 Collabora, Ltd. 4 | * Copyright © 2017 Canonical Ltd. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining 7 | * a copy of this software and associated documentation files (the 8 | * "Software"), to deal in the Software without restriction, including 9 | * without limitation the rights to use, copy, modify, merge, publish, 10 | * distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to 12 | * the following conditions: 13 | * 14 | * The above copyright notice and this permission notice (including the 15 | * next paragraph) shall be included in all copies or substantial 16 | * portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 22 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 23 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #include 29 | #include 30 | 31 | #include "helpers.h" 32 | 33 | #include "in_process_server.h" 34 | 35 | /* tests, that attempt to crash the compositor on purpose */ 36 | 37 | static struct wl_buffer * 38 | create_bad_shm_buffer(wlcs::Client& client, int width, int height) 39 | { 40 | struct wl_shm *shm = client.shm(); 41 | int stride = width * 4; 42 | int size = stride * height; 43 | struct wl_shm_pool *pool; 44 | struct wl_buffer *buffer; 45 | int fd; 46 | 47 | fd = wlcs::helpers::create_anonymous_file(size); 48 | 49 | pool = wl_shm_create_pool(shm, fd, size); 50 | buffer = wl_shm_pool_create_buffer( 51 | pool, 52 | 0, 53 | width, 54 | height, 55 | stride, 56 | WL_SHM_FORMAT_ARGB8888); 57 | wl_shm_pool_destroy(pool); 58 | 59 | /* Truncate the file to a small size, so that the compositor 60 | * will access it out-of-bounds, and hit SIGBUS. 61 | */ 62 | assert(ftruncate(fd, 12) == 0); 63 | close(fd); 64 | 65 | return buffer; 66 | } 67 | 68 | using BadBufferTest = wlcs::InProcessServer; 69 | 70 | TEST_F(BadBufferTest, test_truncated_shm_file) 71 | { 72 | using namespace testing; 73 | 74 | wlcs::Client client{the_server()}; 75 | 76 | bool buffer_consumed{false}; 77 | 78 | auto surface = client.create_visible_surface(200, 200); 79 | 80 | wl_buffer* bad_buffer = create_bad_shm_buffer(client, 200, 200); 81 | 82 | wl_surface_attach(surface, bad_buffer, 0, 0); 83 | wl_surface_damage(surface, 0, 0, 200, 200); 84 | 85 | surface.add_frame_callback([&buffer_consumed](int) { buffer_consumed = true; }); 86 | 87 | wl_surface_commit(surface); 88 | 89 | try 90 | { 91 | client.dispatch_until([&buffer_consumed]() { return buffer_consumed; }); 92 | } 93 | catch (wlcs::ProtocolError const& err) 94 | { 95 | wl_buffer_destroy(bad_buffer); 96 | EXPECT_THAT(err.error_code(), Eq(WL_SHM_ERROR_INVALID_FD)); 97 | EXPECT_THAT(err.interface(), Eq(&wl_buffer_interface)); 98 | return; 99 | } 100 | 101 | FAIL() << "Expected protocol error not raised"; 102 | } 103 | 104 | TEST_F(BadBufferTest, client_lies_about_buffer_size) 105 | { 106 | using namespace testing; 107 | 108 | wlcs::Client client{the_server()}; 109 | 110 | auto surface = client.create_visible_surface(200, 200); 111 | 112 | auto const width = 200, height = 200; 113 | auto const incorrect_stride = width; 114 | 115 | auto fd = wlcs::helpers::create_anonymous_file(height * incorrect_stride); 116 | 117 | auto shm_pool = wl_shm_create_pool(client.shm(), fd, height * incorrect_stride); 118 | 119 | auto bad_buffer = wl_shm_pool_create_buffer( 120 | shm_pool, 121 | 0, 122 | width, height, 123 | incorrect_stride, // Stride is in bytes, not pixels, so this is ¼ the correct value. 124 | WL_SHM_FORMAT_ARGB8888); 125 | 126 | try 127 | { 128 | /* Buffer creation should fail, so all we need is for the create_buffer 129 | * call to be processed 130 | */ 131 | client.roundtrip(); 132 | } 133 | catch (wlcs::ProtocolError const& err) 134 | { 135 | wl_buffer_destroy(bad_buffer); 136 | EXPECT_THAT(err.error_code(), Eq(WL_SHM_ERROR_INVALID_STRIDE)); 137 | EXPECT_THAT(err.interface(), Eq(&wl_shm_pool_interface)); 138 | return; 139 | } 140 | 141 | FAIL() << "Expected protocol error not raised"; 142 | } 143 | 144 | // This should be identical to the first tests case of the previous test. It tests if a 2nd instance of the server can 145 | // successfully handle a bad buffer. There have been issues with the server installing a SIGBUS handler (via 146 | // wl_shm_buffer_begin_access()) that only works for the first server instance. 147 | 148 | using SecondBadBufferTest = wlcs::InProcessServer; 149 | 150 | TEST_F(SecondBadBufferTest, DISABLED_test_truncated_shm_file) 151 | { 152 | using namespace testing; 153 | 154 | wlcs::Client client{the_server()}; 155 | 156 | bool buffer_consumed{false}; 157 | 158 | auto surface = client.create_visible_surface(200, 200); 159 | 160 | wl_buffer* bad_buffer = create_bad_shm_buffer(client, 200, 200); 161 | 162 | wl_surface_attach(surface, bad_buffer, 0, 0); 163 | wl_surface_damage(surface, 0, 0, 200, 200); 164 | 165 | surface.add_frame_callback([&buffer_consumed](int) { buffer_consumed = true; }); 166 | 167 | wl_surface_commit(surface); 168 | 169 | try 170 | { 171 | client.dispatch_until([&buffer_consumed]() { return buffer_consumed; }); 172 | } 173 | catch (wlcs::ProtocolError const& err) 174 | { 175 | wl_buffer_destroy(bad_buffer); 176 | EXPECT_THAT(err.error_code(), Eq(WL_SHM_ERROR_INVALID_FD)); 177 | EXPECT_THAT(err.interface(), Eq(&wl_buffer_interface)); 178 | return; 179 | } 180 | 181 | FAIL() << "Expected protocol error not raised"; 182 | } 183 | -------------------------------------------------------------------------------- /tests/wl_output.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | 19 | #include "helpers.h" 20 | #include "in_process_server.h" 21 | #include "version_specifier.h" 22 | 23 | #include 24 | 25 | #include 26 | 27 | using namespace testing; 28 | using namespace wlcs; 29 | 30 | using WlOutputTest = wlcs::InProcessServer; 31 | 32 | TEST_F(WlOutputTest, wl_output_properties_set) 33 | { 34 | wlcs::Client client{the_server()}; 35 | 36 | ASSERT_THAT(client.output_count(), Ge(1u)); 37 | auto output = client.output_state(0); 38 | 39 | EXPECT_THAT((bool)output.geometry_position, Eq(true)); 40 | EXPECT_THAT((bool)output.mode_size, Eq(true)); 41 | EXPECT_THAT((bool)output.scale, Eq(true)); 42 | } 43 | 44 | TEST_F(WlOutputTest, wl_output_release) 45 | { 46 | wlcs::Client client{the_server()}; 47 | 48 | { 49 | // Acquire *any* wl_output; we don't care which 50 | auto const output = 51 | client.bind_if_supported(wlcs::AtLeastVersion{WL_OUTPUT_RELEASE_SINCE_VERSION}); 52 | client.roundtrip(); 53 | } 54 | // output is now released 55 | 56 | client.roundtrip(); 57 | } 58 | -------------------------------------------------------------------------------- /tests/xdg_decoration_v1.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2020 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #include "xdg_decoration_unstable_v1.h" 18 | 19 | #include "expect_protocol_error.h" 20 | #include "generated/xdg-decoration-unstable-v1-client.h" 21 | #include "in_process_server.h" 22 | #include "xdg_shell_stable.h" 23 | #include "gmock/gmock.h" 24 | 25 | #include 26 | #include 27 | 28 | using testing::_; 29 | using testing::AtLeast; 30 | using testing::Eq; 31 | using namespace wlcs; 32 | 33 | class XdgDecorationV1Test : public StartedInProcessServer 34 | { 35 | public: 36 | Client a_client{the_server()}; 37 | ZxdgDecorationManagerV1 manager{a_client}; 38 | Surface a_surface{a_client}; 39 | XdgSurfaceStable xdg_surface{a_client, a_surface}; 40 | }; 41 | 42 | TEST_F(XdgDecorationV1Test, happy_path) 43 | { 44 | XdgToplevelStable xdg_toplevel{xdg_surface}; 45 | ZxdgToplevelDecorationV1 decoration{manager, xdg_toplevel}; 46 | 47 | EXPECT_NO_THROW(a_client.roundtrip()); 48 | } 49 | 50 | TEST_F(XdgDecorationV1Test, duplicate_decorations_throw_already_constructed) 51 | { 52 | XdgToplevelStable xdg_toplevel{xdg_surface}; 53 | ZxdgToplevelDecorationV1 decoration{manager, xdg_toplevel}; 54 | ZxdgToplevelDecorationV1 duplicate_decoration{manager, xdg_toplevel}; 55 | 56 | EXPECT_PROTOCOL_ERROR( 57 | { a_client.roundtrip(); }, 58 | &zxdg_decoration_manager_v1_interface, 59 | ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED); 60 | } 61 | 62 | TEST_F(XdgDecorationV1Test, destroying_toplevel_before_decoration_throws_orphaned) 63 | { 64 | auto* xdg_toplevel2 = new XdgToplevelStable{xdg_surface}; 65 | ZxdgToplevelDecorationV1 decoration{manager, *xdg_toplevel2}; 66 | delete xdg_toplevel2; 67 | 68 | EXPECT_PROTOCOL_ERROR( 69 | { a_client.roundtrip(); }, &zxdg_decoration_manager_v1_interface, ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ORPHANED); 70 | } 71 | 72 | TEST_F(XdgDecorationV1Test, set_mode_client_results_in_a_configure_event) 73 | { 74 | XdgToplevelStable xdg_toplevel{xdg_surface}; 75 | ZxdgToplevelDecorationV1 decoration{manager, xdg_toplevel}; 76 | 77 | zxdg_toplevel_decoration_v1_set_mode(decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); 78 | 79 | EXPECT_CALL(decoration, configure(_)).Times(AtLeast(1)); 80 | 81 | a_client.roundtrip(); 82 | } 83 | 84 | TEST_F(XdgDecorationV1Test, set_mode_server_results_in_a_configure_event) 85 | { 86 | XdgToplevelStable xdg_toplevel{xdg_surface}; 87 | ZxdgToplevelDecorationV1 decoration{manager, xdg_toplevel}; 88 | 89 | zxdg_toplevel_decoration_v1_set_mode(decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); 90 | 91 | EXPECT_CALL(decoration, configure(_)).Times(AtLeast(1)); 92 | 93 | a_client.roundtrip(); 94 | } 95 | 96 | TEST_F(XdgDecorationV1Test, unset_mode_results_in_a_configure_event) 97 | { 98 | XdgToplevelStable xdg_toplevel{xdg_surface}; 99 | ZxdgToplevelDecorationV1 decoration{manager, xdg_toplevel}; 100 | 101 | zxdg_toplevel_decoration_v1_unset_mode(decoration); 102 | 103 | EXPECT_CALL(decoration, configure(_)).Times(AtLeast(1)); 104 | 105 | a_client.roundtrip(); 106 | } 107 | -------------------------------------------------------------------------------- /tests/xdg_output_v1.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Canonical Ltd. 3 | * 4 | * This program is free software: you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License version 3, 6 | * as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | * Authored by: William Wold 17 | */ 18 | 19 | #include "in_process_server.h" 20 | #include "xdg_output_v1.h" 21 | 22 | #include 23 | 24 | using namespace testing; 25 | using namespace wlcs; 26 | 27 | using XdgOutputV1Test = wlcs::InProcessServer; 28 | 29 | TEST_F(XdgOutputV1Test, xdg_output_properties_set) 30 | { 31 | Client client{the_server()}; 32 | ASSERT_THAT(client.output_count(), Ge(1u)); 33 | 34 | XdgOutputManagerV1 xdg_output_manager{client}; 35 | XdgOutputV1 xdg_output{xdg_output_manager, 0}; 36 | client.roundtrip(); 37 | 38 | auto const& state = xdg_output.state(); 39 | ASSERT_THAT((bool)state.logical_position, true); 40 | ASSERT_THAT((bool)state.logical_size, true); 41 | ASSERT_THAT((bool)state.name, true); 42 | // Description is optional 43 | } 44 | -------------------------------------------------------------------------------- /tests/xdg_surface_v6.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2012 Intel Corporation 3 | * Copyright © 2013 Collabora, Ltd. 4 | * Copyright © 2018 Canonical Ltd. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining 7 | * a copy of this software and associated documentation files (the 8 | * "Software"), to deal in the Software without restriction, including 9 | * without limitation the rights to use, copy, modify, merge, publish, 10 | * distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to 12 | * the following conditions: 13 | * 14 | * The above copyright notice and this permission notice (including the 15 | * next paragraph) shall be included in all copies or substantial 16 | * portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 22 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 23 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #include "helpers.h" 29 | #include "in_process_server.h" 30 | #include "xdg_shell_v6.h" 31 | 32 | #include 33 | 34 | using namespace testing; 35 | using XdgSurfaceV6Test = wlcs::InProcessServer; 36 | 37 | TEST_F(XdgSurfaceV6Test, supports_xdg_shell_v6_protocol) 38 | { 39 | wlcs::Client client{the_server()}; 40 | ASSERT_THAT(client.xdg_shell_v6(), NotNull()); 41 | wlcs::Surface surface{client}; 42 | wlcs::XdgSurfaceV6 xdg_surface{client, surface}; 43 | } 44 | 45 | TEST_F(XdgSurfaceV6Test, gets_configure_event) 46 | { 47 | wlcs::Client client{the_server()}; 48 | wlcs::Surface surface{client}; 49 | wlcs::XdgSurfaceV6 xdg_surface{client, surface}; 50 | 51 | EXPECT_CALL(xdg_surface, configure).WillOnce([&](uint32_t serial) 52 | { 53 | zxdg_surface_v6_ack_configure(xdg_surface, serial); 54 | }); 55 | 56 | wlcs::XdgToplevelV6 toplevel{xdg_surface}; 57 | surface.attach_buffer(600, 400); 58 | 59 | client.roundtrip(); 60 | } 61 | -------------------------------------------------------------------------------- /tools/make_release_tarball: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | RELEASE_TAG=HEAD 6 | 7 | while [ $# -gt 0 ] 8 | do 9 | if [ "$1" == "--skip-checks" ] 10 | then 11 | skip_checks=true 12 | fi 13 | if [ "$1" == "--release-tag" ] 14 | then 15 | shift 16 | RELEASE_TAG=$1 17 | fi 18 | shift 19 | done 20 | 21 | if [ ! -e tools/make_release_tarball -o "$1" != "" ] 22 | then 23 | echo "Handy script for creating tarball: Use from the checkout directory" 24 | exit 0 25 | fi 26 | 27 | set -e 28 | 29 | VERSION=$(grep -E "project\(wlcs VERSION [[:digit:]]+(\.[[:digit:]]+)+\)" CMakeLists.txt | grep -E --only-matching "[[:digit:]]+(.[[:digit:]])+") 30 | 31 | VERSIONED_NAME=wlcs-$VERSION 32 | 33 | SCRATCH_DIR=$(mktemp -d) 34 | BUILD_DIR=$(mktemp -d) 35 | INSTALL_DIR=$(mktemp -d) 36 | 37 | function cleanup() { 38 | ARG=$? 39 | [ -d $SCRATCH_DIR ] && rm -r $SCRATCH_DIR 40 | [ -d $BUILD_DIR ] && rm -r $BUILD_DIR 41 | [ -d $INSTALL_DIR ] && rm -r $INSTALL_DIR 42 | exit $ARG 43 | } 44 | 45 | trap cleanup EXIT 46 | 47 | echo "Generating WLCS tarball…" 48 | git archive --format=tar --prefix=$VERSIONED_NAME/ $RELEASE_TAG | xz -9 > $SCRATCH_DIR/$VERSIONED_NAME.tar.xz 49 | 50 | if [ ! -v skip_checks ] 51 | then 52 | (cd $SCRATCH_DIR; tar xvJf $SCRATCH_DIR/$VERSIONED_NAME.tar.xz) 53 | 54 | echo "Testing that the tarball is buildable" 55 | (cd $BUILD_DIR ; cmake $SCRATCH_DIR/$VERSIONED_NAME ) 56 | make -C $BUILD_DIR -j $(nproc) 57 | 58 | echo "Testing that the tarball is installable" 59 | make -C $BUILD_DIR install DESTDIR=$INSTALL_DIR 60 | fi 61 | 62 | mv $SCRATCH_DIR/$VERSIONED_NAME.tar.xz . 63 | echo "$VERSIONED_NAME.tar.xz successfully created and tested" 64 | 65 | -------------------------------------------------------------------------------- /tools/ppa-upload.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | LP_CREDS="$1" 6 | if [ -z "${LP_CREDS}" ]; then 7 | echo "ERROR: pass the Launchpad credentials file as argument" >&2 8 | exit 2 9 | fi 10 | 11 | if [ -z "${RELEASE}" ]; then 12 | echo "ERROR: RELEASE environment variable needs to be set to the" >&2 13 | echo " target Ubuntu version." >&2 14 | exit 1 15 | fi 16 | 17 | GIT_BRANCH=${GITHUB_REF-$( git rev-parse --abbrev-ref HEAD )} 18 | # determine the patch release 19 | if ! [[ "${GIT_BRANCH}" =~ ^(refs/(heads|tags)/)?(main|(release/|v)([0-9\.]+))$ ]]; then 20 | echo "ERROR: This script should only run on main or release tags" >&2 21 | echo " or branches." >&2 22 | exit 3 23 | fi 24 | 25 | source <( python <&2 43 | exit 2 44 | fi 45 | 46 | GIT_REVISION=$( git rev-parse --short HEAD ) 47 | 48 | if [[ "${GIT_BRANCH}" =~ ^(refs/(heads|tags)/)?(release/|v)([0-9\.]+)$ ]]; then 49 | # we're on a release branch 50 | TARGET_PPA=ppa:mir-team/rc 51 | WLCS_SERIES=${BASH_REMATCH[4]} 52 | if [[ "$( git describe --tags --exact-match )" =~ ^v([0-9\.]+)$ ]]; then 53 | # this is a final release, use the tag version 54 | WLCS_VERSION=${BASH_REMATCH[1]} 55 | else 56 | # find the last tagged patch version 57 | PATCH_VERSION=$( git describe --abbrev=0 --match "v${WLCS_SERIES}*" \ 58 | 2> /dev/null | sed 's/^v//') 59 | if [ -z "${PATCH_VERSION}" ]; then 60 | # start with patch version 0 61 | WLCS_VERSION=${WLCS_SERIES}.0 62 | else 63 | # increment the patch version 64 | WLCS_VERSION=$( echo ${PATCH_VERSION} | perl -pe 's/^((\d+\.)*)(\d+)$/$1.($3+1)/e' ) 65 | fi 66 | 67 | # use the number of commits since main 68 | GIT_COMMITS=$( git rev-list --count origin/main..HEAD ) 69 | WLCS_VERSION=${WLCS_VERSION}~rc${GIT_COMMITS}.git${GIT_REVISION} 70 | fi 71 | else 72 | # look for a release tag within parents 2..n 73 | PARENT=2 74 | while git rev-parse HEAD^${PARENT} >/dev/null 2>&1; do 75 | if [[ "$( git describe --exact-match HEAD^${PARENT} )" =~ ^v([0-9\.]+)$ ]]; then 76 | # copy packages from ppa:mir-team/rc to ppa:mir-team/release 77 | RELEASE_VERSION=${BASH_REMATCH[1]}-0ubuntu${UBUNTU_VERSION} 78 | echo "Copying wlcs_${RELEASE_VERSION} from ppa:mir-team/rc to ppa:mir-team/release…" 79 | python - ${RELEASE_VERSION} < ../wlcs_${WLCS_VERSION}.orig.tar.xz 147 | 148 | dpkg-buildpackage \ 149 | -I".git" \ 150 | -I"build" \ 151 | -i"^.git|^build" \ 152 | -d -S 153 | 154 | dput ${TARGET_PPA} ../wlcs_${PPA_VERSION}_source.changes 155 | -------------------------------------------------------------------------------- /wlcs.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | exec_prefix=@PKGCONFIG_BINDIR@ 3 | libexecdir=@PKGCONFIG_LIBEXECDIR@ 4 | includedir=@PKGCONFIG_INCLUDEDIR@ 5 | 6 | test_runner=${libexecdir}/wlcs/wlcs 7 | 8 | Name: wlcs 9 | Description: Wayland Conformance Suite test harness 10 | Version: @PROJECT_VERSION@ 11 | Requires.private: wayland-client 12 | Cflags: -I${includedir} 13 | --------------------------------------------------------------------------------