From 52445b9ba050aba9ba1ee96bf9b2c69ec891fe80 Mon Sep 17 00:00:00 2001 From: Fabio Lenherr / DashieTM Date: Sat, 18 Nov 2023 15:08:56 +0100 Subject: [PATCH 1/8] fix: Use buffer for sending volume updates --- src/components/input/outputStreamEntry.rs | 3 +++ src/components/input/sourceBox.rs | 14 ++++++---- src/components/input/sourceEntry.rs | 3 +++ src/components/output/inputStreamEntry.rs | 13 ++++++++-- src/components/output/inputStreamEntryImpl.rs | 2 ++ src/components/output/sinkBox.rs | 26 ++++++++++++++++--- src/resources/resetInputStreamEntry.ui | 5 +++- src/resources/resetUI.cmb | 11 +++++--- 8 files changed, 61 insertions(+), 16 deletions(-) diff --git a/src/components/input/outputStreamEntry.rs b/src/components/input/outputStreamEntry.rs index afff09f..ac9025e 100644 --- a/src/components/input/outputStreamEntry.rs +++ b/src/components/input/outputStreamEntry.rs @@ -20,6 +20,9 @@ glib::wrapper! { @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Orientable; } +unsafe impl Send for OutputStreamEntry {} +unsafe impl Sync for OutputStreamEntry {} + impl OutputStreamEntry { pub fn new(source_box: Arc, stream: OutputStream) -> Self { let obj: Self = Object::builder().build(); diff --git a/src/components/input/sourceBox.rs b/src/components/input/sourceBox.rs index 2bf3353..7e9e0de 100644 --- a/src/components/input/sourceBox.rs +++ b/src/components/input/sourceBox.rs @@ -192,9 +192,10 @@ pub fn populate_outputstreams(input_box: Arc) { for stream in streams { let index = stream.index; let input_stream = Arc::new(OutputStreamEntry::new(input_box.clone(), stream)); + let input_stream_clone = input_stream.clone(); let entry = Arc::new(ListEntry::new(&*input_stream)); entry.set_activatable(false); - list.insert(index, (entry.clone(), input_stream.clone())); + list.insert(index, (entry.clone(), input_stream_clone)); input_box_imp.resetOutputStreams.append(&*entry); } }); @@ -352,7 +353,9 @@ pub fn start_input_box_listener( let mut map = output_box_imp.resetSourceMap.write().unwrap(); map.remove(&alias.unwrap().2); let mut index = output_box_imp.resetModelIndex.write().unwrap(); - *index -= 1; + if *index != 0 { + *index -= 1; + } }); }); true @@ -406,9 +409,10 @@ pub fn start_input_box_listener( let mut list = output_box_imp.resetOutputStreamList.write().unwrap(); let index = ir.stream.index; let output_stream = Arc::new(OutputStreamEntry::new(output_box.clone(), ir.stream)); + let output_stream_clone = output_stream.clone(); let entry = Arc::new(ListEntry::new(&*output_stream)); entry.set_activatable(false); - list.insert(index, (entry.clone(), output_stream.clone())); + list.insert(index, (entry.clone(), output_stream_clone)); output_box_imp.resetOutputStreams.append(&*entry); }); }); @@ -486,12 +490,12 @@ pub fn start_input_box_listener( let output_box = source_box.clone(); let output_box_imp = output_box.imp(); let mut list = output_box_imp.resetOutputStreamList.write().unwrap(); - let entry = list.get(&ir.index); + let entry = list.remove(&ir.index); if entry.is_none() { + println!("tried to remove nonexistant?? wat"); return; } output_box_imp.resetOutputStreams.remove(&*entry.unwrap().0); - list.remove(&ir.index); }); }); true diff --git a/src/components/input/sourceEntry.rs b/src/components/input/sourceEntry.rs index 067c63b..0e8a082 100644 --- a/src/components/input/sourceEntry.rs +++ b/src/components/input/sourceEntry.rs @@ -19,6 +19,9 @@ glib::wrapper! { @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Orientable; } +unsafe impl Send for SourceEntry {} +unsafe impl Sync for SourceEntry {} + impl SourceEntry { pub fn new(is_default: bool, check_group: Arc, stream: Source) -> Self { let obj: Self = Object::builder().build(); diff --git a/src/components/output/inputStreamEntry.rs b/src/components/output/inputStreamEntry.rs index bfd69ae..5509048 100644 --- a/src/components/output/inputStreamEntry.rs +++ b/src/components/output/inputStreamEntry.rs @@ -1,5 +1,6 @@ +use std::cell::RefCell; use std::sync::Arc; -use std::time::Duration; +use std::time::{Duration, SystemTime}; use adw::glib; use adw::glib::Object; @@ -8,7 +9,8 @@ use dbus::blocking::Connection; use dbus::Error; use glib::subclass::types::ObjectSubclassIsExt; use glib::{clone, Cast, Propagation}; -use gtk::{gio, StringObject}; +use gtk::prelude::ScaleExt; +use gtk::{gio, PositionType, StringObject}; use ReSet_Lib::audio::audio::InputStream; use super::inputStreamEntryImpl; @@ -59,6 +61,13 @@ impl InputStreamEntry { let stream = stream.unwrap(); let index = stream.index; let channels = stream.channels; + { + let mut time = imp.volumeTimeStamp.borrow_mut(); + if time.is_some() && time.unwrap().elapsed().unwrap() < Duration::from_millis(50) { + return Propagation::Proceed; + } + *time = Some(SystemTime::now()); + } set_inputstream_volume(value, index, channels); Propagation::Proceed }), diff --git a/src/components/output/inputStreamEntryImpl.rs b/src/components/output/inputStreamEntryImpl.rs index 29ec348..b42e0db 100644 --- a/src/components/output/inputStreamEntryImpl.rs +++ b/src/components/output/inputStreamEntryImpl.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; use std::sync::Arc; +use std::time::SystemTime; use gtk::subclass::prelude::*; use gtk::{glib, Button, CompositeTemplate, DropDown, Label, ProgressBar, Scale}; @@ -25,6 +26,7 @@ pub struct InputStreamEntry { pub resetVolumeMeter: TemplateChild, pub stream: Arc>, pub associatedSink: Arc>, + pub volumeTimeStamp: RefCell>, } #[glib::object_subclass] diff --git a/src/components/output/sinkBox.rs b/src/components/output/sinkBox.rs index 88c9a81..55b5f72 100644 --- a/src/components/output/sinkBox.rs +++ b/src/components/output/sinkBox.rs @@ -35,7 +35,13 @@ unsafe impl Sync for SinkBox {} impl SinkBox { pub fn new() -> Self { - Object::builder().build() + let obj: Self = Object::builder().build(); + { + let imp = obj.imp(); + let mut model_index = imp.resetModelIndex.write().unwrap(); + *model_index = 0; + } + obj } pub fn setupCallbacks(&self) { @@ -53,6 +59,12 @@ impl SinkBox { } } +impl Default for SinkBox { + fn default() -> Self { + Self::new() + } +} + pub fn populate_sinks(output_box: Arc) { gio::spawn_blocking(move || { let output_box_ref = output_box.clone(); @@ -81,7 +93,7 @@ pub fn populate_sinks(output_box: Arc) { let default_sink = output_box_imp.resetDefaultSink.clone(); let sink = default_sink.borrow(); - let volume = sink.volume.first().unwrap_or_else(|| &(0 as u32)); + let volume = sink.volume.first().unwrap_or(&0); let fraction = (*volume as f64 / 655.36).round(); let percentage = (fraction).to_string() + "%"; output_box_imp.resetVolumePercentage.set_text(&percentage); @@ -239,7 +251,11 @@ fn get_default_sink() -> Sink { res.unwrap().0 } -pub fn start_output_box_listener(conn: Connection, listeners: Arc, sink_box: Arc) -> Connection { +pub fn start_output_box_listener( + conn: Connection, + listeners: Arc, + sink_box: Arc, +) -> Connection { if listeners.network_listener.load(Ordering::SeqCst) { return conn; } @@ -339,7 +355,9 @@ pub fn start_output_box_listener(conn: Connection, listeners: Arc, si let mut map = output_box_imp.resetSinkMap.write().unwrap(); map.remove(&alias.unwrap().2); let mut index = output_box_imp.resetModelIndex.write().unwrap(); - *index -= 1; + if *index != 0 { + *index -= 1; + } }); }); true diff --git a/src/resources/resetInputStreamEntry.ui b/src/resources/resetInputStreamEntry.ui index 42b0929..925133c 100644 --- a/src/resources/resetInputStreamEntry.ui +++ b/src/resources/resetInputStreamEntry.ui @@ -42,7 +42,7 @@ - 2005.4016 + 10000.0 2005.4016 100270.08 @@ -50,6 +50,9 @@ True center bottom + + 100% + diff --git a/src/resources/resetUI.cmb b/src/resources/resetUI.cmb index 4704a10..afcce47 100644 --- a/src/resources/resetUI.cmb +++ b/src/resources/resetUI.cmb @@ -438,7 +438,7 @@ (7,9,"GtkScale","value-pos","bottom",None,None,None,None,None,None,None,None,None), (7,9,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None), (7,9,"GtkWidget","valign","center",None,None,None,None,None,None,None,None,None), - (7,10,"GtkAdjustment","page-increment","2005.4016",None,None,None,None,None,None,None,None,None), + (7,10,"GtkAdjustment","page-increment","10000.0",None,None,None,None,None,None,None,None,None), (7,10,"GtkAdjustment","step-increment","2005.4016",None,None,None,None,None,None,None,None,None), (7,10,"GtkAdjustment","upper","100270.08",None,None,None,None,None,None,None,None,None), (7,11,"GtkButton","icon-name","audio-volume-high-symbolic",None,None,None,None,None,None,None,None,None), @@ -798,10 +798,13 @@ (3,42,"GtkWidget",1,1,None,None,None,None,None,None), - (3,42,"GtkWidget",2,2,None,1,None,None,None,None) + (3,42,"GtkWidget",2,2,None,1,None,None,None,None), + (7,9,"GtkScale",1,1,None,None,None,None,None,None), + (7,9,"GtkScale",2,2,"100%",1,None,None,None,None) - (7,9,"GtkScale",2,2,"value","50.0"), - (3,42,"GtkWidget",2,2,"name","b") + (7,9,"GtkScale",2,2,"value","65536.0"), + (3,42,"GtkWidget",2,2,"name","b"), + (7,9,"GtkScale",2,2,"position","bottom") From 5a0e5d86bb207d585884873a33491e896f7e4c83 Mon Sep 17 00:00:00 2001 From: Fabio Lenherr / DashieTM Date: Sat, 18 Nov 2023 15:10:09 +0100 Subject: [PATCH 2/8] chore: Bump version of daemon --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2cdc7a3..e56a067 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" description = "A wip universal Linux settings application." [dependencies] -reset_daemon = "0.1.7" +reset_daemon = "0.1.8" ReSet-Lib = "0.2.8" adw = { version = "0.5.3", package = "libadwaita", features = ["v1_4"] } dbus = "0.9.7" From 03fc3790c0544f2735fbb3025c7374de66d9eb52 Mon Sep 17 00:00:00 2001 From: Fabio Lenherr / DashieTM Date: Sat, 18 Nov 2023 15:28:23 +0100 Subject: [PATCH 3/8] fix: Use buffer for all audio sliders --- flatpak/cargo-sources.json | 10 +-- src/components/input/outputStreamEntry.rs | 65 +++++++++++-------- src/components/input/outputStreamEntryImpl.rs | 2 + src/components/input/sourceBox.rs | 11 +++- src/components/input/sourceBoxImpl.rs | 2 + src/components/input/sourceEntry.rs | 41 +++++++----- src/components/input/sourceEntryImpl.rs | 2 + src/components/output/inputStreamEntry.rs | 4 +- src/components/output/sinkBox.rs | 11 +++- src/components/output/sinkBoxImpl.rs | 2 + src/components/output/sinkEntry.rs | 9 ++- src/components/output/sinkEntryImpl.rs | 2 + src/resources/resetAudioInput.ui | 3 + src/resources/resetAudioOutput.ui | 3 + src/resources/resetInputStreamEntry.ui | 2 +- src/resources/resetOutputStreamEntry.ui | 3 + src/resources/resetSinkEntry.ui | 3 + src/resources/resetSourceEntry.ui | 3 + src/resources/resetUI.cmb | 26 +++++++- 19 files changed, 145 insertions(+), 59 deletions(-) diff --git a/flatpak/cargo-sources.json b/flatpak/cargo-sources.json index 9ff0d58..2764156 100644 --- a/flatpak/cargo-sources.json +++ b/flatpak/cargo-sources.json @@ -1042,14 +1042,14 @@ { "type": "archive", "archive-type": "tar-gzip", - "url": "https://static.crates.io/crates/reset_daemon/reset_daemon-0.1.7.crate", - "sha256": "f7b48ba0698bdb4ead119140a557346907b40ae17cac324687a032b4d6ea9851", - "dest": "cargo/vendor/reset_daemon-0.1.7" + "url": "https://static.crates.io/crates/reset_daemon/reset_daemon-0.1.8.crate", + "sha256": "a861e230340e001757325a01fa33cfce9e29111f0228dd2abd1d62206f742803", + "dest": "cargo/vendor/reset_daemon-0.1.8" }, { "type": "inline", - "contents": "{\"package\": \"f7b48ba0698bdb4ead119140a557346907b40ae17cac324687a032b4d6ea9851\", \"files\": {}}", - "dest": "cargo/vendor/reset_daemon-0.1.7", + "contents": "{\"package\": \"a861e230340e001757325a01fa33cfce9e29111f0228dd2abd1d62206f742803\", \"files\": {}}", + "dest": "cargo/vendor/reset_daemon-0.1.8", "dest-filename": ".cargo-checksum.json" }, { diff --git a/src/components/input/outputStreamEntry.rs b/src/components/input/outputStreamEntry.rs index ac9025e..81846a2 100644 --- a/src/components/input/outputStreamEntry.rs +++ b/src/components/input/outputStreamEntry.rs @@ -1,5 +1,5 @@ use std::sync::Arc; -use std::time::Duration; +use std::time::{Duration, SystemTime}; use adw::glib; use adw::glib::Object; @@ -50,6 +50,15 @@ impl OutputStreamEntry { let stream = stream.unwrap(); let index = stream.index; let channels = stream.channels; + { + let mut time = imp.volumeTimeStamp.borrow_mut(); + if time.is_some() + && time.unwrap().elapsed().unwrap() < Duration::from_millis(50) + { + return Propagation::Proceed; + } + *time = Some(SystemTime::now()); + } set_outputstream_volume(value, index, channels); Propagation::Proceed }), @@ -127,39 +136,39 @@ impl OutputStreamEntry { fn set_outputstream_volume(value: f64, index: u32, channels: u16) -> bool { gio::spawn_blocking(move || { - let conn = Connection::new_session().unwrap(); - let proxy = conn.with_proxy( - "org.xetibo.ReSet", - "/org/xetibo/ReSet", - Duration::from_millis(1000), - ); - let _: Result<(), Error> = proxy.method_call( - "org.xetibo.ReSet", - "SetOutputStreamVolume", - (index, channels, value as u32), - ); - // if res.is_err() { - // return false; - // } - // res.unwrap().0 + let conn = Connection::new_session().unwrap(); + let proxy = conn.with_proxy( + "org.xetibo.ReSet", + "/org/xetibo/ReSet", + Duration::from_millis(1000), + ); + let _: Result<(), Error> = proxy.method_call( + "org.xetibo.ReSet", + "SetOutputStreamVolume", + (index, channels, value as u32), + ); + // if res.is_err() { + // return false; + // } + // res.unwrap().0 }); true } fn toggle_output_stream_mute(index: u32, muted: bool) -> bool { gio::spawn_blocking(move || { - let conn = Connection::new_session().unwrap(); - let proxy = conn.with_proxy( - "org.xetibo.ReSet", - "/org/xetibo/ReSet", - Duration::from_millis(1000), - ); - let _: Result<(), Error> = - proxy.method_call("org.xetibo.ReSet", "SetOutputStreamMute", (index, muted)); - // if res.is_err() { - // return false; - // } - // res.unwrap().0 + let conn = Connection::new_session().unwrap(); + let proxy = conn.with_proxy( + "org.xetibo.ReSet", + "/org/xetibo/ReSet", + Duration::from_millis(1000), + ); + let _: Result<(), Error> = + proxy.method_call("org.xetibo.ReSet", "SetOutputStreamMute", (index, muted)); + // if res.is_err() { + // return false; + // } + // res.unwrap().0 }); true } diff --git a/src/components/input/outputStreamEntryImpl.rs b/src/components/input/outputStreamEntryImpl.rs index 59122e8..3a3bed1 100644 --- a/src/components/input/outputStreamEntryImpl.rs +++ b/src/components/input/outputStreamEntryImpl.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; use std::sync::Arc; +use std::time::SystemTime; use crate::components::input::outputStreamEntry; use gtk::subclass::prelude::*; @@ -24,6 +25,7 @@ pub struct OutputStreamEntry { pub resetVolumeMeter: TemplateChild, pub stream: Arc>, pub associatedSource: Arc>, + pub volumeTimeStamp: RefCell>, } #[glib::object_subclass] diff --git a/src/components/input/sourceBox.rs b/src/components/input/sourceBox.rs index 7e9e0de..cbb40c9 100644 --- a/src/components/input/sourceBox.rs +++ b/src/components/input/sourceBox.rs @@ -1,6 +1,6 @@ use std::sync::atomic::Ordering; use std::sync::Arc; -use std::time::Duration; +use std::time::{Duration, SystemTime}; use crate::components::base::listEntry::ListEntry; use crate::components::base::utils::{ @@ -151,6 +151,15 @@ pub fn populate_sources(input_box: Arc) { let source = imp.resetDefaultSource.borrow(); let index = source.index; let channels = source.channels; + { + let mut time = imp.volumeTimeStamp.borrow_mut(); + if time.is_some() + && time.unwrap().elapsed().unwrap() < Duration::from_millis(50) + { + return Propagation::Proceed; + } + *time = Some(SystemTime::now()); + } set_source_volume(value, index, channels); Propagation::Proceed }); diff --git a/src/components/input/sourceBoxImpl.rs b/src/components/input/sourceBoxImpl.rs index b141dd2..3c60b5d 100644 --- a/src/components/input/sourceBoxImpl.rs +++ b/src/components/input/sourceBoxImpl.rs @@ -1,6 +1,7 @@ use std::cell::RefCell; use std::collections::HashMap; use std::sync::{Arc, RwLock}; +use std::time::SystemTime; use crate::components::base::listEntry::ListEntry; use crate::components::input::sourceBox; @@ -43,6 +44,7 @@ pub struct SourceBox { // first u32 is the index of the source, the second the index in the model list and the third is // the full name pub resetSourceMap: Arc>>, + pub volumeTimeStamp: RefCell>, } #[glib::object_subclass] diff --git a/src/components/input/sourceEntry.rs b/src/components/input/sourceEntry.rs index 0e8a082..f8dd676 100644 --- a/src/components/input/sourceEntry.rs +++ b/src/components/input/sourceEntry.rs @@ -1,5 +1,5 @@ use std::sync::Arc; -use std::time::Duration; +use std::time::{Duration, SystemTime}; use adw::glib; use adw::glib::Object; @@ -44,6 +44,15 @@ impl SourceEntry { let source = imp.stream.borrow(); let index = source.index; let channels = source.channels; + { + let mut time = imp.volumeTimeStamp.borrow_mut(); + if time.is_some() + && time.unwrap().elapsed().unwrap() < Duration::from_millis(50) + { + return Propagation::Proceed; + } + *time = Some(SystemTime::now()); + } set_source_volume(value, index, channels); Propagation::Proceed }), @@ -83,21 +92,21 @@ impl SourceEntry { pub fn set_source_volume(value: f64, index: u32, channels: u16) -> bool { gio::spawn_blocking(move || { - let conn = Connection::new_session().unwrap(); - let proxy = conn.with_proxy( - "org.xetibo.ReSet", - "/org/xetibo/ReSet", - Duration::from_millis(1000), - ); - let _: Result<(), Error> = proxy.method_call( - "org.xetibo.ReSet", - "SetSourceVolume", - (index, channels, value as u32), - ); - // if res.is_err() { - // return false; - // } - // res.unwrap().0 + let conn = Connection::new_session().unwrap(); + let proxy = conn.with_proxy( + "org.xetibo.ReSet", + "/org/xetibo/ReSet", + Duration::from_millis(1000), + ); + let _: Result<(), Error> = proxy.method_call( + "org.xetibo.ReSet", + "SetSourceVolume", + (index, channels, value as u32), + ); + // if res.is_err() { + // return false; + // } + // res.unwrap().0 }); true } diff --git a/src/components/input/sourceEntryImpl.rs b/src/components/input/sourceEntryImpl.rs index 57c3e44..e838e5d 100644 --- a/src/components/input/sourceEntryImpl.rs +++ b/src/components/input/sourceEntryImpl.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; use std::sync::Arc; +use std::time::SystemTime; use gtk::subclass::prelude::*; use gtk::{glib, Button, CompositeTemplate, Label, ProgressBar, Scale, CheckButton}; @@ -24,6 +25,7 @@ pub struct SourceEntry { #[template_child] pub resetVolumeMeter: TemplateChild, pub stream: Arc>, + pub volumeTimeStamp: RefCell>, } #[glib::object_subclass] diff --git a/src/components/output/inputStreamEntry.rs b/src/components/output/inputStreamEntry.rs index 5509048..3c80f5b 100644 --- a/src/components/output/inputStreamEntry.rs +++ b/src/components/output/inputStreamEntry.rs @@ -1,4 +1,3 @@ -use std::cell::RefCell; use std::sync::Arc; use std::time::{Duration, SystemTime}; @@ -9,8 +8,7 @@ use dbus::blocking::Connection; use dbus::Error; use glib::subclass::types::ObjectSubclassIsExt; use glib::{clone, Cast, Propagation}; -use gtk::prelude::ScaleExt; -use gtk::{gio, PositionType, StringObject}; +use gtk::{gio, StringObject}; use ReSet_Lib::audio::audio::InputStream; use super::inputStreamEntryImpl; diff --git a/src/components/output/sinkBox.rs b/src/components/output/sinkBox.rs index 55b5f72..35fe537 100644 --- a/src/components/output/sinkBox.rs +++ b/src/components/output/sinkBox.rs @@ -1,6 +1,6 @@ use std::sync::atomic::Ordering; use std::sync::Arc; -use std::time::Duration; +use std::time::{Duration, SystemTime}; use crate::components::base::listEntry::ListEntry; use crate::components::base::utils::{ @@ -159,6 +159,15 @@ pub fn populate_sinks(output_box: Arc) { let sink = imp.resetDefaultSink.borrow(); let index = sink.index; let channels = sink.channels; + { + let mut time = imp.volumeTimeStamp.borrow_mut(); + if time.is_some() + && time.unwrap().elapsed().unwrap() < Duration::from_millis(50) + { + return Propagation::Proceed; + } + *time = Some(SystemTime::now()); + } set_sink_volume(value, index, channels); Propagation::Proceed }); diff --git a/src/components/output/sinkBoxImpl.rs b/src/components/output/sinkBoxImpl.rs index d472158..783aba6 100644 --- a/src/components/output/sinkBoxImpl.rs +++ b/src/components/output/sinkBoxImpl.rs @@ -1,6 +1,7 @@ use std::cell::RefCell; use std::collections::HashMap; use std::sync::{Arc, RwLock}; +use std::time::SystemTime; use crate::components::base::listEntry::ListEntry; use crate::components::output::inputStreamEntry::InputStreamEntry; @@ -46,6 +47,7 @@ pub struct SinkBox { // the full name pub resetSinkMap: Arc>>, // pub : Arc>>, + pub volumeTimeStamp: RefCell>, } #[glib::object_subclass] diff --git a/src/components/output/sinkEntry.rs b/src/components/output/sinkEntry.rs index d49e5ac..592532a 100644 --- a/src/components/output/sinkEntry.rs +++ b/src/components/output/sinkEntry.rs @@ -1,5 +1,5 @@ use std::sync::Arc; -use std::time::Duration; +use std::time::{Duration, SystemTime}; use adw::glib; use adw::glib::Object; @@ -42,6 +42,13 @@ impl SinkEntry { let sink = imp.stream.borrow(); let index = sink.index; let channels = sink.channels; + { + let mut time = imp.volumeTimeStamp.borrow_mut(); + if time.is_some() && time.unwrap().elapsed().unwrap() < Duration::from_millis(50) { + return Propagation::Proceed; + } + *time = Some(SystemTime::now()); + } set_sink_volume(value, index, channels); Propagation::Proceed }), diff --git a/src/components/output/sinkEntryImpl.rs b/src/components/output/sinkEntryImpl.rs index 84b92dd..ce65020 100644 --- a/src/components/output/sinkEntryImpl.rs +++ b/src/components/output/sinkEntryImpl.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; use std::sync::Arc; +use std::time::SystemTime; use crate::components::output::sinkEntry; use gtk::subclass::prelude::*; @@ -23,6 +24,7 @@ pub struct SinkEntry { #[template_child] pub resetVolumeMeter: TemplateChild, pub stream: Arc>, + pub volumeTimeStamp: RefCell>, } #[glib::object_subclass] diff --git a/src/resources/resetAudioInput.ui b/src/resources/resetAudioInput.ui index db18217..d8e51cc 100644 --- a/src/resources/resetAudioInput.ui +++ b/src/resources/resetAudioInput.ui @@ -92,6 +92,9 @@ True center bottom + + 100% + diff --git a/src/resources/resetAudioOutput.ui b/src/resources/resetAudioOutput.ui index b0c736f..1b01d0f 100644 --- a/src/resources/resetAudioOutput.ui +++ b/src/resources/resetAudioOutput.ui @@ -92,6 +92,9 @@ True center bottom + + 100% + diff --git a/src/resources/resetInputStreamEntry.ui b/src/resources/resetInputStreamEntry.ui index 925133c..3ea0fba 100644 --- a/src/resources/resetInputStreamEntry.ui +++ b/src/resources/resetInputStreamEntry.ui @@ -42,7 +42,7 @@ - 10000.0 + 2005.4016 2005.4016 100270.08 diff --git a/src/resources/resetOutputStreamEntry.ui b/src/resources/resetOutputStreamEntry.ui index 6fe5643..082b585 100644 --- a/src/resources/resetOutputStreamEntry.ui +++ b/src/resources/resetOutputStreamEntry.ui @@ -50,6 +50,9 @@ True center bottom + + 100% + diff --git a/src/resources/resetSinkEntry.ui b/src/resources/resetSinkEntry.ui index 9102f70..0d89cc5 100644 --- a/src/resources/resetSinkEntry.ui +++ b/src/resources/resetSinkEntry.ui @@ -50,6 +50,9 @@ True center bottom + + 100% + diff --git a/src/resources/resetSourceEntry.ui b/src/resources/resetSourceEntry.ui index 8fa52a2..21a8b82 100644 --- a/src/resources/resetSourceEntry.ui +++ b/src/resources/resetSourceEntry.ui @@ -50,6 +50,9 @@ True center bottom + + 100% + diff --git a/src/resources/resetUI.cmb b/src/resources/resetUI.cmb index afcce47..414033d 100644 --- a/src/resources/resetUI.cmb +++ b/src/resources/resetUI.cmb @@ -438,7 +438,7 @@ (7,9,"GtkScale","value-pos","bottom",None,None,None,None,None,None,None,None,None), (7,9,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None), (7,9,"GtkWidget","valign","center",None,None,None,None,None,None,None,None,None), - (7,10,"GtkAdjustment","page-increment","10000.0",None,None,None,None,None,None,None,None,None), + (7,10,"GtkAdjustment","page-increment","2005.4016",None,None,None,None,None,None,None,None,None), (7,10,"GtkAdjustment","step-increment","2005.4016",None,None,None,None,None,None,None,None,None), (7,10,"GtkAdjustment","upper","100270.08",None,None,None,None,None,None,None,None,None), (7,11,"GtkButton","icon-name","audio-volume-high-symbolic",None,None,None,None,None,None,None,None,None), @@ -800,11 +800,31 @@ (3,42,"GtkWidget",1,1,None,None,None,None,None,None), (3,42,"GtkWidget",2,2,None,1,None,None,None,None), (7,9,"GtkScale",1,1,None,None,None,None,None,None), - (7,9,"GtkScale",2,2,"100%",1,None,None,None,None) + (7,9,"GtkScale",2,2,"100%",1,None,None,None,None), + (8,99,"GtkScale",1,1,None,None,None,None,None,None), + (8,99,"GtkScale",2,2,"100%",1,None,None,None,None), + (12,25,"GtkScale",1,1,None,None,None,None,None,None), + (12,25,"GtkScale",2,2,"100%",1,None,None,None,None), + (13,17,"GtkScale",1,1,None,None,None,None,None,None), + (13,17,"GtkScale",2,2,"100%",1,None,None,None,None), + (18,7,"GtkScale",1,1,None,None,None,None,None,None), + (18,7,"GtkScale",2,2,"100%",1,None,None,None,None), + (19,7,"GtkScale",1,1,None,None,None,None,None,None), + (19,7,"GtkScale",2,2,"100%",1,None,None,None,None) (7,9,"GtkScale",2,2,"value","65536.0"), (3,42,"GtkWidget",2,2,"name","b"), - (7,9,"GtkScale",2,2,"position","bottom") + (7,9,"GtkScale",2,2,"position","bottom"), + (8,99,"GtkScale",2,2,"position","bottom"), + (8,99,"GtkScale",2,2,"value","65536.0"), + (12,25,"GtkScale",2,2,"value","65536.0"), + (12,25,"GtkScale",2,2,"position","bottom"), + (13,17,"GtkScale",2,2,"value","65536.0"), + (13,17,"GtkScale",2,2,"position","bottom"), + (18,7,"GtkScale",2,2,"position","bottom"), + (18,7,"GtkScale",2,2,"value","65536.0"), + (19,7,"GtkScale",2,2,"position","bottom"), + (19,7,"GtkScale",2,2,"value","65536.0") From 9108ab0d744b5b596303cd03ee9d13cf481997f6 Mon Sep 17 00:00:00 2001 From: Fabio Lenherr / DashieTM Date: Sat, 18 Nov 2023 22:15:09 +0100 Subject: [PATCH 4/8] feat: Add initial Bluetooth functionality --- Cargo.toml | 2 +- src/components/base/cardEntry.rs | 74 +++++++++++ src/components/base/cardEntryImpl.rs | 52 ++++++++ src/components/base/listEntryImpl.rs | 4 +- src/components/base/mod.rs | 2 + src/components/bluetooth/bluetoothBox.rs | 133 ++++++++++++++++++-- src/components/output/sinkBox.rs | 44 ++++++- src/components/output/sinkBoxImpl.rs | 6 + src/components/window/handleSidebarClick.rs | 10 +- src/resources/resetAudioOutput.ui | 84 +++++++++++++ src/resources/resetCardEntry.ui | 34 +++++ src/resources/resetCards.ui | 20 +++ src/resources/resetUI.cmb | 68 +++++++++- src/resources/resources.gresource.xml | 1 + 14 files changed, 514 insertions(+), 20 deletions(-) create mode 100644 src/components/base/cardEntry.rs create mode 100644 src/components/base/cardEntryImpl.rs create mode 100644 src/resources/resetCardEntry.ui create mode 100644 src/resources/resetCards.ui diff --git a/Cargo.toml b/Cargo.toml index e56a067..a51490f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ description = "A wip universal Linux settings application." [dependencies] reset_daemon = "0.1.8" -ReSet-Lib = "0.2.8" +ReSet-Lib = "0.3.4" adw = { version = "0.5.3", package = "libadwaita", features = ["v1_4"] } dbus = "0.9.7" gtk = { version = "0.7.3", package = "gtk4", features = ["v4_12"] } diff --git a/src/components/base/cardEntry.rs b/src/components/base/cardEntry.rs new file mode 100644 index 0000000..c3948a6 --- /dev/null +++ b/src/components/base/cardEntry.rs @@ -0,0 +1,74 @@ +use std::time::Duration; + +use adw::glib; +use adw::glib::Object; +use dbus::blocking::Connection; +use dbus::Error; +use glib::subclass::types::ObjectSubclassIsExt; +use glib::{clone, Cast}; +use gtk::{gio, StringObject}; +use ReSet_Lib::audio::audio::Card; + +use super::cardEntryImpl; + +glib::wrapper! { + pub struct CardEntry(ObjectSubclass) + @extends gtk::Box, gtk::Widget, + @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Orientable; +} + +impl CardEntry { + pub fn new(card: Card) -> Self { + let entry: Self = Object::builder().build(); + { + let imp = entry.imp(); + let mut map = imp.resetCardMap.borrow_mut(); + imp.resetCardName.set_text(&card.name); + let mut i: u32 = 0; + let mut index: u32 = 0; + for profile in card.profiles.iter() { + if profile.name == card.active_profile { + index = i; + } + imp.resetCardList.append(&profile.description); + map.insert( + profile.description.clone(), + (card.index, profile.name.clone()), + ); + i += 1; + } + imp.resetCardDropdown.set_selected(index); + imp.resetCardDropdown + .connect_selected_notify(clone!(@weak imp => move |dropdown| { + let selected = dropdown.selected_item(); + if selected.is_none() { + return; + } + let selected = selected.unwrap(); + let selected = selected.downcast_ref::().unwrap(); + let selected = selected.string().to_string(); + let map = imp.resetCardMap.borrow(); + let (device_index, profile_name) = map.get(&selected).unwrap(); + set_card_profile_of_device(*device_index, profile_name.clone()); + })); + } + entry + } +} + +fn set_card_profile_of_device(device_index: u32, profile_name: String) -> bool { + gio::spawn_blocking(move || { + let conn = Connection::new_session().unwrap(); + let proxy = conn.with_proxy( + "org.xetibo.ReSet", + "/org/xetibo/ReSet", + Duration::from_millis(1000), + ); + let _: Result<(), Error> = proxy.method_call( + "org.xetibo.ReSet", + "SetCardProfileOfDevice", + (device_index, profile_name), + ); + }); + true +} diff --git a/src/components/base/cardEntryImpl.rs b/src/components/base/cardEntryImpl.rs new file mode 100644 index 0000000..673d20a --- /dev/null +++ b/src/components/base/cardEntryImpl.rs @@ -0,0 +1,52 @@ +use std::cell::RefCell; +use std::collections::HashMap; + +use crate::components::base::listEntry::ListEntry; +use gtk::subclass::prelude::*; +use gtk::{glib, CompositeTemplate, TemplateChild, Label, DropDown, StringList}; + +use super::cardEntry; + +#[allow(non_snake_case)] +#[derive(Default, CompositeTemplate)] +#[template(resource = "/org/Xetibo/ReSet/resetCardEntry.ui")] +pub struct CardEntry { + #[template_child] + pub resetCardName: TemplateChild