diff --git a/Cargo.lock b/Cargo.lock index bc03a77..3fde790 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -496,10 +496,12 @@ dependencies = [ "chrono", "ffmpeg-sidecar", "glib 0.10.3", + "gstreamer", "libadwaita", "open", "subprocess", "tempfile", + "zbus 5.3.0", ] [[package]] @@ -620,6 +622,16 @@ dependencies = [ "target-lexicon", ] +[[package]] +name = "cfg-expr" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d4ba6e40bd1184518716a6e1a781bf9160e286d219ccdb8ab2612e74cfe4789" +dependencies = [ + "smallvec", + "target-lexicon", +] + [[package]] name = "cfg-if" version = "0.1.10" @@ -1486,7 +1498,7 @@ version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3092cf797a5f1210479ea38070d9ae8a5b8e9f8f1be9f32f4643c529c7d70016" dependencies = [ - "gio-sys", + "gio-sys 0.16.3", "glib-sys 0.16.3", "gobject-sys 0.16.3", "libc", @@ -1517,7 +1529,7 @@ checksum = "de55cb49432901fe2b3534177fa06844665b9b0911d85d8601a8d8b88b7791db" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", - "gio-sys", + "gio-sys 0.16.3", "glib-sys 0.16.3", "gobject-sys 0.16.3", "libc", @@ -1568,7 +1580,7 @@ dependencies = [ "futures-core", "futures-io", "futures-util", - "gio-sys", + "gio-sys 0.16.3", "glib 0.16.9", "libc", "once_cell", @@ -1590,6 +1602,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "gio-sys" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8446d9b475730ebef81802c1738d972db42fde1c5a36a627ebc4d665fc87db04" +dependencies = [ + "glib-sys 0.20.7", + "gobject-sys 0.20.7", + "libc", + "system-deps 7.0.3", + "windows-sys 0.59.0", +] + [[package]] name = "glib" version = "0.10.3" @@ -1621,7 +1646,7 @@ dependencies = [ "futures-executor", "futures-task", "futures-util", - "gio-sys", + "gio-sys 0.16.3", "glib-macros 0.16.8", "glib-sys 0.16.3", "gobject-sys 0.16.3", @@ -1631,6 +1656,27 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "glib" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f969edf089188d821a30cde713b6f9eb08b20c63fc2e584aba2892a7984a8cc0" +dependencies = [ + "bitflags 2.8.0", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys 0.20.8", + "glib-macros 0.20.7", + "glib-sys 0.20.7", + "gobject-sys 0.20.7", + "libc", + "memchr", + "smallvec", +] + [[package]] name = "glib-macros" version = "0.10.1" @@ -1662,6 +1708,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "glib-macros" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715601f8f02e71baef9c1f94a657a9a77c192aea6097cf9ae7e5e177cd8cde68" +dependencies = [ + "heck 0.5.0", + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "glib-sys" version = "0.10.1" @@ -1682,6 +1741,16 @@ dependencies = [ "system-deps 6.2.2", ] +[[package]] +name = "glib-sys" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b360ff0f90d71de99095f79c526a5888c9c92fc9ee1b19da06c6f5e75f0c2a53" +dependencies = [ + "libc", + "system-deps 7.0.3", +] + [[package]] name = "glob" version = "0.3.2" @@ -1722,6 +1791,17 @@ dependencies = [ "system-deps 6.2.2", ] +[[package]] +name = "gobject-sys" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a56235e971a63bfd75abb13ef70064e1346388723422a68580d8a6fbac6423" +dependencies = [ + "glib-sys 0.20.7", + "libc", + "system-deps 7.0.3", +] + [[package]] name = "graphene-rs" version = "0.16.3" @@ -1777,6 +1857,43 @@ dependencies = [ "system-deps 6.2.2", ] +[[package]] +name = "gstreamer" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "700cb1b2e86dda424f85eb728102a111602317e40b4dd71cf1c0dc04e0cc5d95" +dependencies = [ + "cfg-if 1.0.0", + "futures-channel", + "futures-core", + "futures-util", + "glib 0.20.7", + "gstreamer-sys", + "itertools 0.13.0", + "libc", + "muldiv", + "num-integer", + "num-rational", + "once_cell", + "option-operations", + "paste", + "pin-project-lite", + "smallvec", + "thiserror 2.0.11", +] + +[[package]] +name = "gstreamer-sys" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16cf1ae0a869aa7066ce3c685b76053b4b4f48f364a5b18c4b1f36ef57469719" +dependencies = [ + "glib-sys 0.20.7", + "gobject-sys 0.20.7", + "libc", + "system-deps 7.0.3", +] + [[package]] name = "gtk4" version = "0.5.5" @@ -1823,7 +1940,7 @@ dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", "gdk4-sys", - "gio-sys", + "gio-sys 0.16.3", "glib-sys 0.16.3", "gobject-sys 0.16.3", "graphene-sys", @@ -2325,7 +2442,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de902982372b454a0081d7fd9dd567b37b73ae29c8f6da1820374d345fd95d5b" dependencies = [ "gdk4-sys", - "gio-sys", + "gio-sys 0.16.3", "glib-sys 0.16.3", "gobject-sys 0.16.3", "gtk4-sys", @@ -2511,6 +2628,12 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "muldiv" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956787520e75e9bd233246045d19f42fb73242759cc57fba9611d940ae96d4b0" + [[package]] name = "nb-connect" version = "1.2.0" @@ -2724,6 +2847,15 @@ dependencies = [ "pathdiff", ] +[[package]] +name = "option-operations" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c26d27bb1aeab65138e4bf7666045169d1717febcc9ff870166be8348b223d0" +dependencies = [ + "paste", +] + [[package]] name = "ordered-multimap" version = "0.3.1" @@ -3589,7 +3721,20 @@ version = "6.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" dependencies = [ - "cfg-expr", + "cfg-expr 0.15.8", + "heck 0.5.0", + "pkg-config", + "toml 0.8.19", + "version-compare 0.2.0", +] + +[[package]] +name = "system-deps" +version = "7.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d23aaf9f331227789a99e8de4c91bf46703add012bdfd45fdecdfb2975a005" +dependencies = [ + "cfg-expr 0.17.2", "heck 0.5.0", "pkg-config", "toml 0.8.19", @@ -4734,10 +4879,46 @@ dependencies = [ "windows-sys 0.52.0", "xdg-home", "zbus_macros 4.4.0", - "zbus_names", + "zbus_names 3.0.0", "zvariant 4.2.0", ] +[[package]] +name = "zbus" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "192a0d989036cd60a1e91a54c9851fb9ad5bd96125d41803eed79d2e2ef74bd7" +dependencies = [ + "async-broadcast", + "async-executor", + "async-fs", + "async-io 2.4.0", + "async-lock 3.4.0", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2 0.7.11", + "event-listener 5.4.0", + "futures-core", + "futures-util", + "hex", + "nix 0.29.0", + "ordered-stream", + "serde", + "serde_repr", + "static_assertions", + "tracing", + "uds_windows", + "windows-sys 0.59.0", + "winnow 0.6.24", + "xdg-home", + "zbus_macros 5.3.0", + "zbus_names 4.1.1", + "zvariant 5.2.0", +] + [[package]] name = "zbus_macros" version = "1.9.3" @@ -4760,7 +4941,22 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.96", - "zvariant_utils", + "zvariant_utils 2.1.0", +] + +[[package]] +name = "zbus_macros" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3685b5c81fce630efc3e143a4ded235b107f1b1cdf186c3f115529e5e5ae4265" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.96", + "zbus_names 4.1.1", + "zvariant 5.2.0", + "zvariant_utils 3.1.0", ] [[package]] @@ -4774,6 +4970,18 @@ dependencies = [ "zvariant 4.2.0", ] +[[package]] +name = "zbus_names" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "519629a3f80976d89c575895b05677cbc45eaf9f70d62a364d819ba646409cc8" +dependencies = [ + "serde", + "static_assertions", + "winnow 0.6.24", + "zvariant 5.2.0", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -4980,6 +5188,21 @@ dependencies = [ "zvariant_derive 4.2.0", ] +[[package]] +name = "zvariant" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55e6b9b5f1361de2d5e7d9fd1ee5f6f7fcb6060618a1f82f3472f58f2b8d4be9" +dependencies = [ + "endi", + "enumflags2 0.7.11", + "serde", + "static_assertions", + "winnow 0.6.24", + "zvariant_derive 5.2.0", + "zvariant_utils 3.1.0", +] + [[package]] name = "zvariant_derive" version = "2.10.0" @@ -5002,7 +5225,20 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.96", - "zvariant_utils", + "zvariant_utils 2.1.0", +] + +[[package]] +name = "zvariant_derive" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "573a8dd76961957108b10f7a45bac6ab1ea3e9b7fe01aff88325dc57bb8f5c8b" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.96", + "zvariant_utils 3.1.0", ] [[package]] @@ -5015,3 +5251,17 @@ dependencies = [ "quote", "syn 2.0.96", ] + +[[package]] +name = "zvariant_utils" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd46446ea2a1f353bfda53e35f17633afa79f4fe290a611c94645c69fe96a50" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "static_assertions", + "syn 2.0.96", + "winnow 0.6.24", +] diff --git a/core/Cargo.toml b/core/Cargo.toml index 18370c3..9d1455c 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -14,6 +14,8 @@ async-std = {version = "1.12.0", features = ["attributes"]} chrono = { version = "0.4.19", optional = true } ffmpeg-sidecar = "2.0.5" glib = { version = "0.10.3", optional = true } +gstreamer = "0.23.4" open = "5.1.4" subprocess = {version = "0.2.6", optional = true } tempfile = "3.10.1" +zbus = "5.3.0" diff --git a/core/src/ffmpeg_linux.rs b/core/src/ffmpeg_linux.rs index 226d87e..04734d3 100644 --- a/core/src/ffmpeg_linux.rs +++ b/core/src/ffmpeg_linux.rs @@ -3,6 +3,7 @@ use adw::gtk::{CheckButton, ComboBoxText, Entry, FileChooserNative, SpinButton}; #[cfg(feature = "gtk")] use adw::gtk::prelude::*; use anyhow::{anyhow, Error, Result}; +use chrono::Timelike; #[cfg(feature = "gtk")] use chrono::Utc; use ffmpeg_sidecar::child::FfmpegChild; @@ -18,11 +19,12 @@ use std::time::Duration; #[cfg(feature = "cmd")] use std::time::Instant; -use crate::utils::{is_video_record, RecordMode}; +use crate::utils::{is_video_record, is_wayland, RecordMode}; #[cfg(feature = "cmd")] use crate::utils::{is_input_audio_record, is_output_audio_record, is_valid}; #[cfg(feature = "gtk")] use crate::utils::validate_video_file; +use crate::wayland_linux::{CursorModeTypes, RecordTypes, WaylandRecorder}; #[cfg(feature = "cmd")] #[derive(Clone)] @@ -56,6 +58,7 @@ pub struct Ffmpeg { pub output: String, pub temp_video_filename: String, pub saved_filename: String, + pub width: Option, pub height: Option, pub input_audio_process: Option>>, pub output_audio_process: Option>>, @@ -70,6 +73,7 @@ pub struct Ffmpeg { pub record_mouse: CheckButton, pub show_area: CheckButton, pub video_switch: CheckButton, + pub wayland_recorder: WaylandRecorder, } #[cfg(feature = "cmd")] @@ -87,6 +91,7 @@ impl Ffmpeg { ); let mut ffmpeg_command = FfmpegCommand::new(); let format = "x11grab"; + self.width = Some(width); self.height = Some(height); // Record video to tmp if audio record enabled @@ -483,6 +488,35 @@ impl Ffmpeg { //if mode == RecordMode::Window && !self.follow_mouse.is_active() { // TODO pulse = gstreamer for video && add to cmd linux + add convert function to gstreamer ouput //} else { + if is_wayland() { + let folder_path = Path::new(&self.saved_filename) + .parent() + .ok_or_else(|| anyhow!("Failed to get parent path."))?; + self.temp_video_filename = folder_path + .join(format!(".blue-recorder-{}.webm", Utc::now().nanosecond())) + .to_string_lossy() + .to_string(); + + // Start recording + let stream = glib::MainContext::default().block_on(self.wayland_recorder.start( + self.temp_video_filename.clone(), + match mode { + RecordMode::Screen => RecordTypes::Monitor, + RecordMode::Window => RecordTypes::Window, + _ => RecordTypes::MonitorOrWindow, + }, + if self.record_mouse.is_active() { + CursorModeTypes::Show + } else { + CursorModeTypes::Hidden + }, + )); + + self.width = Some(width); + self.height = Some(height); + return Ok(()); + } + let display = format!("{}+{},{}", std::env::var("DISPLAY").unwrap_or_else(|_| ":0".to_string()) .as_str(), @@ -491,6 +525,7 @@ impl Ffmpeg { ); let mut ffmpeg_command = FfmpegCommand::new(); let format = "x11grab"; + self.width = Some(width); self.height = Some(height); let filename = self.saved_filename.clone(); self.output = Path::new(&filename).extension() @@ -637,6 +672,17 @@ impl Ffmpeg { return Err(Error::msg(format!("{}", error))); }, } + } else if self.video_switch.is_active() && is_wayland() { + glib::MainContext::default().block_on(self.wayland_recorder.stop()); + match self.merge() { + Ok(_) => { + self.clean()?; + }, + Err(error) => { + self.clean()?; + return Err(Error::msg(format!("{}", error))); + } + } } Ok(()) } diff --git a/core/src/lib.rs b/core/src/lib.rs index bcac829..a9fd692 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,5 +1,7 @@ +pub mod wayland_linux; + pub mod ffmpeg_linux; pub mod ffmpeg_windows; -pub mod utils; +pub mod utils; \ No newline at end of file diff --git a/core/src/wayland_linux.rs b/core/src/wayland_linux.rs new file mode 100644 index 0000000..0837d49 --- /dev/null +++ b/core/src/wayland_linux.rs @@ -0,0 +1,300 @@ +use anyhow::{Error, Result}; +use gst::prelude::*; +use gstreamer as gst; +use std::collections::HashMap; +use zbus::{ + export::futures_util::TryStreamExt, + message, proxy, + zvariant::{Dict, ObjectPath, OwnedObjectPath, Str, Structure, Value}, + Connection, MessageStream, +}; + +#[derive(Clone, Copy)] +pub enum RecordTypes { + Default, + Monitor, + Window, + MonitorOrWindow, +} + +#[derive(Clone, Copy)] +pub enum CursorModeTypes { + Default, + Hidden, + Show, +} + +#[proxy( + interface = "org.freedesktop.portal.ScreenCast", + default_service = "org.freedesktop.portal.Desktop", + default_path = "/org/freedesktop/portal/desktop" +)] +trait ScreenCast { + async fn create_session(&self, options: HashMap<&str, Value<'_>>) -> Result; + async fn select_sources( + &self, + session_handle: ObjectPath<'_>, + options: HashMap<&str, Value<'_>>, + ) -> Result; + async fn start( + &self, + session_handle: ObjectPath<'_>, + parent_window: &str, + options: HashMap<&str, Value<'_>>, + ) -> Result; +} + +#[derive(Clone)] +pub struct WaylandRecorder { + connection: Connection, + screen_cast_proxy: ScreenCastProxy<'static>, + session_path: String, + pipeline: Option, + filename: String, +} + +impl WaylandRecorder { + pub async fn new() -> Self { + let connection = Connection::session() + .await + .expect("failed to connect to session bus"); + let screen_cast_proxy = ScreenCastProxy::new(&connection) + .await + .expect("failed to create dbus proxy for screen-cast"); + gst::init().expect("failed to initialize gstreamer"); + + WaylandRecorder { + connection, + screen_cast_proxy, + session_path: String::new(), + filename: String::from("blue_recorder.webm"), + pipeline: None, + } + } + + pub async fn start( + &mut self, + filename: String, + record_type: RecordTypes, + cursor_mode_type: CursorModeTypes, + ) -> (i32, i32) { + self.screen_cast_proxy + .create_session(HashMap::from([ + ("handle_token", Value::from("blue_recorder_1")), + ("session_handle_token", Value::from("blue_recorder_1")), + ])) + .await + .expect("failed to create session"); + + let (mut height, mut width) = (0, 0); + + let mut message_stream = MessageStream::from(self.connection.clone()); + + self.filename = filename.clone(); + + while let Some(msg) = message_stream + .try_next() + .await + .expect("failed to get message") + { + match msg.message_type() { + message::Type::Signal => { + let body = msg.body(); + let (response_num, response): (u32, HashMap<&str, Value>) = + body.deserialize().unwrap(); + + if response_num > 0 { + return (height, width); + } + + if response.len() == 0 { + continue; + } + + if response.contains_key("session_handle") { + self.handle_session( + self.screen_cast_proxy.clone(), + response.clone(), + record_type, + cursor_mode_type, + ) + .await + .expect("failed to handle session"); + continue; + } + + if response.contains_key("streams") { + let stream = self.record_screen_cast(response.clone()) + .await + .expect("failed to record screen cast"); + + width = stream.0; + height = stream.1; + break; + } + } + _ => { + println!("\n\nUnkown message: {:?}", msg); + } + } + } + + (height, width) + } + + pub async fn stop(&mut self) { + if let Some(pipeline) = self.pipeline.clone() { + pipeline + .set_state(gst::State::Null) + .expect("failed to stop pipeline"); + } + + if self.session_path.len() > 0 { + println!( + "Closing session...: {:?}", + self.session_path.replace("request", "session") + ); + self.connection + .clone() + .call_method( + Some("org.freedesktop.portal.Desktop"), + self.session_path.clone().replace("request", "session"), + Some("org.freedesktop.portal.Session"), + "Close", + &(), + ) + .await + .expect("failed to close session"); + self.session_path = String::new(); + } + } + + async fn handle_session( + &mut self, + screen_cast_proxy: ScreenCastProxy<'_>, + response: HashMap<&str, Value<'_>>, + record_type: RecordTypes, + cursor_mode_type: CursorModeTypes, + ) -> Result<()> { + let response_session_handle = response + .get("session_handle") + .expect("cannot get session_handle") + .clone() + .downcast::() + .expect("cannot down cast session_handle"); + + self.session_path = response_session_handle.clone(); + + screen_cast_proxy + .select_sources( + ObjectPath::try_from(response_session_handle.clone())?, + HashMap::from([ + ("handle_token", Value::from("blue_recorder_1")), + ( + "types", + Value::from(match record_type { + RecordTypes::Monitor => 1u32, + RecordTypes::Window => 2u32, + RecordTypes::MonitorOrWindow => 3u32, + _ => 0u32, + }), + ), + ( + "cursor_mode", + Value::from(match cursor_mode_type { + CursorModeTypes::Hidden => 1u32, + CursorModeTypes::Show => 2u32, + _ => 0u32, + }), + ), + ]), + ) + .await?; + + screen_cast_proxy + .start( + ObjectPath::try_from(response_session_handle.clone())?, + "parent_window", + HashMap::from([("handle_token", Value::from("blue_recorder_1"))]), + ) + .await?; + Ok(()) + } + + async fn record_screen_cast(&mut self, response: HashMap<&str, Value<'_>>) -> Result<(i32, i32)> { + let streams: &Value<'_> = response.get("streams").expect("cannot get streams"); + + let (mut width, mut height) = (0, 0); + + let stream_fields = streams + .clone() + .downcast::>() + .expect("cannot down cast streams to vec array") + .first() + .expect("cannot get first object from streams array") + .clone() + .downcast::() + .expect("cannot down cast first object to structure"); + + if let Some(field) = stream_fields.fields().get(1) { + let dict = field + .clone() + .downcast::() + .expect("cannot down cast field to value"); + + let size_str = Str::from("size"); + let size = dict + .get::(&size_str) + .expect("cannot get size") + .expect("cannot get size structure"); + + let fields = size.fields(); + + let size = fields + .iter() + .map(|field| { + field + .clone() + .downcast::() + .expect("cannot down cast width to i32") + }) + .collect::>(); + + let [stream_width, stream_height] = size.as_slice() else { + return Err(Error::msg("cannot get width and height")); + }; + + width = *stream_width; + height = *stream_height; + } + + // get fields from nested structure inside elements + // NOTICE: this is not the best way to get node_id, but it works for now + let stream_node_id: u32 = stream_fields.fields() + .first() + .expect("cannot get first field from structure") + .clone() + .downcast::() + .expect("cannot down cast first field to u32"); + + // launch gstreamer pipeline + let gst_element: gst::Element = gst::parse::launch(&format!( + "pipewiresrc path={stream_node_id} ! videorate ! video/x-raw,framerate=60/1 ! videoconvert ! vp8enc min-quantizer=0 max-quantizer=1 keyframe-mode=disabled buffer-size=20000 ! webmmux ! filesink location={filename}", + filename = self.filename + )).expect("failed to launch gstreamer pipeline"); + + // start pipeline + let pipeline: gst::Pipeline = gst_element + .dynamic_cast::() + .expect("pipeline error"); + + self.pipeline = Some(pipeline.clone()); + + pipeline + .set_state(gst::State::Playing) + .expect("failed to start pipeline"); + + println!("Recording Wayland screen cast..."); + Ok((width, height)) + } +} diff --git a/gui/src/ui.rs b/gui/src/ui.rs index 7c504fa..ff78c7f 100644 --- a/gui/src/ui.rs +++ b/gui/src/ui.rs @@ -12,6 +12,7 @@ use blue_recorder_core::utils::{disable_input_widgets, enable_input_widgets, is_overwrite, is_wayland, play_record, RecordMode, validate_video_file}; #[cfg(any(target_os = "freebsd", target_os = "linux"))] use blue_recorder_core::utils::{audio_output_source, sources_descriptions_list}; +use blue_recorder_core::wayland_linux::WaylandRecorder; #[cfg(target_os = "windows")] use cpal::traits::{DeviceTrait, HostTrait}; use std::cell::RefCell; @@ -791,6 +792,7 @@ fn build_ui(application: &Application, error_dialog: MessageDialog, error_messag show_area: area_switch, video_switch: video_switch.clone() })); + #[cfg(any(target_os = "freebsd", target_os = "linux"))] let ffmpeg_record_interface: Rc> = Rc::new(RefCell::new(Ffmpeg { audio_input_id: audio_source_combobox.clone(), @@ -803,6 +805,7 @@ fn build_ui(application: &Application, error_dialog: MessageDialog, error_messag output: String::new(), temp_video_filename: String::new(), saved_filename: String::new(), + width: None, height: None, input_audio_process: None, output_audio_process: None, @@ -817,6 +820,7 @@ fn build_ui(application: &Application, error_dialog: MessageDialog, error_messag record_mouse: mouse_switch.clone(), show_area: area_switch, video_switch: video_switch.clone(), + wayland_recorder: glib::MainContext::default().block_on(WaylandRecorder::new()) })); // Record button @@ -832,8 +836,7 @@ fn build_ui(application: &Application, error_dialog: MessageDialog, error_messag let _error_dialog = error_dialog.clone(); let _error_message = error_message.clone(); let _follow_mouse_switch = follow_mouse_switch.clone(); - let mut _input_widgets = input_widgets.clone(); - //let main_context = glib::MainContext::default(); + let mut _input_widgets: Vec = input_widgets.clone(); let _main_window = main_window.clone(); let _mouse_switch = mouse_switch.clone(); let _play_button = play_button.clone(); @@ -841,7 +844,6 @@ fn build_ui(application: &Application, error_dialog: MessageDialog, error_messag let _record_time_label = record_time_label.clone(); let _stop_button = stop_button.clone(); let _video_switch = video_switch.clone(); - //let wayland_record = main_context.block_on(WaylandRecorder::new()); let mut _ffmpeg_record_interface = ffmpeg_record_interface.clone(); let second_click: Rc> = Rc::new(RefCell::new(RecordClick { is_record_button_clicked: false, @@ -900,7 +902,7 @@ fn build_ui(application: &Application, error_dialog: MessageDialog, error_messag second_click.clone(), ); } - } else if _delay_spin.value() as u16 == 0 && !is_wayland() { + } else if _delay_spin.value() as u16 == 0 { let _area_capture = area_capture.borrow_mut(); disable_input_widgets(_input_widgets.clone()); start_timer(record_time_label.clone());