mirror of
https://github.com/Xetibo/ReSet.git
synced 2025-04-19 02:58:33 +02:00
feat: Add default Sink and Source Switching
This commit is contained in:
parent
dbcf2ab635
commit
c619284146
|
@ -72,7 +72,11 @@ pub fn populate_sources(output_box: Arc<SourceBox>) {
|
||||||
output_box_imp.resetVolumePercentage.set_text(&percentage);
|
output_box_imp.resetVolumePercentage.set_text(&percentage);
|
||||||
output_box_imp.resetVolumeSlider.set_value(*volume as f64);
|
output_box_imp.resetVolumeSlider.set_value(*volume as f64);
|
||||||
for stream in sinks {
|
for stream in sinks {
|
||||||
let entry = ListEntry::new(&SourceEntry::new(stream));
|
let mut is_default = false;
|
||||||
|
if output_box_imp.resetDefaultSource.borrow().name == stream.name {
|
||||||
|
is_default = true;
|
||||||
|
}
|
||||||
|
let entry = ListEntry::new(&SourceEntry::new(is_default, output_box_imp.resetDefaultCheckButton.clone(), stream));
|
||||||
entry.set_activatable(false);
|
entry.set_activatable(false);
|
||||||
output_box_imp.resetSources.append(&entry);
|
output_box_imp.resetSources.append(&entry);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::sync::{Arc, Mutex};
|
||||||
use crate::components::base::listEntry::ListEntry;
|
use crate::components::base::listEntry::ListEntry;
|
||||||
use crate::components::input::sourceBox;
|
use crate::components::input::sourceBox;
|
||||||
use gtk::subclass::prelude::*;
|
use gtk::subclass::prelude::*;
|
||||||
use gtk::{glib, CompositeTemplate, DropDown, TemplateChild};
|
use gtk::{glib, CompositeTemplate, DropDown, TemplateChild, CheckButton};
|
||||||
use gtk::{prelude::*, Button, Label, ProgressBar, Scale};
|
use gtk::{prelude::*, Button, Label, ProgressBar, Scale};
|
||||||
use ReSet_Lib::audio::audio::{OutputStream, Source};
|
use ReSet_Lib::audio::audio::{OutputStream, Source};
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ pub struct SourceBox {
|
||||||
pub resetOutputStreamButton: TemplateChild<ListEntry>,
|
pub resetOutputStreamButton: TemplateChild<ListEntry>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub resetOutputStreams: TemplateChild<gtk::Box>,
|
pub resetOutputStreams: TemplateChild<gtk::Box>,
|
||||||
|
pub resetDefaultCheckButton: Arc<CheckButton>,
|
||||||
pub resetDefaultSource: Arc<RefCell<Source>>,
|
pub resetDefaultSource: Arc<RefCell<Source>>,
|
||||||
pub resetSourceList: Arc<Mutex<Vec<Source>>>,
|
pub resetSourceList: Arc<Mutex<Vec<Source>>>,
|
||||||
pub resetOutputStreamList: Arc<Mutex<Vec<OutputStream>>>,
|
pub resetOutputStreamList: Arc<Mutex<Vec<OutputStream>>>,
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use adw::glib;
|
use adw::glib;
|
||||||
use adw::glib::Object;
|
use adw::glib::Object;
|
||||||
use adw::prelude::{ButtonExt, RangeExt};
|
use adw::prelude::{ButtonExt, RangeExt, CheckButtonExt};
|
||||||
use dbus::blocking::Connection;
|
use dbus::blocking::Connection;
|
||||||
use dbus::Error;
|
use dbus::Error;
|
||||||
use glib::subclass::types::ObjectSubclassIsExt;
|
use glib::subclass::types::ObjectSubclassIsExt;
|
||||||
use glib::{clone, Propagation};
|
use glib::{clone, Propagation};
|
||||||
use ReSet_Lib::audio::audio::Source;
|
use ReSet_Lib::audio::audio::Source;
|
||||||
|
use gtk::CheckButton;
|
||||||
|
|
||||||
use super::sourceEntryImpl;
|
use super::sourceEntryImpl;
|
||||||
|
|
||||||
|
@ -20,7 +22,7 @@ glib::wrapper! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SourceEntry {
|
impl SourceEntry {
|
||||||
pub fn new(stream: Source) -> Self {
|
pub fn new(is_default: bool, check_group: Arc<CheckButton>, stream: Source) -> Self {
|
||||||
let obj: Self = Object::builder().build();
|
let obj: Self = Object::builder().build();
|
||||||
// TODO use event callback for progress bar -> this is the "im speaking" indicator
|
// TODO use event callback for progress bar -> this is the "im speaking" indicator
|
||||||
// TODO map the slider to volume
|
// TODO map the slider to volume
|
||||||
|
@ -30,6 +32,7 @@ impl SourceEntry {
|
||||||
{
|
{
|
||||||
let imp = obj.imp();
|
let imp = obj.imp();
|
||||||
imp.resetSourceName.set_text(stream.name.clone().as_str());
|
imp.resetSourceName.set_text(stream.name.clone().as_str());
|
||||||
|
let name = Arc::new(stream.name.clone());
|
||||||
let volume = stream.volume.first().unwrap_or_else(|| &(0 as u32));
|
let volume = stream.volume.first().unwrap_or_else(|| &(0 as u32));
|
||||||
let fraction = (*volume as f64 / 655.36).round();
|
let fraction = (*volume as f64 / 655.36).round();
|
||||||
let percentage = (fraction).to_string() + "%";
|
let percentage = (fraction).to_string() + "%";
|
||||||
|
@ -49,6 +52,18 @@ impl SourceEntry {
|
||||||
Propagation::Proceed
|
Propagation::Proceed
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
imp.resetSelectedSource.set_group(Some(&*check_group));
|
||||||
|
// check_group.set_group(Some(&*imp.resetSelectedSink));
|
||||||
|
if is_default {
|
||||||
|
imp.resetSelectedSource.set_active(true);
|
||||||
|
} else {
|
||||||
|
imp.resetSelectedSource.set_active(false);
|
||||||
|
}
|
||||||
|
imp.resetSelectedSource.connect_toggled(move |button| {
|
||||||
|
if button.is_active() {
|
||||||
|
set_default_source(name.clone());
|
||||||
|
}
|
||||||
|
});
|
||||||
imp.resetSourceMute
|
imp.resetSourceMute
|
||||||
.connect_clicked(clone!(@weak imp => move |_| {
|
.connect_clicked(clone!(@weak imp => move |_| {
|
||||||
let stream = imp.stream.clone();
|
let stream = imp.stream.clone();
|
||||||
|
@ -102,3 +117,20 @@ pub fn toggle_source_mute(index: u32, muted: bool) -> bool {
|
||||||
}
|
}
|
||||||
res.unwrap().0
|
res.unwrap().0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_default_source(name: Arc<String>) {
|
||||||
|
thread::spawn(move || {
|
||||||
|
let conn = Connection::new_session().unwrap();
|
||||||
|
let proxy = conn.with_proxy(
|
||||||
|
"org.xetibo.ReSet",
|
||||||
|
"/org/xetibo/ReSet",
|
||||||
|
Duration::from_millis(1000),
|
||||||
|
);
|
||||||
|
let res: Result<(bool,), Error> =
|
||||||
|
proxy.method_call("org.xetibo.ReSet", "SetDefaultSink", (name.as_str(),));
|
||||||
|
if res.is_err() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// handle change
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -73,7 +73,11 @@ pub fn populate_sinks(output_box: Arc<SinkBox>) {
|
||||||
output_box_imp.resetVolumeSlider.set_value(*volume as f64);
|
output_box_imp.resetVolumeSlider.set_value(*volume as f64);
|
||||||
for stream in sinks {
|
for stream in sinks {
|
||||||
// TODO create sink handler -> currently only allows input streams
|
// TODO create sink handler -> currently only allows input streams
|
||||||
let entry = ListEntry::new(&SinkEntry::new(stream));
|
let mut is_default = false;
|
||||||
|
if output_box_imp.resetDefaultSink.borrow().name == stream.name {
|
||||||
|
is_default = true;
|
||||||
|
}
|
||||||
|
let entry = ListEntry::new(&SinkEntry::new(is_default, output_box_imp.resetDefaultCheckButton.clone(), stream));
|
||||||
entry.set_activatable(false);
|
entry.set_activatable(false);
|
||||||
output_box_imp.resetSinks.append(&entry);
|
output_box_imp.resetSinks.append(&entry);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::sync::{Arc, Mutex};
|
||||||
use crate::components::base::listEntry::ListEntry;
|
use crate::components::base::listEntry::ListEntry;
|
||||||
use crate::components::output::inputStreamEntry::InputStreamEntry;
|
use crate::components::output::inputStreamEntry::InputStreamEntry;
|
||||||
use gtk::subclass::prelude::*;
|
use gtk::subclass::prelude::*;
|
||||||
use gtk::{glib, Box, Button, CompositeTemplate, DropDown, Label, TemplateChild};
|
use gtk::{glib, Box, Button, CompositeTemplate, DropDown, Label, TemplateChild, CheckButton};
|
||||||
use gtk::{prelude::*, ProgressBar, Scale};
|
use gtk::{prelude::*, ProgressBar, Scale};
|
||||||
use ReSet_Lib::audio::audio::{InputStream, Sink};
|
use ReSet_Lib::audio::audio::{InputStream, Sink};
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ pub struct SinkBox {
|
||||||
pub resetInputStreamButton: TemplateChild<ListEntry>,
|
pub resetInputStreamButton: TemplateChild<ListEntry>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub resetInputStreams: TemplateChild<Box>,
|
pub resetInputStreams: TemplateChild<Box>,
|
||||||
|
pub resetDefaultCheckButton: Arc<CheckButton>,
|
||||||
pub resetDefaultSink: Arc<RefCell<Sink>>,
|
pub resetDefaultSink: Arc<RefCell<Sink>>,
|
||||||
pub resetSinkList: Arc<Mutex<Vec<Sink>>>,
|
pub resetSinkList: Arc<Mutex<Vec<Sink>>>,
|
||||||
pub resetInputStreamList: Arc<Mutex<Vec<InputStream>>>,
|
pub resetInputStreamList: Arc<Mutex<Vec<InputStream>>>,
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use adw::glib;
|
use adw::glib;
|
||||||
use adw::glib::Object;
|
use adw::glib::Object;
|
||||||
use adw::prelude::{ButtonExt, RangeExt};
|
use adw::prelude::{ButtonExt, CheckButtonExt, RangeExt};
|
||||||
use dbus::blocking::Connection;
|
use dbus::blocking::Connection;
|
||||||
use dbus::Error;
|
use dbus::Error;
|
||||||
use glib::subclass::types::ObjectSubclassIsExt;
|
use glib::subclass::types::ObjectSubclassIsExt;
|
||||||
use glib::{clone, Propagation};
|
use glib::{clone, Propagation};
|
||||||
|
use gtk::CheckButton;
|
||||||
use ReSet_Lib::audio::audio::Sink;
|
use ReSet_Lib::audio::audio::Sink;
|
||||||
|
|
||||||
use super::sinkEntryImpl;
|
use super::sinkEntryImpl;
|
||||||
|
@ -20,16 +21,14 @@ glib::wrapper! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SinkEntry {
|
impl SinkEntry {
|
||||||
pub fn new(stream: Sink) -> Self {
|
pub fn new(is_default: bool, check_group: Arc<CheckButton>, stream: Sink) -> Self {
|
||||||
let obj: Self = Object::builder().build();
|
let obj: Self = Object::builder().build();
|
||||||
// TODO use event callback for progress bar -> this is the "im speaking" indicator
|
// TODO use event callback for progress bar -> this is the "im speaking" indicator
|
||||||
// TODO map the slider to volume
|
|
||||||
// TODO properly use volume fraction
|
|
||||||
// TODO map mute to callback
|
|
||||||
// TODO map dropdown
|
// TODO map dropdown
|
||||||
{
|
{
|
||||||
let imp = obj.imp();
|
let imp = obj.imp();
|
||||||
imp.resetSinkName.set_text(stream.name.clone().as_str());
|
imp.resetSinkName.set_text(stream.name.clone().as_str());
|
||||||
|
let name = Arc::new(stream.name.clone());
|
||||||
let volume = stream.volume.first().unwrap_or_else(|| &(0 as u32));
|
let volume = stream.volume.first().unwrap_or_else(|| &(0 as u32));
|
||||||
let fraction = (*volume as f64 / 655.36).round();
|
let fraction = (*volume as f64 / 655.36).round();
|
||||||
let percentage = (fraction).to_string() + "%";
|
let percentage = (fraction).to_string() + "%";
|
||||||
|
@ -49,6 +48,18 @@ impl SinkEntry {
|
||||||
Propagation::Proceed
|
Propagation::Proceed
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
imp.resetSelectedSink.set_group(Some(&*check_group));
|
||||||
|
// check_group.set_group(Some(&*imp.resetSelectedSink));
|
||||||
|
if is_default {
|
||||||
|
imp.resetSelectedSink.set_active(true);
|
||||||
|
} else {
|
||||||
|
imp.resetSelectedSink.set_active(false);
|
||||||
|
}
|
||||||
|
imp.resetSelectedSink.connect_toggled(move |button| {
|
||||||
|
if button.is_active() {
|
||||||
|
set_default_sink(name.clone());
|
||||||
|
}
|
||||||
|
});
|
||||||
imp.resetSinkMute
|
imp.resetSinkMute
|
||||||
.connect_clicked(clone!(@weak imp => move |_| {
|
.connect_clicked(clone!(@weak imp => move |_| {
|
||||||
let stream = imp.stream.clone();
|
let stream = imp.stream.clone();
|
||||||
|
@ -102,3 +113,21 @@ pub fn toggle_sink_mute(index: u32, muted: bool) -> bool {
|
||||||
}
|
}
|
||||||
res.unwrap().0
|
res.unwrap().0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_default_sink(name: Arc<String>) {
|
||||||
|
thread::spawn(move || {
|
||||||
|
dbg!(name.clone());
|
||||||
|
let conn = Connection::new_session().unwrap();
|
||||||
|
let proxy = conn.with_proxy(
|
||||||
|
"org.xetibo.ReSet",
|
||||||
|
"/org/xetibo/ReSet",
|
||||||
|
Duration::from_millis(1000),
|
||||||
|
);
|
||||||
|
let res: Result<(bool,), Error> =
|
||||||
|
proxy.method_call("org.xetibo.ReSet", "SetDefaultSink", (name.as_str(),));
|
||||||
|
if res.is_err() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// handle change
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue