diff --git a/.github/workflows/close-snap.yml b/.github/workflows/close-snap.yml index 1c5d5126f03..967b0ed2c2e 100644 --- a/.github/workflows/close-snap.yml +++ b/.github/workflows/close-snap.yml @@ -20,7 +20,9 @@ jobs: SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_TOKEN }} run: | snapcraft close mir-libs "22/edge/pr${{ github.event.number }}" || true - snapcraft close confined-shell "edge/mir-pr${{ github.event.number }}" || true - for snap in mir-test-tools miriway ubuntu-frame; do + for snap in confined-shell miriway; do + snapcraft close "$snap" "edge/mir-pr${{ github.event.number }}" || true + done + for snap in mir-test-tools ubuntu-frame; do snapcraft close "$snap" "22/edge/mir-pr${{ github.event.number }}" || true done diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index ea3e67c7775..1ed0edd3599 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -55,8 +55,12 @@ jobs: sudo apt-add-repository --yes ppa:mir-team/dev sudo apt-get install --no-install-recommends \ dmz-cursor-theme \ + glmark2-es2 \ + glmark2-es2-wayland \ lcov \ - ninja-build + mesa-utils \ + ninja-build \ + xwayland # deal with incompataibles preinstalled sudo apt-get remove --yes \ @@ -84,7 +88,7 @@ jobs: run: ccache --show-stats --zero-stats - name: Test - timeout-minutes: 5 + timeout-minutes: 10 env: CTEST_OUTPUT_ON_FAILURE: 1 XDG_RUNTIME_DIR: /tmp diff --git a/.github/workflows/snap.yml b/.github/workflows/snap.yml index 36ff726e8ab..276d96bc3e9 100644 --- a/.github/workflows/snap.yml +++ b/.github/workflows/snap.yml @@ -29,10 +29,12 @@ jobs: fetch-depth: 0 # needed for version determination - name: Build and publish the snap - uses: canonical/actions/build-snap@multiarch + uses: canonical/actions/build-snap@release with: architecture: ${{ matrix.architecture }} snapcraft-token: ${{ secrets.SNAPCRAFT_TOKEN }} + launchpad-credentials: ${{ secrets.LAUNCHPAD_CREDENTIALS }} + launchpad-accept-public-upload: true publish: ${{ github.event_name == 'pull_request' && github.repository == github.event.pull_request.head.repo.full_name }} publish-channel: 22/edge/pr${{ github.event.number }} @@ -68,6 +70,7 @@ jobs: - snap: Miriway/Miriway track: latest review-opts: --allow-classic + snapcraft-channel: edge steps: - name: Check out code @@ -82,10 +85,13 @@ jobs: sed -i 's@- mir-libs.*$@\0/pr${{ github.event.number }}@' snap/snapcraft.yaml - name: Build and publish the snap - uses: canonical/actions/build-snap@multiarch + uses: canonical/actions/build-snap@release with: architecture: ${{ matrix.architecture }} review-opts: ${{ matrix.review-opts }} snapcraft-token: ${{ secrets.SNAPCRAFT_TOKEN }} + launchpad-credentials: ${{ secrets.LAUNCHPAD_CREDENTIALS }} + launchpad-accept-public-upload: true publish: true publish-channel: ${{ matrix.track }}/edge/mir-pr${{ github.event.number }} + snapcraft-channel: ${{ matrix.snapcraft-channel || 'stable' }} diff --git a/.github/workflows/spread.yml b/.github/workflows/spread.yml index 9539dea7c97..c78de37c6b7 100644 --- a/.github/workflows/spread.yml +++ b/.github/workflows/spread.yml @@ -32,10 +32,8 @@ jobs: if ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}; then TASKS='"lxd:ubuntu-22.04:spread/build/ubuntu:asan" "lxd:ubuntu-22.04:spread/build/ubuntu:tsan" - "lxd:ubuntu-22.04:spread/build/ubuntu:ubsan" "lxd:ubuntu-22.04:spread/build/ubuntu:asan_clang" - "lxd:ubuntu-22.04:spread/build/ubuntu:tsan_clang" - "lxd:ubuntu-22.04:spread/build/ubuntu:ubsan_clang"' + "lxd:ubuntu-22.04:spread/build/ubuntu:tsan_clang"' fi TASKS+='"lxd:alpine-3.18:spread/build/alpine:amd64" @@ -50,7 +48,9 @@ jobs: "lxd:fedora-38:spread/build/fedora:amd64" "lxd:fedora-rawhide:spread/build/fedora:amd64" "lxd:ubuntu-22.04:spread/build/sbuild:ubuntu_devel" - "lxd:ubuntu-22.04:spread/build/sbuild:ubuntu_proposed"' + "lxd:ubuntu-22.04:spread/build/sbuild:ubuntu_proposed" + "lxd:ubuntu-22.04:spread/build/ubuntu:ubsan" + "lxd:ubuntu-22.04:spread/build/ubuntu:ubsan_clang"' echo ${TASKS:-} | jq -cs '{ "spread-task": . }' | awk '{ print "matrix=" $0 }' >> $GITHUB_OUTPUT @@ -112,7 +112,13 @@ jobs: echo "max_size = 800M" > ${CCACHE_DIR}/ccache.conf - name: Run Spread task - run: snap run spread-mir-ci.spread -v ${{ matrix.spread-task }} + run: snap run spread-mir-ci.spread -reuse -v ${{ matrix.spread-task }} - name: CCache stats run: cat ${CCACHE_DIR}/ccache.stats + + - if: ${{ failure() && runner.debug }} + name: Setup upterm session + uses: lhotari/action-upterm@v1 + with: + limit-access-to-actor: true diff --git a/.mailmap b/.mailmap new file mode 100644 index 00000000000..2f522e7a887 --- /dev/null +++ b/.mailmap @@ -0,0 +1,4 @@ +Sophie Winter <9331264+wmww@users.noreply.github.com> +Sophie Winter +Sophie Winter +Sophie Winter diff --git a/CMakeLists.txt b/CMakeLists.txt index 64df5031da0..09d68b397ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,51 +144,22 @@ if(cmake_build_type_lower MATCHES "coverage") endif() if(cmake_build_type_lower MATCHES "addresssanitizer") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fsanitize=address") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address") - if (CMAKE_COMPILER_IS_GNUCXX) - # Work around GCC bug. It should automatically link to asan when - # -fsanitize=address is used, but doesn't. - # - # Linking everything with asan is harmless and simple, so do that. - link_libraries(asan) # Workaround for LP:1413474 - endif() + add_compile_options(-fsanitize=address -fno-omit-frame-pointer) + add_link_options(-fsanitize=address) elseif(cmake_build_type_lower MATCHES "threadsanitizer") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -fno-omit-frame-pointer") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread -fno-omit-frame-pointer") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fsanitize=thread") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=thread") - if (CMAKE_COMPILER_IS_GNUCXX) - # Work around GCC bug. It should automatically link to tsan when - # -fsanitize=thread is used, but doesn't. - # - # Linking everything with tsan is harmless and simple, so do that. - link_libraries(tsan) # Workaround for LP:1413474 - endif() + add_compile_options(-fsanitize=thread -fno-omit-frame-pointer) + add_link_options(-fsanitize=thread) elseif(cmake_build_type_lower MATCHES "ubsanitizer") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-omit-frame-pointer") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-omit-frame-pointer") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fsanitize=undefined") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=undefined") + add_compile_options(-fsanitize=undefined -fno-omit-frame-pointer) + add_link_options(-fsanitize=undefined) # "Symbol already defined" errors occur with pre-compiled headers SET(MIR_USE_PRECOMPILED_HEADERS OFF CACHE BOOL "Use precompiled headers" FORCE) - if (CMAKE_COMPILER_IS_GNUCXX) - # Work around GCC bug. It should automatically link to asan when - # -fsanitize=undefined is used, but doesn't. - # - # Linking everything with ubsan is harmless and simple, so do that. - link_libraries(ubsan) # Workaround for LP:1413474 - endif() # We have inline classes as interfaces used by .so's and implemented elsewhere. # This results in multiple trivial implementations. So let's not warn about that. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-sanitize=vptr") + add_compile_options(-fno-sanitize=vptr) else() # AddressSanitizer builds fail if we disallow undefined symbols - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-undefined") + add_link_options(-Wl,--no-undefined) endif() enable_testing() diff --git a/cmake/FindGtestGmock.cmake b/cmake/FindGtestGmock.cmake index e0e3c9c1a32..507a543bbc3 100644 --- a/cmake/FindGtestGmock.cmake +++ b/cmake/FindGtestGmock.cmake @@ -1,7 +1,7 @@ include(FindPackageHandleStandardArgs) -pkg_check_modules(GTEST QUIET "gtest >= 1.8.0") -pkg_check_modules(GTEST_MAIN QUIET "gtest_main >= 1.8.0") +pkg_check_modules(GTEST QUIET gtest>=1.8.0) +pkg_check_modules(GTEST_MAIN QUIET gtest_main>=1.8.0) if (GTEST_FOUND AND GTEST_MAIN_FOUND) # If we can find package configuration for gtest use it! set(GTEST_LIBRARY ${GTEST_LIBRARIES}) diff --git a/cmake/MirCommon.cmake b/cmake/MirCommon.cmake index b6df9e71c69..76aa9e41ce3 100644 --- a/cmake/MirCommon.cmake +++ b/cmake/MirCommon.cmake @@ -317,7 +317,7 @@ function (mir_generate_protocol_wrapper TARGET_NAME NAME_PREFIX PROTOCOL_FILE) get_filename_component(PROTOCOL_NAME "${PROTOCOL_FILE}" NAME_WE) set(OUTPUT_PATH_HEADER "${CMAKE_CURRENT_BINARY_DIR}/${PROTOCOL_NAME}_wrapper.h") set(OUTPUT_PATH_SRC "${CMAKE_CURRENT_BINARY_DIR}/${PROTOCOL_NAME}_wrapper.cpp") - set(PROTOCOL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${PROTOCOL_FILE}") + set(PROTOCOL_PATH "${PROJECT_SOURCE_DIR}/wayland-protocols/${PROTOCOL_FILE}") add_custom_command( OUTPUT "${OUTPUT_PATH_HEADER}" "${OUTPUT_PATH_SRC}" VERBATIM diff --git a/debian/control b/debian/control index f0117044346..29d8af348b8 100644 --- a/debian/control +++ b/debian/control @@ -196,7 +196,7 @@ Pre-Depends: ${misc:Pre-Depends} Depends: ${misc:Depends}, ${shlibs:Depends}, xwayland, - glmark2-es2, + glmark2-es2-x11 | glmark2-es2, glmark2-es2-wayland, mesa-utils-extra, dmz-cursor-theme, diff --git a/doc/sphinx/.sphinx/requirements.txt b/doc/sphinx/.sphinx/requirements.txt index 9ae1d947e69..a891699b360 100644 --- a/doc/sphinx/.sphinx/requirements.txt +++ b/doc/sphinx/.sphinx/requirements.txt @@ -13,3 +13,4 @@ sphinxcontrib-jquery sphinx-notfound-page breathe exhale +sphinxcontrib-mermaid diff --git a/doc/sphinx/architecture.md b/doc/sphinx/architecture.md new file mode 100644 index 00000000000..2e700b549d9 --- /dev/null +++ b/doc/sphinx/architecture.md @@ -0,0 +1,69 @@ +# Architecture +This document introduces the architecture of *Mir* at a high-level. + +## Audience +This document is intended to provide contributors to *Mir* an overview of *Mir*'s systems. It is *not* intended to guide compositor authors. + +## Index +- [APIs for compositor authors](#apis-for-compositor-authors) +- [The Mir Engine](#the-mir-engine) +- [Platforms](#platforms) +- [Supporting Libraries](#supporting-libraries) + +## APIs for compositor authors +```{mermaid} high_level_diagram.mmd +``` + +*Mir* provides compositor authors with a set of libraries that they can use to build Wayland based shells. These libraries are: +- *miral* +- *miroil* +- *mirwayland* + +### Miral +The most commonly used library is **miral**. `miral` (the "*Mir* Abstraction Layer") is an API that makes *Mir* easy for compositor authors to work with. It provides core window management concepts and an interface that is more ABI stable than Mir's internal API. While `miral` is built on the [*Mir* engine](#the-mir-engine), compositor authors are encouraged to only interact with the high-level `miral` library. + +### Miroil +**miroil** is a custom library for the [Lomiri](https://lomiri.com/) folks. It is like `miral` in that it provides an abstraction over the [*Mir* engine](#the-mir-engine). However, most compositor authors will not interact with `miroil`. + +### Mirwayland +Compositor authors may want to define their own wayland protocol extensions in addition to the ones that the core *Mir* implementation defines. The `mirwayland` library satisfies this requirement. This library may be used in conjunction with either `miral` or `miroil`. + +## The Mir engine +```{mermaid} mirserver.mmd +``` + +The **mirserver** library is the core implementation of *Mir*. It serves as the engine for both `miral` and `miroil`. This library does the heavy-lifting for the compositor and, as a result, is the largest piece of *Mir*. This section will explain the primary concepts that drive the engine. + +### Core Concepts +At the heart of `mirserver` are two interfaces: the **Shell** and the **Scene**. The `Shell` is responsible for fielding requests from the rest system. The `Shell` modifies the state of the `Scene` to reflect the requested changes. + +For example, the `Frontend` would ask the `Shell` to initiate dragging a window. The `Shell` would then decide how to move that window to and update the state of the `Scene` to reflect that change. + +### From Scene to Screen +Knowing that the `Scene` holds the state of what is to be displayed, we can talk about the **Compositor**. The `Compositor` gets the collection of items to render from the `Scene`, +renders them with the help of the [rendering platform](#platforms), and sends them off to the [display platform](#platforms) to be displayed. + +### From Interaction to Shell +As stated previously, the `Shell` handles requests from the system and updates the state of the `Scene` accordingly. These requests come from a variety of sources, which we will investigate now. + +**Frontend Wayland**: Responsible for connecting the Wayland protocol with the rest of *Mir*. The `WaylandConnector` class connects requests made via the Wayland protocol to the core state of the compositor. + +**Frontend XWayland**: Responsible for connecting requests sent by an `XWayland` server to the rest of *Mir*. The `XWaylandConnector` establishes this connection. This frontend spawns an `XWayland` server as a subprocess. + +**Input**: Handles everything having to do with input, including mouse, keyboard, touch, and more. This system interacts with the specific [input platform](#platforms) and bubbles up events through a list of `InputDispatcher`s, which enables different pieces of the software to react to events. + +For example, a compositor's window manager may respond to a key press event by opening up a new terminal via a request to the `Shell`. + +## Platforms +We briefly hinted at the existence of so-called "platforms" previously, but they are deserving of a dedicated section. A **Platform** is an adapter that allows the system to work across different graphics, input, and rendering stacks. They come in three flavors: +- **Display Platform**: Determines what the compositor is rendering to. This may be a physical monitor via GBM/KMS (or EGLStreams for Nvidia), an X11 or Wayland window, or a completely virtual buffer. +- **Input Platform**: Determines where the compositor is getting input from. This could be native event via `libinput`, X input events, or Wayland input events. +- **Rendering Platform**: Determines how the compositor renders the final image. For now, only a GL backend is supported. + +The GBM/KMS platform is most typically what will be used, as it is the native platform. The X11 platform is useful for development. The Wayland platform is specifically useful for Ubuntu Touch, where they are hosting *Mir* in another Wayland compositor. + +## Supporting Libraries +*Mir* leans on a few core libraries to support the entire system. These libraries contain data structures and utilities that are shared throughout the project, including `miral` and `miroil`. + +- **Core**: Fundamental data concepts, like file descriptors and rectangles. These data structures tend not to be *Mir*-specific. +- **Common**: *Mir*-specific data concepts like *Mir* event building, logging, and timing utilities. \ No newline at end of file diff --git a/doc/sphinx/conf.py b/doc/sphinx/conf.py index fa20cf163f2..d2b247a143f 100644 --- a/doc/sphinx/conf.py +++ b/doc/sphinx/conf.py @@ -17,7 +17,6 @@ extensions = [ 'sphinx_design', - 'sphinx_tabs.tabs', 'sphinx_reredirects', 'youtube-links', 'related-links', diff --git a/doc/sphinx/custom_conf.py.in b/doc/sphinx/custom_conf.py.in index 661a09b9efb..d7e6ddd3679 100644 --- a/doc/sphinx/custom_conf.py.in +++ b/doc/sphinx/custom_conf.py.in @@ -114,6 +114,7 @@ custom_extensions = [ 'breathe', 'exhale', 'sphinx.ext.graphviz', + 'sphinxcontrib.mermaid' ] # Add files or directories that should be excluded from processing. @@ -172,3 +173,7 @@ breathe_projects = {"Mir": "./xml/"} breathe_default_project = "Mir" breathe_default_members = ('members', 'undoc-members') breathe_order_parameters_first = True + +# Mermaid +mermaid_version = "10.5.0" +mermaid_d3_zoom = True diff --git a/doc/sphinx/getting_involved_in_mir.md b/doc/sphinx/getting_involved_in_mir.md index 4e0a8de9b06..4b0666f1d5b 100644 --- a/doc/sphinx/getting_involved_in_mir.md +++ b/doc/sphinx/getting_involved_in_mir.md @@ -42,15 +42,17 @@ from the corresponding files under `spread/build`. This creates an example shell (miral-shell) in the bin directory. This can be run directly: - bin/miral-shell + bin/miral-app With the default options this runs in a window on X (which is convenient for development). The miral-shell example is simple, don’t expect to see a sophisticated launcher -by default. You can start mir apps from the command-line. For example: +by default. Within this window you can start a terminal with Ctrl-Alt-Shift-T +(the "Shift" is needed to avoid Ubuntu's DE intercepting the input). From this +terminal you can start apps. For example: - bin/miral-run qterminal + $ gedit To exit from miral-shell press Ctrl-Alt-BkSp. diff --git a/doc/sphinx/high_level_diagram.mmd b/doc/sphinx/high_level_diagram.mmd new file mode 100644 index 00000000000..5871b405e0b --- /dev/null +++ b/doc/sphinx/high_level_diagram.mmd @@ -0,0 +1,14 @@ + +classDiagram + CompositorAuthor --> miral: Uses + CompositorAuthor --> miroil: Uses + CompositorAuthor --> mirwayland: Uses + + miral --> mirserver: Uses + miroil --> mirserver: Uses + mirwayland --> mirserver: Uses + + note for core "Universal" + note for common "Universal" + class core + class common diff --git a/doc/sphinx/index.md b/doc/sphinx/index.md index 6d960f73882..25f8b75ae5a 100644 --- a/doc/sphinx/index.md +++ b/doc/sphinx/index.md @@ -31,5 +31,6 @@ The server API is introduced here: [Introducing the MirAL API](introducing_the_m getting_and_using_mir getting_involved_in_mir +architecture api/library_root ``` diff --git a/doc/sphinx/mirserver.mmd b/doc/sphinx/mirserver.mmd new file mode 100644 index 00000000000..f55feb9fe14 --- /dev/null +++ b/doc/sphinx/mirserver.mmd @@ -0,0 +1,20 @@ + +classDiagram + Compositor --> Scene: Get renderables + Compositor --> Display: Get outputs + Compositor --> RenderingPlatform: Handles rendering + Compositor --> DisplayPlatform: Outputs image to + Shell --> miral: Get shell behavior + Shell --> Scene: Updates + InputDispatcher <-- InputPlatform: Sends events to + Seat <-- InputDispatcher: Sends events to + Seat --> Shell: Sends events to + FrontendWayland --> Shell: Makes requests to + FrontendXWayland --> Shell: Makes request to + Scene o-- IdleHub + Scene o-- Clipboard + Scene o-- SceneChangeNotifiers + + + %%Server --> Core + %%Server --> Common diff --git a/examples/client/CMakeLists.txt b/examples/client/CMakeLists.txt index 88948559857..d416e3bfc23 100644 --- a/examples/client/CMakeLists.txt +++ b/examples/client/CMakeLists.txt @@ -1,5 +1,17 @@ -mir_add_wrapped_executable(mir_demo_client_wayland wayland_client.c) +set(OUTPUT_PATH_HEADER "${CMAKE_CURRENT_BINARY_DIR}/xdg-shell.h") +set(OUTPUT_PATH_SRC "${CMAKE_CURRENT_BINARY_DIR}/xdg-shell.c") +set(PROTOCOL_PATH "${PROJECT_SOURCE_DIR}/wayland-protocols/xdg-shell.xml") + +add_custom_command( + OUTPUT "${OUTPUT_PATH_HEADER}" "${OUTPUT_PATH_SRC}" + VERBATIM + COMMAND "sh" "-c" "wayland-scanner client-header ${PROTOCOL_PATH} ${OUTPUT_PATH_HEADER}" + COMMAND "sh" "-c" "wayland-scanner private-code ${PROTOCOL_PATH} ${OUTPUT_PATH_SRC}" +) + +mir_add_wrapped_executable(mir_demo_client_wayland wayland_client.c ${OUTPUT_PATH_HEADER} ${OUTPUT_PATH_SRC}) target_link_libraries (mir_demo_client_wayland PkgConfig::WAYLAND_CLIENT) +target_include_directories(mir_demo_client_wayland PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) mir_add_wrapped_executable(mir_demo_client_wayland_egl_spinner spinner.cpp) diff --git a/examples/client/wayland_client.c b/examples/client/wayland_client.c index a52b04c9234..21c7aff4399 100644 --- a/examples/client/wayland_client.c +++ b/examples/client/wayland_client.c @@ -30,14 +30,46 @@ #include #include +#include "xdg-shell.h" -struct globals +static int const pixel_size = 4; +#define NO_OF_BUFFERS 4 + +static inline uint32_t min(uint32_t a, uint32_t b) +{ + return a < b ? a : b; +} + +static struct globals { struct wl_compositor* compositor; struct wl_shm* shm; struct wl_seat* seat; struct wl_output* output; - struct wl_shell* shell; + struct xdg_wm_base *xdg_wm_base; +} globals; + +void check_globals(void) +{ + bool fail = false; + if (!globals.compositor) { puts("ERROR: no wl_compositor*"); fail = true; } + if (!globals.shm) { puts("ERROR: no wl_shm*"); fail = true; } + if (!globals.seat) { puts("ERROR: no wl_seat*"); fail = true; } + if (!globals.output) { puts("ERROR: no wl_output*"); fail = true; } + if (!globals.xdg_wm_base) { puts("ERROR: no xdg_wm_base*"); fail = true; } + + if (fail) abort(); +} + +static void handle_xdg_wm_base_ping(void* _, struct xdg_wm_base* shell, uint32_t serial) +{ + (void)_; + xdg_wm_base_pong(shell, serial); +} + +static struct xdg_wm_base_listener const shell_listener = +{ + &handle_xdg_wm_base_ping, }; static void new_global( @@ -47,30 +79,30 @@ static void new_global( char const* interface, uint32_t version) { - (void)version; - struct globals* globals = data; + (void)data; if (strcmp(interface, "wl_compositor") == 0) { - globals->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 3); + globals.compositor = wl_registry_bind(registry, id, &wl_compositor_interface, min(version, 3)); } else if (strcmp(interface, "wl_shm") == 0) { - globals->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); + globals.shm = wl_registry_bind(registry, id, &wl_shm_interface, min(version, 1)); // Normally we'd add a listener to pick up the supported formats here // As luck would have it, I know that argb8888 is the only format we support :) } else if (strcmp(interface, "wl_seat") == 0) { - globals->seat = wl_registry_bind(registry, id, &wl_seat_interface, 4); + globals.seat = wl_registry_bind(registry, id, &wl_seat_interface, min(version, 4)); } else if (strcmp(interface, "wl_output") == 0) { - globals->output = wl_registry_bind(registry, id, &wl_output_interface, 2); + globals.output = wl_registry_bind(registry, id, &wl_output_interface, min(version, 2)); } - else if (strcmp(interface, "wl_shell") == 0) + else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { - globals->shell = wl_registry_bind(registry, id, &wl_shell_interface, 1); + globals.xdg_wm_base = wl_registry_bind(registry, id, &xdg_wm_base_interface, min(version, 1)); + xdg_wm_base_add_listener(globals.xdg_wm_base, &shell_listener, NULL); } } @@ -130,28 +162,57 @@ make_shm_pool(struct wl_shm* shm, int size, void **data) return pool; } -struct draw_context +static struct wl_buffer_listener const buffer_listener; + +typedef struct buffer { + struct wl_buffer* buffer; + bool available; + int width; + int height; void* content_area; +} buffer; + +typedef struct draw_context +{ struct wl_display* display; struct wl_surface* surface; struct wl_callback* new_frame_signal; - struct Buffers - { - struct wl_buffer* buffer; - bool available; - } buffers[4]; + int width; + int height; + buffer buffers[NO_OF_BUFFERS]; bool waiting_for_buffer; -}; +} draw_context; -static struct wl_buffer* find_free_buffer(struct draw_context* ctx) +static void prepare_buffer(buffer* b, draw_context* ctx) { - for (int i = 0; i < 4 ; ++i) + void* pool_data = NULL; + struct wl_shm_pool* shm_pool = make_shm_pool(globals.shm, ctx->width * ctx->height * pixel_size, &pool_data); + + b->buffer = wl_shm_pool_create_buffer(shm_pool, 0, ctx->width, ctx->height, ctx->width*pixel_size, WL_SHM_FORMAT_ARGB8888); + b->available = true; + b->width = ctx->width; + b->height = ctx->height; + b->content_area = pool_data; + wl_buffer_add_listener(b->buffer, &buffer_listener, ctx); + wl_shm_pool_destroy(shm_pool); +} + +static buffer* +find_free_buffer(draw_context* ctx) +{ + for (buffer* b = ctx->buffers; b != ctx->buffers + NO_OF_BUFFERS ; ++b) { - if (ctx->buffers[i].available) + if (b->available) { - ctx->buffers[i].available = false; - return ctx->buffers[i].buffer; + if (b->width != ctx->width || b->height != ctx->height) + { + wl_buffer_destroy(b->buffer); + prepare_buffer(b, ctx); + } + + b->available = false; + return b; } } return NULL; @@ -166,8 +227,8 @@ static const struct wl_callback_listener frame_listener = static void update_free_buffers(void* data, struct wl_buffer* buffer) { - struct draw_context* ctx = data; - for (int i = 0; i < 4 ; ++i) + draw_context* ctx = data; + for (int i = 0; i < NO_OF_BUFFERS ; ++i) { if (ctx->buffers[i].buffer == buffer) { @@ -191,23 +252,23 @@ static void draw_new_stuff( { (void)time; static unsigned char current_value = 128; - struct draw_context* ctx = data; + draw_context* ctx = data; wl_callback_destroy(callback); - struct wl_buffer* buffer = find_free_buffer(ctx); - if (!buffer) + buffer* ctx_buffer = find_free_buffer(ctx); + if (!ctx_buffer) { ctx->waiting_for_buffer = false; return; } - memset(ctx->content_area, current_value, 400 * 400 * 4); + memset(ctx_buffer->content_area, current_value, ctx_buffer->width * ctx_buffer->height * pixel_size); ++current_value; ctx->new_frame_signal = wl_surface_frame(ctx->surface); wl_callback_add_listener(ctx->new_frame_signal, &frame_listener, ctx); - wl_surface_attach(ctx->surface, buffer, 0, 0); + wl_surface_attach(ctx->surface, ctx_buffer->buffer, 0, 0); wl_surface_commit(ctx->surface); } @@ -368,47 +429,98 @@ static void shutdown(int signum) } } +void handle_xdg_surface_configure(void* _, struct xdg_surface* shell_surface, uint32_t serial) +{ + (void)_, (void)shell_surface, (void)serial; +} + +static struct xdg_surface_listener const shell_surface_listener = +{ + handle_xdg_surface_configure, +}; + +void handle_xdg_toplevel_configure(void *data, + struct xdg_toplevel *xdg_toplevel, + int32_t width_, + int32_t height_, + struct wl_array *states) +{ + (void)xdg_toplevel, (void)states; + draw_context* ctx = data; + + if (width_ > 0) ctx->width = width_; + if (height_ > 0) ctx->height = height_; +} + +void handle_xdg_toplevel_close(void *data, + struct xdg_toplevel *xdg_toplevel) +{ + (void)data, (void)xdg_toplevel; +} + +void handle_xdg_toplevel_configure_bounds(void *data, + struct xdg_toplevel *xdg_toplevel, + int32_t width_, + int32_t height_) +{ + (void)data, (void)xdg_toplevel; + (void)width_, (void)height_; +} + +void handle_xdg_toplevel__capabilities(void *data, + struct xdg_toplevel *xdg_toplevel, + struct wl_array *capabilities) +{ + (void)data, (void)xdg_toplevel, (void)capabilities; +} + +static struct xdg_toplevel_listener const shell_toplevel_listener = +{ + handle_xdg_toplevel_configure, + handle_xdg_toplevel_close, + handle_xdg_toplevel_configure_bounds, + handle_xdg_toplevel__capabilities, +}; + int main(int argc, char** argv) { (void)argc; (void)argv; struct wl_display* display = wl_display_connect(NULL); - struct globals* globals; - globals = calloc(sizeof *globals, 1); struct wl_registry* registry = wl_display_get_registry(display); - wl_registry_add_listener(registry, ®istry_listener, globals); + wl_registry_add_listener(registry, ®istry_listener, NULL); wl_display_roundtrip(display); - struct wl_pointer* pointer = wl_seat_get_pointer(globals->seat); - wl_pointer_add_listener(pointer, &pointer_listener, NULL); + check_globals(); - void* pool_data = NULL; - struct wl_shm_pool* shm_pool = make_shm_pool(globals->shm, 400 * 400 * 4, &pool_data); + struct wl_pointer* pointer = wl_seat_get_pointer(globals.seat); + wl_pointer_add_listener(pointer, &pointer_listener, NULL); - struct draw_context* ctx = calloc(sizeof *ctx, 1); + draw_context* ctx = calloc(sizeof *ctx, 1); + ctx->display = display; + ctx->surface = wl_compositor_create_surface(globals.compositor); + ctx->width = 400; + ctx->height = 400; - for (int i = 0; i < 4; ++i) + for (buffer* b = ctx->buffers; b != ctx->buffers + NO_OF_BUFFERS ; ++b) { - ctx->buffers[i].buffer = wl_shm_pool_create_buffer(shm_pool, 0, 400, 400, 400*4, WL_SHM_FORMAT_ARGB8888); - ctx->buffers[i].available = true; - wl_buffer_add_listener(ctx->buffers[i].buffer, &buffer_listener, ctx); + prepare_buffer(b, ctx); } - ctx->display = display; - ctx->surface = wl_compositor_create_surface(globals->compositor); - ctx->content_area = pool_data; + struct xdg_surface* shell_surface = xdg_wm_base_get_xdg_surface(globals.xdg_wm_base, ctx->surface); + xdg_surface_add_listener(shell_surface, &shell_surface_listener, NULL); - struct wl_shell_surface* window = wl_shell_get_shell_surface(globals->shell, ctx->surface); - wl_shell_surface_set_toplevel(window); + struct xdg_toplevel* shell_toplevel = xdg_surface_get_toplevel(shell_surface); + xdg_toplevel_add_listener(shell_toplevel, &shell_toplevel_listener, ctx); struct wl_callback* first_frame = wl_display_sync(display); wl_callback_add_listener(first_frame, &frame_listener, ctx); - wl_output_add_listener(globals->output, &output_listener, NULL); + wl_output_add_listener(globals.output, &output_listener, NULL); struct sigaction sig_handler_new; sigfillset(&sig_handler_new.sa_mask); diff --git a/include/platform/mir/graphics/display_configuration_policy.h b/include/platform/mir/graphics/display_configuration_policy.h index 3caa300e5d7..261894f6f64 100644 --- a/include/platform/mir/graphics/display_configuration_policy.h +++ b/include/platform/mir/graphics/display_configuration_policy.h @@ -30,6 +30,7 @@ class DisplayConfigurationPolicy virtual ~DisplayConfigurationPolicy() = default; virtual void apply_to(DisplayConfiguration& conf) = 0; + virtual void confirm(DisplayConfiguration const& conf) = 0; protected: DisplayConfigurationPolicy() = default; diff --git a/spread.yaml b/spread.yaml index 006ad944d62..500c6fc570f 100644 --- a/spread.yaml +++ b/spread.yaml @@ -34,8 +34,9 @@ environment: BUILD_TYPE/asan,asan_clang: AddressSanitizer BUILD_TYPE/tsan,tsan_clang: ThreadSanitizer BUILD_TYPE/ubsan,ubsan_clang: UBSanitizer - NOCHECK: "" - NOCHECK/asan,tsan,ubsan,asan_clang,tsan_clang,ubsan_clang: nocheck + DEB_BUILD_EXTRA: + DEB_BUILD_EXTRA/ubsan,ubsan_clang: nostrip + DEB_BUILD_EXTRA/asan,asan_clang,tsan,tsan_clang: nostrip nocheck CTEST_OUTPUT_ON_FAILURE: 1 CCACHE_DIR: /root/.ccache # Needed for precompiled headers (https://ccache.dev/manual/latest.html#_precompiled_headers) diff --git a/spread/build/sbuild/task.yaml b/spread/build/sbuild/task.yaml index bfb71939a2b..2acac15463a 100644 --- a/spread/build/sbuild/task.yaml +++ b/spread/build/sbuild/task.yaml @@ -1,5 +1,5 @@ environment: - DEB_BUILD_OPTIONS: "${NOCHECK}" + DEB_BUILD_OPTIONS: "${DEB_BUILD_EXTRA}" NO_PKG_MANGLE: 1 systems: [ubuntu-*] diff --git a/spread/build/ubuntu/task.yaml b/spread/build/ubuntu/task.yaml index b47b0b44aa7..a9f227b3940 100644 --- a/spread/build/ubuntu/task.yaml +++ b/spread/build/ubuntu/task.yaml @@ -1,5 +1,5 @@ environment: - DEB_BUILD_OPTIONS: "parallel=$( nproc ) noopt ${NOCHECK}" + DEB_BUILD_OPTIONS: "parallel=$( nproc ) noopt ${DEB_BUILD_EXTRA}" NO_PKG_MANGLE: 1 systems: [ubuntu-*] @@ -12,20 +12,19 @@ summary: Build Ubuntu packages execute: | cd $SPREAD_PATH - apt-get install --yes software-properties-common + NODBG=$( [[ "${DEB_BUILD_OPTIONS}" != *nostrip* ]] && echo true || echo false ) # Add Mir dev PPA for any out-of-archive packages needed # (Currently: a newer version of WLCS) - add-apt-repository ppa:mir-team/dev + add-apt-repository ppa:mir-team/dev --component "main $( $NODBG || echo main/debug )" # to get dpkg-architecture and mk-build-deps apt-get install \ --yes \ - --no-install-recommends \ ccache \ devscripts \ dpkg-dev \ - equivs + $( $NODBG || echo wlcs-dbgsym ) # set host and build environment up source <( dpkg-architecture --print-set --host-arch ${ARCH} ) @@ -59,18 +58,13 @@ execute: | apt-get update apt-get --yes install qemu-user-static binfmt-support - - # Quirk for the eglexternalplatform-dev build dependency - sed -i 's/\(eglexternalplatform-dev\)/\1:all/' debian/control fi # Mark the "release" in the changelog debchange --release "CI release" # install dependencies - mk-build-deps \ - --install \ - --tool "apt-get --yes -o Debug::pkgProblemResolver=yes -o APT::Immediate-Configure=0" + apt-get build-dep --yes ./ # use clang if [ "${CLANG}" -eq 1 ]; then @@ -93,6 +87,6 @@ execute: | echo "OVERRIDE_CONFIGURE_OPTIONS += -DCMAKE_CXX_COMPILER_LAUNCHER=ccache" >> debian/opts.mk # build and run tests - debian/rules build + UBSAN_OPTIONS=halt_on_error=1 debian/rules build ccache --show-stats --zero-stats > ${CCACHE_DIR}/ccache.stats diff --git a/src/common/input/xkb_mapper.cpp b/src/common/input/xkb_mapper.cpp index a2dc541c585..ff64b529f14 100644 --- a/src/common/input/xkb_mapper.cpp +++ b/src/common/input/xkb_mapper.cpp @@ -153,7 +153,7 @@ void mircv::XKBMapper::update_modifier() xkb_modifiers_.depressed |= device_xkb_modifiers.depressed; xkb_modifiers_.latched |= device_xkb_modifiers.latched; xkb_modifiers_.locked |= device_xkb_modifiers.locked; - if (mapping_state.first == last_device_id) + if (last_device_id && mapping_state.first == last_device_id.value()) { xkb_modifiers_.effective_layout = device_xkb_modifiers.effective_layout; } diff --git a/src/include/common/mir/input/xkb_mapper.h b/src/include/common/mir/input/xkb_mapper.h index b7555677fe6..78971ff8fc1 100644 --- a/src/include/common/mir/input/xkb_mapper.h +++ b/src/include/common/mir/input/xkb_mapper.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -111,7 +112,7 @@ class XKBMapper : public KeyMapper std::shared_ptr default_compiled_keymap; XKBComposeTablePtr compose_table; MirXkbModifiers xkb_modifiers_; - MirInputDeviceId last_device_id; + std::optional last_device_id; mir::optional_value modifier_state; std::unordered_map> device_mapping; diff --git a/src/include/server/mir/graphics/default_display_configuration_policy.h b/src/include/server/mir/graphics/default_display_configuration_policy.h index fca7812ff09..c81ed612523 100644 --- a/src/include/server/mir/graphics/default_display_configuration_policy.h +++ b/src/include/server/mir/graphics/default_display_configuration_policy.h @@ -29,21 +29,24 @@ namespace graphics class CloneDisplayConfigurationPolicy : public DisplayConfigurationPolicy { public: - void apply_to(DisplayConfiguration& conf); + void apply_to(DisplayConfiguration& conf) override; + void confirm(DisplayConfiguration const& conf) override; }; /// Each screen placed to the right of the previous one class SideBySideDisplayConfigurationPolicy : public DisplayConfigurationPolicy { public: - void apply_to(graphics::DisplayConfiguration& conf); + void apply_to(graphics::DisplayConfiguration& conf) override; + void confirm(DisplayConfiguration const& conf) override; }; /// Just use the first screen class SingleDisplayConfigurationPolicy : public DisplayConfigurationPolicy { public: - void apply_to(graphics::DisplayConfiguration& conf); + void apply_to(graphics::DisplayConfiguration& conf) override; + void confirm(DisplayConfiguration const& conf) override; }; /** @} */ } diff --git a/src/miral/display_configuration_option.cpp b/src/miral/display_configuration_option.cpp index 69d390cbc6e..47f6dba523a 100644 --- a/src/miral/display_configuration_option.cpp +++ b/src/miral/display_configuration_option.cpp @@ -25,6 +25,7 @@ #include namespace mg = mir::graphics; +using namespace mir::geometry; namespace { @@ -46,11 +47,15 @@ char const* const display_scale_opt = "display-scale"; char const* const display_scale_descr = "Scale for all displays"; char const* const display_scale_default = "1.0"; +char const* const display_autoscale_opt = "display-autoscale"; +char const* const display_autoscale_descr = "Target height in logical pixels for all displays"; + class PixelFormatSelector : public mg::DisplayConfigurationPolicy { public: PixelFormatSelector(std::shared_ptr const& base_policy, bool with_alpha); virtual void apply_to(mg::DisplayConfiguration& conf); + virtual void confirm(mg::DisplayConfiguration const& conf); private: std::shared_ptr const base_policy; bool const with_alpha; @@ -94,6 +99,11 @@ void PixelFormatSelector::apply_to(mg::DisplayConfiguration& conf) }); } +void PixelFormatSelector::confirm(mg::DisplayConfiguration const& conf) +{ + base_policy->confirm(conf); +} + class ScaleSetter : public mg::DisplayConfigurationPolicy { public: @@ -104,6 +114,7 @@ class ScaleSetter : public mg::DisplayConfigurationPolicy } void apply_to(mg::DisplayConfiguration& conf) override; + void confirm(mg::DisplayConfiguration const& conf) override; private: std::shared_ptr const base_policy; float const with_scale; @@ -119,12 +130,58 @@ void ScaleSetter::apply_to(mg::DisplayConfiguration& conf) }); } +void ScaleSetter::confirm(mg::DisplayConfiguration const& conf) +{ + base_policy->confirm(conf); +} + +class AutoscaleSetter : public mg::DisplayConfigurationPolicy +{ +public: + AutoscaleSetter(std::shared_ptr const& base_policy, int target) + : base_policy{base_policy}, + target{target} + { + } + + void apply_to(mg::DisplayConfiguration& conf) override; + void confirm(mg::DisplayConfiguration const& conf) override; +private: + void apply_to(mg::UserDisplayConfigurationOutput& output); + std::shared_ptr const base_policy; + int target; +}; + +void AutoscaleSetter::apply_to(mg::DisplayConfiguration& conf) +{ + base_policy->apply_to(conf); + conf.for_each_output( + [this](mg::UserDisplayConfigurationOutput& output) { if (output.connected) apply_to(output); }); +} + +void AutoscaleSetter::confirm(mg::DisplayConfiguration const& conf) +{ + base_policy->confirm(conf); +} + +void AutoscaleSetter::apply_to(mg::UserDisplayConfigurationOutput& output) +{ + auto const output_height = + (output.orientation == mir_orientation_normal || output.orientation == mir_orientation_inverted) ? + output.modes[output.current_mode_index].size.height.as_int() : + output.modes[output.current_mode_index].size.height.as_int(); + + static auto const steps = 4.0; + output.scale = roundf((steps * output_height) / target) / steps; +} + void miral::display_configuration_options(mir::Server& server) { // Add choice of monitor configuration server.add_configuration_option(display_config_opt, display_config_descr, sidebyside_opt_val); server.add_configuration_option(display_alpha_opt, display_alpha_descr, display_alpha_off); server.add_configuration_option(display_scale_opt, display_scale_descr, display_scale_default); + server.add_configuration_option(display_autoscale_opt, display_autoscale_descr, mir::OptionType::integer); server.wrap_display_configuration_policy( [&](std::shared_ptr const& wrapped) @@ -134,6 +191,7 @@ void miral::display_configuration_options(mir::Server& server) auto display_layout = options->get(display_config_opt); auto with_alpha = options->get(display_alpha_opt) == display_alpha_on; auto const scale_str = options->get(display_scale_opt); + auto const is_auto_scale = options->is_set(display_autoscale_opt); double scale{0}; static double const scale_min = 0.01; @@ -177,6 +235,23 @@ void miral::display_configuration_options(mir::Server& server) layout_selector = std::make_shared(layout_selector, scale); } + if (is_auto_scale) + { + if (scale != 1.0) + { + mir::fatal_error("Display scale option can't be used with autoscale"); + } + + if (display_layout.compare(0, strlen(static_opt_val), static_opt_val) == 0) + { + mir::fatal_error("Display autoscale option can't be used with static display configuration"); + } + + auto const auto_scale_target = options->get(display_autoscale_opt); + + layout_selector = std::make_shared(layout_selector, auto_scale_target); + } + // Whatever the layout select a pixel format with requested alpha return std::make_shared(layout_selector, with_alpha); }); diff --git a/src/miral/runner.cpp b/src/miral/runner.cpp index 2458aab3a10..0f90af159de 100644 --- a/src/miral/runner.cpp +++ b/src/miral/runner.cpp @@ -258,7 +258,7 @@ void miral::MirRunner::stop() if (auto const server = self->weak_server.lock()) { - server->stop(); + server->the_main_loop()->enqueue(this, [server] { server->stop(); }); } } diff --git a/src/miral/static_display_config.cpp b/src/miral/static_display_config.cpp index 73be9049f50..0e2ebdc2f45 100644 --- a/src/miral/static_display_config.cpp +++ b/src/miral/static_display_config.cpp @@ -328,6 +328,10 @@ void miral::YamlFileDisplayConfig::apply_to(mg::DisplayConfiguration& conf) mir::log_info(out.str()); } +void miral::YamlFileDisplayConfig::confirm(mir::graphics::DisplayConfiguration const&) +{ +} + void miral::YamlFileDisplayConfig::apply_default_configuration(mg::DisplayConfiguration& conf) { conf.for_each_output([config=Config{}](mg::UserDisplayConfigurationOutput& conf_output) @@ -549,7 +553,7 @@ void miral::ReloadingYamlFileDisplayConfig::config_path(std::string newpath) check_for_layout_override(); } -void miral::ReloadingYamlFileDisplayConfig::apply_to(mir::graphics::DisplayConfiguration& conf) +void miral::ReloadingYamlFileDisplayConfig::confirm(mir::graphics::DisplayConfiguration const& conf) { std::lock_guard lock{mutex}; if (!config_path_) @@ -584,8 +588,6 @@ void miral::ReloadingYamlFileDisplayConfig::apply_to(mir::graphics::DisplayConfi filename.c_str()); } } - - YamlFileDisplayConfig::apply_to(conf); } auto miral::ReloadingYamlFileDisplayConfig::the_main_loop() const -> std::shared_ptr diff --git a/src/miral/static_display_config.h b/src/miral/static_display_config.h index b01527b7f4a..1df3a1cd984 100644 --- a/src/miral/static_display_config.h +++ b/src/miral/static_display_config.h @@ -45,6 +45,7 @@ class YamlFileDisplayConfig : public mir::graphics::DisplayConfigurationPolicy void load_config(std::istream& config_file, std::string const& filename); void apply_to(mir::graphics::DisplayConfiguration& conf) override; + virtual void confirm(mir::graphics::DisplayConfiguration const& conf) override; void select_layout(std::string const& layout); @@ -94,7 +95,7 @@ class ReloadingYamlFileDisplayConfig : public YamlFileDisplayConfig void config_path(std::string newpath); - void apply_to(mir::graphics::DisplayConfiguration& conf) override; + void confirm(mir::graphics::DisplayConfiguration const& conf) override; void check_for_layout_override(); diff --git a/src/miroil/persist_display_config.cpp b/src/miroil/persist_display_config.cpp index 4426163f4f1..404e008d976 100644 --- a/src/miroil/persist_display_config.cpp +++ b/src/miroil/persist_display_config.cpp @@ -77,6 +77,10 @@ struct DisplayConfigurationPolicyAdapter : mg::DisplayConfigurationPolicy self->apply_to(conf, *wrapped_policy, *custom_policy); } + void confirm(mg::DisplayConfiguration const&) override + { + } + std::shared_ptr const self; std::shared_ptr const wrapped_policy; std::shared_ptr const custom_policy; diff --git a/src/platform/graphics/CMakeLists.txt b/src/platform/graphics/CMakeLists.txt index ea9bd7887d8..3f29e523e90 100644 --- a/src/platform/graphics/CMakeLists.txt +++ b/src/platform/graphics/CMakeLists.txt @@ -36,7 +36,7 @@ add_library(mirplatformgraphicscommon OBJECT egl_buffer_copy.cpp ) -mir_generate_protocol_wrapper(mirplatformgraphicscommon "zwp_" protocol/linux-dmabuf-unstable-v1.xml) +mir_generate_protocol_wrapper(mirplatformgraphicscommon "zwp_" linux-dmabuf-unstable-v1.xml) if (DRM_VERSION VERSION_GREATER 2.4.107) target_compile_definitions( diff --git a/src/platforms/eglstream-kms/server/display.cpp b/src/platforms/eglstream-kms/server/display.cpp index 059a1dde5d5..d213951902b 100644 --- a/src/platforms/eglstream-kms/server/display.cpp +++ b/src/platforms/eglstream-kms/server/display.cpp @@ -178,6 +178,21 @@ class DisplayBuffer pending_flip = satisfied_promise.get_future(); } + ~DisplayBuffer() + { + if (output_stream != EGL_NO_STREAM_KHR) + { + eglDestroyStreamKHR(dpy, output_stream); + output_stream = nullptr; + } + + if (ctx != EGL_NO_CONTEXT) + { + eglDestroyContext(dpy, ctx); + ctx = nullptr; + } + } + mir::geometry::Rectangle view_area() const override { return output->extents(); diff --git a/src/platforms/eglstream-kms/server/platform.cpp b/src/platforms/eglstream-kms/server/platform.cpp index c4e7b6d6de9..d9a5a160abe 100644 --- a/src/platforms/eglstream-kms/server/platform.cpp +++ b/src/platforms/eglstream-kms/server/platform.cpp @@ -249,6 +249,14 @@ mge::DisplayPlatform::DisplayPlatform( provider = std::make_shared(display, drm_node); } +mge::DisplayPlatform::~DisplayPlatform() +{ + if (display != EGL_NO_DISPLAY) + { + eglTerminate(display); + } +} + auto mge::DisplayPlatform::create_display( std::shared_ptr const& configuration_policy, std::shared_ptr const& gl_config) diff --git a/src/platforms/eglstream-kms/server/platform.h b/src/platforms/eglstream-kms/server/platform.h index 53371c2ff64..1eee5f51cf1 100644 --- a/src/platforms/eglstream-kms/server/platform.h +++ b/src/platforms/eglstream-kms/server/platform.h @@ -65,6 +65,8 @@ class DisplayPlatform : public graphics::DisplayPlatform EGLDeviceEXT device, std::shared_ptr display_report); + ~DisplayPlatform(); + auto create_display( std::shared_ptr const& initial_conf_policy, std::shared_ptr const& gl_config) diff --git a/src/platforms/wayland/display.cpp b/src/platforms/wayland/display.cpp index f653eedd10c..520c17d40b2 100644 --- a/src/platforms/wayland/display.cpp +++ b/src/platforms/wayland/display.cpp @@ -329,7 +329,9 @@ void mir::graphics::wayland::Display::pointer_motion(wl_pointer* pointer, uint32 { { std::lock_guard lock{sink_mutex}; - pointer_pos = geom::PointF{wl_fixed_to_double(x), wl_fixed_to_double(y)} + geom::DisplacementF{pointer_displacement}; + auto const descaled_x = pointer_scale * wl_fixed_to_double(x); + auto const descaled_y = pointer_scale * wl_fixed_to_double(y); + pointer_pos = geom::PointF{descaled_x, descaled_y} + pointer_displacement; pointer_time = std::chrono::milliseconds{time}; } diff --git a/src/platforms/wayland/displayclient.cpp b/src/platforms/wayland/displayclient.cpp index 4240fcdec0d..ccf96dbaa54 100644 --- a/src/platforms/wayland/displayclient.cpp +++ b/src/platforms/wayland/displayclient.cpp @@ -56,6 +56,7 @@ class mgw::DisplayClient::Output : DisplayConfigurationOutput dcout; geom::Size output_size; + float host_scale{1.0f}; wl_output* const output; DisplayClient* const owner_; @@ -254,7 +255,7 @@ void mgw::DisplayClient::Output::mode(uint32_t flags, int32_t width, int32_t hei void mgw::DisplayClient::Output::scale(int32_t factor) { - dcout.scale = factor; + host_scale = factor; } void mgw::DisplayClient::Output::done() @@ -275,7 +276,7 @@ void mgw::DisplayClient::Output::done() xdg_toplevel_add_listener(shell_toplevel, &shell_toplevel_listener, this); xdg_toplevel_set_fullscreen(shell_toplevel, output); - wl_surface_set_buffer_scale(surface, round(dcout.scale)); + wl_surface_set_buffer_scale(surface, round(host_scale)); wl_surface_commit(surface); // After the next roundtrip the surface should be configured @@ -301,9 +302,9 @@ void mgw::DisplayClient::Output::surface_configure(uint32_t serial) xdg_surface_ack_configure(shell_surface, serial); bool const size_is_changed = pending_toplevel_size && ( !dcout.custom_logical_size || dcout.custom_logical_size.value() != pending_toplevel_size.value()); - dcout.custom_logical_size = pending_toplevel_size.value(); + dcout.custom_logical_size = host_scale*pending_toplevel_size.value(); pending_toplevel_size.reset(); - output_size = dcout.extents().size * dcout.scale; + output_size = dcout.extents().size; if (!has_initialized) { has_initialized = true; @@ -567,12 +568,13 @@ void mgw::DisplayClient::remove_global( { DisplayClient* self = static_cast(data); - std::lock_guard lock{self->outputs_mutex}; + std::unique_lock lock{self->outputs_mutex}; auto const output = self->bound_outputs.find(id); if (output != self->bound_outputs.end()) { self->outputs_to_be_deleted.push_back(std::move(output->second)); self->bound_outputs.erase(output); + lock.unlock(); self->on_display_config_changed(); } // TODO: We should probably also delete any other globals we've bound to that disappear. @@ -643,7 +645,9 @@ void mgw::DisplayClient::pointer_enter( { if (surface == out.second->surface) { - pointer_displacement = out.second->dcout.top_left - geometry::Point{}; + // Pointer events are displaced and scaled according to the surface + pointer_displacement = geom::DisplacementF{out.second->dcout.top_left - geometry::Point{}}; + pointer_scale = out.second->host_scale; break; } } diff --git a/src/platforms/wayland/displayclient.h b/src/platforms/wayland/displayclient.h index ffb068bbca6..b1ad98a999e 100644 --- a/src/platforms/wayland/displayclient.h +++ b/src/platforms/wayland/displayclient.h @@ -162,8 +162,9 @@ class DisplayClient xkb_keymap* keyboard_map_ = nullptr; xkb_state* keyboard_state_ = nullptr; bool fake_pointer_frame = false; - geometry::Displacement pointer_displacement; // Position of current output + geometry::DisplacementF pointer_displacement; // Position of current output geometry::Displacement touch_displacement; // Position of current output + float pointer_scale{1.0f}; std::unique_ptr registry; diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index 6e71b1ad921..e71dc66be2a 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -26,7 +26,6 @@ add_subdirectory(graphics/) add_subdirectory(input/) add_subdirectory(report/) add_subdirectory(scene/) -add_subdirectory(frontend/) add_subdirectory(frontend_wayland/) add_subdirectory(frontend_xwayland/) add_subdirectory(shell/) @@ -86,7 +85,6 @@ set(MIR_SERVER_OBJECTS $ $ $ - $ $ $ $ diff --git a/src/server/frontend/CMakeLists.txt b/src/server/frontend/CMakeLists.txt deleted file mode 100644 index 8f0839e4600..00000000000 --- a/src/server/frontend/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -set( - FRONTEND_SOURCES - - session_credentials.cpp - ${PROJECT_SOURCE_DIR}/src/include/server/mir/frontend/buffer_stream.h -) - -add_library( - mirfrontend OBJECT - - ${FRONTEND_SOURCES} -) - diff --git a/src/server/frontend_wayland/CMakeLists.txt b/src/server/frontend_wayland/CMakeLists.txt index c5472667bee..d3d068297a1 100644 --- a/src/server/frontend_wayland/CMakeLists.txt +++ b/src/server/frontend_wayland/CMakeLists.txt @@ -57,6 +57,8 @@ set( std_layout_uptr.h shm.cpp shm.h ${PROJECT_SOURCE_DIR}/src/include/server/mir/frontend/pointer_input_dispatcher.h + session_credentials.cpp + ${PROJECT_SOURCE_DIR}/src/include/server/mir/frontend/buffer_stream.h ) add_custom_command( diff --git a/src/server/frontend/session_credentials.cpp b/src/server/frontend_wayland/session_credentials.cpp similarity index 100% rename from src/server/frontend/session_credentials.cpp rename to src/server/frontend_wayland/session_credentials.cpp diff --git a/src/server/frontend_wayland/wayland_surface_observer.cpp b/src/server/frontend_wayland/wayland_surface_observer.cpp index 8285a9ea45d..baa03a9600a 100644 --- a/src/server/frontend_wayland/wayland_surface_observer.cpp +++ b/src/server/frontend_wayland/wayland_surface_observer.cpp @@ -77,7 +77,7 @@ void mf::WaylandSurfaceObserver::content_resized_to(ms::Surface const*, geom::Si run_on_wayland_thread_unless_window_destroyed( [content_size](Impl* impl, WindowWlSurfaceRole* window) { - if (content_size != impl->window_size) + if (impl->requested_size.value_or(impl->window_size) != content_size) { impl->requested_size = content_size; window->handle_resize(std::nullopt, content_size); diff --git a/src/server/frontend_wayland/window_wl_surface_role.cpp b/src/server/frontend_wayland/window_wl_surface_role.cpp index 15e84d3c299..8ce33965ccc 100644 --- a/src/server/frontend_wayland/window_wl_surface_role.cpp +++ b/src/server/frontend_wayland/window_wl_surface_role.cpp @@ -290,7 +290,7 @@ auto mf::WindowWlSurfaceRole::pending_size() const -> geom::Size auto mf::WindowWlSurfaceRole::current_size() const -> geom::Size { - auto size = committed_size.value_or(geom::Size{640, 480}); + auto size = geom::Size{640, 480}; if ((!committed_width_set_explicitly || !committed_height_set_explicitly) && surface) { if (auto const buffer_size = surface.value().buffer_size()) @@ -357,11 +357,7 @@ void mf::WindowWlSurfaceRole::commit(WlSurfaceState const& state) spec().state = mir_window_state_hidden; } - if (!committed_size || size != committed_size.value()) - { - spec().width = size.width; - spec().height = size.height; - } + apply_client_size(spec()); if (state.surface_data_needs_refresh()) { @@ -386,7 +382,6 @@ void mf::WindowWlSurfaceRole::commit(WlSurfaceState const& state) create_scene_surface(); } - committed_size = size; if (pending_explicit_width) committed_width_set_explicitly = true; if (pending_explicit_height) @@ -457,9 +452,9 @@ void mf::WindowWlSurfaceRole::create_scene_surface() return; auto& mods = spec(); - auto const request_size = pending_size(); - mods.width = request_size.width; - mods.height = request_size.height; + + apply_client_size(mods); + mods.streams = std::vector{}; mods.input_shape = std::vector{}; surface.value().populate_surface_data(mods.streams.value(), mods.input_shape.value(), {}); @@ -475,10 +470,7 @@ void mf::WindowWlSurfaceRole::create_scene_surface() // The shell isn't guaranteed to respect the requested size // TODO: make initial updates atomic somehow auto const content_size = scene_surface->content_size(); - if (content_size != request_size) - { - observer->content_resized_to(scene_surface.get(), content_size); - } + observer->content_resized_to(scene_surface.get(), content_size); auto const focus_state = scene_surface->focus_state(); if (focus_state != mir_window_focus_state_unfocused) { @@ -504,3 +496,26 @@ void mf::WindowWlSurfaceRole::create_scene_surface() // Invalidates mods pending_changes.reset(); } + +void mf::WindowWlSurfaceRole::apply_client_size(mir::shell::SurfaceSpecification& mods) +{ + if ((!committed_width_set_explicitly || !committed_height_set_explicitly) && surface) + { + if (auto const buffer_size = surface.value().buffer_size()) + { + if (!committed_width_set_explicitly) + { + mods.width = buffer_size->width; + } + if (!committed_height_set_explicitly) + { + mods.height = buffer_size->height; + } + } + } + + if (pending_explicit_width) + mods.width = pending_explicit_width.value(); + if (pending_explicit_height) + mods.height = pending_explicit_height.value(); +} diff --git a/src/server/frontend_wayland/window_wl_surface_role.h b/src/server/frontend_wayland/window_wl_surface_role.h index c07372f2ad5..ab6093fe540 100644 --- a/src/server/frontend_wayland/window_wl_surface_role.h +++ b/src/server/frontend_wayland/window_wl_surface_role.h @@ -149,9 +149,6 @@ class WindowWlSurfaceRole bool committed_height_set_explicitly{false}; /// @} - /// The last committed window size (either explicitly set or taken from the surface buffer size) - std::optional committed_size; - /// The min and max size of the window as of last commit /// @{ geometry::Size committed_min_size; @@ -164,6 +161,8 @@ class WindowWlSurfaceRole // Ask the derived class to destroy the wayland role object (as only it can do that) virtual void destroy_role() const = 0; + + void apply_client_size(mir::shell::SurfaceSpecification& mods); }; } diff --git a/src/server/frontend_wayland/wl_shell.cpp b/src/server/frontend_wayland/wl_shell.cpp index 9642d1890a8..b5718349bd4 100644 --- a/src/server/frontend_wayland/wl_shell.cpp +++ b/src/server/frontend_wayland/wl_shell.cpp @@ -65,7 +65,7 @@ class WlShellSurface : public wayland::ShellSurface, public WindowWlSurfaceRole mir::shell::SurfaceSpecification mods; if (flags & mw::ShellSurface::Transient::inactive) - mods.type = mir_window_type_gloss; + mods.type = mir_window_type_tip; if (auto parent = parent_surface.scene_surface()) mods.parent = parent.value(); mods.aux_rect = geom::Rectangle{{x, y}, {}}; @@ -118,7 +118,7 @@ class WlShellSurface : public wayland::ShellSurface, public WindowWlSurfaceRole mir::shell::SurfaceSpecification mods; if (flags & mw::ShellSurface::Transient::inactive) - mods.type = mir_window_type_gloss; + mods.type = mir_window_type_tip; if (auto parent = parent_surface.scene_surface()) mods.parent = parent.value(); mods.aux_rect = geom::Rectangle{{x, y}, {}}; diff --git a/src/server/frontend_wayland/xdg_shell_stable.cpp b/src/server/frontend_wayland/xdg_shell_stable.cpp index 532c7beb045..db33552b161 100644 --- a/src/server/frontend_wayland/xdg_shell_stable.cpp +++ b/src/server/frontend_wayland/xdg_shell_stable.cpp @@ -320,7 +320,7 @@ mf::XdgPopupStable::XdgPopupStable( xdg_surface{xdg_surface} { positioner.ensure_complete(); - positioner.type = mir_window_type_gloss; + positioner.type = mir_window_type_tip; if (parent_role) { if (auto scene_surface = parent_role.value()->scene_surface()) diff --git a/src/server/frontend_wayland/xdg_shell_v6.cpp b/src/server/frontend_wayland/xdg_shell_v6.cpp index e45701d7b62..ce65f88ff0e 100644 --- a/src/server/frontend_wayland/xdg_shell_v6.cpp +++ b/src/server/frontend_wayland/xdg_shell_v6.cpp @@ -318,7 +318,7 @@ mf::XdgPopupV6::XdgPopupV6( auto const& parent_role = parent_surface->window_role(); auto parent_scene_surface = parent_role ? parent_role.value().scene_surface() : std::nullopt; - specification->type = mir_window_type_gloss; + specification->type = mir_window_type_tip; if (parent_scene_surface) specification->parent = parent_scene_surface.value(); else diff --git a/src/server/frontend_xwayland/xwayland_surface.cpp b/src/server/frontend_xwayland/xwayland_surface.cpp index 165c3b0417e..e211e59348b 100644 --- a/src/server/frontend_xwayland/xwayland_surface.cpp +++ b/src/server/frontend_xwayland/xwayland_surface.cpp @@ -216,7 +216,7 @@ auto wm_window_type_to_mir_window_type( wm_type == connection->_NET_WM_WINDOW_TYPE_DND || wm_type == connection->_NET_WM_WINDOW_TYPE_DIALOG) { - return mir_window_type_gloss; + return mir_window_type_tip; } else if (mir::verbose_xwayland_logging_enabled()) { @@ -231,7 +231,7 @@ auto wm_window_type_to_mir_window_type( // be taken as _NET_WM_WINDOW_TYPE_NORMAL." if (is_transient_for && !override_redirect) { - return mir_window_type_gloss; + return mir_window_type_tip; } else { @@ -1221,20 +1221,25 @@ void mf::XWaylandSurface::prep_surface_spec(ProofOfMutexLock const&, msh::Surfac } } -#define SCALE_SIZE(type, prop) \ - if (mods.prop) \ - { \ - mods.prop = std::max(geom::type{1}, mods.prop.value() * inv_scale); \ - } + auto scale_size_clamped = [inv_scale](auto& optional_prop) + { + if (optional_prop) + { + using ValueType = typename std::remove_reference::type; + using UnderlyingType = typename ValueType::ValueType; + auto constexpr raw_max = std::numeric_limits::max(); - SCALE_SIZE(Width, width); - SCALE_SIZE(Height, height); - SCALE_SIZE(Width, min_width); - SCALE_SIZE(Height, min_height); - SCALE_SIZE(Width, max_width); - SCALE_SIZE(Height, max_height); + double const double_value = optional_prop.value().as_value() * inv_scale; + optional_prop = std::max(ValueType{1}, ValueType{std::min(double_value, double{raw_max})}); + } + }; -#undef SCALE_SIZE + scale_size_clamped(mods.width); + scale_size_clamped(mods.height); + scale_size_clamped(mods.min_width); + scale_size_clamped(mods.min_height); + scale_size_clamped(mods.max_width); + scale_size_clamped(mods.max_height); // NOTE: exclusive rect not checked because it is not used by XWayland surfaces // NOTE: aux rect related properties not checks because they are only set in this method diff --git a/src/server/graphics/default_display_configuration_policy.cpp b/src/server/graphics/default_display_configuration_policy.cpp index 19ca41c12a4..7f333a1f9db 100644 --- a/src/server/graphics/default_display_configuration_policy.cpp +++ b/src/server/graphics/default_display_configuration_policy.cpp @@ -88,6 +88,10 @@ void mg::CloneDisplayConfigurationPolicy::apply_to(DisplayConfiguration& conf) }); } +void mg::CloneDisplayConfigurationPolicy::confirm(mir::graphics::DisplayConfiguration const&) +{ +} + void mg::SideBySideDisplayConfigurationPolicy::apply_to(graphics::DisplayConfiguration& conf) { int max_x = 0; @@ -113,6 +117,9 @@ void mg::SideBySideDisplayConfigurationPolicy::apply_to(graphics::DisplayConfigu }); } +void mg::SideBySideDisplayConfigurationPolicy::confirm(mir::graphics::DisplayConfiguration const&) +{ +} void mg::SingleDisplayConfigurationPolicy::apply_to(graphics::DisplayConfiguration& conf) { @@ -137,3 +144,7 @@ void mg::SingleDisplayConfigurationPolicy::apply_to(graphics::DisplayConfigurati } }); } + +void mg::SingleDisplayConfigurationPolicy::confirm(mir::graphics::DisplayConfiguration const&) +{ +} \ No newline at end of file diff --git a/src/server/graphics/multiplexing_display.cpp b/src/server/graphics/multiplexing_display.cpp index 7966392edba..0981f5ccf83 100644 --- a/src/server/graphics/multiplexing_display.cpp +++ b/src/server/graphics/multiplexing_display.cpp @@ -33,6 +33,7 @@ mg::MultiplexingDisplay::MultiplexingDisplay( { auto conf = configuration(); initial_configuration_policy.apply_to(*conf); + initial_configuration_policy.confirm(*conf); configure(*conf); } diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt index afb47940234..5b2143d4907 100644 --- a/src/wayland/CMakeLists.txt +++ b/src/wayland/CMakeLists.txt @@ -16,25 +16,25 @@ add_library(mirwayland SHARED ${STANDARD_SOURCES} ) -mir_generate_protocol_wrapper(mirwayland "wl_" protocol/wayland.xml) -mir_generate_protocol_wrapper(mirwayland "z" protocol/xdg-shell-unstable-v6.xml) -mir_generate_protocol_wrapper(mirwayland "" protocol/xdg-shell.xml) -mir_generate_protocol_wrapper(mirwayland "z" protocol/xdg-output-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwlr_" protocol/wlr-layer-shell-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwlr_" protocol/wlr-foreign-toplevel-management-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" protocol/pointer-constraints-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" protocol/relative-pointer-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" protocol/virtual-keyboard-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" protocol/text-input-unstable-v3.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" protocol/text-input-unstable-v2.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" protocol/text-input-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" protocol/input-method-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" protocol/input-method-unstable-v2.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" protocol/idle-inhibit-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" protocol/primary-selection-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "z" protocol/wlr-screencopy-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwlr_" protocol/wlr-virtual-pointer-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "ext_" protocol/ext-session-lock-v1.xml) +mir_generate_protocol_wrapper(mirwayland "wl_" wayland.xml) +mir_generate_protocol_wrapper(mirwayland "z" xdg-shell-unstable-v6.xml) +mir_generate_protocol_wrapper(mirwayland "" xdg-shell.xml) +mir_generate_protocol_wrapper(mirwayland "z" xdg-output-unstable-v1.xml) +mir_generate_protocol_wrapper(mirwayland "zwlr_" wlr-layer-shell-unstable-v1.xml) +mir_generate_protocol_wrapper(mirwayland "zwlr_" wlr-foreign-toplevel-management-unstable-v1.xml) +mir_generate_protocol_wrapper(mirwayland "zwp_" pointer-constraints-unstable-v1.xml) +mir_generate_protocol_wrapper(mirwayland "zwp_" relative-pointer-unstable-v1.xml) +mir_generate_protocol_wrapper(mirwayland "zwp_" virtual-keyboard-unstable-v1.xml) +mir_generate_protocol_wrapper(mirwayland "zwp_" text-input-unstable-v3.xml) +mir_generate_protocol_wrapper(mirwayland "zwp_" text-input-unstable-v2.xml) +mir_generate_protocol_wrapper(mirwayland "zwp_" text-input-unstable-v1.xml) +mir_generate_protocol_wrapper(mirwayland "zwp_" input-method-unstable-v1.xml) +mir_generate_protocol_wrapper(mirwayland "zwp_" input-method-unstable-v2.xml) +mir_generate_protocol_wrapper(mirwayland "zwp_" idle-inhibit-unstable-v1.xml) +mir_generate_protocol_wrapper(mirwayland "zwp_" primary-selection-unstable-v1.xml) +mir_generate_protocol_wrapper(mirwayland "z" wlr-screencopy-unstable-v1.xml) +mir_generate_protocol_wrapper(mirwayland "zwlr_" wlr-virtual-pointer-unstable-v1.xml) +mir_generate_protocol_wrapper(mirwayland "ext_" ext-session-lock-v1.xml) target_link_libraries(mirwayland PUBLIC diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index dc299191d30..bdd26b76846 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,67 +1,3 @@ -# get a gtest version string the regex will match -if (GTEST_FOUND AND GTEST_MAIN_FOUND) - set(GTEST_VERSION_STR ${GTEST_VERSION}) - set(GTEST_DETECTION_METHOD "pkg-config") -elseif (DEFINED ENV{GTEST_VERSION}) - set(GTEST_VERSION_STR $ENV{GTEST_VERSION}) - set(GTEST_DETECTION_METHOD "GTEST_VERSION environment variable") -else() - find_program(APT_EXECUTABLE - NAMES "apt") - find_program(RPM_EXECUTABLE - NAMES "rpm") - find_program(PACMAN_EXECUTABLE - NAMES "pacman") - find_program(GTEST_CONFIG_EXECUTABLE - NAMES "gtest-config" "gtest-conf") - if(APT_EXECUTABLE) - EXEC_PROGRAM(${APT_EXECUTABLE} "/" - ARGS "policy" "libgtest-dev" - OUTPUT_VARIABLE GTEST_VERSION_STR) - set(GTEST_DETECTION_METHOD "output of apt") - elseif(RPM_EXECUTABLE) - EXEC_PROGRAM(${RPM_EXECUTABLE} "/" - ARGS "-q" "gtest-devel" - OUTPUT_VARIABLE GTEST_VERSION_STR) - set(GTEST_DETECTION_METHOD "output of rpm") - elseif(PACMAN_EXECUTABLE) - EXEC_PROGRAM(${PACMAN_EXECUTABLE} "/" - ARGS "-Q" "gtest" - OUTPUT_VARIABLE GTEST_VERSION_STR) - set(GTEST_DETECTION_METHOD "output of pacman") - elseif(GTEST_CONFIG_EXECUTABLE) - EXEC_PROGRAM(${GTEST_CONFIG_EXECUTABLE} "/" - ARGS "--version" - OUTPUT_VARIABLE GTEST_VERSION_STR) - set(GTEST_DETECTION_METHOD "output of gtest-config") - else() - message(WARNING "Could not detect GTest version, Assuming v1.8.0 (or compatible) and hoping for the best") - set(GTEST_VERSION_STR "1.8.0") - add_compile_definitions(GTEST_VERSION_UNKNOWN) - set(GTEST_DETECTION_METHOD "best guess, could not detect") - endif() -endif() - -string(REGEX MATCH - "([0-9])\\.([0-9]+)\\.([0-9])" GTEST_VERSION_PARSED - ${GTEST_VERSION_STR}) -if (GTEST_VERSION_PARSED) - set(GTEST_VERSION_MAJOR ${CMAKE_MATCH_1}) - set(GTEST_VERSION_MINOR ${CMAKE_MATCH_2}) - set(GTEST_VERSION_PATCH ${CMAKE_MATCH_3}) - message("Using GTest v${GTEST_VERSION_MAJOR}.${GTEST_VERSION_MINOR}.${GTEST_VERSION_PATCH} (parsed from ${GTEST_DETECTION_METHOD})") -else() - message(WARNING "Could not parse GTest version: ${GTEST_VERSION_STR} (${GTEST_DETECTION_METHOD}), Assuming v1.8.0 (or compatible) and hoping for the best") - set(GTEST_VERSION_MAJOR 1) - set(GTEST_VERSION_MINOR 8) - set(GTEST_VERSION_PATCH 0) - add_compile_definitions(GTEST_VERSION_UNKNOWN) -endif() - -add_compile_definitions(GTEST_VERSION_MAJOR=${GTEST_VERSION_MAJOR}) -add_compile_definitions(GTEST_VERSION_MINOR=${GTEST_VERSION_MINOR}) -add_compile_definitions(GTEST_VERSION_PATCH=${GTEST_VERSION_PATCH}) - pkg_check_modules(UMOCKDEV REQUIRED IMPORTED_TARGET umockdev-1.0>=0.6) if (NOT UMOCKDEV_FOUND) message(FATAL_ERROR "Umockdev not found, cannot build without disabling tests (via MIR_ENABLE_TESTS).") diff --git a/tests/acceptance-tests/wayland/CMakeLists.txt b/tests/acceptance-tests/wayland/CMakeLists.txt index f6864f16f43..caaedda69d7 100644 --- a/tests/acceptance-tests/wayland/CMakeLists.txt +++ b/tests/acceptance-tests/wayland/CMakeLists.txt @@ -33,6 +33,14 @@ set_target_properties( pkg_get_variable(WLCS_BINARY wlcs test_runner) +if(cmake_build_type_lower MATCHES "addresssanitizer") + set(WLCS_BINARY ${WLCS_BINARY}.asan) +elseif(cmake_build_type_lower MATCHES "threadsanitizer") + set(WLCS_BINARY ${WLCS_BINARY}.tsan) +elseif(cmake_build_type_lower MATCHES "ubsanitizer") + set(WLCS_BINARY ${WLCS_BINARY}.ubsan) +endif() + set(EXPECTED_FAILURES ClientSurfaceEventsTest.surface_gets_enter_event diff --git a/tests/include/check_gtest_version.h b/tests/include/check_gtest_version.h deleted file mode 100644 index c4e6ed82295..00000000000 --- a/tests/include/check_gtest_version.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef GMOCK_CHECK_VERSION_H_ -#define GMOCK_CHECK_VERSION_H_ - -// NOTE: GTEST_VERSION_* macros are pulled out of the gtest-config utility in cmake, they are NOT provided by any GTest headers. - -#if !defined(GTEST_VERSION_MAJOR) || !defined(GTEST_VERSION_MINOR) || !defined(GTEST_VERSION_PATCH) -#error GTest version macro(s) (GTEST_VERSION_MAJOR, GTEST_VERSION_MINOR or GTEST_VERSION_PATCH) not defined, They should have been defined in tests/CMakeLists.txt -#endif - -#ifdef GTEST_VERSION_MAJOR -#if GTEST_VERSION_MAJOR != 1 -#error only GTest version 1.x.x supported -#endif -#endif - -#define GTEST_AT_LEAST(x, y, z) (GTEST_VERSION_MAJOR > x || (GTEST_VERSION_MAJOR == x && (GTEST_VERSION_MINOR > y || (GTEST_VERSION_MINOR == y && (GTEST_VERSION_PATCH >= z))))) - -#endif // GMOCK_CHECK_VERSION_H_ diff --git a/tests/include/mir/test/doubles/mock_drm.h b/tests/include/mir/test/doubles/mock_drm.h index 453c95c1fa7..6e41f9b2048 100644 --- a/tests/include/mir/test/doubles/mock_drm.h +++ b/tests/include/mir/test/doubles/mock_drm.h @@ -156,7 +156,7 @@ class MockDRM MOCK_METHOD6(drmModeCrtcGetGamma, int(int fd, uint32_t crtc_id, uint32_t size, uint16_t* red, uint16_t* green, uint16_t* blue)); MOCK_METHOD6(drmModeCrtcSetGamma, int(int fd, uint32_t crtc_id, uint32_t size, - uint16_t* red, uint16_t* green, uint16_t* blue)); + uint16_t const* red, uint16_t const* green, uint16_t const* blue)); MOCK_METHOD1(drmGetVersion, drmVersionPtr(int)); MOCK_METHOD1(drmFreeVersion, void(drmVersionPtr)); diff --git a/tests/include/mir/test/doubles/null_display_configuration_policy.h b/tests/include/mir/test/doubles/null_display_configuration_policy.h index 54907ffd1b8..d62f905791d 100644 --- a/tests/include/mir/test/doubles/null_display_configuration_policy.h +++ b/tests/include/mir/test/doubles/null_display_configuration_policy.h @@ -29,6 +29,7 @@ class NullDisplayConfigurationPolicy : public graphics::DisplayConfigurationPoli { public: void apply_to(graphics::DisplayConfiguration&) override {} + void confirm(graphics::DisplayConfiguration const&) override {} }; } } diff --git a/tests/include/mir/test/input_config_matchers.h b/tests/include/mir/test/input_config_matchers.h index e912834ccd6..aa6c3bd35ba 100644 --- a/tests/include/mir/test/input_config_matchers.h +++ b/tests/include/mir/test/input_config_matchers.h @@ -16,7 +16,6 @@ #ifndef MIR_TEST_INPUT_CONFIG_MATCHERS_H #define MIR_TEST_INPUT_CONFIG_MATCHERS_H -#include "check_gtest_version.h" #include "mir/input/mir_input_config.h" #include @@ -35,12 +34,8 @@ class InputConfigElementsMatcher // Constructs the matcher from a sequence of element values or // element matchers. template -#if GTEST_AT_LEAST(1, 8, 1) InputConfigElementsMatcher(UnorderedMatcherRequire::Flags matcher_flags, InputIter first, InputIter last) : UnorderedElementsAreMatcherImplBase{matcher_flags} -#else - InputConfigElementsMatcher(InputIter first, InputIter last) -#endif { for (; first != last; ++first) { @@ -76,11 +71,7 @@ class InputConfigElementsMatcher return false; } -#if GTEST_AT_LEAST(1, 8, 1) bool matrix_matched = VerifyMatchMatrix(element_printouts, matrix, listener); -#else - bool matrix_matched = VerifyAllElementsAndMatchersAreMatched(element_printouts, matrix, listener); -#endif return matrix_matched && FindPairing(matrix, listener); } diff --git a/tests/mir_test_doubles/mock_drm.cpp b/tests/mir_test_doubles/mock_drm.cpp index 157998ecca1..a96b05d04fd 100644 --- a/tests/mir_test_doubles/mock_drm.cpp +++ b/tests/mir_test_doubles/mock_drm.cpp @@ -539,6 +539,24 @@ testing::Matcher mtd::IsFdOfDevice(char const* device) return ::testing::MakeMatcher(new mtd::MockDRM::IsFdOfDeviceMatcher(device)); } +// The signature of drmModeCrtcSetGamma() changes from passing the gamma as `uint16_t*` to `uint16_t const*` +// We need to provide a definition that matches +namespace +{ +template +struct Decode_drmModeCrtcSetGamma_signature; + +template +struct Decode_drmModeCrtcSetGamma_signature +{ + using gamma_t = Arg; +}; +using gamma_t = Decode_drmModeCrtcSetGamma_signature::gamma_t; +} + +// Ensure we get a compile error if the definition doesn't match the declaration (instead of providing an overload) +extern "C" +{ int drmOpen(const char *name, const char *busid) { return global_mock->drmOpen(name, busid); @@ -598,8 +616,7 @@ int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size, return global_mock->drmModeCrtcGetGamma(fd, crtc_id, size, red, green, blue); } -int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size, - uint16_t* red, uint16_t* green, uint16_t* blue) +int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size, gamma_t red, gamma_t green, gamma_t blue) { return global_mock->drmModeCrtcSetGamma(fd, crtc_id, size, red, green, blue); } @@ -801,3 +818,4 @@ int drmCheckModesettingSupported(char const* busid) { return global_mock->drmCheckModesettingSupported(busid); } +} diff --git a/tests/mir_test_framework/mmap_wrapper.cpp b/tests/mir_test_framework/mmap_wrapper.cpp index af0197c32c7..1301ee2f6c2 100644 --- a/tests/mir_test_framework/mmap_wrapper.cpp +++ b/tests/mir_test_framework/mmap_wrapper.cpp @@ -39,18 +39,6 @@ mtf::MmapHandlerHandle mtf::add_mmap_handler(MmapHandler handler) return MmapInterposer::add(std::move(handler)); } -auto real_mmap_symbol_name() -> char const* -{ -#if _FILE_OFFSET_BITS == 64 - // mmap64 is defined everywhere, so even though off_t == off64_t on 64-bit platforms - // this is still appropriate. - return "mmap64"; -#else - // This will get us the 32-bit off_t version on 32-bit platforms - return "mmap"; -#endif -} - void* mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { if (auto val = MmapInterposer::run(addr, length, prot, flags, fd, offset)) @@ -58,16 +46,19 @@ void* mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) return *val; } - void* (*real_mmap)(void *addr, size_t length, int prot, int flags, int fd, off_t offset); - *(void **)(&real_mmap) = dlsym(RTLD_NEXT, real_mmap_symbol_name()); + static void* (*real_mmap)(void *addr, size_t length, int prot, int flags, int fd, off_t offset); + + // Where mmap64 is defined, even if off_t == off64_t on 64-bit platforms, this is still appropriate. + if (!real_mmap) + { + *(void **)(&real_mmap) = dlsym(RTLD_NEXT, "mmap64"); + } -#if _FILE_OFFSET_BITS == 64 - // Empirically, mmap64 is NOT defined everywhere, but on 64-bit platforms this is appropriate + // Empirically, mmap64 is NOT defined everywhere, but then this is appropriate if (!real_mmap) { - *(void **)(&real_mmap) = dlsym(RTLD_NEXT, "mmap"); + *(void **)(&real_mmap) = dlsym(RTLD_NEXT, __func__); } -#endif if (!real_mmap) { diff --git a/tests/miral/CMakeLists.txt b/tests/miral/CMakeLists.txt index 60d9aca67a8..e7d52891c62 100644 --- a/tests/miral/CMakeLists.txt +++ b/tests/miral/CMakeLists.txt @@ -76,7 +76,7 @@ mir_add_wrapped_executable(miral-test NOINSTALL org_kde_kwin_server_decoration.c org_kde_kwin_server_decoration.h ) -mir_generate_protocol_wrapper(miral-test "org_kde_kwin_" protocol/server-decoration.xml) +mir_generate_protocol_wrapper(miral-test "org_kde_kwin_" server-decoration.xml) set_source_files_properties(server_example_decoration.cpp PROPERTIES COMPILE_FLAGS "-I${CMAKE_CURRENT_BINARY_DIR}") diff --git a/tests/performance-tests/CMakeLists.txt b/tests/performance-tests/CMakeLists.txt index 61645e32cc6..e39ef538c4e 100644 --- a/tests/performance-tests/CMakeLists.txt +++ b/tests/performance-tests/CMakeLists.txt @@ -18,12 +18,13 @@ install(PROGRAMS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/mir-smoke-test-runner DESTINATION ${CMAKE_INSTALL_BINDIR} ) +find_program(EGLINFO_EXECUTABLE eglinfo) find_program(XVFB_RUN_EXECUTABLE xvfb-run) find_program(GLMARK2_EXECUTABLE glmark2-es2-wayland) CMAKE_DEPENDENT_OPTION( MIR_RUN_SMOKE_TESTS "Run mir-smoke-test-runner as part of testsuite" ON - "XVFB_RUN_EXECUTABLE" OFF + "EGLINFO_EXECUTABLE;XVFB_RUN_EXECUTABLE" OFF ) CMAKE_DEPENDENT_OPTION( diff --git a/tests/unit-tests/graphics/test_multiplexing_display.cpp b/tests/unit-tests/graphics/test_multiplexing_display.cpp index dfa83582d96..34321b7b32c 100644 --- a/tests/unit-tests/graphics/test_multiplexing_display.cpp +++ b/tests/unit-tests/graphics/test_multiplexing_display.cpp @@ -679,6 +679,10 @@ TEST(MultiplexingDisplay, applies_initial_display_configuration) }); } + void confirm(mg::DisplayConfiguration const&) override + { + } + auto expected_location_for_display(mg::DisplayConfigurationOutput const& display) -> geom::Point { auto it = std::find_if( diff --git a/tests/unit-tests/graphics/test_shm_buffer.cpp b/tests/unit-tests/graphics/test_shm_buffer.cpp index 9ac627ca5b0..ff46e573f32 100644 --- a/tests/unit-tests/graphics/test_shm_buffer.cpp +++ b/tests/unit-tests/graphics/test_shm_buffer.cpp @@ -21,8 +21,6 @@ #include "mir/test/doubles/mock_gl.h" #include "mir/test/doubles/mock_egl.h" -#include "check_gtest_version.h" - #include #include #include @@ -286,7 +284,6 @@ std::string to_string(MirPixelFormat format) } } -#if GTEST_AT_LEAST(1, 8, 0) INSTANTIATE_TEST_SUITE_P( ShmBuffer, UploadTest, @@ -295,13 +292,6 @@ INSTANTIATE_TEST_SUITE_P( { return std::to_string(info.param.format); }); -#else -// TODO: The version of gtest in 16.04 doesn't have the “print the test nicely” option. -INSTANTIATE_TEST_SUITE_P( - ShmBuffer, - UploadTest, - ValuesIn(test_cases)); -#endif namespace { diff --git a/tests/unit-tests/platforms/gbm-kms/kms/test_display_multi_monitor.cpp b/tests/unit-tests/platforms/gbm-kms/kms/test_display_multi_monitor.cpp index 8f34ccd195e..111a1dcc7fa 100644 --- a/tests/unit-tests/platforms/gbm-kms/kms/test_display_multi_monitor.cpp +++ b/tests/unit-tests/platforms/gbm-kms/kms/test_display_multi_monitor.cpp @@ -76,6 +76,10 @@ class ClonedDisplayConfigurationPolicy : public mg::DisplayConfigurationPolicy } }); } + + void confirm(mg::DisplayConfiguration const&) + { + } }; class SideBySideDisplayConfigurationPolicy : public mg::DisplayConfigurationPolicy @@ -105,6 +109,10 @@ class SideBySideDisplayConfigurationPolicy : public mg::DisplayConfigurationPoli } }); } + + void confirm(mg::DisplayConfiguration const&) + { + } }; class MesaDisplayMultiMonitorTest : public ::testing::Test diff --git a/tests/unit-tests/scene/test_mediating_display_changer.cpp b/tests/unit-tests/scene/test_mediating_display_changer.cpp index e726846f030..671c45a5441 100644 --- a/tests/unit-tests/scene/test_mediating_display_changer.cpp +++ b/tests/unit-tests/scene/test_mediating_display_changer.cpp @@ -55,6 +55,7 @@ class MockDisplayConfigurationPolicy : public mg::DisplayConfigurationPolicy public: ~MockDisplayConfigurationPolicy() noexcept {} MOCK_METHOD(void, apply_to, (mg::DisplayConfiguration&)); + MOCK_METHOD(void, confirm, (mg::DisplayConfiguration const&)); }; diff --git a/src/wayland/protocol/ext-session-lock-v1.xml b/wayland-protocols/ext-session-lock-v1.xml similarity index 100% rename from src/wayland/protocol/ext-session-lock-v1.xml rename to wayland-protocols/ext-session-lock-v1.xml diff --git a/src/wayland/protocol/idle-inhibit-unstable-v1.xml b/wayland-protocols/idle-inhibit-unstable-v1.xml similarity index 100% rename from src/wayland/protocol/idle-inhibit-unstable-v1.xml rename to wayland-protocols/idle-inhibit-unstable-v1.xml diff --git a/src/wayland/protocol/input-method-unstable-v1.xml b/wayland-protocols/input-method-unstable-v1.xml similarity index 100% rename from src/wayland/protocol/input-method-unstable-v1.xml rename to wayland-protocols/input-method-unstable-v1.xml diff --git a/src/wayland/protocol/input-method-unstable-v2.xml b/wayland-protocols/input-method-unstable-v2.xml similarity index 100% rename from src/wayland/protocol/input-method-unstable-v2.xml rename to wayland-protocols/input-method-unstable-v2.xml diff --git a/src/platform/graphics/protocol/linux-dmabuf-unstable-v1.xml b/wayland-protocols/linux-dmabuf-unstable-v1.xml similarity index 100% rename from src/platform/graphics/protocol/linux-dmabuf-unstable-v1.xml rename to wayland-protocols/linux-dmabuf-unstable-v1.xml diff --git a/src/wayland/protocol/pointer-constraints-unstable-v1.xml b/wayland-protocols/pointer-constraints-unstable-v1.xml similarity index 100% rename from src/wayland/protocol/pointer-constraints-unstable-v1.xml rename to wayland-protocols/pointer-constraints-unstable-v1.xml diff --git a/src/wayland/protocol/primary-selection-unstable-v1.xml b/wayland-protocols/primary-selection-unstable-v1.xml similarity index 100% rename from src/wayland/protocol/primary-selection-unstable-v1.xml rename to wayland-protocols/primary-selection-unstable-v1.xml diff --git a/src/wayland/protocol/relative-pointer-unstable-v1.xml b/wayland-protocols/relative-pointer-unstable-v1.xml similarity index 100% rename from src/wayland/protocol/relative-pointer-unstable-v1.xml rename to wayland-protocols/relative-pointer-unstable-v1.xml diff --git a/tests/miral/protocol/server-decoration.xml b/wayland-protocols/server-decoration.xml similarity index 100% rename from tests/miral/protocol/server-decoration.xml rename to wayland-protocols/server-decoration.xml diff --git a/src/wayland/protocol/text-input-unstable-v1.xml b/wayland-protocols/text-input-unstable-v1.xml similarity index 100% rename from src/wayland/protocol/text-input-unstable-v1.xml rename to wayland-protocols/text-input-unstable-v1.xml diff --git a/src/wayland/protocol/text-input-unstable-v2.xml b/wayland-protocols/text-input-unstable-v2.xml similarity index 100% rename from src/wayland/protocol/text-input-unstable-v2.xml rename to wayland-protocols/text-input-unstable-v2.xml diff --git a/src/wayland/protocol/text-input-unstable-v3.xml b/wayland-protocols/text-input-unstable-v3.xml similarity index 100% rename from src/wayland/protocol/text-input-unstable-v3.xml rename to wayland-protocols/text-input-unstable-v3.xml diff --git a/src/wayland/protocol/virtual-keyboard-unstable-v1.xml b/wayland-protocols/virtual-keyboard-unstable-v1.xml similarity index 100% rename from src/wayland/protocol/virtual-keyboard-unstable-v1.xml rename to wayland-protocols/virtual-keyboard-unstable-v1.xml diff --git a/src/wayland/protocol/wayland.xml b/wayland-protocols/wayland.xml similarity index 100% rename from src/wayland/protocol/wayland.xml rename to wayland-protocols/wayland.xml diff --git a/src/wayland/protocol/wlr-foreign-toplevel-management-unstable-v1.xml b/wayland-protocols/wlr-foreign-toplevel-management-unstable-v1.xml similarity index 100% rename from src/wayland/protocol/wlr-foreign-toplevel-management-unstable-v1.xml rename to wayland-protocols/wlr-foreign-toplevel-management-unstable-v1.xml diff --git a/src/wayland/protocol/wlr-layer-shell-unstable-v1.xml b/wayland-protocols/wlr-layer-shell-unstable-v1.xml similarity index 100% rename from src/wayland/protocol/wlr-layer-shell-unstable-v1.xml rename to wayland-protocols/wlr-layer-shell-unstable-v1.xml diff --git a/src/wayland/protocol/wlr-screencopy-unstable-v1.xml b/wayland-protocols/wlr-screencopy-unstable-v1.xml similarity index 100% rename from src/wayland/protocol/wlr-screencopy-unstable-v1.xml rename to wayland-protocols/wlr-screencopy-unstable-v1.xml diff --git a/src/wayland/protocol/wlr-virtual-pointer-unstable-v1.xml b/wayland-protocols/wlr-virtual-pointer-unstable-v1.xml similarity index 100% rename from src/wayland/protocol/wlr-virtual-pointer-unstable-v1.xml rename to wayland-protocols/wlr-virtual-pointer-unstable-v1.xml diff --git a/src/wayland/protocol/xdg-output-unstable-v1.xml b/wayland-protocols/xdg-output-unstable-v1.xml similarity index 100% rename from src/wayland/protocol/xdg-output-unstable-v1.xml rename to wayland-protocols/xdg-output-unstable-v1.xml diff --git a/src/wayland/protocol/xdg-shell-unstable-v6.xml b/wayland-protocols/xdg-shell-unstable-v6.xml similarity index 100% rename from src/wayland/protocol/xdg-shell-unstable-v6.xml rename to wayland-protocols/xdg-shell-unstable-v6.xml diff --git a/src/wayland/protocol/xdg-shell.xml b/wayland-protocols/xdg-shell.xml similarity index 100% rename from src/wayland/protocol/xdg-shell.xml rename to wayland-protocols/xdg-shell.xml