From 4ae5b4f8b82f42a60350edfb7ca9e7c80f751126 Mon Sep 17 00:00:00 2001 From: Colin Kinloch Date: Sun, 28 May 2023 01:04:24 +0100 Subject: [PATCH] Wayland: Use viewporter (#836) --- CMakeLists.txt | 11 +- cmake/ECMFindModuleHelpers.cmake | 279 +++++++++++++++++++++++++++ cmake/ECMFindModuleHelpersStub.cmake | 1 + cmake/FindWayland.cmake | 141 +++++++++++++- cmake/FindWaylandProtocols.cmake | 38 ++++ cmake/FindWaylandScanner.cmake | 162 ++++++++++++++++ src/Cafe/CMakeLists.txt | 2 +- src/gui/CMakeLists.txt | 2 +- src/gui/canvas/VulkanCanvas.cpp | 5 +- src/gui/helpers/wxWayland.h | 27 ++- 10 files changed, 647 insertions(+), 21 deletions(-) create mode 100644 cmake/ECMFindModuleHelpers.cmake create mode 100644 cmake/ECMFindModuleHelpersStub.cmake create mode 100644 cmake/FindWaylandProtocols.cmake create mode 100644 cmake/FindWaylandScanner.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ce81a04..26d676bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,7 +125,16 @@ endif() if (UNIX AND NOT APPLE) find_package(X11 REQUIRED) if (ENABLE_WAYLAND) - find_package(Wayland REQUIRED) + find_package(Wayland REQUIRED Client) + find_package(WaylandScanner REQUIRED) + find_package(WaylandProtocols 1.15 REQUIRED) + + ecm_add_wayland_client_protocol(WAYLAND_PROTOCOL_SRCS + PROTOCOL "${WaylandProtocols_DATADIR}/stable/viewporter/viewporter.xml" + BASENAME viewporter) + add_library(CemuWaylandProtocols STATIC ${WAYLAND_PROTOCOL_SRCS}) + target_include_directories(CemuWaylandProtocols PUBLIC "${CMAKE_CURRENT_BINARY_DIR}") + add_compile_definitions(HAS_WAYLAND) endif() find_package(GTK3 REQUIRED) diff --git a/cmake/ECMFindModuleHelpers.cmake b/cmake/ECMFindModuleHelpers.cmake new file mode 100644 index 00000000..a4837403 --- /dev/null +++ b/cmake/ECMFindModuleHelpers.cmake @@ -0,0 +1,279 @@ +# SPDX-FileCopyrightText: 2014 Alex Merry +# +# SPDX-License-Identifier: BSD-3-Clause + +#[=======================================================================[.rst: +ECMFindModuleHelpers +-------------------- + +Helper macros for find modules: ``ecm_find_package_version_check()``, +``ecm_find_package_parse_components()`` and +``ecm_find_package_handle_library_components()``. + +:: + + ecm_find_package_version_check() + +Prints warnings if the CMake version or the project's required CMake version +is older than that required by extra-cmake-modules. + +:: + + ecm_find_package_parse_components( + RESULT_VAR + KNOWN_COMPONENTS [ [...]] + [SKIP_DEPENDENCY_HANDLING]) + +This macro will populate with a list of components found in +_FIND_COMPONENTS, after checking that all those components are in the +list of ``KNOWN_COMPONENTS``; if there are any unknown components, it will print +an error or warning (depending on the value of _FIND_REQUIRED) and call +``return()``. + +The order of components in is guaranteed to match the order they +are listed in the ``KNOWN_COMPONENTS`` argument. + +If ``SKIP_DEPENDENCY_HANDLING`` is not set, for each component the variable +__component_deps will be checked for dependent components. +If is listed in _FIND_COMPONENTS, then all its (transitive) +dependencies will also be added to . + +:: + + ecm_find_package_handle_library_components( + COMPONENTS [ [...]] + [SKIP_DEPENDENCY_HANDLING]) + [SKIP_PKG_CONFIG]) + +Creates an imported library target for each component. The operation of this +macro depends on the presence of a number of CMake variables. + +The __lib variable should contain the name of this library, +and __header variable should contain the name of a header +file associated with it (whatever relative path is normally passed to +'#include'). __header_subdir variable can be used to specify +which subdirectory of the include path the headers will be found in. +``ecm_find_package_components()`` will then search for the library +and include directory (creating appropriate cache variables) and create an +imported library target named ::. + +Additional variables can be used to provide additional information: + +If ``SKIP_PKG_CONFIG``, the __pkg_config variable is set, and +pkg-config is found, the pkg-config module given by +__pkg_config will be searched for and used to help locate the +library and header file. It will also be used to set +__VERSION. + +Note that if version information is found via pkg-config, +__FIND_VERSION can be set to require a particular version +for each component. + +If ``SKIP_DEPENDENCY_HANDLING`` is not set, the ``INTERFACE_LINK_LIBRARIES`` property +of the imported target for will be set to contain the imported +targets for the components listed in __component_deps. +_FOUND will also be set to ``FALSE`` if any of the components in +__component_deps are not found. This requires the components +in __component_deps to be listed before in the +``COMPONENTS`` argument. + +The following variables will be set: + +``_TARGETS`` + the imported targets +``_LIBRARIES`` + the found libraries +``_INCLUDE_DIRS`` + the combined required include directories for the components +``_DEFINITIONS`` + the "other" CFLAGS provided by pkg-config, if any +``_VERSION`` + the value of ``__VERSION`` for the first component that + has this variable set (note that components are searched for in the order + they are passed to the macro), although if it is already set, it will not + be altered + +.. note:: + These variables are never cleared, so if + ``ecm_find_package_handle_library_components()`` is called multiple times with + different components (typically because of multiple ``find_package()`` calls) then + ``_TARGETS``, for example, will contain all the targets found in any + call (although no duplicates). + +Since pre-1.0.0. +#]=======================================================================] + +include(CMakeParseArguments) + +macro(ecm_find_package_version_check module_name) + if(CMAKE_VERSION VERSION_LESS 3.16.0) + message(FATAL_ERROR "CMake 3.16.0 is required by Find${module_name}.cmake") + endif() + if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 3.16.0) + message(AUTHOR_WARNING "Your project should require at least CMake 3.16.0 to use Find${module_name}.cmake") + endif() +endmacro() + +macro(ecm_find_package_parse_components module_name) + set(ecm_fppc_options SKIP_DEPENDENCY_HANDLING) + set(ecm_fppc_oneValueArgs RESULT_VAR) + set(ecm_fppc_multiValueArgs KNOWN_COMPONENTS DEFAULT_COMPONENTS) + cmake_parse_arguments(ECM_FPPC "${ecm_fppc_options}" "${ecm_fppc_oneValueArgs}" "${ecm_fppc_multiValueArgs}" ${ARGN}) + + if(ECM_FPPC_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unexpected arguments to ecm_find_package_parse_components: ${ECM_FPPC_UNPARSED_ARGUMENTS}") + endif() + if(NOT ECM_FPPC_RESULT_VAR) + message(FATAL_ERROR "Missing RESULT_VAR argument to ecm_find_package_parse_components") + endif() + if(NOT ECM_FPPC_KNOWN_COMPONENTS) + message(FATAL_ERROR "Missing KNOWN_COMPONENTS argument to ecm_find_package_parse_components") + endif() + if(NOT ECM_FPPC_DEFAULT_COMPONENTS) + set(ECM_FPPC_DEFAULT_COMPONENTS ${ECM_FPPC_KNOWN_COMPONENTS}) + endif() + + if(${module_name}_FIND_COMPONENTS) + set(ecm_fppc_requestedComps ${${module_name}_FIND_COMPONENTS}) + + if(NOT ECM_FPPC_SKIP_DEPENDENCY_HANDLING) + # Make sure deps are included + foreach(ecm_fppc_comp ${ecm_fppc_requestedComps}) + foreach(ecm_fppc_dep_comp ${${module_name}_${ecm_fppc_comp}_component_deps}) + list(FIND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}" ecm_fppc_index) + if("${ecm_fppc_index}" STREQUAL "-1") + if(NOT ${module_name}_FIND_QUIETLY) + message(STATUS "${module_name}: ${ecm_fppc_comp} requires ${${module_name}_${ecm_fppc_comp}_component_deps}") + endif() + list(APPEND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}") + endif() + endforeach() + endforeach() + else() + message(STATUS "Skipping dependency handling for ${module_name}") + endif() + list(REMOVE_DUPLICATES ecm_fppc_requestedComps) + + # This makes sure components are listed in the same order as + # KNOWN_COMPONENTS (potentially important for inter-dependencies) + set(${ECM_FPPC_RESULT_VAR}) + foreach(ecm_fppc_comp ${ECM_FPPC_KNOWN_COMPONENTS}) + list(FIND ecm_fppc_requestedComps "${ecm_fppc_comp}" ecm_fppc_index) + if(NOT "${ecm_fppc_index}" STREQUAL "-1") + list(APPEND ${ECM_FPPC_RESULT_VAR} "${ecm_fppc_comp}") + list(REMOVE_AT ecm_fppc_requestedComps ${ecm_fppc_index}) + endif() + endforeach() + # if there are any left, they are unknown components + if(ecm_fppc_requestedComps) + set(ecm_fppc_msgType STATUS) + if(${module_name}_FIND_REQUIRED) + set(ecm_fppc_msgType FATAL_ERROR) + endif() + if(NOT ${module_name}_FIND_QUIETLY) + message(${ecm_fppc_msgType} "${module_name}: requested unknown components ${ecm_fppc_requestedComps}") + endif() + return() + endif() + else() + set(${ECM_FPPC_RESULT_VAR} ${ECM_FPPC_DEFAULT_COMPONENTS}) + endif() +endmacro() + +macro(ecm_find_package_handle_library_components module_name) + set(ecm_fpwc_options SKIP_PKG_CONFIG SKIP_DEPENDENCY_HANDLING) + set(ecm_fpwc_oneValueArgs) + set(ecm_fpwc_multiValueArgs COMPONENTS) + cmake_parse_arguments(ECM_FPWC "${ecm_fpwc_options}" "${ecm_fpwc_oneValueArgs}" "${ecm_fpwc_multiValueArgs}" ${ARGN}) + + if(ECM_FPWC_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unexpected arguments to ecm_find_package_handle_components: ${ECM_FPWC_UNPARSED_ARGUMENTS}") + endif() + if(NOT ECM_FPWC_COMPONENTS) + message(FATAL_ERROR "Missing COMPONENTS argument to ecm_find_package_handle_components") + endif() + + include(FindPackageHandleStandardArgs) + find_package(PkgConfig QUIET) + foreach(ecm_fpwc_comp ${ECM_FPWC_COMPONENTS}) + set(ecm_fpwc_dep_vars) + set(ecm_fpwc_dep_targets) + if(NOT SKIP_DEPENDENCY_HANDLING) + foreach(ecm_fpwc_dep ${${module_name}_${ecm_fpwc_comp}_component_deps}) + list(APPEND ecm_fpwc_dep_vars "${module_name}_${ecm_fpwc_dep}_FOUND") + list(APPEND ecm_fpwc_dep_targets "${module_name}::${ecm_fpwc_dep}") + endforeach() + endif() + + if(NOT ECM_FPWC_SKIP_PKG_CONFIG AND ${module_name}_${ecm_fpwc_comp}_pkg_config) + pkg_check_modules(PKG_${module_name}_${ecm_fpwc_comp} QUIET + ${${module_name}_${ecm_fpwc_comp}_pkg_config}) + endif() + + find_path(${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR + NAMES ${${module_name}_${ecm_fpwc_comp}_header} + HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_INCLUDE_DIRS} + PATH_SUFFIXES ${${module_name}_${ecm_fpwc_comp}_header_subdir} + ) + find_library(${module_name}_${ecm_fpwc_comp}_LIBRARY + NAMES ${${module_name}_${ecm_fpwc_comp}_lib} + HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_LIBRARY_DIRS} + ) + + set(${module_name}_${ecm_fpwc_comp}_VERSION "${PKG_${module_name}_${ecm_fpwc_comp}_VERSION}") + if(NOT ${module_name}_VERSION) + set(${module_name}_VERSION ${${module_name}_${ecm_fpwc_comp}_VERSION}) + endif() + + set(FPHSA_NAME_MISMATCHED 1) + find_package_handle_standard_args(${module_name}_${ecm_fpwc_comp} + FOUND_VAR + ${module_name}_${ecm_fpwc_comp}_FOUND + REQUIRED_VARS + ${module_name}_${ecm_fpwc_comp}_LIBRARY + ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR + ${ecm_fpwc_dep_vars} + VERSION_VAR + ${module_name}_${ecm_fpwc_comp}_VERSION + ) + unset(FPHSA_NAME_MISMATCHED) + + mark_as_advanced( + ${module_name}_${ecm_fpwc_comp}_LIBRARY + ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR + ) + + if(${module_name}_${ecm_fpwc_comp}_FOUND) + list(APPEND ${module_name}_LIBRARIES + "${${module_name}_${ecm_fpwc_comp}_LIBRARY}") + list(APPEND ${module_name}_INCLUDE_DIRS + "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}") + set(${module_name}_DEFINITIONS + ${${module_name}_DEFINITIONS} + ${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS}) + if(NOT TARGET ${module_name}::${ecm_fpwc_comp}) + add_library(${module_name}::${ecm_fpwc_comp} UNKNOWN IMPORTED) + set_target_properties(${module_name}::${ecm_fpwc_comp} PROPERTIES + IMPORTED_LOCATION "${${module_name}_${ecm_fpwc_comp}_LIBRARY}" + INTERFACE_COMPILE_OPTIONS "${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS}" + INTERFACE_INCLUDE_DIRECTORIES "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}" + INTERFACE_LINK_LIBRARIES "${ecm_fpwc_dep_targets}" + ) + endif() + list(APPEND ${module_name}_TARGETS + "${module_name}::${ecm_fpwc_comp}") + endif() + endforeach() + if(${module_name}_LIBRARIES) + list(REMOVE_DUPLICATES ${module_name}_LIBRARIES) + endif() + if(${module_name}_INCLUDE_DIRS) + list(REMOVE_DUPLICATES ${module_name}_INCLUDE_DIRS) + endif() + if(${module_name}_DEFINITIONS) + list(REMOVE_DUPLICATES ${module_name}_DEFINITIONS) + endif() + if(${module_name}_TARGETS) + list(REMOVE_DUPLICATES ${module_name}_TARGETS) + endif() +endmacro() diff --git a/cmake/ECMFindModuleHelpersStub.cmake b/cmake/ECMFindModuleHelpersStub.cmake new file mode 100644 index 00000000..acc8c804 --- /dev/null +++ b/cmake/ECMFindModuleHelpersStub.cmake @@ -0,0 +1 @@ +include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpers.cmake) diff --git a/cmake/FindWayland.cmake b/cmake/FindWayland.cmake index 813bcf06..926fd485 100644 --- a/cmake/FindWayland.cmake +++ b/cmake/FindWayland.cmake @@ -1,14 +1,137 @@ -find_package(PkgConfig) +# SPDX-FileCopyrightText: 2014 Alex Merry +# SPDX-FileCopyrightText: 2014 Martin Gräßlin +# +# SPDX-License-Identifier: BSD-3-Clause -pkg_search_module(WAYLAND_CLIENT IMPORTED_TARGET wayland-client) +#[=======================================================================[.rst: +FindWayland +----------- -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Wayland - REQUIRED_VARS - WAYLAND_CLIENT_LIBRARIES - VERSION_VAR WAYLAND_CLIENT_VERSION +Try to find Wayland. + +This is a component-based find module, which makes use of the COMPONENTS +and OPTIONAL_COMPONENTS arguments to find_module. The following components +are available:: + + Client Server Cursor Egl + +If no components are specified, this module will act as though all components +were passed to OPTIONAL_COMPONENTS. + +This module will define the following variables, independently of the +components searched for or found: + +``Wayland_FOUND`` + TRUE if (the requested version of) Wayland is available +``Wayland_VERSION`` + Found Wayland version +``Wayland_TARGETS`` + A list of all targets imported by this module (note that there may be more + than the components that were requested) +``Wayland_LIBRARIES`` + This can be passed to target_link_libraries() instead of the imported + targets +``Wayland_INCLUDE_DIRS`` + This should be passed to target_include_directories() if the targets are + not used for linking +``Wayland_DEFINITIONS`` + This should be passed to target_compile_options() if the targets are not + used for linking +``Wayland_DATADIR`` + The core wayland protocols data directory + Since 5.73.0 + +For each searched-for components, ``Wayland__FOUND`` will be set to +TRUE if the corresponding Wayland library was found, and FALSE otherwise. If +``Wayland__FOUND`` is TRUE, the imported target +``Wayland::`` will be defined. This module will also attempt to +determine ``Wayland_*_VERSION`` variables for each imported target, although +``Wayland_VERSION`` should normally be sufficient. + +In general we recommend using the imported targets, as they are easier to use +and provide more control. Bear in mind, however, that if any target is in the +link interface of an exported library, it must be made available by the +package config file. + +Since pre-1.0.0. +#]=======================================================================] + +include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake) + +ecm_find_package_version_check(Wayland) + +set(Wayland_known_components + Client + Server + Cursor + Egl +) +foreach(_comp ${Wayland_known_components}) + string(TOLOWER "${_comp}" _lc_comp) + set(Wayland_${_comp}_component_deps) + set(Wayland_${_comp}_pkg_config "wayland-${_lc_comp}") + set(Wayland_${_comp}_lib "wayland-${_lc_comp}") + set(Wayland_${_comp}_header "wayland-${_lc_comp}.h") +endforeach() +set(Wayland_Egl_component_deps Client) + +ecm_find_package_parse_components(Wayland + RESULT_VAR Wayland_components + KNOWN_COMPONENTS ${Wayland_known_components} +) +ecm_find_package_handle_library_components(Wayland + COMPONENTS ${Wayland_components} ) -if (Wayland_FOUND) - add_library(Wayland::client ALIAS PkgConfig::WAYLAND_CLIENT) +# If pkg-config didn't provide us with version information, +# try to extract it from wayland-version.h +# (Note that the version from wayland-egl.pc will probably be +# the Mesa version, rather than the Wayland version, but that +# version will be ignored as we always find wayland-client.pc +# first). +if(NOT Wayland_VERSION) + find_file(Wayland_VERSION_HEADER + NAMES wayland-version.h + HINTS ${Wayland_INCLUDE_DIRS} + ) + mark_as_advanced(Wayland_VERSION_HEADER) + if(Wayland_VERSION_HEADER) + file(READ ${Wayland_VERSION_HEADER} _wayland_version_header_contents) + string(REGEX REPLACE + "^.*[ \t]+WAYLAND_VERSION[ \t]+\"([0-9.]*)\".*$" + "\\1" + Wayland_VERSION + "${_wayland_version_header_contents}" + ) + unset(_wayland_version_header_contents) + endif() endif() + +find_package_handle_standard_args(Wayland + FOUND_VAR + Wayland_FOUND + REQUIRED_VARS + Wayland_LIBRARIES + VERSION_VAR + Wayland_VERSION + HANDLE_COMPONENTS +) + +pkg_get_variable(Wayland_DATADIR wayland-scanner pkgdatadir) +if (CMAKE_CROSSCOMPILING AND (NOT EXISTS "${Wayland_DATADIR}/wayland.xml")) + # PKG_CONFIG_SYSROOT_DIR only applies to -I and -L flags, so pkg-config + # does not prepend CMAKE_SYSROOT when cross-compiling unless you pass + # --define-prefix explicitly. Therefore we have to manually do prepend + # it here when cross-compiling. + # See https://gitlab.kitware.com/cmake/cmake/-/issues/16647#note_844761 + set(Wayland_DATADIR ${CMAKE_SYSROOT}${Wayland_DATADIR}) +endif() +if (NOT EXISTS "${Wayland_DATADIR}/wayland.xml") + message(WARNING "Could not find wayland.xml in ${Wayland_DATADIR}") +endif() + +include(FeatureSummary) +set_package_properties(Wayland PROPERTIES + URL "https://wayland.freedesktop.org/" + DESCRIPTION "C library implementation of the Wayland protocol: a protocol for a compositor to talk to its clients" +) diff --git a/cmake/FindWaylandProtocols.cmake b/cmake/FindWaylandProtocols.cmake new file mode 100644 index 00000000..a4449885 --- /dev/null +++ b/cmake/FindWaylandProtocols.cmake @@ -0,0 +1,38 @@ +# SPDX-FileCopyrightText: 2019 Vlad Zahorodnii +# +# SPDX-License-Identifier: BSD-3-Clause + +#[=======================================================================[.rst: +FindWaylandProtocols +-------------------- + +Try to find wayland-protocols on a Unix system. + +This will define the following variables: + +``WaylandProtocols_FOUND`` + True if (the requested version of) wayland-protocols is available +``WaylandProtocols_VERSION`` + The version of wayland-protocols +``WaylandProtocols_DATADIR`` + The wayland protocols data directory +#]=======================================================================] + +find_package(PkgConfig QUIET) +pkg_check_modules(PKG_wayland_protocols QUIET wayland-protocols) + +set(WaylandProtocols_VERSION ${PKG_wayland_protocols_VERSION}) +pkg_get_variable(WaylandProtocols_DATADIR wayland-protocols pkgdatadir) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(WaylandProtocols + FOUND_VAR WaylandProtocols_FOUND + REQUIRED_VARS WaylandProtocols_DATADIR + VERSION_VAR WaylandProtocols_VERSION +) + +include(FeatureSummary) +set_package_properties(WaylandProtocols PROPERTIES + DESCRIPTION "Specifications of extended Wayland protocols" + URL "https://wayland.freedesktop.org/" +) diff --git a/cmake/FindWaylandScanner.cmake b/cmake/FindWaylandScanner.cmake new file mode 100644 index 00000000..f8495800 --- /dev/null +++ b/cmake/FindWaylandScanner.cmake @@ -0,0 +1,162 @@ +# SPDX-FileCopyrightText: 2012-2014 Pier Luigi Fiorini +# +# SPDX-License-Identifier: BSD-3-Clause + +#[=======================================================================[.rst: +FindWaylandScanner +------------------ + +Try to find wayland-scanner. + +If the wayland-scanner executable is not in your PATH, you can provide +an alternative name or full path location with the ``WaylandScanner_EXECUTABLE`` +variable. + +This will define the following variables: + +``WaylandScanner_FOUND`` + True if wayland-scanner is available. + +``WaylandScanner_EXECUTABLE`` + The wayland-scanner executable. + +If ``WaylandScanner_FOUND`` is TRUE, it will also define the following imported +target: + +``Wayland::Scanner`` + The wayland-scanner executable. + +This module provides the following functions to generate C protocol +implementations: + + - ``ecm_add_wayland_client_protocol`` + - ``ecm_add_wayland_server_protocol`` + +:: + + ecm_add_wayland_client_protocol( + PROTOCOL + BASENAME ) + + ecm_add_wayland_client_protocol( + PROTOCOL + BASENAME ) + +Generate Wayland client protocol files from ```` XML +definition for the ```` interface and append those files +to ```` or ````. + +:: + + ecm_add_wayland_server_protocol( + PROTOCOL + BASENAME ) + + ecm_add_wayland_server_protocol( + PROTOCOL + BASENAME ) + +Generate Wayland server protocol files from ```` XML +definition for the ```` interface and append those files +to ```` or ````. + +Since 1.4.0. +#]=======================================================================] + +include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake) + +ecm_find_package_version_check(WaylandScanner) + +# Find wayland-scanner +find_program(WaylandScanner_EXECUTABLE NAMES wayland-scanner) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(WaylandScanner + FOUND_VAR + WaylandScanner_FOUND + REQUIRED_VARS + WaylandScanner_EXECUTABLE +) + +mark_as_advanced(WaylandScanner_EXECUTABLE) + +if(NOT TARGET Wayland::Scanner AND WaylandScanner_FOUND) + add_executable(Wayland::Scanner IMPORTED) + set_target_properties(Wayland::Scanner PROPERTIES + IMPORTED_LOCATION "${WaylandScanner_EXECUTABLE}" + ) +endif() + +include(FeatureSummary) +set_package_properties(WaylandScanner PROPERTIES + URL "https://wayland.freedesktop.org/" + DESCRIPTION "Executable that converts XML protocol files to C code" +) + + +include(CMakeParseArguments) + +function(ecm_add_wayland_client_protocol target_or_sources_var) + # Parse arguments + set(oneValueArgs PROTOCOL BASENAME) + cmake_parse_arguments(ARGS "" "${oneValueArgs}" "" ${ARGN}) + + if(ARGS_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown keywords given to ecm_add_wayland_client_protocol(): \"${ARGS_UNPARSED_ARGUMENTS}\"") + endif() + + get_filename_component(_infile ${ARGS_PROTOCOL} ABSOLUTE) + set(_client_header "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-client-protocol.h") + set(_code "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-protocol.c") + + set_source_files_properties(${_client_header} GENERATED) + set_source_files_properties(${_code} GENERATED) + set_property(SOURCE ${_client_header} ${_code} PROPERTY SKIP_AUTOMOC ON) + + add_custom_command(OUTPUT "${_client_header}" + COMMAND ${WaylandScanner_EXECUTABLE} client-header ${_infile} ${_client_header} + DEPENDS ${_infile} VERBATIM) + + add_custom_command(OUTPUT "${_code}" + COMMAND ${WaylandScanner_EXECUTABLE} public-code ${_infile} ${_code} + DEPENDS ${_infile} ${_client_header} VERBATIM) + + if (TARGET ${target_or_sources_var}) + target_sources(${target_or_sources_var} PRIVATE "${_client_header}" "${_code}") + else() + list(APPEND ${target_or_sources_var} "${_client_header}" "${_code}") + set(${target_or_sources_var} ${${target_or_sources_var}} PARENT_SCOPE) + endif() +endfunction() + + +function(ecm_add_wayland_server_protocol target_or_sources_var) + # Parse arguments + set(oneValueArgs PROTOCOL BASENAME) + cmake_parse_arguments(ARGS "" "${oneValueArgs}" "" ${ARGN}) + + if(ARGS_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown keywords given to ecm_add_wayland_server_protocol(): \"${ARGS_UNPARSED_ARGUMENTS}\"") + endif() + + ecm_add_wayland_client_protocol(${target_or_sources_var} + PROTOCOL ${ARGS_PROTOCOL} + BASENAME ${ARGS_BASENAME}) + + get_filename_component(_infile ${ARGS_PROTOCOL} ABSOLUTE) + set(_server_header "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-server-protocol.h") + set(_server_code "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-protocol.c") + set_property(SOURCE ${_server_header} ${_server_code} PROPERTY SKIP_AUTOMOC ON) + set_source_files_properties(${_server_header} GENERATED) + + add_custom_command(OUTPUT "${_server_header}" + COMMAND ${WaylandScanner_EXECUTABLE} server-header ${_infile} ${_server_header} + DEPENDS ${_infile} VERBATIM) + + if (TARGET ${target_or_sources_var}) + target_sources(${target_or_sources_var} PRIVATE "${_server_header}") + else() + list(APPEND ${target_or_sources_var} "${_server_header}") + set(${target_or_sources_var} ${${target_or_sources_var}} PARENT_SCOPE) + endif() +endfunction() diff --git a/src/Cafe/CMakeLists.txt b/src/Cafe/CMakeLists.txt index 0daffbb8..8da22176 100644 --- a/src/Cafe/CMakeLists.txt +++ b/src/Cafe/CMakeLists.txt @@ -505,7 +505,7 @@ target_link_libraries(CemuCafe PRIVATE if (ENABLE_WAYLAND) # PUBLIC because wayland-client.h is included in VulkanAPI.h - target_link_libraries(CemuCafe PUBLIC Wayland::client) + target_link_libraries(CemuCafe PUBLIC Wayland::Client) endif() if (ENABLE_WXWIDGETS) diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 74eaf7de..90dc91c0 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -153,7 +153,7 @@ if(ENABLE_WXWIDGETS AND UNIX AND NOT APPLE) # PUBLIC because gdk/gdkkeysyms.h is included in guiWrapper.h target_link_libraries(CemuGui PUBLIC GTK3::gtk) if (ENABLE_WAYLAND) - target_link_libraries(CemuGui PRIVATE Wayland::client) + target_link_libraries(CemuGui PRIVATE Wayland::Client CemuWaylandProtocols) endif() endif() diff --git a/src/gui/canvas/VulkanCanvas.cpp b/src/gui/canvas/VulkanCanvas.cpp index 00ebeb2d..ceddeb52 100644 --- a/src/gui/canvas/VulkanCanvas.cpp +++ b/src/gui/canvas/VulkanCanvas.cpp @@ -67,9 +67,8 @@ void VulkanCanvas::OnResize(wxSizeEvent& event) #if BOOST_OS_LINUX && HAS_WAYLAND if(m_subsurface) { - int32_t x,y; - GetScreenPosition(&x,&y); - m_subsurface->setPosition(x, y); + auto sRect = GetScreenRect(); + m_subsurface->setSize(sRect.GetX(), sRect.GetY(), sRect.GetWidth(), sRect.GetHeight()); } #endif const wxSize size = GetSize(); diff --git a/src/gui/helpers/wxWayland.h b/src/gui/helpers/wxWayland.h index f921783b..a3b82119 100644 --- a/src/gui/helpers/wxWayland.h +++ b/src/gui/helpers/wxWayland.h @@ -7,16 +7,22 @@ #include #include #include +#include "wayland-viewporter-client-protocol.h" class wxWlSubsurface { static void registry_add_object(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) { + auto wlSubsurface = static_cast(data); + if (!strcmp(interface, wl_subcompositor_interface.name)) { - auto wlSubsurface = static_cast(data); wlSubsurface->m_subcompositor = static_cast(wl_registry_bind(registry, name, &wl_subcompositor_interface, 1)); } + else if (!strcmp(interface, wp_viewporter_interface.name)) + { + wlSubsurface->m_viewporter = static_cast(wl_registry_bind(registry, name, &wp_viewporter_interface, 1)); + } } static void registry_remove_object(void* /*data*/, struct wl_registry* /*registry*/, uint32_t /*name*/) {} @@ -24,8 +30,12 @@ class wxWlSubsurface wl_subcompositor* m_subcompositor; wl_surface* m_surface; wl_subsurface* m_subsurface; + wp_viewporter* m_viewporter = NULL; + wp_viewport* m_viewport = NULL; int32_t m_xPos = 0; int32_t m_yPos = 0; + int32_t m_width = 0; + int32_t m_height = 0; public: wxWlSubsurface(wxWindow* window) @@ -41,25 +51,30 @@ public: wl_registry_add_listener(registry, &m_registry_listener, this); wl_display_roundtrip(display); m_surface = wl_compositor_create_surface(compositor); + if (m_viewporter) + m_viewport = wp_viewporter_get_viewport(m_viewporter, m_surface); wl_region* region = wl_compositor_create_region(compositor); wl_surface_set_input_region(m_surface, region); m_subsurface = wl_subcompositor_get_subsurface(m_subcompositor, m_surface, surface); wl_subsurface_set_desync(m_subsurface); - window->GetScreenPosition(&m_xPos, &m_yPos); - wl_subsurface_set_position(m_subsurface, m_xPos, m_yPos); - wl_surface_commit(m_surface); + auto sRect = window->GetScreenRect(); + setSize(sRect.x, sRect.y, sRect.width, sRect.height); wl_region_destroy(region); } wl_surface* getSurface() const { return m_surface; } - void setPosition(int32_t xPos, int32_t yPos) + void setSize(int32_t xPos, int32_t yPos, int32_t width, int32_t height) { - if (xPos != m_xPos || m_yPos != yPos) + if (xPos != m_xPos || m_yPos != yPos || m_width != width || m_height != height) { m_xPos = xPos; m_yPos = yPos; + m_height = height; + m_width = width; wl_subsurface_set_position(m_subsurface, m_xPos, m_yPos); + if (m_viewport) + wp_viewport_set_destination(m_viewport, m_width, m_height); wl_surface_commit(m_surface); } }