diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index 85e16e24..00000000 --- a/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[workspace] -members = ["src/core/rust/gst-wayland-display", "src/core/rust/gst-plugin-wayland-display"] - -[workspace.dependencies] -gst = { version = "0.20", package = "gstreamer", features = ["v1_18"] } -gst-video = { version = "0.20", package = "gstreamer-video", features = ["v1_18"] } -tracing = "0.1.37" -once_cell = "1.17.0" diff --git a/cmake/CMakeCargo.cmake b/cmake/CMakeCargo.cmake deleted file mode 100644 index b708fffe..00000000 --- a/cmake/CMakeCargo.cmake +++ /dev/null @@ -1,74 +0,0 @@ -function(cargo_build) - cmake_parse_arguments(CARGO "" "NAME" "" ${ARGN}) - string(REPLACE "-" "_" LIB_NAME ${CARGO_NAME}) - - set(CARGO_TARGET_DIR ${CMAKE_CURRENT_BINARY_DIR}) - - if(WIN32) - if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(LIB_TARGET "x86_64-pc-windows-msvc") - else() - set(LIB_TARGET "i686-pc-windows-msvc") - endif() - elseif(ANDROID) - if(ANDROID_SYSROOT_ABI STREQUAL "x86") - set(LIB_TARGET "i686-linux-android") - elseif(ANDROID_SYSROOT_ABI STREQUAL "x86_64") - set(LIB_TARGET "x86_64-linux-android") - elseif(ANDROID_SYSROOT_ABI STREQUAL "arm") - set(LIB_TARGET "arm-linux-androideabi") - elseif(ANDROID_SYSROOT_ABI STREQUAL "arm64") - set(LIB_TARGET "aarch64-linux-android") - endif() - elseif(IOS) - set(LIB_TARGET "universal") - elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin) - set(LIB_TARGET "x86_64-apple-darwin") - else() - option(CARGO_TARGET_BUILD "Custom set the --target option for cargo, ex: aarch64-unknown-linux-gnu") - if(CARGO_TARGET_BUILD) - set(LIB_TARGET ${CARGO_TARGET_BUILD}) - elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(LIB_TARGET "x86_64-unknown-linux-gnu") - else() - set(LIB_TARGET "i686-unknown-linux-gnu") - endif() - endif() - - if(NOT CMAKE_BUILD_TYPE) - set(LIB_BUILD_TYPE "debug") - elseif(${CMAKE_BUILD_TYPE} STREQUAL "Release") - set(LIB_BUILD_TYPE "release") - else() - set(LIB_BUILD_TYPE "debug") - endif() - - set(LIB_FILE "${CARGO_TARGET_DIR}/${LIB_TARGET}/${LIB_BUILD_TYPE}/${CMAKE_STATIC_LIBRARY_PREFIX}${LIB_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}") - - if(IOS) - set(CARGO_ARGS "lipo") - else() - set(CARGO_ARGS "build") - list(APPEND CARGO_ARGS "--target" ${LIB_TARGET}) - endif() - - if(${LIB_BUILD_TYPE} STREQUAL "release") - list(APPEND CARGO_ARGS "--release") - endif() - - file(GLOB_RECURSE LIB_SOURCES "*.rs") - - set(CARGO_ENV_COMMAND ${CMAKE_COMMAND} -E env "CARGO_TARGET_DIR=${CARGO_TARGET_DIR}") - - add_custom_command( - OUTPUT ${LIB_FILE} - COMMAND ${CARGO_ENV_COMMAND} ${CARGO_EXECUTABLE} ARGS ${CARGO_ARGS} - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - DEPENDS ${LIB_SOURCES} - COMMENT "running cargo") - message(STATUS "Linking to Rust library: ${LIB_FILE}") - add_custom_target(${CARGO_NAME}_target ALL DEPENDS ${LIB_FILE}) - add_library(${CARGO_NAME} STATIC IMPORTED GLOBAL) - add_dependencies(${CARGO_NAME} ${CARGO_NAME}_target) - set_target_properties(${CARGO_NAME} PROPERTIES IMPORTED_LOCATION ${LIB_FILE}) -endfunction() \ No newline at end of file diff --git a/cmake/CMakeDetermineRustCompiler.cmake b/cmake/CMakeDetermineRustCompiler.cmake deleted file mode 100644 index c6e847ec..00000000 --- a/cmake/CMakeDetermineRustCompiler.cmake +++ /dev/null @@ -1,25 +0,0 @@ - -if(NOT CMAKE_Rust_COMPILER) - find_package(Rust) - if(RUST_FOUND) - set(CMAKE_Rust_COMPILER "${RUSTC_EXECUTABLE}") - set(CMAKE_Rust_COMPILER_ID "Rust") - set(CMAKE_Rust_COMPILER_VERSION "${RUST_VERSION}") - set(CMAKE_Rust_PLATFORM_ID "Rust") - endif() -endif() - -message(STATUS "Cargo Home: ${CARGO_HOME}") -message(STATUS "Rust Compiler Version: ${RUSTC_VERSION}") - -mark_as_advanced(CMAKE_Rust_COMPILER) - -if(CMAKE_Rust_COMPILER) - set(CMAKE_Rust_COMPILER_LOADED 1) -endif(CMAKE_Rust_COMPILER) - -configure_file(${CMAKE_MODULE_PATH}/CMakeRustCompiler.cmake.in - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${CMAKE_VERSION}/CMakeRustCompiler.cmake IMMEDIATE @ONLY) - -set(CMAKE_Rust_COMPILER_ENV_VAR "RUSTC") - diff --git a/cmake/CMakeRustCompiler.cmake.in b/cmake/CMakeRustCompiler.cmake.in deleted file mode 100644 index 5916c1c3..00000000 --- a/cmake/CMakeRustCompiler.cmake.in +++ /dev/null @@ -1,15 +0,0 @@ - -set(CMAKE_Rust_COMPILER "@CMAKE_Rust_COMPILER@") -set(CMAKE_Rust_COMPILER_ID "@CMAKE_Rust_COMPILER_ID@") -set(CMAKE_Rust_COMPILER_VERSION "@CMAKE_Rust_COMPILER_VERSION@") -set(CMAKE_Rust_COMPILER_LOADED @CMAKE_Rust_COMPILER_LOADED@) -set(CMAKE_Rust_PLATFORM_ID "@CMAKE_Rust_PLATFORM_ID@") - -SET(CMAKE_Rust_SOURCE_FILE_EXTENSIONS rs) -SET(CMAKE_Rust_LINKER_PREFERENCE 40) -#SET(CMAKE_Rust_OUTPUT_EXTENSION_REPLACE 1) -SET(CMAKE_STATIC_LIBRARY_PREFIX_Rust "") -SET(CMAKE_STATIC_LIBRARY_SUFFIX_Rust .a) - -set(CMAKE_Rust_COMPILER_ENV_VAR "RUSTC") - diff --git a/cmake/CMakeRustInformation.cmake b/cmake/CMakeRustInformation.cmake deleted file mode 100644 index 05d96c94..00000000 --- a/cmake/CMakeRustInformation.cmake +++ /dev/null @@ -1,106 +0,0 @@ - -# -# Usage: rustc [OPTIONS] INPUT -# -# Options: -# -h --help Display this message -# --cfg SPEC Configure the compilation environment -# -L [KIND=]PATH Add a directory to the library search path. The -# optional KIND can be one of dependency, crate, native, -# framework or all (the default). -# -l [KIND=]NAME Link the generated crate(s) to the specified native -# library NAME. The optional KIND can be one of static, -# dylib, or framework. If omitted, dylib is assumed. -# --crate-type [bin|lib|rlib|dylib|cdylib|staticlib|metadata] -# Comma separated list of types of crates for the -# compiler to emit -# --crate-name NAME Specify the name of the crate being built -# --emit [asm|llvm-bc|llvm-ir|obj|link|dep-info] -# Comma separated list of types of output for the -# compiler to emit -# --print [crate-name|file-names|sysroot|cfg|target-list|target-cpus|target-features|relocation-models|code-models] -# Comma separated list of compiler information to print -# on stdout -# -g Equivalent to -C debuginfo=2 -# -O Equivalent to -C opt-level=2 -# -o FILENAME Write output to -# --out-dir DIR Write output to compiler-chosen filename in -# --explain OPT Provide a detailed explanation of an error message -# --test Build a test harness -# --target TARGET Target triple for which the code is compiled -# -W --warn OPT Set lint warnings -# -A --allow OPT Set lint allowed -# -D --deny OPT Set lint denied -# -F --forbid OPT Set lint forbidden -# --cap-lints LEVEL Set the most restrictive lint level. More restrictive -# lints are capped at this level -# -C --codegen OPT[=VALUE] -# Set a codegen option -# -V --version Print version info and exit -# -v --verbose Use verbose output -# -# Additional help: -# -C help Print codegen options -# -W help Print 'lint' options and default settings -# -Z help Print internal options for debugging rustc -# --help -v Print the full set of options rustc accepts -# - -# - -include(CMakeLanguageInformation) - -if(UNIX) - set(CMAKE_Rust_OUTPUT_EXTENSION .o) -else() - set(CMAKE_Rust_OUTPUT_EXTENSION .obj) -endif() - -set(CMAKE_Rust_ECHO_ALL "echo \"TARGET: TARGET_BASE: ") -set(CMAKE_Rust_ECHO_ALL "${CMAKE_Rust_ECHO_ALL} OBJECT: OBJECTS: OBJECT_DIR: SOURCE: SOURCES: ") -set(CMAKE_Rust_ECHO_ALL "${CMAKE_Rust_ECHO_ALL} LINK_LIBRARIES: FLAGS: LINK_FLAGS: \"") - -if(NOT CMAKE_Rust_CREATE_SHARED_LIBRARY) - set(CMAKE_Rust_CREATE_SHARED_LIBRARY - "echo \"CMAKE_Rust_CREATE_SHARED_LIBRARY\"" - "${CMAKE_Rust_ECHO_ALL}" - ) -endif() - -if(NOT CMAKE_Rust_CREATE_SHARED_MODULE) - set(CMAKE_Rust_CREATE_SHARED_MODULE - "echo \"CMAKE_Rust_CREATE_SHARED_MODULE\"" - "${CMAKE_Rust_ECHO_ALL}" - ) -endif() - -if(NOT CMAKE_Rust_CREATE_STATIC_LIBRARY) - set(CMAKE_Rust_CREATE_STATIC_LIBRARY - "echo \"CMAKE_Rust_CREATE_STATIC_LIBRARY\"" - "${CMAKE_Rust_ECHO_ALL}" - ) -endif() - -if(NOT CMAKE_Rust_COMPILE_OBJECT) - set(CMAKE_Rust_COMPILE_OBJECT - "echo \"CMAKE_Rust_COMPILE_OBJECT\"" - "${CMAKE_Rust_ECHO_ALL}" - "${CMAKE_Rust_COMPILER} --emit obj -o ") -endif() - -if(NOT CMAKE_Rust_LINK_EXECUTABLE) - set(CMAKE_Rust_LINK_EXECUTABLE - "echo \"CMAKE_Rust_LINK_EXECUTABLE\"" - "${CMAKE_Rust_ECHO_ALL}" - ) -endif() - -mark_as_advanced( - CMAKE_Rust_FLAGS - CMAKE_Rust_FLAGS_DEBUG - CMAKE_Rust_FLAGS_MINSIZEREL - CMAKE_Rust_FLAGS_RELEASE - CMAKE_Rust_FLAGS_RELWITHDEBINFO) - -set(CMAKE_Rust_INFORMATION_LOADED 1) - diff --git a/cmake/CMakeTestRustCompiler.cmake b/cmake/CMakeTestRustCompiler.cmake deleted file mode 100644 index ff75bb3e..00000000 --- a/cmake/CMakeTestRustCompiler.cmake +++ /dev/null @@ -1,3 +0,0 @@ - -set(CMAKE_Rust_COMPILER_WORKS 1 CACHE INTERNAL "") - diff --git a/cmake/CargoLink.cmake b/cmake/CargoLink.cmake deleted file mode 100644 index 1db2241b..00000000 --- a/cmake/CargoLink.cmake +++ /dev/null @@ -1,64 +0,0 @@ - -function(cargo_print) - execute_process(COMMAND ${CMAKE_COMMAND} -E echo "${ARGN}") -endfunction() - -function(cargo_link) - cmake_parse_arguments(CARGO_LINK "" "NAME" "TARGETS;EXCLUDE" ${ARGN}) - - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cargo-link.c" "void cargo_link() {}") - add_library(${CARGO_LINK_NAME} "${CMAKE_CURRENT_BINARY_DIR}/cargo-link.c") - target_link_libraries(${CARGO_LINK_NAME} ${CARGO_LINK_TARGETS}) - - get_target_property(LINK_LIBRARIES ${CARGO_LINK_NAME} LINK_LIBRARIES) - - foreach(LINK_LIBRARY ${LINK_LIBRARIES}) - get_target_property(_INTERFACE_LINK_LIBRARIES ${LINK_LIBRARY} INTERFACE_LINK_LIBRARIES) - list(APPEND LINK_LIBRARIES ${_INTERFACE_LINK_LIBRARIES}) - endforeach() - list(REMOVE_DUPLICATES LINK_LIBRARIES) - - if(CARGO_LINK_EXCLUDE) - list(REMOVE_ITEM LINK_LIBRARIES ${CARGO_LINK_EXCLUDE}) - endif() - - set(LINK_DIRECTORIES "") - foreach(LINK_LIBRARY ${LINK_LIBRARIES}) - if(TARGET ${LINK_LIBRARY}) - get_target_property(_IMPORTED_CONFIGURATIONS ${LINK_LIBRARY} IMPORTED_CONFIGURATIONS) - list(FIND _IMPORTED_CONFIGURATIONS "RELEASE" _IMPORTED_CONFIGURATION_INDEX) - if (NOT (${_IMPORTED_CONFIGURATION_INDEX} GREATER -1)) - set(_IMPORTED_CONFIGURATION_INDEX 0) - endif() - list(GET _IMPORTED_CONFIGURATIONS ${_IMPORTED_CONFIGURATION_INDEX} _IMPORTED_CONFIGURATION) - get_target_property(_IMPORTED_LOCATION ${LINK_LIBRARY} "IMPORTED_LOCATION_${_IMPORTED_CONFIGURATION}") - get_filename_component(_IMPORTED_DIR ${_IMPORTED_LOCATION} DIRECTORY) - get_filename_component(_IMPORTED_NAME ${_IMPORTED_LOCATION} NAME_WE) - if(NOT WIN32) - string(REGEX REPLACE "^lib" "" _IMPORTED_NAME ${_IMPORTED_NAME}) - endif() - list(APPEND LINK_DIRECTORIES ${_IMPORTED_DIR}) - cargo_print("cargo:rustc-link-lib=static=${_IMPORTED_NAME}") - else() - if("${LINK_LIBRARY}" MATCHES "^.*/(.+)\\.framework$") - set(FRAMEWORK_NAME ${CMAKE_MATCH_1}) - cargo_print("cargo:rustc-link-lib=framework=${FRAMEWORK_NAME}") - elseif("${LINK_LIBRARY}" MATCHES "^(.*)/(.+)\\.so$") - set(LIBRARY_DIR ${CMAKE_MATCH_1}) - set(LIBRARY_NAME ${CMAKE_MATCH_2}) - if(NOT WIN32) - string(REGEX REPLACE "^lib" "" LIBRARY_NAME ${LIBRARY_NAME}) - endif() - list(APPEND LINK_DIRECTORIES ${LIBRARY_DIR}) - cargo_print("cargo:rustc-link-lib=${LIBRARY_NAME}") - else() - cargo_print("cargo:rustc-link-lib=${LINK_LIBRARY}") - endif() - endif() - endforeach() - list(REMOVE_DUPLICATES LINK_DIRECTORIES) - - foreach(LINK_DIRECTORY ${LINK_DIRECTORIES}) - cargo_print("cargo:rustc-link-search=native=${LINK_DIRECTORY}") - endforeach() -endfunction() diff --git a/docker/wolf.Dockerfile b/docker/wolf.Dockerfile index 6905c6a3..9590ce49 100644 --- a/docker/wolf.Dockerfile +++ b/docker/wolf.Dockerfile @@ -26,9 +26,20 @@ RUN apt-get update -y && \ libpci-dev \ && rm -rf /var/lib/apt/lists/* -## Install Rust in order to build our custom compositor (the build will be done inside Cmake) -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y -ENV PATH="/root/.cargo/bin:${PATH}" +## Install Rust in order to build our custom compositor +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y +ENV PATH="$HOME/.cargo/bin:${PATH}" + +WORKDIR /tmp/ +RUN <<_GST_WAYLAND_DISPLAY + #!/bin/bash + set -e + + git clone https://github.com/games-on-whales/gst-wayland-display + cd gst-wayland-display + cargo install cargo-c + cargo cinstall --prefix=/usr/local +_GST_WAYLAND_DISPLAY COPY . /wolf/ WORKDIR /wolf @@ -75,6 +86,9 @@ RUN apt-get update -y && \ && rm -rf /var/lib/apt/lists/* ENV GST_PLUGIN_PATH=/usr/local/lib/x86_64-linux-gnu/gstreamer-1.0/ +# Copying out our custom compositor from the build stage +COPY --from=wolf-builder /usr/local/lib/gstreamer-1.0/* $GST_PLUGIN_PATH +COPY --from=wolf-builder /usr/local/lib/liblibgstwaylanddisplay* /usr/local/lib/ WORKDIR /wolf diff --git a/docs/modules/user/pages/quickstart.adoc b/docs/modules/user/pages/quickstart.adoc index 57f483e3..30865f92 100644 --- a/docs/modules/user/pages/quickstart.adoc +++ b/docs/modules/user/pages/quickstart.adoc @@ -112,7 +112,7 @@ docker run \ -v /dev/input:/dev/input:rw \ -v /run/udev:/run/udev:rw \ -v /etc/wolf/ensure-groups:/opt/gow/ensure-groups:rw \ - wolf/wolf:test + ghcr.io/games-on-whales/wolf:stable .... Docker compose: diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 40d53846..adf5c0ae 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -13,12 +13,11 @@ target_link_libraries(wolf_core PUBLIC wolf::docker) file(GLOB CORE_HEADERS CONFIGURE_DEPENDS src/core/*.hpp) set(CORE_SRC "") +find_package(PkgConfig) option(LINK_RUST_WAYLAND "Link to our custom Rust wayland compositor" ON) if (LINK_RUST_WAYLAND AND UNIX AND NOT APPLE) - # Adapted from: https://github.com/Devolutions/CMakeRust/ - enable_language(Rust) - include(CMakeCargo) - add_subdirectory(rust/gst-wayland-display) + pkg_check_modules(libgstwaylanddisplay REQUIRED IMPORTED_TARGET libgstwaylanddisplay) + target_link_libraries(wolf_core PUBLIC PkgConfig::libgstwaylanddisplay) endif () FetchContent_Declare( @@ -35,8 +34,7 @@ FetchContent_MakeAvailable(immer) target_link_libraries_system(wolf_core PUBLIC immer) unset(FPHSA_NAME_MISMATCHED) -find_package(PkgConfig) -pkg_check_modules(GSTREAMER REQUIRED IMPORTED_TARGET gstreamer-1.0 gstreamer-base-1.0 gstreamer-app-1.0) +pkg_check_modules(GSTREAMER REQUIRED IMPORTED_TARGET gstreamer-1.0 gstreamer-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0) pkg_check_modules(GLIB2 REQUIRED IMPORTED_TARGET glib-2.0) if (NOT (GSTREAMER_FOUND)) @@ -55,7 +53,6 @@ if (UNIX AND NOT APPLE) target_link_libraries(wolf_core PUBLIC wolf::uinput) if (LINK_RUST_WAYLAND) - target_link_libraries_system(wolf_core PUBLIC gstwaylanddisplay) list(APPEND CORE_SRC src/platforms/linux/virtual-display/wayland-display.cpp) else () message(WARNING "Missing virtual display implementation for this platform") diff --git a/src/core/rust/gst-plugin-wayland-display/Cargo.toml b/src/core/rust/gst-plugin-wayland-display/Cargo.toml deleted file mode 100644 index 1e12b469..00000000 --- a/src/core/rust/gst-plugin-wayland-display/Cargo.toml +++ /dev/null @@ -1,44 +0,0 @@ -[package] -name = "gst-plugin-wayland-display" -authors = ["Victoria Brekenfeld "] -version = "0.1.0" -edition = "2021" -license = "MIT" -description = "GStreamer Wayland Compositor Src" -repository = "https://github.com/games-on-whales/wolf" -rust-version = "1.67" - -[lib] -name = "gstwaylanddisplaysrc" -crate-type = ["cdylib", "rlib"] -path = "src/lib.rs" - -[features] -static = [] -capi = [] -doc = [] - -[dependencies] -gst.workspace = true -gst-base = { version = "0.20", package = "gstreamer-base", features = ["v1_18"] } -gst-video.workspace = true -gst-wayland-display = { path = "../gst-wayland-display" } -tracing.workspace = true -once_cell.workspace = true -tracing-subscriber = "0.3.16" - -[build-dependencies] -gst-plugin-version-helper = "0.7.5" - -[package.metadata.capi] -min_version = "0.8.0" - -[package.metadata.capi.header] -enabled = false - -[package.metadata.capi.library] -install_subdir = "gstreamer-1.0" -versioning = false - -[package.metadata.capi.pkg_config] -requires_private = "gstreamer-1.0, gstreamer-base-1.0, gstreamer-video-1.0, gobject-2.0, glib-2.0, gmodule-2.0" diff --git a/src/core/rust/gst-plugin-wayland-display/build.rs b/src/core/rust/gst-plugin-wayland-display/build.rs deleted file mode 100644 index cda12e57..00000000 --- a/src/core/rust/gst-plugin-wayland-display/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - gst_plugin_version_helper::info() -} diff --git a/src/core/rust/gst-plugin-wayland-display/src/lib.rs b/src/core/rust/gst-plugin-wayland-display/src/lib.rs deleted file mode 100644 index 48b6e1f2..00000000 --- a/src/core/rust/gst-plugin-wayland-display/src/lib.rs +++ /dev/null @@ -1,21 +0,0 @@ -use gst::glib; - -pub mod utils; -mod waylandsrc; - -fn plugin_init(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - waylandsrc::register(plugin)?; - Ok(()) -} - -gst::plugin_define!( - waylanddisplaysrc, - env!("CARGO_PKG_DESCRIPTION"), - plugin_init, - concat!(env!("CARGO_PKG_VERSION"), "-", env!("COMMIT_ID")), - "MIT", - env!("CARGO_PKG_NAME"), - env!("CARGO_PKG_NAME"), - env!("CARGO_PKG_REPOSITORY"), - env!("BUILD_REL_DATE") -); diff --git a/src/core/rust/gst-plugin-wayland-display/src/utils.rs b/src/core/rust/gst-plugin-wayland-display/src/utils.rs deleted file mode 100644 index 416700fb..00000000 --- a/src/core/rust/gst-plugin-wayland-display/src/utils.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::fmt::{self, Write}; - -use gst::glib; -use once_cell::sync::Lazy; -use tracing::field::{Field, Visit}; - -pub static CAT: Lazy = Lazy::new(|| { - gst::DebugCategory::new( - "waylanddisplaysrc", - gst::DebugColorFlags::empty(), - Some("Wayland Display Source Bin"), - ) -}); - -#[derive(Debug, Clone)] -pub struct GstLayer; - -pub struct StringVisitor<'a> { - string: &'a mut String, -} - -impl<'a> Visit for StringVisitor<'a> { - fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { - write!(self.string, "{} = {:?}; ", field.name(), value).unwrap(); - } -} - -impl tracing_subscriber::Layer for GstLayer -where - S: tracing::Subscriber, -{ - fn on_event( - &self, - event: &tracing::Event<'_>, - _ctx: tracing_subscriber::layer::Context<'_, S>, - ) { - let mut message = String::new(); - event.record(&mut StringVisitor { - string: &mut message, - }); - - CAT.log( - Option::<&crate::waylandsrc::WaylandDisplaySrc>::None, - match event.metadata().level() { - &tracing::Level::ERROR => gst::DebugLevel::Error, - &tracing::Level::WARN => gst::DebugLevel::Warning, - &tracing::Level::INFO => gst::DebugLevel::Info, - &tracing::Level::DEBUG => gst::DebugLevel::Debug, - &tracing::Level::TRACE => gst::DebugLevel::Trace, - }, - glib::GString::from(event.metadata().file().unwrap_or("")).as_gstr(), - event.metadata().module_path().unwrap_or(""), - event.metadata().line().unwrap_or(0), - format_args!("{}", message), - ); - } -} diff --git a/src/core/rust/gst-plugin-wayland-display/src/waylandsrc/imp.rs b/src/core/rust/gst-plugin-wayland-display/src/waylandsrc/imp.rs deleted file mode 100644 index 84159499..00000000 --- a/src/core/rust/gst-plugin-wayland-display/src/waylandsrc/imp.rs +++ /dev/null @@ -1,282 +0,0 @@ -use std::sync::Mutex; - -use gst::message::Application; -use gst_video::{VideoCapsBuilder, VideoFormat}; - -use gst::subclass::prelude::*; -use gst::{glib, Event, Fraction}; -use gst::{ - glib::{once_cell::sync::Lazy, ValueArray}, - LibraryError, -}; -use gst::{prelude::*, Structure}; - -use gst_base::subclass::base_src::CreateSuccess; -use gst_base::subclass::prelude::*; -use gst_base::traits::BaseSrcExt; - -use gstwaylanddisplay::WaylandDisplay; -use tracing_subscriber::layer::SubscriberExt; -use tracing_subscriber::Registry; - -use crate::utils::{GstLayer, CAT}; - -pub struct WaylandDisplaySrc { - state: Mutex>, - settings: Mutex, -} - -impl Default for WaylandDisplaySrc { - fn default() -> Self { - WaylandDisplaySrc { - state: Mutex::new(None), - settings: Mutex::new(Settings::default()), - } - } -} - -#[derive(Debug, Default)] -pub struct Settings { - render_node: Option, -} - -pub struct State { - display: WaylandDisplay, -} - -#[glib::object_subclass] -impl ObjectSubclass for WaylandDisplaySrc { - const NAME: &'static str = "GstWaylandDisplaySrc"; - type Type = super::WaylandDisplaySrc; - type ParentType = gst_base::PushSrc; - type Interfaces = (); -} - -impl ObjectImpl for WaylandDisplaySrc { - fn properties() -> &'static [glib::ParamSpec] { - static PROPERTIES: Lazy> = Lazy::new(|| { - vec![glib::ParamSpecString::builder("render-node") - .nick("DRM Render Node") - .blurb("DRM Render Node to use (e.g. /dev/dri/renderD128") - .construct() - .build()] - }); - - PROPERTIES.as_ref() - } - - fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) { - match pspec.name() { - "render-node" => { - let mut settings = self.settings.lock().unwrap(); - settings.render_node = value - .get::>() - .expect("Type checked upstream"); - } - _ => unreachable!(), - } - } - - fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { - match pspec.name() { - "render-node" => { - let settings = self.settings.lock().unwrap(); - settings - .render_node - .clone() - .unwrap_or_else(|| String::from("/dev/dri/renderD128")) - .to_value() - } - _ => unreachable!(), - } - } - - fn constructed(&self) { - self.parent_constructed(); - - let obj = self.obj(); - obj.set_element_flags(gst::ElementFlags::SOURCE); - obj.set_live(true); - obj.set_format(gst::Format::Time); - obj.set_automatic_eos(false); - obj.set_do_timestamp(true); - } -} - -impl GstObjectImpl for WaylandDisplaySrc {} - -impl ElementImpl for WaylandDisplaySrc { - fn metadata() -> Option<&'static gst::subclass::ElementMetadata> { - static ELEMENT_METADATA: Lazy = Lazy::new(|| { - gst::subclass::ElementMetadata::new( - "Wayland display source", - "Source/Video", - "GStreamer video src running a wayland compositor", - "Victoria Brekenfeld ", - ) - }); - - Some(&*ELEMENT_METADATA) - } - - fn pad_templates() -> &'static [gst::PadTemplate] { - static PAD_TEMPLATES: Lazy> = Lazy::new(|| { - let caps = gst_video::VideoCapsBuilder::new() - .format(VideoFormat::Rgbx) - .height_range(..i32::MAX) - .width_range(..i32::MAX) - .framerate_range(Fraction::new(1, 1)..Fraction::new(i32::MAX, 1)) - .build(); - let src_pad_template = gst::PadTemplate::new( - "src", - gst::PadDirection::Src, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - - vec![src_pad_template] - }); - - PAD_TEMPLATES.as_ref() - } - - fn change_state( - &self, - transition: gst::StateChange, - ) -> Result { - let res = self.parent_change_state(transition); - match res { - Ok(gst::StateChangeSuccess::Success) => { - if transition.next() == gst::State::Paused { - // this is a live source - Ok(gst::StateChangeSuccess::NoPreroll) - } else { - Ok(gst::StateChangeSuccess::Success) - } - } - x => x, - } - } - - fn query(&self, query: &mut gst::QueryRef) -> bool { - ElementImplExt::parent_query(self, query) - } -} - -impl BaseSrcImpl for WaylandDisplaySrc { - fn query(&self, query: &mut gst::QueryRef) -> bool { - BaseSrcImplExt::parent_query(self, query) - } - - fn caps(&self, filter: Option<&gst::Caps>) -> Option { - let mut caps = VideoCapsBuilder::new() - .format(VideoFormat::Rgbx) - .height_range(..i32::MAX) - .width_range(..i32::MAX) - .framerate_range(Fraction::new(1, 1)..Fraction::new(i32::MAX, 1)) - .build(); - - if let Some(filter) = filter { - caps = caps.intersect(filter); - } - - Some(caps) - } - - fn negotiate(&self) -> Result<(), gst::LoggableError> { - self.parent_negotiate() - } - - fn event(&self, event: &Event) -> bool { - if event.type_() == gst::EventType::CustomUpstream { - let structure = event.structure().expect("Unable to get message structure"); - if structure.has_name("VirtualDevicesReady") { - let mut state = self.state.lock().unwrap(); - let display = &mut state.as_mut().unwrap().display; - - let paths = structure - .get::("paths") - .expect("Should contain paths"); - for value in paths.into_iter() { - let path = value.get::().expect("Paths are strings"); - display.add_input_device(path); - } - - return true; - } - } - self.parent_event(event) - } - - fn set_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> { - let video_info = gst_video::VideoInfo::from_caps(caps).expect("failed to get video info"); - self.state - .lock() - .unwrap() - .as_mut() - .unwrap() - .display - .set_video_info(video_info); - - self.parent_set_caps(caps) - } - - fn start(&self) -> Result<(), gst::ErrorMessage> { - let mut state = self.state.lock().unwrap(); - if state.is_some() { - return Ok(()); - } - - let settings = self.settings.lock().unwrap(); - let elem = self.obj().upcast_ref::().to_owned(); - let subscriber = Registry::default().with(GstLayer); - - let Ok(mut display) = tracing::subscriber::with_default(subscriber, || WaylandDisplay::new(settings.render_node.clone())) else { - return Err(gst::error_msg!(LibraryError::Failed, ("Failed to open drm node {}, if you want to utilize software rendering set `render-node=software`.", settings.render_node.as_deref().unwrap_or("/dev/dri/renderD128")))); - }; - - let mut structure = Structure::builder("wayland.src"); - for (key, var) in display.env_vars().flat_map(|var| var.split_once("=")) { - structure = structure.field(key, var); - } - let structure = structure.build(); - if let Err(err) = elem.post_message(Application::builder(structure).src(&elem).build()) { - gst::warning!(CAT, "Failed to post environment to gstreamer bus: {}", err); - } - - *state = Some(State { display }); - - Ok(()) - } - - fn stop(&self) -> Result<(), gst::ErrorMessage> { - let mut state = self.state.lock().unwrap(); - if let Some(state) = state.take() { - let subscriber = Registry::default().with(GstLayer); - tracing::subscriber::with_default(subscriber, || std::mem::drop(state.display)); - } - Ok(()) - } - - fn is_seekable(&self) -> bool { - false - } -} - -impl PushSrcImpl for WaylandDisplaySrc { - fn create( - &self, - _buffer: Option<&mut gst::BufferRef>, - ) -> Result { - let mut state_guard = self.state.lock().unwrap(); - let Some(state) = state_guard.as_mut() else { - return Err(gst::FlowError::Eos); - }; - - let subscriber = Registry::default().with(GstLayer); - tracing::subscriber::with_default(subscriber, || { - state.display.frame().map(CreateSuccess::NewBuffer) - }) - } -} diff --git a/src/core/rust/gst-plugin-wayland-display/src/waylandsrc/mod.rs b/src/core/rust/gst-plugin-wayland-display/src/waylandsrc/mod.rs deleted file mode 100644 index 42c52b47..00000000 --- a/src/core/rust/gst-plugin-wayland-display/src/waylandsrc/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -use gst::glib; -use gst::prelude::*; - -mod imp; - -glib::wrapper! { - pub struct WaylandDisplaySrc(ObjectSubclass) @extends gst_base::PushSrc, gst_base::BaseSrc, gst::Element, gst::Object; -} - -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "waylanddisplaysrc", - gst::Rank::Marginal, - WaylandDisplaySrc::static_type(), - ) -} diff --git a/src/core/rust/gst-wayland-display/CMakeLists.txt b/src/core/rust/gst-wayland-display/CMakeLists.txt deleted file mode 100644 index ac07594b..00000000 --- a/src/core/rust/gst-wayland-display/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -cargo_build(NAME gstwaylanddisplay) - -target_include_directories(gstwaylanddisplay INTERFACE include) - -############### -# Extra deps -### - -find_package(Libinput REQUIRED) -find_package(Libxkbcommon REQUIRED) -find_package(WaylandServer REQUIRED) -pkg_check_modules(GST_VIDEO REQUIRED IMPORTED_TARGET gstreamer-video-1.0) -pkg_check_modules(GOBJECT REQUIRED IMPORTED_TARGET gobject-2.0 glib-2.0 gmodule-2.0 gio-2.0) - -target_link_libraries(gstwaylanddisplay - INTERFACE - Libinput::Libinput - XkbCommon::libxkbcommon - wayland::server - PkgConfig::GOBJECT - PkgConfig::GST_VIDEO) - diff --git a/src/core/rust/gst-wayland-display/Cargo.toml b/src/core/rust/gst-wayland-display/Cargo.toml deleted file mode 100644 index cb586803..00000000 --- a/src/core/rust/gst-wayland-display/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "gst-wayland-display" -authors = ["Victoria Brekenfeld "] -version = "0.1.0" -edition = "2021" -license = "MIT" -description = "Wayland Compositor producing GStreamer buffers" - -[lib] -name = "gstwaylanddisplay" -crate-type = ["cdylib", "staticlib", "rlib"] -path = "src/lib.rs" - -[dependencies] -gst.workspace = true -gst-video.workspace = true -tracing.workspace = true -once_cell.workspace = true -wayland-backend = "0.1.0" -wayland-scanner = "0.30.0" - -[dependencies.smithay] -git = "https://github.com/smithay/Smithay" -rev = "b1c682742a" -default-features = false -features = [ "backend_drm", "backend_egl", "backend_libinput", "backend_udev", "renderer_gl", "use_system_lib", "desktop", "wayland_frontend" ] diff --git a/src/core/rust/gst-wayland-display/include/waylanddisplay.h b/src/core/rust/gst-wayland-display/include/waylanddisplay.h deleted file mode 100644 index 7ec02bf4..00000000 --- a/src/core/rust/gst-wayland-display/include/waylanddisplay.h +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include - -typedef void *WaylandDisplay; - -WaylandDisplay display_init(const char *render_node); -void display_finish(WaylandDisplay dpy); - -size_t display_get_devices_len(WaylandDisplay dpy); -size_t display_get_devices(WaylandDisplay dpy, const char **devices, size_t max_len); -size_t display_get_envvars_len(WaylandDisplay dpy); -size_t display_get_envvars(WaylandDisplay dpy, const char **vars, size_t max_len); - -void display_add_input_device(WaylandDisplay dpy, const char *path); -void display_set_video_info(WaylandDisplay dpy, const GstVideoInfo *info); -GstBuffer *display_get_frame(WaylandDisplay dpy); diff --git a/src/core/rust/gst-wayland-display/resources/cursor.rgba b/src/core/rust/gst-wayland-display/resources/cursor.rgba deleted file mode 100644 index 729c1cc4..00000000 Binary files a/src/core/rust/gst-wayland-display/resources/cursor.rgba and /dev/null differ diff --git a/src/core/rust/gst-wayland-display/resources/protocols/wayland-drm.xml b/src/core/rust/gst-wayland-display/resources/protocols/wayland-drm.xml deleted file mode 100644 index eaf2654a..00000000 --- a/src/core/rust/gst-wayland-display/resources/protocols/wayland-drm.xml +++ /dev/null @@ -1,189 +0,0 @@ - - - - - Copyright © 2008-2011 Kristian Høgsberg - Copyright © 2010-2011 Intel Corporation - - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that\n the above copyright notice appear in - all copies and that both that copyright notice and this permission - notice appear in supporting documentation, and that the name of - the copyright holders not be used in advertising or publicity - pertaining to distribution of the software without specific, - written prior permission. The copyright holders make no - representations about the suitability of this software for any - purpose. It is provided "as is" without express or implied - warranty. - - THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - THIS SOFTWARE. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Bitmask of capabilities. - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/core/rust/gst-wayland-display/src/comp/focus.rs b/src/core/rust/gst-wayland-display/src/comp/focus.rs deleted file mode 100644 index 01d8039c..00000000 --- a/src/core/rust/gst-wayland-display/src/comp/focus.rs +++ /dev/null @@ -1,156 +0,0 @@ -use smithay::{ - backend::input::KeyState, - desktop::{PopupKind, Window}, - input::{ - keyboard::{KeyboardTarget, KeysymHandle, ModifiersState}, - pointer::{AxisFrame, ButtonEvent, MotionEvent, PointerTarget, RelativeMotionEvent}, - Seat, - }, - reexports::wayland_server::{backend::ObjectId, protocol::wl_surface::WlSurface}, - utils::{IsAlive, Serial}, - wayland::seat::WaylandFocus, -}; - -#[derive(Debug, Clone, PartialEq)] -pub enum FocusTarget { - Wayland(Window), - Popup(PopupKind), -} - -impl IsAlive for FocusTarget { - fn alive(&self) -> bool { - match self { - FocusTarget::Wayland(w) => w.alive(), - FocusTarget::Popup(p) => p.alive(), - } - } -} - -impl From for FocusTarget { - fn from(w: Window) -> Self { - FocusTarget::Wayland(w) - } -} - -impl From for FocusTarget { - fn from(p: PopupKind) -> Self { - FocusTarget::Popup(p) - } -} - -impl KeyboardTarget for FocusTarget { - fn enter( - &self, - seat: &Seat, - data: &mut super::State, - keys: Vec>, - serial: Serial, - ) { - match self { - FocusTarget::Wayland(w) => KeyboardTarget::enter(w, seat, data, keys, serial), - FocusTarget::Popup(p) => { - KeyboardTarget::enter(p.wl_surface(), seat, data, keys, serial) - } - } - } - - fn leave(&self, seat: &Seat, data: &mut super::State, serial: Serial) { - match self { - FocusTarget::Wayland(w) => KeyboardTarget::leave(w, seat, data, serial), - FocusTarget::Popup(p) => KeyboardTarget::leave(p.wl_surface(), seat, data, serial), - } - } - - fn key( - &self, - seat: &Seat, - data: &mut super::State, - key: KeysymHandle<'_>, - state: KeyState, - serial: Serial, - time: u32, - ) { - match self { - FocusTarget::Wayland(w) => w.key(seat, data, key, state, serial, time), - FocusTarget::Popup(p) => p.wl_surface().key(seat, data, key, state, serial, time), - } - } - - fn modifiers( - &self, - seat: &Seat, - data: &mut super::State, - modifiers: ModifiersState, - serial: Serial, - ) { - match self { - FocusTarget::Wayland(w) => w.modifiers(seat, data, modifiers, serial), - FocusTarget::Popup(p) => p.wl_surface().modifiers(seat, data, modifiers, serial), - } - } -} - -impl PointerTarget for FocusTarget { - fn enter(&self, seat: &Seat, data: &mut super::State, event: &MotionEvent) { - match self { - FocusTarget::Wayland(w) => PointerTarget::enter(w, seat, data, event), - FocusTarget::Popup(p) => PointerTarget::enter(p.wl_surface(), seat, data, event), - } - } - - fn motion(&self, seat: &Seat, data: &mut super::State, event: &MotionEvent) { - match self { - FocusTarget::Wayland(w) => w.motion(seat, data, event), - FocusTarget::Popup(p) => p.wl_surface().motion(seat, data, event), - } - } - - fn relative_motion( - &self, - seat: &Seat, - data: &mut super::State, - event: &RelativeMotionEvent, - ) { - match self { - FocusTarget::Wayland(w) => w.relative_motion(seat, data, event), - FocusTarget::Popup(p) => p.wl_surface().relative_motion(seat, data, event), - } - } - - fn button(&self, seat: &Seat, data: &mut super::State, event: &ButtonEvent) { - match self { - FocusTarget::Wayland(w) => w.button(seat, data, event), - FocusTarget::Popup(p) => p.wl_surface().button(seat, data, event), - } - } - - fn axis(&self, seat: &Seat, data: &mut super::State, frame: AxisFrame) { - match self { - FocusTarget::Wayland(w) => w.axis(seat, data, frame), - FocusTarget::Popup(p) => p.wl_surface().axis(seat, data, frame), - } - } - - fn leave(&self, seat: &Seat, data: &mut super::State, serial: Serial, time: u32) { - match self { - FocusTarget::Wayland(w) => PointerTarget::leave(w, seat, data, serial, time), - FocusTarget::Popup(p) => PointerTarget::leave(p.wl_surface(), seat, data, serial, time), - } - } -} - -impl WaylandFocus for FocusTarget { - fn wl_surface(&self) -> Option { - match self { - FocusTarget::Wayland(w) => w.wl_surface(), - FocusTarget::Popup(p) => Some(p.wl_surface().clone()), - } - } - - fn same_client_as(&self, object_id: &ObjectId) -> bool { - match self { - FocusTarget::Wayland(w) => w.same_client_as(object_id), - FocusTarget::Popup(p) => p.wl_surface().same_client_as(object_id), - } - } -} diff --git a/src/core/rust/gst-wayland-display/src/comp/input.rs b/src/core/rust/gst-wayland-display/src/comp/input.rs deleted file mode 100644 index 03ab4602..00000000 --- a/src/core/rust/gst-wayland-display/src/comp/input.rs +++ /dev/null @@ -1,264 +0,0 @@ -use super::{focus::FocusTarget, State}; -use smithay::{ - backend::{ - input::{ - Axis, AxisSource, Event, InputEvent, KeyState, KeyboardKeyEvent, PointerAxisEvent, - PointerButtonEvent, PointerMotionEvent, - }, - libinput::LibinputInputBackend, - }, - input::{ - keyboard::{keysyms, FilterResult}, - pointer::{AxisFrame, ButtonEvent, MotionEvent, RelativeMotionEvent}, - }, - reexports::{ - input::LibinputInterface, - nix::{fcntl, fcntl::OFlag, sys::stat}, - wayland_server::protocol::wl_pointer, - }, - utils::{Logical, Point, Serial, SERIAL_COUNTER}, -}; -use std::{ - os::{fd::FromRawFd, unix::io::OwnedFd}, - path::Path, - time::Instant, -}; - -pub struct NixInterface; - -impl LibinputInterface for NixInterface { - fn open_restricted(&mut self, path: &Path, flags: i32) -> Result { - fcntl::open(path, OFlag::from_bits_truncate(flags), stat::Mode::empty()) - .map(|fd| unsafe { OwnedFd::from_raw_fd(fd) }) - .map_err(|err| err as i32) - } - fn close_restricted(&mut self, fd: OwnedFd) { - let _ = fd; - } -} - -impl State { - pub fn process_input_event(&mut self, event: InputEvent) { - match event { - InputEvent::Keyboard { event, .. } => { - let keycode = event.key_code(); - let state = event.state(); - let serial = SERIAL_COUNTER.next_serial(); - let time = event.time_msec(); - let keyboard = self.seat.get_keyboard().unwrap(); - - keyboard.input::<(), _>( - self, - keycode, - state, - serial, - time, - |data, modifiers, handle| { - if state == KeyState::Pressed { - if modifiers.ctrl - && modifiers.shift - && !modifiers.alt - && !modifiers.logo - { - match handle.modified_sym() { - keysyms::KEY_Tab => { - if let Some(element) = data.space.elements().last().cloned() - { - data.surpressed_keys.insert(keysyms::KEY_Tab); - let location = - data.space.element_location(&element).unwrap(); - data.space.map_element(element.clone(), location, true); - data.seat.get_keyboard().unwrap().set_focus( - data, - Some(FocusTarget::from(element)), - serial, - ); - return FilterResult::Intercept(()); - } - } - keysyms::KEY_Q => { - if let Some(target) = - data.seat.get_keyboard().unwrap().current_focus() - { - match target { - FocusTarget::Wayland(window) => { - window.toplevel().send_close(); - } - _ => return FilterResult::Forward, - }; - data.surpressed_keys.insert(keysyms::KEY_Q); - return FilterResult::Intercept(()); - } - } - _ => {} - } - } - } else { - if data.surpressed_keys.remove(&handle.modified_sym()) { - return FilterResult::Intercept(()); - } - } - - FilterResult::Forward - }, - ); - } - InputEvent::PointerMotion { event, .. } => { - self.last_pointer_movement = Instant::now(); - let serial = SERIAL_COUNTER.next_serial(); - let delta = event.delta(); - self.pointer_location += delta; - self.pointer_location = self.clamp_coords(self.pointer_location); - - let pointer = self.seat.get_pointer().unwrap(); - let under = self - .space - .element_under(self.pointer_location) - .map(|(w, pos)| (w.clone().into(), pos)); - pointer.motion( - self, - under.clone(), - &MotionEvent { - location: self.pointer_location, - serial, - time: event.time_msec(), - }, - ); - pointer.relative_motion( - self, - under, - &RelativeMotionEvent { - delta, - delta_unaccel: event.delta_unaccel(), - utime: event.time(), - }, - ) - } - InputEvent::PointerMotionAbsolute { event } => { - self.last_pointer_movement = Instant::now(); - let serial = SERIAL_COUNTER.next_serial(); - if let Some(output) = self.output.as_ref() { - let output_size = output - .current_mode() - .unwrap() - .size - .to_f64() - .to_logical(output.current_scale().fractional_scale()) - .to_i32_round(); - self.pointer_location = ( - event.absolute_x_transformed(output_size.w), - event.absolute_y_transformed(output_size.h), - ) - .into(); - - let pointer = self.seat.get_pointer().unwrap(); - let under = self - .space - .element_under(self.pointer_location) - .map(|(w, pos)| (w.clone().into(), pos)); - pointer.motion( - self, - under.clone(), - &MotionEvent { - location: self.pointer_location, - serial, - time: event.time_msec(), - }, - ); - } - } - InputEvent::PointerButton { event, .. } => { - self.last_pointer_movement = Instant::now(); - let serial = SERIAL_COUNTER.next_serial(); - let button = event.button_code(); - - let state = wl_pointer::ButtonState::from(event.state()); - if wl_pointer::ButtonState::Pressed == state { - self.update_keyboard_focus(serial); - }; - self.seat.get_pointer().unwrap().button( - self, - &ButtonEvent { - button, - state: state.try_into().unwrap(), - serial, - time: event.time_msec(), - }, - ); - } - InputEvent::PointerAxis { event, .. } => { - self.last_pointer_movement = Instant::now(); - let horizontal_amount = event - .amount(Axis::Horizontal) - .or_else(|| event.amount_discrete(Axis::Horizontal).map(|x| x * 2.0)) - .unwrap_or(0.0); - let vertical_amount = event - .amount(Axis::Vertical) - .or_else(|| event.amount_discrete(Axis::Vertical).map(|y| y * 2.0)) - .unwrap_or(0.0); - let horizontal_amount_discrete = event.amount_discrete(Axis::Horizontal); - let vertical_amount_discrete = event.amount_discrete(Axis::Vertical); - - { - let mut frame = AxisFrame::new(event.time_msec()).source(event.source()); - if horizontal_amount != 0.0 { - frame = frame.value(Axis::Horizontal, horizontal_amount); - if let Some(discrete) = horizontal_amount_discrete { - frame = frame.discrete(Axis::Horizontal, discrete as i32); - } - } else if event.source() == AxisSource::Finger { - frame = frame.stop(Axis::Horizontal); - } - if vertical_amount != 0.0 { - frame = frame.value(Axis::Vertical, vertical_amount); - if let Some(discrete) = vertical_amount_discrete { - frame = frame.discrete(Axis::Vertical, discrete as i32); - } - } else if event.source() == AxisSource::Finger { - frame = frame.stop(Axis::Vertical); - } - self.seat.get_pointer().unwrap().axis(self, frame); - } - } - _ => {} - } - } - - fn clamp_coords(&self, pos: Point) -> Point { - if let Some(output) = self.output.as_ref() { - if let Some(mode) = output.current_mode() { - return ( - pos.x.max(0.0).min(mode.size.w as f64), - pos.y.max(0.0).min(mode.size.h as f64), - ) - .into(); - } - } - pos - } - - fn update_keyboard_focus(&mut self, serial: Serial) { - let pointer = self.seat.get_pointer().unwrap(); - let keyboard = self.seat.get_keyboard().unwrap(); - // change the keyboard focus unless the pointer or keyboard is grabbed - // We test for any matching surface type here but always use the root - // (in case of a window the toplevel) surface for the focus. - // So for example if a user clicks on a subsurface or popup the toplevel - // will receive the keyboard focus. Directly assigning the focus to the - // matching surface leads to issues with clients dismissing popups and - // subsurface menus (for example firefox-wayland). - // see here for a discussion about that issue: - // https://gitlab.freedesktop.org/wayland/wayland/-/issues/294 - if !pointer.is_grabbed() && !keyboard.is_grabbed() { - if let Some((window, _)) = self - .space - .element_under(self.pointer_location) - .map(|(w, p)| (w.clone(), p)) - { - self.space.raise_element(&window, true); - keyboard.set_focus(self, Some(FocusTarget::from(window)), serial); - return; - } - } - } -} diff --git a/src/core/rust/gst-wayland-display/src/comp/mod.rs b/src/core/rust/gst-wayland-display/src/comp/mod.rs deleted file mode 100644 index 19fabb58..00000000 --- a/src/core/rust/gst-wayland-display/src/comp/mod.rs +++ /dev/null @@ -1,521 +0,0 @@ -use std::{ - collections::{HashMap, HashSet}, - ffi::CString, - os::unix::prelude::AsRawFd, - sync::{mpsc::Sender, Arc, Mutex, Weak}, - time::{Duration, Instant}, -}; - -use super::Command; -use gst_video::VideoInfo; -use once_cell::sync::Lazy; -use smithay::{ - backend::{ - allocator::dmabuf::Dmabuf, - drm::{DrmNode, NodeType}, - egl::{EGLContext, EGLDevice, EGLDisplay}, - libinput::LibinputInputBackend, - renderer::{ - damage::{DamageTrackedRenderer, DamageTrackedRendererError as DTRError}, - element::memory::MemoryRenderBuffer, - gles2::{Gles2Renderbuffer, Gles2Renderer}, - Bind, ImportMemWl, Offscreen, - }, - }, - desktop::{ - utils::{ - send_frames_surface_tree, surface_presentation_feedback_flags_from_states, - surface_primary_scanout_output, update_surface_primary_scanout_output, - OutputPresentationFeedback, - }, - PopupManager, Space, Window, - }, - input::{keyboard::XkbConfig, pointer::CursorImageStatus, Seat, SeatState}, - output::{Mode as OutputMode, Output, PhysicalProperties, Subpixel}, - reexports::{ - calloop::{ - channel::{Channel, Event}, - generic::Generic, - timer::{TimeoutAction, Timer}, - EventLoop, Interest, LoopHandle, Mode, PostAction, - }, - input::Libinput, - wayland_protocols::wp::presentation_time::server::wp_presentation_feedback, - wayland_server::{ - backend::{ClientData, ClientId, DisconnectReason}, - Display, DisplayHandle, - }, - }, - utils::{Clock, Logical, Monotonic, Physical, Point, Rectangle, Size, Transform}, - wayland::{ - compositor::{with_states, CompositorState}, - data_device::DataDeviceState, - dmabuf::{DmabufGlobal, DmabufState}, - output::OutputManagerState, - presentation::PresentationState, - shell::xdg::{XdgShellState, XdgToplevelSurfaceData}, - shm::ShmState, - socket::ListeningSocketSource, - viewporter::ViewporterState, - relative_pointer::RelativePointerManagerState, - }, -}; -use wayland_backend::server::GlobalId; - -mod focus; -mod input; -mod rendering; - -pub use self::focus::*; -pub use self::input::*; -pub use self::rendering::*; -use crate::{utils::RenderTarget, wayland::protocols::wl_drm::create_drm_global}; - -static EGL_DISPLAYS: Lazy, Weak>>> = - Lazy::new(|| Mutex::new(HashMap::new())); - -struct ClientState; -impl ClientData for ClientState { - fn initialized(&self, _client_id: ClientId) {} - fn disconnected(&self, _client_id: ClientId, _reason: DisconnectReason) {} -} - -pub(crate) struct Data { - pub(crate) display: Display, - pub(crate) state: State, -} - -#[allow(dead_code)] -pub(crate) struct State { - handle: LoopHandle<'static, Data>, - should_quit: bool, - clock: Clock, - - // render - dtr: Option, - renderbuffer: Option, - pub renderer: Gles2Renderer, - egl_display_ref: Arc, - dmabuf_global: Option<(DmabufGlobal, GlobalId)>, - last_render: Option, - - // management - pub output: Option, - pub video_info: Option, - pub seat: Seat, - pub space: Space, - pub popups: PopupManager, - pointer_location: Point, - last_pointer_movement: Instant, - cursor_element: MemoryRenderBuffer, - pub cursor_state: CursorImageStatus, - surpressed_keys: HashSet, - pub pending_windows: Vec, - input_context: Libinput, - - // wayland state - pub dh: DisplayHandle, - pub compositor_state: CompositorState, - pub data_device_state: DataDeviceState, - pub dmabuf_state: DmabufState, - output_state: OutputManagerState, - presentation_state: PresentationState, - relative_ptr_state: RelativePointerManagerState, - pub seat_state: SeatState, - pub shell_state: XdgShellState, - pub shm_state: ShmState, - viewporter_state: ViewporterState, -} - -pub fn get_egl_device_for_node(drm_node: &DrmNode) -> EGLDevice { - let drm_node = drm_node - .node_with_type(NodeType::Render) - .and_then(Result::ok) - .unwrap_or(drm_node.clone()); - EGLDevice::enumerate() - .expect("Failed to enumerate EGLDevices") - .find(|d| d.try_get_render_node().unwrap_or_default() == Some(drm_node)) - .expect("Unable to find EGLDevice for drm-node") -} - -pub(crate) fn init( - command_src: Channel, - render: impl Into, - devices_tx: Sender>, - envs_tx: Sender>, -) { - let clock = Clock::new().expect("Failed to initialize clock"); - let mut display = Display::::new().unwrap(); - let dh = display.handle(); - - // init state - let compositor_state = CompositorState::new::(&dh); - let data_device_state = DataDeviceState::new::(&dh); - let mut dmabuf_state = DmabufState::new(); - let output_state = OutputManagerState::new_with_xdg_output::(&dh); - let presentation_state = PresentationState::new::(&dh, clock.id() as _); - let relative_ptr_state = RelativePointerManagerState::new::(&dh); - let mut seat_state = SeatState::new(); - let shell_state = XdgShellState::new::(&dh); - let viewporter_state = ViewporterState::new::(&dh); - - let render_target = render.into(); - let render_node: Option = render_target.clone().into(); - - // init render backend - let (egl_display_ref, context) = { - let mut displays = EGL_DISPLAYS.lock().unwrap(); - let maybe_display = displays - .get(&render_node) - .and_then(|weak_display| weak_display.upgrade()); - - let egl = match maybe_display { - Some(display) => display, - None => { - let device = match render_node.as_ref() { - Some(render_node) => get_egl_device_for_node(render_node), - None => EGLDevice::enumerate() - .expect("Failed to enumerate EGLDevices") - .find(|device| { - device - .extensions() - .iter() - .any(|e| e == "EGL_MESA_device_software") - }) - .expect("Failed to find software device"), - }; - let display = - Arc::new(EGLDisplay::new(device).expect("Failed to initialize EGL display")); - displays.insert(render_node, Arc::downgrade(&display)); - display - } - }; - let context = EGLContext::new(&egl).expect("Failed to initialize EGL context"); - (egl, context) - }; - let renderer = unsafe { Gles2Renderer::new(context) }.expect("Failed to initialize renderer"); - let _ = devices_tx.send(render_target.as_devices()); - - let shm_state = ShmState::new::(&dh, vec![]); - let dmabuf_global = if let RenderTarget::Hardware(node) = render_target { - let formats = Bind::::supported_formats(&renderer) - .expect("Failed to query formats") - .into_iter() - .collect::>(); - - // dma buffer - let dmabuf_global = dmabuf_state.create_global::(&dh, formats.clone()); - // wl_drm (mesa protocol, so we don't need EGL_WL_bind_display) - let wl_drm_global = create_drm_global::( - &dh, - node.dev_path().expect("Failed to determine DrmNode path?"), - formats.clone(), - &dmabuf_global, - ); - - Some((dmabuf_global, wl_drm_global)) - } else { - None - }; - - let cursor_element = - MemoryRenderBuffer::from_memory(CURSOR_DATA_BYTES, (64, 64), 1, Transform::Normal, None); - - // init input backend - let libinput_context = Libinput::new_from_path(NixInterface); - let input_context = libinput_context.clone(); - let libinput_backend = LibinputInputBackend::new(libinput_context); - - let space = Space::default(); - - let mut seat = seat_state.new_wl_seat(&dh, "seat-0"); - seat.add_keyboard(XkbConfig::default(), 200, 25) - .expect("Failed to add keyboard to seat"); - seat.add_pointer(); - - let mut event_loop = - EventLoop::::try_new_high_precision().expect("Unable to create event_loop"); - let state = State { - handle: event_loop.handle(), - should_quit: false, - clock, - - renderer, - egl_display_ref, - dtr: None, - renderbuffer: None, - dmabuf_global, - video_info: None, - last_render: None, - - space, - popups: PopupManager::default(), - seat, - output: None, - pointer_location: (0., 0.).into(), - last_pointer_movement: Instant::now(), - cursor_element, - cursor_state: CursorImageStatus::Default, - surpressed_keys: HashSet::new(), - pending_windows: Vec::new(), - input_context, - - dh: display.handle(), - compositor_state, - data_device_state, - dmabuf_state, - output_state, - presentation_state, - relative_ptr_state, - seat_state, - shell_state, - shm_state, - viewporter_state, - }; - - // init event loop - event_loop - .handle() - .insert_source(libinput_backend, move |event, _, data| { - data.state.process_input_event(event) - }) - .unwrap(); - - event_loop - .handle() - .insert_source(command_src, move |event, _, data| { - match event { - Event::Msg(Command::VideoInfo(info)) => { - let size: Size = - (info.width() as i32, info.height() as i32).into(); - let framerate = info.fps(); - let duration = Duration::from_secs_f64( - framerate.numer() as f64 / framerate.denom() as f64, - ); - - // init wayland objects - let output = data.state.output.get_or_insert_with(|| { - let output = Output::new( - "HEADLESS-1".into(), - PhysicalProperties { - make: "Virtual".into(), - model: "Wolf".into(), - size: (0, 0).into(), - subpixel: Subpixel::Unknown, - }, - ); - output.create_global::(&data.display.handle()); - output - }); - let mode = OutputMode { - size: size.into(), - refresh: (duration.as_secs_f64() * 1000.0).round() as i32, - }; - output.change_current_state(Some(mode), None, None, None); - output.set_preferred(mode); - let dtr = DamageTrackedRenderer::from_output(&output); - - data.state.space.map_output(&output, (0, 0)); - data.state.dtr = Some(dtr); - data.state.pointer_location = (size.w as f64 / 2.0, size.h as f64 / 2.0).into(); - data.state.renderbuffer = Some( - data.state - .renderer - .create_buffer((info.width() as i32, info.height() as i32).into()) - .expect("Failed to create renderbuffer"), - ); - data.state.video_info = Some(info); - - let new_size = size - .to_f64() - .to_logical(output.current_scale().fractional_scale()) - .to_i32_round(); - for window in data.state.space.elements() { - let toplevel = window.toplevel(); - let max_size = Rectangle::from_loc_and_size( - (0, 0), - with_states(toplevel.wl_surface(), |states| { - states - .data_map - .get::() - .map(|attrs| attrs.lock().unwrap().max_size) - }) - .unwrap_or(new_size), - ); - - let new_size = max_size - .intersection(Rectangle::from_loc_and_size((0, 0), new_size)) - .map(|rect| rect.size); - toplevel.with_pending_state(|state| state.size = new_size); - toplevel.send_configure(); - } - } - Event::Msg(Command::InputDevice(path)) => { - tracing::info!(path, "Adding input device."); - data.state.input_context.path_add_device(&path); - } - Event::Msg(Command::Buffer(buffer_sender)) => { - let wait = if let Some(last_render) = data.state.last_render { - let framerate = data.state.video_info.as_ref().unwrap().fps(); - let duration = Duration::from_secs_f64( - framerate.denom() as f64 / framerate.numer() as f64, - ); - let time_passed = Instant::now().duration_since(last_render); - if time_passed < duration { - Some(duration - time_passed) - } else { - None - } - } else { - None - }; - - let render = move |data: &mut Data, now: Instant| { - if let Err(_) = match data.state.create_frame() { - Ok((buf, damage, render_element_states)) => { - data.state.last_render = Some(now); - let res = buffer_sender.send(Ok(buf)); - - if let Some(output) = data.state.output.as_ref() { - let mut output_presentation_feedback = - OutputPresentationFeedback::new(output); - for window in data.state.space.elements() { - window.with_surfaces(|surface, states| { - update_surface_primary_scanout_output( - surface, - output, - states, - &render_element_states, - |next_output, _, _, _| next_output, - ); - }); - window.send_frame( - output, - data.state.clock.now(), - Some(Duration::ZERO), - |_, _| Some(output.clone()), - ); - window.take_presentation_feedback( - &mut output_presentation_feedback, - surface_primary_scanout_output, - |surface, _| { - surface_presentation_feedback_flags_from_states( - surface, - &render_element_states, - ) - }, - ); - } - if damage.is_some() { - output_presentation_feedback.presented( - data.state.clock.now(), - output - .current_mode() - .map(|mode| mode.refresh as u32) - .unwrap_or_default(), - 0, - wp_presentation_feedback::Kind::Vsync, - ); - } - if let CursorImageStatus::Surface(wl_surface) = - &data.state.cursor_state - { - send_frames_surface_tree( - wl_surface, - output, - data.state.clock.now(), - None, - |_, _| Some(output.clone()), - ) - } - } - - res - } - Err(err) => { - tracing::error!(?err, "Rendering failed."); - buffer_sender.send(Err(match err { - DTRError::OutputNoMode(_) => unreachable!(), - DTRError::Rendering(err) => err.into(), - })) - } - } { - data.state.should_quit = true; - } - }; - - match wait { - Some(duration) => { - if let Err(err) = data.state.handle.insert_source( - Timer::from_duration(duration), - move |now, _, data| { - render(data, now); - TimeoutAction::Drop - }, - ) { - tracing::error!(?err, "Event loop error."); - data.state.should_quit = true; - }; - } - None => render(data, Instant::now()), - }; - } - Event::Msg(Command::Quit) | Event::Closed => { - data.state.should_quit = true; - } - }; - }) - .unwrap(); - - let source = ListeningSocketSource::new_auto().unwrap(); - let socket_name = source.socket_name().to_string_lossy().into_owned(); - tracing::info!(?socket_name, "Listening on wayland socket."); - event_loop - .handle() - .insert_source(source, |client_stream, _, data| { - if let Err(err) = data - .display - .handle() - .insert_client(client_stream, std::sync::Arc::new(ClientState)) - { - tracing::error!(?err, "Error adding wayland client."); - }; - }) - .expect("Failed to init wayland socket source"); - - event_loop - .handle() - .insert_source( - Generic::new( - display.backend().poll_fd().as_raw_fd(), - Interest::READ, - Mode::Level, - ), - |_, _, data| { - data.display.dispatch_clients(&mut data.state).unwrap(); - Ok(PostAction::Continue) - }, - ) - .expect("Failed to init wayland server source"); - - let env_vars = vec![CString::new(format!("WAYLAND_DISPLAY={}", socket_name)).unwrap()]; - if let Err(err) = envs_tx.send(env_vars) { - tracing::warn!(?err, "Failed to post environment to application."); - } - - let mut data = Data { display, state }; - let signal = event_loop.get_signal(); - if let Err(err) = event_loop.run(None, &mut data, |data| { - data.display - .flush_clients() - .expect("Failed to flush clients"); - data.state.space.refresh(); - data.state.popups.cleanup(); - - if data.state.should_quit { - signal.stop(); - } - }) { - tracing::error!(?err, "Event loop broke."); - } -} diff --git a/src/core/rust/gst-wayland-display/src/comp/rendering.rs b/src/core/rust/gst-wayland-display/src/comp/rendering.rs deleted file mode 100644 index 3813f11e..00000000 --- a/src/core/rust/gst-wayland-display/src/comp/rendering.rs +++ /dev/null @@ -1,121 +0,0 @@ -use std::time::{Duration, Instant}; - -use smithay::{ - backend::renderer::{ - damage::DamageTrackedRendererError as DTRError, - element::{ - memory::MemoryRenderBufferRenderElement, surface::WaylandSurfaceRenderElement, - RenderElementStates, - }, - gles2::Gles2Renderer, - Bind, ExportMem, ImportAll, ImportMem, Renderer, Unbind, - }, - desktop::space::render_output, - input::pointer::CursorImageStatus, - render_elements, - utils::{Physical, Rectangle}, -}; - -use super::State; - -pub const CURSOR_DATA_BYTES: &[u8] = include_bytes!("../../resources/cursor.rgba"); - -render_elements! { - CursorElement where R: Renderer + ImportAll + ImportMem; - Surface=WaylandSurfaceRenderElement, - Memory=MemoryRenderBufferRenderElement -} - -impl State { - pub fn create_frame( - &mut self, - ) -> Result< - ( - gst::Buffer, - Option>>, - RenderElementStates, - ), - DTRError, - > { - assert!(self.output.is_some()); - assert!(self.dtr.is_some()); - assert!(self.video_info.is_some()); - assert!(self.renderbuffer.is_some()); - - let elements = - if Instant::now().duration_since(self.last_pointer_movement) < Duration::from_secs(5) { - match &self.cursor_state { - CursorImageStatus::Default => vec![CursorElement::Memory( - MemoryRenderBufferRenderElement::from_buffer( - &mut self.renderer, - self.pointer_location.to_physical_precise_round(1), - &self.cursor_element, - None, - None, - None, - ) - .map_err(DTRError::Rendering)?, - )], - CursorImageStatus::Surface(wl_surface) => { - smithay::backend::renderer::element::surface::render_elements_from_surface_tree( - &mut self.renderer, - wl_surface, - self.pointer_location.to_physical_precise_round(1), - 1., - ) - } - CursorImageStatus::Hidden => vec![], - } - } else { - vec![] - }; - - self.renderer - .bind(self.renderbuffer.clone().unwrap()) - .map_err(DTRError::Rendering)?; - let (damage, render_element_states) = render_output( - self.output.as_ref().unwrap(), - &mut self.renderer, - 1, - [&self.space], - &*elements, - self.dtr.as_mut().unwrap(), - [0.0, 0.0, 0.0, 1.0], - )?; - - let mapping = self - .renderer - .copy_framebuffer(Rectangle::from_loc_and_size( - (0, 0), - ( - self.video_info.as_ref().unwrap().width() as i32, - self.video_info.as_ref().unwrap().height() as i32, - ), - )) - .expect("Failed to export framebuffer"); - let map = self - .renderer - .map_texture(&mapping) - .expect("Failed to download framebuffer"); - - let buffer = { - let mut buffer = gst::Buffer::with_size(map.len()).expect("failed to create buffer"); - { - let buffer = buffer.get_mut().unwrap(); - - let mut vframe = gst_video::VideoFrameRef::from_buffer_ref_writable( - buffer, - self.video_info.as_ref().unwrap(), - ) - .unwrap(); - let plane_data = vframe.plane_data_mut(0).unwrap(); - plane_data.clone_from_slice(map); - } - - buffer - }; - self.renderer.unbind().map_err(DTRError::Rendering)?; - - Ok((buffer, damage, render_element_states)) - } -} diff --git a/src/core/rust/gst-wayland-display/src/lib.rs b/src/core/rust/gst-wayland-display/src/lib.rs deleted file mode 100644 index 69092e9d..00000000 --- a/src/core/rust/gst-wayland-display/src/lib.rs +++ /dev/null @@ -1,249 +0,0 @@ -use gst::ffi::GstBuffer; -use gst::glib::translate::FromGlibPtrNone; -use gst_video::ffi::GstVideoInfo; -use gst_video::VideoInfo; - -use smithay::backend::drm::CreateDrmNodeError; -use smithay::backend::SwapBuffersError; -use smithay::reexports::calloop::channel::Sender; - -use std::ffi::{c_char, CStr, CString}; -use std::ptr; -use std::str::FromStr; -use std::sync::mpsc::{self, Receiver, SyncSender}; -use std::thread::JoinHandle; - -use utils::RenderTarget; - -pub(crate) mod comp; -pub(crate) mod utils; -pub(crate) mod wayland; - -pub(crate) enum Command { - InputDevice(String), - VideoInfo(VideoInfo), - Buffer(SyncSender>), - Quit, -} - -pub struct WaylandDisplay { - thread_handle: Option>, - command_tx: Sender, - - devices: MaybeRecv>, - envs: MaybeRecv>, -} - -enum MaybeRecv { - Rx(Receiver), - Value(T), -} - -impl MaybeRecv { - fn get(&mut self) -> &T { - match self { - MaybeRecv::Rx(recv) => { - let value = recv.recv().unwrap(); - *self = MaybeRecv::Value(value.clone()); - self.get() - } - MaybeRecv::Value(val) => val, - } - } -} - -impl WaylandDisplay { - pub fn new(render_node: Option) -> Result { - let (channel_tx, channel_rx) = std::sync::mpsc::sync_channel(0); - let (devices_tx, devices_rx) = std::sync::mpsc::channel(); - let (envs_tx, envs_rx) = std::sync::mpsc::channel(); - let render_target = RenderTarget::from_str( - &render_node.unwrap_or_else(|| String::from("/dev/dri/renderD128")), - )?; - - let thread_handle = std::thread::spawn(move || { - if let Err(err) = std::panic::catch_unwind(|| { - // calloops channel is not "UnwindSafe", but the std channel is... *sigh* lets workaround it creatively - let (command_tx, command_src) = smithay::reexports::calloop::channel::channel(); - channel_tx.send(command_tx).unwrap(); - comp::init(command_src, render_target, devices_tx, envs_tx); - }) { - tracing::error!(?err, "Compositor thread panic'ed!"); - } - }); - let command_tx = channel_rx.recv().unwrap(); - - Ok(WaylandDisplay { - thread_handle: Some(thread_handle), - command_tx, - devices: MaybeRecv::Rx(devices_rx), - envs: MaybeRecv::Rx(envs_rx), - }) - } - - pub fn devices(&mut self) -> impl Iterator { - self.devices - .get() - .iter() - .map(|string| string.to_str().unwrap()) - } - - pub fn env_vars(&mut self) -> impl Iterator { - self.envs - .get() - .iter() - .map(|string| string.to_str().unwrap()) - } - - pub fn add_input_device(&self, path: impl Into) { - let _ = self.command_tx.send(Command::InputDevice(path.into())); - } - - pub fn set_video_info(&self, info: VideoInfo) { - let _ = self.command_tx.send(Command::VideoInfo(info)); - } - - pub fn frame(&self) -> Result { - let (buffer_tx, buffer_rx) = mpsc::sync_channel(0); - if let Err(err) = self.command_tx.send(Command::Buffer(buffer_tx)) { - tracing::warn!(?err, "Failed to send buffer command."); - return Err(gst::FlowError::Eos); - } - - match buffer_rx.recv() { - Ok(Ok(buffer)) => Ok(buffer), - Ok(Err(err)) => match err { - SwapBuffersError::AlreadySwapped => unreachable!(), - SwapBuffersError::ContextLost(_) => Err(gst::FlowError::Eos), - SwapBuffersError::TemporaryFailure(_) => Err(gst::FlowError::Error), - }, - Err(err) => { - tracing::warn!(?err, "Failed to recv buffer ack."); - Err(gst::FlowError::Error) - } - } - } -} - -impl Drop for WaylandDisplay { - fn drop(&mut self) { - if let Err(err) = self.command_tx.send(Command::Quit) { - tracing::warn!("Failed to send stop command: {}", err); - return; - }; - if self.thread_handle.take().unwrap().join().is_err() { - tracing::warn!("Failed to join compositor thread"); - }; - } -} - -// C API - -#[no_mangle] -pub extern "C" fn display_init(render_node: *const c_char) -> *mut WaylandDisplay { - let render_node = if !render_node.is_null() { - Some( - unsafe { CStr::from_ptr(render_node) } - .to_string_lossy() - .into_owned(), - ) - } else { - None - }; - - match WaylandDisplay::new(render_node) { - Ok(dpy) => Box::into_raw(Box::new(dpy)), - Err(err) => { - tracing::error!(?err, "Failed to create wayland display."); - ptr::null_mut() - } - } -} - -#[no_mangle] -pub extern "C" fn display_finish(dpy: *mut WaylandDisplay) { - std::mem::drop(unsafe { Box::from_raw(dpy) }) -} - -#[no_mangle] -pub extern "C" fn display_get_devices_len(dpy: *mut WaylandDisplay) -> usize { - let display = unsafe { &mut *dpy }; - display.devices.get().len() -} - -#[no_mangle] -pub extern "C" fn display_get_devices( - dpy: *mut WaylandDisplay, - devices: *mut *const c_char, - max_len: usize, -) -> usize { - let display = unsafe { &mut *dpy }; - let client_devices = unsafe { std::slice::from_raw_parts_mut(devices, max_len) }; - let devices = display.devices.get(); - - for (i, string) in devices.iter().take(max_len).enumerate() { - client_devices[i] = string.as_ptr() as *const _; - } - - std::cmp::max(max_len, devices.len()) -} - -#[no_mangle] -pub extern "C" fn display_get_envvars_len(dpy: *mut WaylandDisplay) -> usize { - let display = unsafe { &mut *dpy }; - display.envs.get().len() -} - -#[no_mangle] -pub extern "C" fn display_get_envvars( - dpy: *mut WaylandDisplay, - env_vars: *mut *const c_char, - max_len: usize, -) -> usize { - let display = unsafe { &mut *dpy }; - let client_env_vars = unsafe { std::slice::from_raw_parts_mut(env_vars, max_len) }; - let env_vars = display.envs.get(); - - for (i, string) in env_vars.iter().take(max_len).enumerate() { - client_env_vars[i] = string.as_ptr() as *const _; - } - - std::cmp::max(max_len, env_vars.len()) -} - -#[no_mangle] -pub extern "C" fn display_add_input_device(dpy: *mut WaylandDisplay, path: *const c_char) { - let display = unsafe { &mut *dpy }; - let path = unsafe { CStr::from_ptr(path) } - .to_string_lossy() - .into_owned(); - - display.add_input_device(path); -} - -#[no_mangle] -pub extern "C" fn display_set_video_info(dpy: *mut WaylandDisplay, info: *const GstVideoInfo) { - let display = unsafe { &mut *dpy }; - if info.is_null() { - tracing::error!("Video Info is null"); - } - let video_info = unsafe { VideoInfo::from_glib_none(info) }; - - display.set_video_info(video_info); -} - -#[no_mangle] -pub extern "C" fn display_get_frame(dpy: *mut WaylandDisplay) -> *mut GstBuffer { - let display = unsafe { &mut *dpy }; - match display.frame() { - Ok(mut frame) => { - let ptr = frame.make_mut().as_mut_ptr(); - std::mem::forget(frame); - ptr - } - Err(err) => { - tracing::error!("Rendering error: {}", err); - ptr::null_mut() - } - } -} diff --git a/src/core/rust/gst-wayland-display/src/utils/mod.rs b/src/core/rust/gst-wayland-display/src/utils/mod.rs deleted file mode 100644 index ca50d83b..00000000 --- a/src/core/rust/gst-wayland-display/src/utils/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod target; - -pub use self::target::*; diff --git a/src/core/rust/gst-wayland-display/src/utils/target.rs b/src/core/rust/gst-wayland-display/src/utils/target.rs deleted file mode 100644 index 712da2e9..00000000 --- a/src/core/rust/gst-wayland-display/src/utils/target.rs +++ /dev/null @@ -1,88 +0,0 @@ -use std::{ffi::CString, os::unix::fs::MetadataExt, str::FromStr}; - -use smithay::{ - backend::{ - drm::{CreateDrmNodeError, DrmNode, NodeType}, - udev, - }, - reexports::nix::sys::stat::major, -}; - -#[derive(Debug, Clone, PartialEq)] -pub enum RenderTarget { - Hardware(DrmNode), - Software, -} - -impl FromStr for RenderTarget { - type Err = CreateDrmNodeError; - fn from_str(s: &str) -> Result { - Ok(match s { - "software" => RenderTarget::Software, - path => RenderTarget::Hardware(DrmNode::from_path(path)?), - }) - } -} - -impl Into> for RenderTarget { - fn into(self) -> Option { - match self { - RenderTarget::Hardware(node) => Some(node), - RenderTarget::Software => None, - } - } -} - -impl Into for DrmNode { - fn into(self) -> RenderTarget { - RenderTarget::Hardware(self) - } -} - -#[cfg(target_os = "linux")] -const NVIDIA_MAJOR: u64 = 195; - -// no clue how this number is on BSDs, feel free to contribute - -impl RenderTarget { - pub fn as_devices(&self) -> Vec { - match self { - RenderTarget::Hardware(node) => { - let mut devices = Vec::new(); - if let Some(primary) = node.dev_path_with_type(NodeType::Primary) { - devices.push(primary); - } - if let Some(render) = node.dev_path_with_type(NodeType::Render) { - devices.push(render); - } - if udev::driver(node.dev_id()) - .ok() - .flatten() - .map(|s| s.to_str() == Some("nvidia")) - .unwrap_or(false) - { - // no idea how match nvidia device nodes to kms/dri-nodes, so lets map all nvidia-nodes to be sure - for entry in std::fs::read_dir("/dev").expect("Unable to access /dev") { - if let Ok(entry) = entry { - if let Ok(metadata) = entry.metadata() { - if metadata.is_file() && major(metadata.dev()) == NVIDIA_MAJOR { - devices.push(entry.path()); - } - } - } - } - } - - devices - .into_iter() - .flat_map(|path| { - path.to_str() - .map(String::from) - .and_then(|string| CString::new(string).ok()) - }) - .collect() - } - RenderTarget::Software => Vec::new(), - } - } -} diff --git a/src/core/rust/gst-wayland-display/src/wayland/handlers/compositor.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/compositor.rs deleted file mode 100644 index b2be453e..00000000 --- a/src/core/rust/gst-wayland-display/src/wayland/handlers/compositor.rs +++ /dev/null @@ -1,147 +0,0 @@ -use smithay::{ - backend::renderer::utils::{import_surface_tree, on_commit_buffer_handler}, - delegate_compositor, - desktop::PopupKind, - reexports::{ - wayland_protocols::xdg::shell::server::xdg_toplevel::State as XdgState, - wayland_server::protocol::{wl_buffer::WlBuffer, wl_surface::WlSurface}, - }, - utils::{Size, SERIAL_COUNTER}, - wayland::{ - buffer::BufferHandler, - compositor::{with_states, CompositorHandler, CompositorState}, - seat::WaylandFocus, - shell::xdg::{XdgPopupSurfaceData, XdgToplevelSurfaceData}, - }, -}; - -use crate::comp::{FocusTarget, State}; - -impl BufferHandler for State { - fn buffer_destroyed(&mut self, _buffer: &WlBuffer) {} -} - -impl CompositorHandler for State { - fn compositor_state(&mut self) -> &mut CompositorState { - &mut self.compositor_state - } - - fn commit(&mut self, surface: &WlSurface) { - on_commit_buffer_handler(surface); - - if let Some(window) = self - .space - .elements() - .find(|w| w.wl_surface().as_ref() == Some(surface)) - { - window.on_commit(); - } - self.popups.commit(surface); - - // send the initial configure if relevant - if let Some(idx) = self - .pending_windows - .iter_mut() - .position(|w| w.wl_surface().as_ref() == Some(surface)) - { - let window = self.pending_windows.swap_remove(idx); - - let toplevel = window.toplevel(); - let (initial_configure_sent, max_size) = with_states(surface, |states| { - let attributes = states.data_map.get::().unwrap(); - let attributes_guard = attributes.lock().unwrap(); - - ( - attributes_guard.initial_configure_sent, - attributes_guard.max_size, - ) - }); - - if self.output.is_none() { - return; - } - - if !initial_configure_sent { - if max_size.w == 0 && max_size.h == 0 { - toplevel.with_pending_state(|state| { - state.size = Some( - self.output - .as_ref() - .unwrap() - .current_mode() - .unwrap() - .size - .to_f64() - .to_logical( - self.output - .as_ref() - .unwrap() - .current_scale() - .fractional_scale(), - ) - .to_i32_round(), - ); - state.states.set(XdgState::Fullscreen); - }); - } - toplevel.with_pending_state(|state| { - state.states.set(XdgState::Activated); - }); - toplevel.send_configure(); - self.pending_windows.push(window); - } else { - let window_size = toplevel.current_state().size.unwrap_or((0, 0).into()); - let output_size: Size = self - .output - .as_ref() - .unwrap() - .current_mode() - .unwrap() - .size - .to_f64() - .to_logical( - self.output - .as_ref() - .unwrap() - .current_scale() - .fractional_scale(), - ) - .to_i32_round(); - let loc = ( - (output_size.w / 2) - (window_size.w / 2), - (output_size.h / 2) - (window_size.h / 2), - ); - self.space.map_element(window.clone(), loc, true); - self.seat.get_keyboard().unwrap().set_focus( - self, - Some(FocusTarget::from(window)), - SERIAL_COUNTER.next_serial(), - ); - } - - return; - } - - if let Some(popup) = self.popups.find_popup(surface) { - let PopupKind::Xdg(ref popup) = popup; - let initial_configure_sent = with_states(surface, |states| { - states - .data_map - .get::() - .unwrap() - .lock() - .unwrap() - .initial_configure_sent - }); - if !initial_configure_sent { - // NOTE: This should never fail as the initial configure is always - // allowed. - popup.send_configure().expect("initial configure failed"); - } - - return; - }; - } -} - -delegate_compositor!(State); diff --git a/src/core/rust/gst-wayland-display/src/wayland/handlers/data_device.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/data_device.rs deleted file mode 100644 index 96792be0..00000000 --- a/src/core/rust/gst-wayland-display/src/wayland/handlers/data_device.rs +++ /dev/null @@ -1,18 +0,0 @@ -use smithay::{ - delegate_data_device, - wayland::data_device::{ - ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler, - }, -}; - -use crate::comp::State; - -impl ServerDndGrabHandler for State {} -impl ClientDndGrabHandler for State {} -impl DataDeviceHandler for State { - fn data_device_state(&self) -> &DataDeviceState { - &self.data_device_state - } -} - -delegate_data_device!(State); diff --git a/src/core/rust/gst-wayland-display/src/wayland/handlers/dmabuf.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/dmabuf.rs deleted file mode 100644 index bbbeb486..00000000 --- a/src/core/rust/gst-wayland-display/src/wayland/handlers/dmabuf.rs +++ /dev/null @@ -1,26 +0,0 @@ -use smithay::{ - backend::{allocator::dmabuf::Dmabuf, renderer::ImportDma}, - delegate_dmabuf, - wayland::dmabuf::{DmabufGlobal, DmabufHandler, DmabufState, ImportError}, -}; - -use crate::comp::State; - -impl DmabufHandler for State { - fn dmabuf_state(&mut self) -> &mut DmabufState { - &mut self.dmabuf_state - } - - fn dmabuf_imported( - &mut self, - _global: &DmabufGlobal, - dmabuf: Dmabuf, - ) -> Result<(), ImportError> { - self.renderer - .import_dmabuf(&dmabuf, None) - .map(|_| ()) - .map_err(|_| ImportError::Failed) - } -} - -delegate_dmabuf!(State); diff --git a/src/core/rust/gst-wayland-display/src/wayland/handlers/mod.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/mod.rs deleted file mode 100644 index eb68bafe..00000000 --- a/src/core/rust/gst-wayland-display/src/wayland/handlers/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub mod compositor; -pub mod data_device; -pub mod dmabuf; -pub mod output; -pub mod presentation; -pub mod relative_pointer; -pub mod seat; -pub mod shm; -pub mod viewporter; -pub mod wl_drm; -pub mod xdg; diff --git a/src/core/rust/gst-wayland-display/src/wayland/handlers/output.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/output.rs deleted file mode 100644 index 1fe24790..00000000 --- a/src/core/rust/gst-wayland-display/src/wayland/handlers/output.rs +++ /dev/null @@ -1,5 +0,0 @@ -use smithay::delegate_output; - -use crate::comp::State; - -delegate_output!(State); diff --git a/src/core/rust/gst-wayland-display/src/wayland/handlers/presentation.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/presentation.rs deleted file mode 100644 index dfdc129c..00000000 --- a/src/core/rust/gst-wayland-display/src/wayland/handlers/presentation.rs +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only - -use crate::comp::State; -use smithay::delegate_presentation; - -delegate_presentation!(State); diff --git a/src/core/rust/gst-wayland-display/src/wayland/handlers/relative_pointer.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/relative_pointer.rs deleted file mode 100644 index 1d1bd5ca..00000000 --- a/src/core/rust/gst-wayland-display/src/wayland/handlers/relative_pointer.rs +++ /dev/null @@ -1,5 +0,0 @@ -use smithay::delegate_relative_pointer; - -use crate::comp::State; - -delegate_relative_pointer!(State); \ No newline at end of file diff --git a/src/core/rust/gst-wayland-display/src/wayland/handlers/seat.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/seat.rs deleted file mode 100644 index ccad3d1b..00000000 --- a/src/core/rust/gst-wayland-display/src/wayland/handlers/seat.rs +++ /dev/null @@ -1,35 +0,0 @@ -use smithay::{ - delegate_seat, - input::{pointer::CursorImageStatus, Seat, SeatHandler, SeatState}, - reexports::wayland_server::Resource, - wayland::data_device::set_data_device_focus, -}; - -use crate::comp::{FocusTarget, State}; - -impl SeatHandler for State { - type KeyboardFocus = FocusTarget; - type PointerFocus = FocusTarget; - - fn seat_state(&mut self) -> &mut SeatState { - &mut self.seat_state - } - - fn focus_changed(&mut self, seat: &Seat, focus: Option<&Self::KeyboardFocus>) { - if let Some(surface) = focus { - let client = match surface { - FocusTarget::Wayland(w) => w.toplevel().wl_surface().client(), - FocusTarget::Popup(p) => p.wl_surface().client(), - }; - set_data_device_focus(&self.dh, seat, client); - } else { - set_data_device_focus(&self.dh, seat, None); - } - } - - fn cursor_image(&mut self, _seat: &Seat, image: CursorImageStatus) { - self.cursor_state = image; - } -} - -delegate_seat!(State); diff --git a/src/core/rust/gst-wayland-display/src/wayland/handlers/shm.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/shm.rs deleted file mode 100644 index 4e600776..00000000 --- a/src/core/rust/gst-wayland-display/src/wayland/handlers/shm.rs +++ /dev/null @@ -1,14 +0,0 @@ -use smithay::{ - delegate_shm, - wayland::shm::{ShmHandler, ShmState}, -}; - -use crate::comp::State; - -impl ShmHandler for State { - fn shm_state(&self) -> &ShmState { - &self.shm_state - } -} - -delegate_shm!(State); diff --git a/src/core/rust/gst-wayland-display/src/wayland/handlers/viewporter.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/viewporter.rs deleted file mode 100644 index 3e5edc3b..00000000 --- a/src/core/rust/gst-wayland-display/src/wayland/handlers/viewporter.rs +++ /dev/null @@ -1,5 +0,0 @@ -use smithay::delegate_viewporter; - -use crate::comp::State; - -delegate_viewporter!(State); diff --git a/src/core/rust/gst-wayland-display/src/wayland/handlers/wl_drm.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/wl_drm.rs deleted file mode 100644 index 4ad8c471..00000000 --- a/src/core/rust/gst-wayland-display/src/wayland/handlers/wl_drm.rs +++ /dev/null @@ -1,3 +0,0 @@ -use crate::{comp::State, wayland::protocols::wl_drm::delegate_wl_drm}; - -delegate_wl_drm!(State); diff --git a/src/core/rust/gst-wayland-display/src/wayland/handlers/xdg.rs b/src/core/rust/gst-wayland-display/src/wayland/handlers/xdg.rs deleted file mode 100644 index 19b8a6a9..00000000 --- a/src/core/rust/gst-wayland-display/src/wayland/handlers/xdg.rs +++ /dev/null @@ -1,83 +0,0 @@ -use smithay::{ - delegate_xdg_shell, - desktop::{ - find_popup_root_surface, PopupKeyboardGrab, PopupKind, PopupPointerGrab, - PopupUngrabStrategy, Window, - }, - input::{pointer::Focus, Seat}, - reexports::wayland_server::protocol::wl_seat::WlSeat, - utils::Serial, - wayland::{ - seat::WaylandFocus, - shell::xdg::{ - PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState, - }, - }, -}; - -use crate::comp::{FocusTarget, State}; - -impl XdgShellHandler for State { - fn xdg_shell_state(&mut self) -> &mut XdgShellState { - &mut self.shell_state - } - - fn new_toplevel(&mut self, surface: ToplevelSurface) { - let window = Window::new(surface); - self.pending_windows.push(window); - } - - fn new_popup(&mut self, surface: PopupSurface, positioner: PositionerState) { - // TODO: properly recompute the geometry with the whole of positioner state - surface.with_pending_state(|state| { - // NOTE: This is not really necessary as the default geometry - // is already set the same way, but for demonstrating how - // to set the initial popup geometry this code is left as - // an example - state.geometry = positioner.get_geometry(); - }); - if let Err(err) = self.popups.track_popup(PopupKind::from(surface)) { - tracing::warn!(?err, "Failed to track popup."); - } - } - - fn grab(&mut self, surface: PopupSurface, seat: WlSeat, serial: Serial) { - let seat: Seat = Seat::from_resource(&seat).unwrap(); - let kind = PopupKind::Xdg(surface.clone()); - if let Some(root) = find_popup_root_surface(&kind).ok().and_then(|root| { - self.space - .elements() - .find(|w| w.wl_surface().map(|s| s == root).unwrap_or(false)) - .cloned() - .map(FocusTarget::from) - }) { - let ret = self.popups.grab_popup(root, surface.into(), &seat, serial); - if let Ok(mut grab) = ret { - if let Some(keyboard) = seat.get_keyboard() { - if keyboard.is_grabbed() - && !(keyboard.has_grab(serial) - || keyboard.has_grab(grab.previous_serial().unwrap_or(serial))) - { - grab.ungrab(PopupUngrabStrategy::All); - return; - } - keyboard.set_focus(self, grab.current_grab(), serial); - keyboard.set_grab(PopupKeyboardGrab::new(&grab), serial); - } - if let Some(pointer) = seat.get_pointer() { - if pointer.is_grabbed() - && !(pointer.has_grab(serial) - || pointer - .has_grab(grab.previous_serial().unwrap_or_else(|| grab.serial()))) - { - grab.ungrab(PopupUngrabStrategy::All); - return; - } - pointer.set_grab(self, PopupPointerGrab::new(&grab), serial, Focus::Clear); - } - } - } - } -} - -delegate_xdg_shell!(State); diff --git a/src/core/rust/gst-wayland-display/src/wayland/mod.rs b/src/core/rust/gst-wayland-display/src/wayland/mod.rs deleted file mode 100644 index 5d3c3fd9..00000000 --- a/src/core/rust/gst-wayland-display/src/wayland/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod handlers; -pub mod protocols; diff --git a/src/core/rust/gst-wayland-display/src/wayland/protocols/mod.rs b/src/core/rust/gst-wayland-display/src/wayland/protocols/mod.rs deleted file mode 100644 index 36d11e75..00000000 --- a/src/core/rust/gst-wayland-display/src/wayland/protocols/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod wl_drm; diff --git a/src/core/rust/gst-wayland-display/src/wayland/protocols/wl_drm.rs b/src/core/rust/gst-wayland-display/src/wayland/protocols/wl_drm.rs deleted file mode 100644 index dc39b45f..00000000 --- a/src/core/rust/gst-wayland-display/src/wayland/protocols/wl_drm.rs +++ /dev/null @@ -1,255 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only - -// Re-export only the actual code, and then only use this re-export -// The `generated` module below is just some boilerplate to properly isolate stuff -// and avoid exposing internal details. -// -// You can use all the types from my_protocol as if they went from `wayland_client::protocol`. -pub use generated::wl_drm; - -mod generated { - use smithay::reexports::wayland_server::{self, protocol::*}; - - pub mod __interfaces { - use smithay::reexports::wayland_server::protocol::__interfaces::*; - use wayland_backend; - wayland_scanner::generate_interfaces!("resources/protocols/wayland-drm.xml"); - } - use self::__interfaces::*; - - wayland_scanner::generate_server_code!("resources/protocols/wayland-drm.xml"); -} - -use smithay::{ - backend::allocator::{ - dmabuf::{Dmabuf, DmabufFlags}, - Format, Fourcc, Modifier, - }, - reexports::wayland_server::{ - backend::GlobalId, protocol::wl_buffer::WlBuffer, Client, DataInit, Dispatch, - DisplayHandle, GlobalDispatch, New, Resource, - }, - wayland::{ - buffer::BufferHandler, - dmabuf::{DmabufGlobal, DmabufHandler, ImportError}, - }, -}; - -use std::{convert::TryFrom, path::PathBuf, sync::Arc}; - -pub struct WlDrmState; - -/// Data associated with a drm global. -pub struct DrmGlobalData { - filter: Box Fn(&'a Client) -> bool + Send + Sync>, - formats: Arc>, - device_path: PathBuf, - dmabuf_global: DmabufGlobal, -} - -pub struct DrmInstanceData { - formats: Arc>, - dmabuf_global: DmabufGlobal, -} - -impl GlobalDispatch for WlDrmState -where - D: GlobalDispatch - + Dispatch - + BufferHandler - + DmabufHandler - + 'static, -{ - fn bind( - _state: &mut D, - _dh: &DisplayHandle, - _client: &Client, - resource: New, - global_data: &DrmGlobalData, - data_init: &mut DataInit<'_, D>, - ) { - let data = DrmInstanceData { - formats: global_data.formats.clone(), - dmabuf_global: global_data.dmabuf_global.clone(), - }; - let drm_instance = data_init.init(resource, data); - - drm_instance.device(global_data.device_path.to_string_lossy().into_owned()); - if drm_instance.version() >= 2 { - drm_instance.capabilities(wl_drm::Capability::Prime as u32); - } - for format in global_data.formats.iter() { - if let Ok(converted) = wl_drm::Format::try_from(*format as u32) { - drm_instance.format(converted as u32); - } - } - } - - fn can_view(client: Client, global_data: &DrmGlobalData) -> bool { - (global_data.filter)(&client) - } -} - -impl Dispatch for WlDrmState -where - D: GlobalDispatch - + Dispatch - + Dispatch - + BufferHandler - + DmabufHandler - + 'static, -{ - fn request( - state: &mut D, - _client: &Client, - drm: &wl_drm::WlDrm, - request: wl_drm::Request, - data: &DrmInstanceData, - _dh: &DisplayHandle, - data_init: &mut DataInit<'_, D>, - ) { - match request { - wl_drm::Request::Authenticate { .. } => drm.authenticated(), - wl_drm::Request::CreateBuffer { .. } => drm.post_error( - wl_drm::Error::InvalidName, - String::from("Flink handles are unsupported, use PRIME"), - ), - wl_drm::Request::CreatePlanarBuffer { .. } => drm.post_error( - wl_drm::Error::InvalidName, - String::from("Flink handles are unsupported, use PRIME"), - ), - wl_drm::Request::CreatePrimeBuffer { - id, - name, - width, - height, - format, - offset0, - stride0, - .. - } => { - let format = match Fourcc::try_from(format) { - Ok(format) => { - if !data.formats.contains(&format) { - drm.post_error( - wl_drm::Error::InvalidFormat, - String::from("Format not advertised by wl_drm"), - ); - return; - } - format - } - Err(_) => { - drm.post_error( - wl_drm::Error::InvalidFormat, - String::from("Format unknown / not advertised by wl_drm"), - ); - return; - } - }; - - if width < 1 || height < 1 { - drm.post_error( - wl_drm::Error::InvalidFormat, - String::from("width or height not positive"), - ); - return; - } - - let mut dma = Dmabuf::builder((width, height), format, DmabufFlags::empty()); - dma.add_plane(name, 0, offset0 as u32, stride0 as u32, Modifier::Invalid); - match dma.build() { - Some(dmabuf) => { - match state.dmabuf_imported(&data.dmabuf_global, dmabuf.clone()) { - Ok(_) => { - // import was successful - data_init.init(id, dmabuf); - } - - Err(ImportError::InvalidFormat) => { - drm.post_error( - wl_drm::Error::InvalidFormat, - "format and plane combination are not valid", - ); - } - - Err(ImportError::Failed) => { - // Buffer import failed. The protocol documentation heavily implies killing the - // client is the right thing to do here. - drm.post_error(wl_drm::Error::InvalidName, "buffer import failed"); - } - } - } - None => { - // Buffer import failed. The protocol documentation heavily implies killing the - // client is the right thing to do here. - drm.post_error( - wl_drm::Error::InvalidName, - "dmabuf global was destroyed on server", - ); - } - } - } - } - } -} - -pub fn create_drm_global( - display: &DisplayHandle, - device_path: PathBuf, - formats: Vec, - dmabuf_global: &DmabufGlobal, -) -> GlobalId -where - D: GlobalDispatch - + Dispatch - + BufferHandler - + DmabufHandler - + 'static, -{ - create_drm_global_with_filter::(display, device_path, formats, dmabuf_global, |_| true) -} - -pub fn create_drm_global_with_filter( - display: &DisplayHandle, - device_path: PathBuf, - formats: Vec, - dmabuf_global: &DmabufGlobal, - client_filter: F, -) -> GlobalId -where - D: GlobalDispatch - + Dispatch - + BufferHandler - + DmabufHandler - + 'static, - F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static, -{ - let formats = Arc::new( - formats - .into_iter() - .filter(|f| f.modifier == Modifier::Invalid) - .map(|f| f.code) - .collect(), - ); - let data = DrmGlobalData { - filter: Box::new(client_filter), - formats, - device_path, - dmabuf_global: dmabuf_global.clone(), - }; - - display.create_global::(2, data) -} - -macro_rules! delegate_wl_drm { - ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => { - smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - $crate::wayland::protocols::wl_drm::wl_drm::WlDrm: $crate::wayland::protocols::wl_drm::DrmGlobalData - ] => $crate::wayland::protocols::wl_drm::WlDrmState); - smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - $crate::wayland::protocols::wl_drm::wl_drm::WlDrm: $crate::wayland::protocols::wl_drm::DrmInstanceData - ] => $crate::wayland::protocols::wl_drm::WlDrmState); - }; -} -pub(crate) use delegate_wl_drm; diff --git a/src/core/src/platforms/linux/virtual-display/wayland-display.cpp b/src/core/src/platforms/linux/virtual-display/wayland-display.cpp index add3f422..2aba83d0 100644 --- a/src/core/src/platforms/linux/virtual-display/wayland-display.cpp +++ b/src/core/src/platforms/linux/virtual-display/wayland-display.cpp @@ -4,13 +4,13 @@ #include extern "C" { -#include +#include } namespace wolf::core::virtual_display { struct WaylandState { - WaylandDisplay display{}; + WaylandDisplay *display{}; immer::vector env{}; immer::vector graphic_devices{}; }; diff --git a/src/moonlight-server/state/default/config.include.toml b/src/moonlight-server/state/default/config.include.toml index 567f46fe..2aaa3983 100644 --- a/src/moonlight-server/state/default/config.include.toml +++ b/src/moonlight-server/state/default/config.include.toml @@ -55,7 +55,7 @@ image = "ghcr.io/games-on-whales/retroarch:edge" mounts = [] env = [ "RUN_GAMESCOPE=true", - "GOW_REQUIRED_DEVICES=/dev/uinput /dev/input/event* /dev/dri/* /dev/nvidia*", + "GOW_REQUIRED_DEVICES=/dev/input/event* /dev/dri/* /dev/nvidia*", ] devices = [ ] @@ -90,7 +90,7 @@ mounts = [] env = [ "PROTON_LOG=1", "RUN_GAMESCOPE=true", - "GOW_REQUIRED_DEVICES=/dev/uinput /dev/input/event* /dev/dri/* /dev/nvidia*", + "GOW_REQUIRED_DEVICES=/dev/input/event* /dev/dri/* /dev/nvidia*", ] devices = [ ] @@ -124,7 +124,7 @@ image = "ghcr.io/games-on-whales/es-de:edge" mounts = [] env = [ "RUN_GAMESCOPE=true", - "GOW_REQUIRED_DEVICES=/dev/uinput /dev/input/event* /dev/dri/* /dev/nvidia*", + "GOW_REQUIRED_DEVICES=/dev/input/event* /dev/dri/* /dev/nvidia*", ] devices = [ ] diff --git a/src/moonlight-server/state/default/config.v2.toml b/src/moonlight-server/state/default/config.v2.toml index e98260d4..80847c16 100644 --- a/src/moonlight-server/state/default/config.v2.toml +++ b/src/moonlight-server/state/default/config.v2.toml @@ -54,7 +54,7 @@ image = "ghcr.io/games-on-whales/retroarch:edge" mounts = [] env = [ "RUN_GAMESCOPE=true", - "GOW_REQUIRED_DEVICES=/dev/uinput /dev/input/event* /dev/dri/* /dev/nvidia*", + "GOW_REQUIRED_DEVICES=/dev/input/event* /dev/dri/* /dev/nvidia*", ] devices = [ ] @@ -89,7 +89,7 @@ mounts = [] env = [ "PROTON_LOG=1", "RUN_GAMESCOPE=true", - "GOW_REQUIRED_DEVICES=/dev/uinput /dev/input/event* /dev/dri/* /dev/nvidia*", + "GOW_REQUIRED_DEVICES=/dev/input/event* /dev/dri/* /dev/nvidia*", ] devices = [ ] @@ -123,7 +123,7 @@ image = "ghcr.io/games-on-whales/es-de:edge" mounts = [] env = [ "RUN_GAMESCOPE=true", - "GOW_REQUIRED_DEVICES=/dev/uinput /dev/input/event* /dev/dri/* /dev/nvidia*", + "GOW_REQUIRED_DEVICES=/dev/input/event* /dev/dri/* /dev/nvidia*", ] devices = [ ]