mirror of
https://github.com/xlmnxp/blue-recorder.git
synced 2025-04-05 17:24:53 +03:00
813 lines
41 KiB
Rust
813 lines
41 KiB
Rust
{4a4b13e9c3a90b943babd1082d1685b7fcb69514 true 42124 main.rs 0xc001e0d730}
extern crate gdk;
|
|
extern crate gio;
|
|
extern crate gtk;
|
|
mod area_capture;
|
|
mod config_management;
|
|
mod ffmpeg_interface;
|
|
mod timer;
|
|
mod wayland_record;
|
|
mod utils;
|
|
|
|
use ffmpeg_interface::Ffmpeg;
|
|
use fluent_bundle::bundle::FluentBundle;
|
|
use fluent_bundle::FluentResource;
|
|
use gtk::glib;
|
|
use gtk::prelude::*;
|
|
use gtk::{
|
|
AboutDialog, Application, Builder, Button, CheckButton, ComboBoxText, CssProvider, Entry,
|
|
FileChooserAction, FileChooserNative, Image, Label, SpinButton,
|
|
ToggleButton, Window,
|
|
};
|
|
use utils::is_wayland;
|
|
use std::cell::RefCell;
|
|
use std::ops::Add;
|
|
use std::path::Path;
|
|
use std::rc::Rc;
|
|
use timer::{recording_delay, start_timer, stop_timer};
|
|
use wayland_record::WaylandRecorder;
|
|
use cpal::traits::{DeviceTrait, HostTrait};
|
|
|
|
|
|
#[async_std::main]
|
|
async fn main() {
|
|
// Create new application
|
|
let application = Application::new(None, Default::default());
|
|
application.connect_activate(build_ui);
|
|
application.run();
|
|
}
|
|
|
|
pub fn build_ui(application: &Application) {
|
|
gtk::init().expect("Failed to initialize GTK.");
|
|
|
|
// UI source
|
|
let ui_src = include_str!("../interfaces/main.ui").to_string();
|
|
let builder: Builder = Builder::from_string(ui_src.as_str());
|
|
|
|
// Init audio source
|
|
let host_audio_device = cpal::default_host();
|
|
|
|
// Translate
|
|
let mut ftl_path = {
|
|
let mut current_exec_dir = std::env::current_exe().unwrap();
|
|
current_exec_dir.pop();
|
|
current_exec_dir
|
|
}.join(Path::new("locales"));
|
|
if !ftl_path.exists() {
|
|
ftl_path = std::fs::canonicalize(Path::new(
|
|
&std::env::var("LC_DIR").unwrap_or_else(|_| String::from("locales")),
|
|
)).unwrap();
|
|
}
|
|
let supported_lang: Vec<String> = std::fs::read_dir(&ftl_path)
|
|
.unwrap()
|
|
.map(|entry| {
|
|
let path = entry.unwrap().path();
|
|
path.file_stem().unwrap().to_string_lossy().to_string()
|
|
}).collect();
|
|
let mut locale = std::env::var("LANG").unwrap_or("en_US".to_string());
|
|
if !supported_lang.contains(&locale) {
|
|
locale = locale.split('_').next().unwrap().to_string();
|
|
if !supported_lang.contains(&locale) {
|
|
locale = String::from("en_US");
|
|
}
|
|
}
|
|
let ftl_file = std::fs::read_to_string(
|
|
format!("{}/{}.ftl", ftl_path.to_str().unwrap(),locale.split('.').next().unwrap())
|
|
).unwrap();
|
|
let res = FluentResource::try_new(ftl_file).unwrap();
|
|
let mut bundle = FluentBundle::default();
|
|
bundle.add_resource(res).expect("Failed to add localization resources to the bundle.");
|
|
|
|
// Config initialize
|
|
config_management::initialize();
|
|
|
|
// Get Objects from UI
|
|
let area_apply_label: Label = builder.object("area_apply").unwrap();
|
|
let area_chooser_window: Window = builder.object("area_chooser_window").unwrap();
|
|
let area_grab_button: ToggleButton = builder.object("area_grab_button").unwrap();
|
|
let area_grab_icon: Image = builder.object("area_grab_icon").unwrap();
|
|
let area_grab_label: Label = builder.object("area_grab_label").unwrap();
|
|
let area_set_button: Button = builder.object("area_set_button").unwrap();
|
|
let about_button: Button = builder.object("aboutbutton").unwrap();
|
|
let about_dialog: AboutDialog = builder.object("about_dialog").unwrap();
|
|
let audio_source_combobox: ComboBoxText = builder.object("audiosource").unwrap();
|
|
let audio_source_label: Label = builder.object("audio_source_label").unwrap();
|
|
let audio_switch: CheckButton = builder.object("audioswitch").unwrap();
|
|
let command_entry: Entry = builder.object("command").unwrap();
|
|
let command_label: Label = builder.object("command_label").unwrap();
|
|
let delay_label: Label = builder.object("delay_label").unwrap();
|
|
let delay_spin: SpinButton = builder.object("delay").unwrap();
|
|
let delay_window: Window = builder.object("delay_window").unwrap();
|
|
let delay_window_button: ToggleButton = builder.object("delay_window_stopbutton").unwrap();
|
|
let delay_window_label: Label = builder.object("delay_window_label").unwrap();
|
|
let delay_window_title: Label = builder.object("delay_window_title").unwrap();
|
|
let filename_entry: Entry = builder.object("filename").unwrap();
|
|
let folder_chooser_button: Button = builder.object("folder_chooser").unwrap();
|
|
let folder_chooser_image: Image = builder.object("folder_chooser_image").unwrap();
|
|
let folder_chooser_label: Label = builder.object("folder_chooser_label").unwrap();
|
|
let follow_mouse_switch: CheckButton = builder.object("followmouseswitch").unwrap();
|
|
let format_chooser_combobox: ComboBoxText = builder.object("comboboxtext1").unwrap();
|
|
let frames_label: Label = builder.object("frames_label").unwrap();
|
|
let frames_spin: SpinButton = builder.object("frames").unwrap();
|
|
let hide_switch: CheckButton = builder.object("hideswitch").unwrap();
|
|
let main_window: Window = builder.object("main_window").unwrap();
|
|
let mouse_switch: CheckButton = builder.object("mouseswitch").unwrap();
|
|
let play_button: Button = builder.object("playbutton").unwrap();
|
|
let quality_label: Label = builder.object("quality_label").unwrap();
|
|
let quality_spin: SpinButton = builder.object("quality").unwrap();
|
|
let record_button: Button = builder.object("recordbutton").unwrap();
|
|
let record_label: Label = builder.object("record_label").unwrap();
|
|
let record_time_label: Label = builder.object("record_time_label").unwrap();
|
|
let screen_grab_button: ToggleButton = builder.object("screen_grab_button").unwrap();
|
|
let screen_grab_icon: Image = builder.object("screen_grab_icon").unwrap();
|
|
let screen_grab_label: Label = builder.object("screen_grab_label").unwrap();
|
|
let speaker_switch: CheckButton = builder.object("speakerswitch").unwrap();
|
|
let stop_button: Button = builder.object("stopbutton").unwrap();
|
|
let stop_label: Label = builder.object("stop_label").unwrap();
|
|
let video_switch: CheckButton = builder.object("videoswitch").unwrap();
|
|
let window_grab_button: ToggleButton = builder.object("window_grab_button").unwrap();
|
|
let window_grab_icon: Image = builder.object("window_grab_icon").unwrap();
|
|
let window_grab_label: Label = builder.object("window_grab_label").unwrap();
|
|
|
|
// --- default properties
|
|
// Windows
|
|
main_window.set_title(Some(&bundle.format_pattern(bundle.get_message("blue-recorder").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
main_window.set_application(Some(application));
|
|
area_chooser_window.set_title(Some(&bundle.format_pattern(bundle.get_message("area-chooser").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string())); // Title is hidden
|
|
|
|
// Hide stop & play buttons
|
|
stop_button.hide();
|
|
play_button.hide();
|
|
|
|
// Comboboxs tooltip
|
|
audio_source_combobox.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("audio-source-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
format_chooser_combobox.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("format-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
|
|
// Hide window grab button in Wayland
|
|
area_grab_button.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("area-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
// Temporary solution
|
|
if is_wayland() {
|
|
// Disabled for the tooltip
|
|
//area_grab_button.set_can_focus(false);
|
|
//area_grab_button.set_can_target(false);
|
|
//area_grab_button.add_css_class("disabled");
|
|
area_grab_button.set_sensitive(false);
|
|
area_grab_button.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("wayland-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
}
|
|
|
|
// Entries
|
|
filename_entry.set_placeholder_text(Some(&bundle.format_pattern(bundle.get_message("file-name").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
command_entry.set_placeholder_text(Some(&bundle.format_pattern(bundle.get_message("default-command").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
filename_entry.set_text(&config_management::get("default", "filename"));
|
|
command_entry.set_text(&config_management::get("default", "command"));
|
|
|
|
// Format combobox
|
|
format_chooser_combobox.append(Some("mp4"), &bundle.format_pattern(bundle.get_message("mp4-format").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
format_chooser_combobox.append(
|
|
Some("mkv"),
|
|
&bundle.format_pattern(bundle.get_message("mkv-format").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
);
|
|
format_chooser_combobox.append(Some("webm"), &bundle.format_pattern(bundle.get_message("webm-format").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
format_chooser_combobox.append(Some("gif"), &bundle.format_pattern(bundle.get_message("gif-format").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
format_chooser_combobox.append(Some("avi"), &bundle.format_pattern(bundle.get_message("avi-format").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
format_chooser_combobox.append(Some("wmv"), &bundle.format_pattern(bundle.get_message("wmv-format").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
format_chooser_combobox.append(Some("nut"), &bundle.format_pattern(bundle.get_message("nut-format").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
//format_chooser_combobox.set_active(Some(config_management::get("default", "format").parse::<u32>().unwrap()));
|
|
|
|
// Get audio sources
|
|
let input_device = host_audio_device.input_devices().unwrap();
|
|
let sources_descriptions: Vec<String> = input_device
|
|
.filter_map(|device| device.name().ok())
|
|
.collect();
|
|
|
|
audio_source_combobox.append(Some("default"), &bundle.format_pattern(bundle.get_message("audio-input").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
for (id, audio_source) in sources_descriptions.iter().enumerate() {
|
|
audio_source_combobox.append(Some(id.to_string().as_str()), audio_source);
|
|
}
|
|
audio_source_combobox.set_active(Some(0));
|
|
|
|
// Switchs
|
|
video_switch.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("video-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
video_switch.set_label(Some(&bundle.format_pattern(bundle.get_message("record-video").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
audio_switch.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("audio-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
audio_switch.set_label(Some(&bundle.format_pattern(bundle.get_message("record-audio").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
mouse_switch.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("mouse-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
mouse_switch.set_label(Some(&bundle.format_pattern(bundle.get_message("show-mouse").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
follow_mouse_switch.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("follow-mouse-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
follow_mouse_switch.set_label(Some(&bundle.format_pattern(bundle.get_message("follow-mouse").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
hide_switch.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("hide-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
hide_switch.set_label(Some(&bundle.format_pattern(bundle.get_message("auto-hide").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
speaker_switch.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("speaker-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
speaker_switch.set_label(Some(&bundle.format_pattern(bundle.get_message("record-speaker").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
video_switch.set_active(config_management::get_bool("default", "videocheck"));
|
|
audio_switch.set_active(config_management::get_bool("default", "audiocheck"));
|
|
mouse_switch.set_active(config_management::get_bool("default", "mousecheck"));
|
|
follow_mouse_switch.set_active(config_management::get_bool("default", "followmousecheck"));
|
|
hide_switch.set_active(config_management::get_bool("default", "hidecheck"));
|
|
speaker_switch.set_active(config_management::get_bool("default", "speakercheck"));
|
|
|
|
let _video_switch = video_switch.clone();
|
|
let _audio_switch = audio_switch.clone();
|
|
let _mouse_switch = mouse_switch.clone();
|
|
let _follow_mouse_switch = follow_mouse_switch.clone();
|
|
video_switch.connect_toggled(move |switch: &CheckButton| {
|
|
config_management::set_bool("default", "videocheck", switch.is_active());
|
|
if switch.is_active() {
|
|
_mouse_switch.set_sensitive(true);
|
|
} else {
|
|
_mouse_switch.set_sensitive(false);
|
|
_follow_mouse_switch.set_sensitive(false);
|
|
_audio_switch.set_active(true);
|
|
_audio_switch.set_sensitive(true);
|
|
_mouse_switch.set_active(false);
|
|
}
|
|
});
|
|
let _follow_mouse_switch = follow_mouse_switch.clone();
|
|
mouse_switch.connect_toggled(move |switch: &CheckButton| {
|
|
config_management::set_bool("default", "mousecheck", switch.is_active());
|
|
if switch.is_active() {
|
|
_follow_mouse_switch.set_sensitive(true);
|
|
} else {
|
|
_follow_mouse_switch.set_active(false);
|
|
_follow_mouse_switch.set_sensitive(false);
|
|
}
|
|
});
|
|
let _mouse_switch = mouse_switch.clone();
|
|
audio_switch.connect_toggled(move |switch: &CheckButton| {
|
|
config_management::set_bool("default", "audiocheck", switch.is_active());
|
|
if !switch.is_active() && !_video_switch.is_active() {
|
|
_video_switch.set_active(true);
|
|
_mouse_switch.set_sensitive(true);
|
|
}
|
|
});
|
|
follow_mouse_switch.connect_toggled(|switch: &CheckButton| {
|
|
config_management::set_bool("default", "followmousecheck", switch.is_active());
|
|
});
|
|
hide_switch.connect_toggled(|switch: &CheckButton| {
|
|
config_management::set_bool("default", "hidecheck", switch.is_active());
|
|
});
|
|
speaker_switch.connect_toggled(|switch: &CheckButton| {
|
|
config_management::set_bool("default", "speakercheck", switch.is_active());
|
|
});
|
|
|
|
match dark_light::detect() {
|
|
// Dark mode
|
|
dark_light::Mode::Dark => {
|
|
// Buttons
|
|
let mut area_icon_path = {
|
|
let mut current_exec_dir = std::env::current_exe().unwrap();
|
|
current_exec_dir.pop();
|
|
current_exec_dir
|
|
}
|
|
.join(Path::new("data/screenshot-ui-area-symbolic-white.svg"));
|
|
|
|
if !area_icon_path.exists() {
|
|
area_icon_path = std::fs::canonicalize(Path::new(
|
|
&std::env::var("DATA_DIR")
|
|
.unwrap_or_else(|_| String::from("data/"))
|
|
.add("screenshot-ui-area-symbolic-white.svg"),
|
|
))
|
|
.unwrap();
|
|
}
|
|
|
|
let mut screen_icon_path = {
|
|
let mut current_exec_dir = std::env::current_exe().unwrap();
|
|
current_exec_dir.pop();
|
|
current_exec_dir
|
|
}
|
|
.join(Path::new("data/screenshot-ui-display-symbolic-white.svg"));
|
|
|
|
if !screen_icon_path.exists() {
|
|
screen_icon_path = std::fs::canonicalize(Path::new(
|
|
&std::env::var("DATA_DIR")
|
|
.unwrap_or_else(|_| String::from("data/"))
|
|
.add("screenshot-ui-display-symbolic-white.svg"),
|
|
))
|
|
.unwrap();
|
|
}
|
|
|
|
let mut window_icon_path = {
|
|
let mut current_exec_dir = std::env::current_exe().unwrap();
|
|
current_exec_dir.pop();
|
|
current_exec_dir
|
|
}
|
|
.join(Path::new("data/screenshot-ui-window-symbolic-white.svg"));
|
|
|
|
if !window_icon_path.exists() {
|
|
window_icon_path = std::fs::canonicalize(Path::new(
|
|
&std::env::var("DATA_DIR")
|
|
.unwrap_or_else(|_| String::from("data/"))
|
|
.add("screenshot-ui-window-symbolic-white.svg"),
|
|
))
|
|
.unwrap();
|
|
}
|
|
|
|
area_grab_icon.set_from_file(Some(area_icon_path));
|
|
screen_grab_icon.set_from_file(Some(screen_icon_path));
|
|
window_grab_icon.set_from_file(Some(&window_icon_path));
|
|
}
|
|
// any theme
|
|
_ => {
|
|
// Buttons
|
|
let mut area_icon_path = {
|
|
let mut current_exec_dir = std::env::current_exe().unwrap();
|
|
current_exec_dir.pop();
|
|
current_exec_dir
|
|
}
|
|
.join(Path::new("data/screenshot-ui-area-symbolic.svg"));
|
|
|
|
if !area_icon_path.exists() {
|
|
area_icon_path = std::fs::canonicalize(Path::new(
|
|
&std::env::var("DATA_DIR")
|
|
.unwrap_or_else(|_| String::from("data/"))
|
|
.add("screenshot-ui-area-symbolic.svg"),
|
|
))
|
|
.unwrap();
|
|
}
|
|
|
|
let mut screen_icon_path = {
|
|
let mut current_exec_dir = std::env::current_exe().unwrap();
|
|
current_exec_dir.pop();
|
|
current_exec_dir
|
|
}
|
|
.join(Path::new("data/screenshot-ui-display-symbolic.svg"));
|
|
|
|
if !screen_icon_path.exists() {
|
|
screen_icon_path = std::fs::canonicalize(Path::new(
|
|
&std::env::var("DATA_DIR")
|
|
.unwrap_or_else(|_| String::from("data/"))
|
|
.add("screenshot-ui-display-symbolic.svg"),
|
|
))
|
|
.unwrap();
|
|
}
|
|
|
|
let mut window_icon_path = {
|
|
let mut current_exec_dir = std::env::current_exe().unwrap();
|
|
current_exec_dir.pop();
|
|
current_exec_dir
|
|
}
|
|
.join(Path::new("data/screenshot-ui-window-symbolic.svg"));
|
|
|
|
if !window_icon_path.exists() {
|
|
window_icon_path = std::fs::canonicalize(Path::new(
|
|
&std::env::var("DATA_DIR")
|
|
.unwrap_or_else(|_| String::from("data/"))
|
|
.add("screenshot-ui-window-symbolic.svg"),
|
|
))
|
|
.unwrap();
|
|
}
|
|
|
|
area_grab_icon.set_from_file(Some(area_icon_path));
|
|
screen_grab_icon.set_from_file(Some(screen_icon_path));
|
|
window_grab_icon.set_from_file(Some(&window_icon_path));
|
|
}
|
|
}
|
|
|
|
// Spin
|
|
frames_spin.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("frames-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
delay_spin.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("delay-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
quality_spin.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("quality-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
frames_spin.set_value(
|
|
config_management::get("default", "frame")
|
|
.parse::<f64>()
|
|
.unwrap(),
|
|
);
|
|
delay_spin.set_value(
|
|
config_management::get("default", "delay")
|
|
.parse::<f64>()
|
|
.unwrap(),
|
|
);
|
|
//quality_spin.set_value(
|
|
//config_management::get("default", "quality")
|
|
//.parse::<f64>()
|
|
//.unwrap(),
|
|
//);
|
|
|
|
let _format_chooser_combobox = format_chooser_combobox.clone();
|
|
let _quality_spin = quality_spin.clone();
|
|
format_chooser_combobox.connect_changed(move |_| {
|
|
if _format_chooser_combobox.active_text().is_some() {
|
|
config_management::set(
|
|
"default",
|
|
"format",
|
|
&_format_chooser_combobox.active().unwrap().to_string(),
|
|
);
|
|
let quality_spin = _quality_spin.clone();
|
|
_quality_spin.connect_value_changed(move |_| {
|
|
config_management::set(
|
|
"default",
|
|
"quality",
|
|
quality_spin.to_string().as_str(),
|
|
);
|
|
});
|
|
}
|
|
});
|
|
|
|
let _frames_spin = frames_spin.to_owned();
|
|
frames_spin.connect_value_changed(move |_| {
|
|
config_management::set(
|
|
"default",
|
|
"frame",
|
|
_frames_spin.value().to_string().as_str(),
|
|
);
|
|
});
|
|
let _delay_spin = delay_spin.to_owned();
|
|
delay_spin.connect_value_changed(move |_| {
|
|
config_management::set("default",
|
|
"delay",
|
|
_delay_spin.value().to_string().as_str());
|
|
});
|
|
let _quality_spin = delay_spin.to_owned();
|
|
quality_spin.connect_value_changed(move |_| {
|
|
config_management::set(
|
|
"default",
|
|
"quality",
|
|
_quality_spin.value().to_string().as_str(),
|
|
);
|
|
});
|
|
|
|
// Labels
|
|
command_label.set_label(&bundle.format_pattern(bundle.get_message("run-command").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
frames_label.set_label(&bundle.format_pattern(bundle.get_message("frames").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
delay_label.set_label(&bundle.format_pattern(bundle.get_message("delay").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
quality_label.set_label(&bundle.format_pattern(bundle.get_message("quality").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
audio_source_label.set_label(&bundle.format_pattern(bundle.get_message("audio-source").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
|
|
// FileChooser
|
|
let folder_chooser_native = FileChooserNative::new(
|
|
Some("Select Folder"),
|
|
Some(&main_window),
|
|
FileChooserAction::SelectFolder,
|
|
Some("Select"),
|
|
Some("Cancel"),
|
|
);
|
|
folder_chooser_native.set_transient_for(Some(&main_window));
|
|
folder_chooser_native.set_modal(true);
|
|
folder_chooser_native
|
|
.set_file(&gio::File::for_uri(&config_management::get(
|
|
"default", "folder",
|
|
)))
|
|
.unwrap();
|
|
let folder_chooser = Some(gio::File::for_uri(&config_management::get(
|
|
"default", "folder",
|
|
)))
|
|
.unwrap();
|
|
let folder_chooser_name = folder_chooser.basename().unwrap();
|
|
folder_chooser_label.set_label(&folder_chooser_name.to_string_lossy());
|
|
let folder_chooser_icon = config_management::folder_icon(folder_chooser_name.to_str());
|
|
folder_chooser_image.set_icon_name(Some(folder_chooser_icon));
|
|
folder_chooser_button.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("folder-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
// Show file chooser dialog
|
|
folder_chooser_button.connect_clicked(glib::clone!(@strong folder_chooser_native => move |_| {
|
|
folder_chooser_native.connect_response(glib::clone!(@strong folder_chooser_native, @strong folder_chooser_label, @strong folder_chooser_image => move |_, response| {
|
|
if response == gtk::ResponseType::Accept {
|
|
folder_chooser_native.file().unwrap();
|
|
let folder_chooser = folder_chooser_native.file().unwrap();
|
|
let folder_chooser_name = folder_chooser.basename().unwrap();
|
|
folder_chooser_label.set_label(&folder_chooser_name.to_string_lossy());
|
|
let folder_chooser_icon = config_management::folder_icon(folder_chooser_name.to_str());
|
|
folder_chooser_image.set_icon_name(Some(folder_chooser_icon));
|
|
};
|
|
folder_chooser_native.hide();
|
|
}));
|
|
folder_chooser_native.show();
|
|
}));
|
|
|
|
// --- connections
|
|
// Show dialog window when about button clicked then hide it after close
|
|
let _about_dialog: AboutDialog = about_dialog.to_owned();
|
|
about_button.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("about-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
about_button.set_label(&bundle.format_pattern(bundle.get_message("about").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
about_button.connect_clicked(move |_| {
|
|
_about_dialog.show();
|
|
_about_dialog.set_hide_on_close(true);
|
|
});
|
|
|
|
// Buttons
|
|
let area_capture: Rc<RefCell<area_capture::AreaCapture>> =
|
|
Rc::new(RefCell::new(area_capture::AreaCapture::new()));
|
|
|
|
let _area_chooser_window = area_chooser_window.clone();
|
|
let mut _area_capture = area_capture.clone();
|
|
area_grab_label.set_label(&bundle.format_pattern(bundle.get_message("select-area").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
area_grab_button.connect_clicked(move |_| {
|
|
_area_chooser_window.show();
|
|
});
|
|
|
|
let _area_chooser_window = area_chooser_window.clone();
|
|
let mut _area_capture = area_capture.clone();
|
|
area_apply_label.set_label(&bundle.format_pattern(bundle.get_message("apply").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
area_set_button.connect_clicked(move |_| {
|
|
_area_chooser_window.hide();
|
|
});
|
|
|
|
let _area_chooser_window = area_chooser_window.clone();
|
|
let mut _area_capture = area_capture.clone();
|
|
let record_window: Rc<RefCell<bool>> = Rc::new(RefCell::new(false));
|
|
let window_grab_button_record_window: Rc<RefCell<bool>> = record_window.clone();
|
|
let screen_grab_button_record_window: Rc<RefCell<bool>> = record_window.clone();
|
|
screen_grab_button.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("screen-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
screen_grab_label.set_label(&bundle.format_pattern(bundle.get_message("select-screen").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
screen_grab_button.connect_clicked(move |_| {
|
|
screen_grab_button_record_window.replace(false);
|
|
_area_chooser_window.hide();
|
|
_area_capture.borrow_mut().reset();
|
|
});
|
|
|
|
let _area_chooser_window: Window = area_chooser_window.clone();
|
|
let mut _area_capture: Rc<RefCell<area_capture::AreaCapture>> = area_capture.clone();
|
|
window_grab_button.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("window-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
window_grab_label.set_label(&bundle.format_pattern(bundle.get_message("select-window").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
window_grab_button.connect_clicked(move |_| {
|
|
_area_chooser_window.hide();
|
|
if is_wayland() {
|
|
window_grab_button_record_window.replace(true);
|
|
} else {
|
|
_area_capture.borrow_mut().get_area();
|
|
}
|
|
});
|
|
|
|
let _delay_spin = delay_spin.clone();
|
|
|
|
let main_context = glib::MainContext::default();
|
|
let wayland_record = main_context.block_on(WaylandRecorder::new());
|
|
let bundle_msg = bundle.format_pattern(bundle.get_message("already-exist").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string();
|
|
// Init record struct
|
|
let ffmpeg_record_interface: Rc<RefCell<Ffmpeg>> = Rc::new(RefCell::new(Ffmpeg {
|
|
filename: (
|
|
folder_chooser_native,
|
|
filename_entry,
|
|
format_chooser_combobox,
|
|
),
|
|
record_video: video_switch,
|
|
record_audio: audio_switch,
|
|
audio_id: audio_source_combobox,
|
|
record_mouse: mouse_switch,
|
|
follow_mouse: follow_mouse_switch,
|
|
record_frames: frames_spin,
|
|
command: command_entry,
|
|
video_process: None,
|
|
audio_process: None,
|
|
saved_filename: None,
|
|
unbound: None,
|
|
window: main_window.clone(),
|
|
record_delay: delay_spin,
|
|
record_wayland: wayland_record,
|
|
record_window,
|
|
main_context,
|
|
temp_video_filename: String::new(),
|
|
bundle: bundle_msg,
|
|
record_quality: quality_spin,
|
|
}));
|
|
|
|
// Record Button
|
|
let _delay_window = delay_window.clone();
|
|
let _delay_window_button = delay_window_button.clone();
|
|
let _ffmpeg_record_interface = ffmpeg_record_interface.clone();
|
|
let _main_window = main_window.clone();
|
|
let _play_button = play_button.clone();
|
|
let _record_button = record_button.clone();
|
|
let _record_time_label = record_time_label.clone();
|
|
let _stop_button = stop_button.clone();
|
|
record_button.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("record-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
record_label.set_label(&bundle.format_pattern(bundle.get_message("record").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
delay_window_title.set_label(&bundle.format_pattern(bundle.get_message("delay-title").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
delay_window_button.set_label(&bundle.format_pattern(bundle.get_message("delay-window-stop").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
record_button.connect_clicked(move |_| {
|
|
_delay_window_button.set_active(false);
|
|
if _delay_spin.value() as u64 > 0 {
|
|
recording_delay(
|
|
_delay_spin.clone(),
|
|
_delay_spin.value() as u64,
|
|
delay_window.clone(),
|
|
_delay_window_button.clone(),
|
|
delay_window_label.clone(),
|
|
_record_button.clone(),
|
|
);
|
|
} else if _delay_spin.value() as u64 == 0 {
|
|
let _area_capture = area_capture.borrow_mut();
|
|
match _ffmpeg_record_interface.borrow_mut().start_record(
|
|
_area_capture.x,
|
|
_area_capture.y,
|
|
_area_capture.width,
|
|
_area_capture.height,
|
|
) {
|
|
None => {
|
|
// Do nothing if the start_record function return nothing
|
|
}
|
|
_ => {
|
|
start_timer(record_time_label.clone());
|
|
record_time_label.set_visible(true);
|
|
if hide_switch.is_active() {
|
|
_main_window.minimize();
|
|
}
|
|
_play_button.hide();
|
|
_record_button.hide();
|
|
_stop_button.show();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Stop Record Button
|
|
let mut _ffmpeg_record_interface = ffmpeg_record_interface.clone();
|
|
let _play_button = play_button.clone();
|
|
let _stop_button = stop_button.clone();
|
|
stop_button.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("stop-tooltip").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
stop_label.set_label(&bundle.format_pattern(bundle.get_message("stop-recording").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
stop_button.connect_clicked(move |_| {
|
|
_record_time_label.set_visible(false);
|
|
stop_timer(_record_time_label.clone());
|
|
_ffmpeg_record_interface.borrow_mut().clone().stop_record();
|
|
record_button.show();
|
|
_stop_button.hide();
|
|
_play_button.show();
|
|
});
|
|
|
|
// Delay Window Button
|
|
let _delay_window_button = delay_window_button.clone();
|
|
delay_window_button.connect_clicked(move |_| {});
|
|
|
|
// Play Button
|
|
let mut _ffmpeg_record_interface = ffmpeg_record_interface.clone();
|
|
play_button.connect_clicked(move |_| {
|
|
_ffmpeg_record_interface.borrow_mut().clone().play_record();
|
|
});
|
|
|
|
// About Dialog
|
|
let mut about_icon_path = {
|
|
let mut current_exec_dir = std::env::current_exe().unwrap();
|
|
current_exec_dir.pop();
|
|
current_exec_dir
|
|
}
|
|
.join(Path::new("data/blue-recorder@x96.png"));
|
|
|
|
if !about_icon_path.exists() {
|
|
about_icon_path = std::fs::canonicalize(Path::new(
|
|
&std::env::var("DATA_DIR")
|
|
.unwrap_or_else(|_| String::from("data/"))
|
|
.add("blue-recorder@x96.png"),
|
|
))
|
|
.unwrap();
|
|
}
|
|
|
|
let logo = Image::from_file(&about_icon_path.to_str().unwrap());
|
|
about_dialog.set_transient_for(Some(&main_window));
|
|
about_dialog.set_program_name(Some(&bundle.format_pattern(bundle.get_message("blue-recorder").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
about_dialog.set_version(Some("0.2.0"));
|
|
about_dialog.set_copyright(Some(&bundle.format_pattern(bundle.get_message("copy-right").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
about_dialog.set_wrap_license(true);
|
|
about_dialog.set_license(Some(&bundle.format_pattern(bundle.get_message("license").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
about_dialog.set_comments(Some(&bundle.format_pattern(bundle.get_message("dialog-comment").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string()));
|
|
// Authors
|
|
about_dialog.add_credit_section(
|
|
&bundle.format_pattern(bundle.get_message("authors").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&[&bundle.format_pattern(bundle.get_message("address-abdullah-al-baroty").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&bundle.format_pattern(bundle.get_message("address-alessandro-toia").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&bundle.format_pattern(bundle.get_message("address-chibani").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&bundle.format_pattern(bundle.get_message("address-hanny-sabbagh").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&bundle.format_pattern(bundle.get_message("address-salem-yaslem").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&bundle.format_pattern(bundle.get_message("address-suliman-altassan").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
]
|
|
);
|
|
// Patreon suppoters
|
|
about_dialog.add_credit_section(
|
|
&bundle.format_pattern(bundle.get_message("patreon").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&[&bundle.format_pattern(bundle.get_message("address-ahmad-gharib").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&bundle.format_pattern(bundle.get_message("address-medium").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&bundle.format_pattern(bundle.get_message("address-william-grunow").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&bundle.format_pattern(bundle.get_message("address-alex-benishek").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
]
|
|
);
|
|
// Designers
|
|
about_dialog.add_credit_section(
|
|
&bundle.format_pattern(bundle.get_message("design").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&[&bundle.format_pattern(bundle.get_message("address-abdullah-al-baroty").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&bundle.format_pattern(bundle.get_message("address-mustapha-assabar").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
]
|
|
);
|
|
// Translators
|
|
about_dialog.add_credit_section(
|
|
&bundle.format_pattern(bundle.get_message("translate").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&[&bundle.format_pattern(bundle.get_message("address-ake-engelbrektson").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&bundle.format_pattern(bundle.get_message("address-amerey").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&bundle.format_pattern(bundle.get_message("address-gmou3").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&bundle.format_pattern(bundle.get_message("address-larry-wei").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&bundle.format_pattern(bundle.get_message("address-mark-wagie").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&bundle.format_pattern(bundle.get_message("address-albanobattistella").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
&bundle.format_pattern(bundle.get_message("address-mr-Narsus").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string(),
|
|
]
|
|
);
|
|
about_dialog.set_website(Some("https://github.com/xlmnxp/blue-recorder/"));
|
|
about_dialog.set_website_label(&bundle.format_pattern(bundle.get_message("website").unwrap()
|
|
.value().unwrap(), None, &mut vec![]).to_string());
|
|
about_dialog.set_logo_icon_name(Some("blue-recorder"));
|
|
about_dialog.set_logo(logo.paintable().as_ref());
|
|
about_dialog.set_modal(true);
|
|
|
|
// Windows
|
|
// Hide area chooser after it deleted.
|
|
let _area_chooser_window = area_chooser_window.clone();
|
|
area_chooser_window.connect_close_request(move |_| {
|
|
_area_chooser_window.hide();
|
|
gtk::Inhibit(true)
|
|
});
|
|
|
|
// Close the application when main window destroy
|
|
main_window.connect_destroy(move |main_window| {
|
|
let mut _ffmpeg_record_interface = ffmpeg_record_interface.clone();
|
|
// Stop recording before close the application
|
|
_ffmpeg_record_interface.borrow_mut().clone().stop_record();
|
|
main_window.close();
|
|
});
|
|
|
|
// Apply CSS
|
|
let provider = CssProvider::new();
|
|
provider.load_from_data(include_str!("styles/global.css").as_bytes());
|
|
gtk::StyleContext::add_provider_for_display(
|
|
&area_chooser_window.display(),
|
|
&provider,
|
|
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
|
|
);
|
|
|
|
main_window.show();
|
|
}
|