mirror of
https://github.com/Xetibo/ReSet.git
synced 2025-04-19 02:58:33 +02:00
commit
e0375b7b45
|
@ -1,4 +1,3 @@
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
@ -8,10 +7,12 @@ use adw::prelude::{ButtonExt, 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, Cast, Propagation};
|
||||||
|
use gtk::StringObject;
|
||||||
use ReSet_Lib::audio::audio::OutputStream;
|
use ReSet_Lib::audio::audio::OutputStream;
|
||||||
|
|
||||||
use super::outputStreamEntryImpl;
|
use super::outputStreamEntryImpl;
|
||||||
|
use super::sourceBox::SourceBox;
|
||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
pub struct OutputStreamEntry(ObjectSubclass<outputStreamEntryImpl::OutputStreamEntry>)
|
pub struct OutputStreamEntry(ObjectSubclass<outputStreamEntryImpl::OutputStreamEntry>)
|
||||||
|
@ -20,12 +21,13 @@ glib::wrapper! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutputStreamEntry {
|
impl OutputStreamEntry {
|
||||||
pub fn new(stream: OutputStream) -> Self {
|
pub fn new(source_box: Arc<SourceBox>, stream: OutputStream) -> 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 mute to callback
|
// TODO map mute to callback
|
||||||
// TODO map dropdown
|
// TODO map dropdown
|
||||||
{
|
{
|
||||||
|
let box_imp = source_box.imp();
|
||||||
let imp = obj.imp();
|
let imp = obj.imp();
|
||||||
let name = stream.application_name.clone() + ": " + stream.name.as_str();
|
let name = stream.application_name.clone() + ": " + stream.name.as_str();
|
||||||
imp.resetSourceName.set_text(name.as_str());
|
imp.resetSourceName.set_text(name.as_str());
|
||||||
|
@ -40,17 +42,75 @@ impl OutputStreamEntry {
|
||||||
let fraction = (value / 655.36).round();
|
let fraction = (value / 655.36).round();
|
||||||
let percentage = (fraction).to_string() + "%";
|
let percentage = (fraction).to_string() + "%";
|
||||||
imp.resetVolumePercentage.set_text(&percentage);
|
imp.resetVolumePercentage.set_text(&percentage);
|
||||||
let stream = imp.stream.borrow();
|
let mut stream = imp.stream.try_borrow();
|
||||||
|
while stream.is_err() {
|
||||||
|
stream = imp.stream.try_borrow();
|
||||||
|
}
|
||||||
|
let stream = stream.unwrap();
|
||||||
let index = stream.index;
|
let index = stream.index;
|
||||||
let channels = stream.channels;
|
let channels = stream.channels;
|
||||||
set_outputstream_volume(value, index, channels);
|
set_outputstream_volume(value, index, channels);
|
||||||
Propagation::Proceed
|
Propagation::Proceed
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
{
|
||||||
|
let mut list = box_imp.resetModelList.try_borrow();
|
||||||
|
while list.is_err() {
|
||||||
|
list = box_imp.resetModelList.try_borrow();
|
||||||
|
}
|
||||||
|
let list = list.unwrap();
|
||||||
|
imp.resetSelectedSource.set_model(Some(&*list));
|
||||||
|
let mut map = box_imp.resetSourceMap.try_borrow();
|
||||||
|
while map.is_err() {
|
||||||
|
map = box_imp.resetSourceMap.try_borrow();
|
||||||
|
}
|
||||||
|
let map = map.unwrap();
|
||||||
|
let mut name = box_imp.resetDefaultSource.try_borrow();
|
||||||
|
while name.is_err() {
|
||||||
|
name = box_imp.resetDefaultSource.try_borrow();
|
||||||
|
}
|
||||||
|
let name = name.unwrap();
|
||||||
|
let name = &name.alias;
|
||||||
|
let index = map.get(name);
|
||||||
|
if index.is_some() {
|
||||||
|
imp.resetSelectedSource.set_selected(index.unwrap().1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
imp.resetSelectedSource.connect_selected_notify(
|
||||||
|
clone!(@weak imp, @weak box_imp => move |dropdown| {
|
||||||
|
let selected = dropdown.selected_item();
|
||||||
|
if selected.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let selected = selected.unwrap();
|
||||||
|
let selected = selected.downcast_ref::<StringObject>().unwrap();
|
||||||
|
let selected = selected.string().to_string();
|
||||||
|
let mut source = box_imp.resetSourceMap.try_borrow();
|
||||||
|
while source.is_err() {
|
||||||
|
source = box_imp.resetSourceMap.try_borrow();
|
||||||
|
}
|
||||||
|
let source = source.unwrap();
|
||||||
|
let source = source.get(&selected);
|
||||||
|
if source.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut stream = imp.stream.try_borrow();
|
||||||
|
while stream.is_err() {
|
||||||
|
stream = imp.stream.try_borrow();
|
||||||
|
}
|
||||||
|
let stream = stream.unwrap();
|
||||||
|
let source = source.unwrap().0;
|
||||||
|
set_source_of_output_stream(stream.index, source);
|
||||||
|
}),
|
||||||
|
);
|
||||||
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();
|
||||||
let mut stream = stream.borrow_mut();
|
let mut stream = stream.try_borrow_mut();
|
||||||
|
while stream.is_err() {
|
||||||
|
stream = imp.stream.try_borrow_mut();
|
||||||
|
}
|
||||||
|
let mut stream = stream.unwrap();
|
||||||
stream.muted = !stream.muted;
|
stream.muted = !stream.muted;
|
||||||
let muted = stream.muted;
|
let muted = stream.muted;
|
||||||
let index = stream.index;
|
let index = stream.index;
|
||||||
|
@ -100,3 +160,21 @@ fn toggle_output_stream_mute(index: u32, muted: bool) -> bool {
|
||||||
}
|
}
|
||||||
res.unwrap().0
|
res.unwrap().0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_source_of_output_stream(stream: u32, source: u32) -> bool {
|
||||||
|
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",
|
||||||
|
"SetSourceOfOutputStream",
|
||||||
|
(stream, source),
|
||||||
|
);
|
||||||
|
if res.is_err() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
res.unwrap().0
|
||||||
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@ use std::cell::RefCell;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::components::input::outputStreamEntry;
|
use crate::components::input::outputStreamEntry;
|
||||||
use ReSet_Lib::audio::audio::OutputStream;
|
|
||||||
use gtk::subclass::prelude::*;
|
use gtk::subclass::prelude::*;
|
||||||
use gtk::{glib, Button, CompositeTemplate, Label, ProgressBar, Scale, DropDown};
|
use gtk::{glib, Button, CompositeTemplate, DropDown, Label, ProgressBar, Scale};
|
||||||
|
use ReSet_Lib::audio::audio::OutputStream;
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Default, CompositeTemplate)]
|
#[derive(Default, CompositeTemplate)]
|
||||||
|
@ -23,6 +23,7 @@ pub struct OutputStreamEntry {
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub resetVolumeMeter: TemplateChild<ProgressBar>,
|
pub resetVolumeMeter: TemplateChild<ProgressBar>,
|
||||||
pub stream: Arc<RefCell<OutputStream>>,
|
pub stream: Arc<RefCell<OutputStream>>,
|
||||||
|
pub associatedSource: Arc<RefCell<(u32, String)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
@ -45,4 +46,3 @@ impl BoxImpl for OutputStreamEntry {}
|
||||||
impl ObjectImpl for OutputStreamEntry {}
|
impl ObjectImpl for OutputStreamEntry {}
|
||||||
|
|
||||||
impl WidgetImpl for OutputStreamEntry {}
|
impl WidgetImpl for OutputStreamEntry {}
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,13 @@ use adw::prelude::{BoxExt, ButtonExt, ListBoxRowExt, RangeExt};
|
||||||
use dbus::blocking::Connection;
|
use dbus::blocking::Connection;
|
||||||
use dbus::Error;
|
use dbus::Error;
|
||||||
use glib::subclass::prelude::ObjectSubclassIsExt;
|
use glib::subclass::prelude::ObjectSubclassIsExt;
|
||||||
use glib::{Propagation, Variant};
|
use glib::{clone, Cast, Propagation, Variant};
|
||||||
use gtk::gio;
|
|
||||||
use gtk::prelude::ActionableExt;
|
use gtk::prelude::ActionableExt;
|
||||||
|
use gtk::{gio, StringObject};
|
||||||
use ReSet_Lib::audio::audio::{OutputStream, Source};
|
use ReSet_Lib::audio::audio::{OutputStream, Source};
|
||||||
|
|
||||||
use super::outputStreamEntry::OutputStreamEntry;
|
use super::outputStreamEntry::OutputStreamEntry;
|
||||||
use super::sourceEntry::{toggle_source_mute, SourceEntry};
|
use super::sourceEntry::{set_default_source, toggle_source_mute, SourceEntry};
|
||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
pub struct SourceBox(ObjectSubclass<sourceBoxImpl::SourceBox>)
|
pub struct SourceBox(ObjectSubclass<sourceBoxImpl::SourceBox>)
|
||||||
|
@ -51,13 +51,23 @@ impl SourceBox {
|
||||||
pub fn populate_sources(output_box: Arc<SourceBox>) {
|
pub fn populate_sources(output_box: Arc<SourceBox>) {
|
||||||
gio::spawn_blocking(move || {
|
gio::spawn_blocking(move || {
|
||||||
let output_box_imp = output_box.imp();
|
let output_box_imp = output_box.imp();
|
||||||
let sinks = get_sources();
|
let sources = get_sources();
|
||||||
|
{
|
||||||
|
let list = output_box_imp.resetModelList.borrow_mut();
|
||||||
|
let mut map = output_box_imp.resetSourceMap.borrow_mut();
|
||||||
|
let mut i: u32 = 0;
|
||||||
|
for source in sources.iter() {
|
||||||
|
list.append(&source.alias);
|
||||||
|
map.insert(source.alias.clone(), (source.index, i, source.name.clone()));
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
output_box_imp
|
output_box_imp
|
||||||
.resetDefaultSource
|
.resetDefaultSource
|
||||||
.replace(get_default_source());
|
.replace(get_default_source());
|
||||||
glib::spawn_future(async move {
|
glib::spawn_future(async move {
|
||||||
glib::idle_add_once(move || {
|
glib::idle_add_once(move || {
|
||||||
// TODO handle default mapping
|
// TODO handle events
|
||||||
let output_box_ref_slider = output_box.clone();
|
let output_box_ref_slider = output_box.clone();
|
||||||
let output_box_ref_mute = output_box.clone();
|
let output_box_ref_mute = output_box.clone();
|
||||||
let output_box_ref = output_box.clone();
|
let output_box_ref = output_box.clone();
|
||||||
|
@ -71,15 +81,49 @@ pub fn populate_sources(output_box: Arc<SourceBox>) {
|
||||||
let percentage = (fraction).to_string() + "%";
|
let percentage = (fraction).to_string() + "%";
|
||||||
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 sources {
|
||||||
let mut is_default = false;
|
let mut is_default = false;
|
||||||
if output_box_imp.resetDefaultSource.borrow().name == stream.name {
|
if output_box_imp.resetDefaultSource.borrow().name == stream.name {
|
||||||
is_default = true;
|
is_default = true;
|
||||||
}
|
}
|
||||||
let entry = ListEntry::new(&SourceEntry::new(is_default, output_box_imp.resetDefaultCheckButton.clone(), stream));
|
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);
|
||||||
}
|
}
|
||||||
|
let list = output_box_imp.resetModelList.borrow();
|
||||||
|
output_box_imp.resetSourceDropdown.set_model(Some(&*list));
|
||||||
|
let map = output_box_imp.resetSourceMap.borrow();
|
||||||
|
let name = output_box_imp.resetDefaultSource.borrow();
|
||||||
|
let name = &name.alias;
|
||||||
|
let index = map.get(name);
|
||||||
|
if index.is_some() {
|
||||||
|
output_box_imp
|
||||||
|
.resetSourceDropdown
|
||||||
|
.set_selected(index.unwrap().1);
|
||||||
|
}
|
||||||
|
output_box_imp.resetSourceDropdown.connect_selected_notify(
|
||||||
|
clone!(@weak output_box_imp => move |dropdown| {
|
||||||
|
let selected = dropdown.selected_item();
|
||||||
|
if selected.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let selected = selected.unwrap();
|
||||||
|
let selected = selected.downcast_ref::<StringObject>().unwrap();
|
||||||
|
let selected = selected.string().to_string();
|
||||||
|
|
||||||
|
let source = output_box_imp.resetSourceMap.borrow();
|
||||||
|
let source = source.get(&selected);
|
||||||
|
if source.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let sink = Arc::new(source.unwrap().2.clone());
|
||||||
|
set_default_source(sink);
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
output_box_ref
|
output_box_ref
|
||||||
.imp()
|
.imp()
|
||||||
|
@ -121,7 +165,7 @@ pub fn populate_sources(output_box: Arc<SourceBox>) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn populate_outputstreams(listeners: Arc<Listeners>, output_box: Arc<SourceBox>) {
|
pub fn populate_outputstreams(_listeners: Arc<Listeners>, output_box: Arc<SourceBox>) {
|
||||||
// TODO add listener
|
// TODO add listener
|
||||||
let output_box_ref = output_box.clone();
|
let output_box_ref = output_box.clone();
|
||||||
|
|
||||||
|
@ -131,7 +175,7 @@ pub fn populate_outputstreams(listeners: Arc<Listeners>, output_box: Arc<SourceB
|
||||||
glib::idle_add_once(move || {
|
glib::idle_add_once(move || {
|
||||||
let output_box_imp = output_box_ref.imp();
|
let output_box_imp = output_box_ref.imp();
|
||||||
for stream in streams {
|
for stream in streams {
|
||||||
let entry = ListEntry::new(&OutputStreamEntry::new(stream));
|
let entry = ListEntry::new(&OutputStreamEntry::new(output_box.clone(), stream));
|
||||||
entry.set_activatable(false);
|
entry.set_activatable(false);
|
||||||
output_box_imp.resetOutputStreams.append(&entry);
|
output_box_imp.resetOutputStreams.append(&entry);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, Mutex};
|
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, CheckButton};
|
use gtk::{glib, CheckButton, CompositeTemplate, DropDown, StringList, TemplateChild};
|
||||||
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};
|
||||||
|
|
||||||
|
@ -37,6 +38,9 @@ pub struct SourceBox {
|
||||||
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>>>,
|
||||||
|
pub resetModelList: Arc<RefCell<StringList>>,
|
||||||
|
// first u32 is the index of the source, the second the index in the model list
|
||||||
|
pub resetSourceMap: Arc<RefCell<HashMap<String, (u32, u32, String)>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -25,13 +24,10 @@ impl SourceEntry {
|
||||||
pub fn new(is_default: bool, check_group: Arc<CheckButton>, 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 handle events
|
||||||
// TODO properly use volume fraction
|
|
||||||
// TODO map mute to callback
|
|
||||||
// TODO map dropdown
|
|
||||||
{
|
{
|
||||||
let imp = obj.imp();
|
let imp = obj.imp();
|
||||||
imp.resetSourceName.set_text(stream.name.clone().as_str());
|
imp.resetSourceName.set_text(stream.alias.clone().as_str());
|
||||||
let name = Arc::new(stream.name.clone());
|
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();
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
@ -8,11 +7,12 @@ use adw::prelude::{ButtonExt, 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::subclass::ObjectImplRef;
|
use glib::{clone, Cast, Propagation};
|
||||||
use glib::{clone, Propagation};
|
use gtk::StringObject;
|
||||||
use ReSet_Lib::audio::audio::InputStream;
|
use ReSet_Lib::audio::audio::InputStream;
|
||||||
|
|
||||||
use super::inputStreamEntryImpl;
|
use super::inputStreamEntryImpl;
|
||||||
|
use super::sinkBox::SinkBox;
|
||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
pub struct InputStreamEntry(ObjectSubclass<inputStreamEntryImpl::InputStreamEntry>)
|
pub struct InputStreamEntry(ObjectSubclass<inputStreamEntryImpl::InputStreamEntry>)
|
||||||
|
@ -21,11 +21,12 @@ glib::wrapper! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputStreamEntry {
|
impl InputStreamEntry {
|
||||||
pub fn new(stream: InputStream) -> Self {
|
pub fn new(sink_box: Arc<SinkBox>, stream: InputStream) -> 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 dropdown
|
// TODO handle events
|
||||||
{
|
{
|
||||||
|
let box_imp = sink_box.imp();
|
||||||
let imp = obj.imp();
|
let imp = obj.imp();
|
||||||
if stream.muted {
|
if stream.muted {
|
||||||
imp.resetSinkMute
|
imp.resetSinkMute
|
||||||
|
@ -42,22 +43,84 @@ impl InputStreamEntry {
|
||||||
imp.resetVolumePercentage.set_text(&percentage);
|
imp.resetVolumePercentage.set_text(&percentage);
|
||||||
imp.resetVolumeSlider.set_value(*volume as f64);
|
imp.resetVolumeSlider.set_value(*volume as f64);
|
||||||
imp.stream.replace(stream);
|
imp.stream.replace(stream);
|
||||||
|
{
|
||||||
|
let sink = box_imp.resetDefaultSink.borrow();
|
||||||
|
imp.associatedSink.replace((sink.index, sink.name.clone()));
|
||||||
|
}
|
||||||
imp.resetVolumeSlider.connect_change_value(
|
imp.resetVolumeSlider.connect_change_value(
|
||||||
clone!(@weak imp => @default-return Propagation::Stop, move |_, _, value| {
|
clone!(@weak imp => @default-return Propagation::Stop, move |_, _, value| {
|
||||||
let fraction = (value / 655.36).round();
|
let fraction = (value / 655.36).round();
|
||||||
let percentage = (fraction).to_string() + "%";
|
let percentage = (fraction).to_string() + "%";
|
||||||
imp.resetVolumePercentage.set_text(&percentage);
|
imp.resetVolumePercentage.set_text(&percentage);
|
||||||
let stream = imp.stream.borrow();
|
let mut stream = imp.stream.try_borrow();
|
||||||
|
while stream.is_err() {
|
||||||
|
stream = imp.stream.try_borrow();
|
||||||
|
}
|
||||||
|
let stream = stream.unwrap();
|
||||||
let index = stream.index;
|
let index = stream.index;
|
||||||
let channels = stream.channels;
|
let channels = stream.channels;
|
||||||
set_inputstream_volume(value, index, channels);
|
set_inputstream_volume(value, index, channels);
|
||||||
Propagation::Proceed
|
Propagation::Proceed
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
{
|
||||||
|
let mut list = box_imp.resetModelList.try_borrow();
|
||||||
|
while list.is_err() {
|
||||||
|
list = box_imp.resetModelList.try_borrow();
|
||||||
|
}
|
||||||
|
let list = list.unwrap();
|
||||||
|
imp.resetSelectedSink.set_model(Some(&*list));
|
||||||
|
let mut map = box_imp.resetSinkMap.try_borrow();
|
||||||
|
while map.is_err() {
|
||||||
|
map = box_imp.resetSinkMap.try_borrow();
|
||||||
|
}
|
||||||
|
let map = map.unwrap();
|
||||||
|
let mut name = box_imp.resetDefaultSink.try_borrow();
|
||||||
|
while name.is_err() {
|
||||||
|
name = box_imp.resetDefaultSink.try_borrow();
|
||||||
|
}
|
||||||
|
let name = name.unwrap();
|
||||||
|
let name = &name.alias;
|
||||||
|
let index = map.get(name);
|
||||||
|
if index.is_some() {
|
||||||
|
imp.resetSelectedSink.set_selected(index.unwrap().1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
imp.resetSelectedSink.connect_selected_notify(
|
||||||
|
clone!(@weak imp, @weak box_imp => move |dropdown| {
|
||||||
|
let selected = dropdown.selected_item();
|
||||||
|
if selected.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let selected = selected.unwrap();
|
||||||
|
let selected = selected.downcast_ref::<StringObject>().unwrap();
|
||||||
|
let selected = selected.string().to_string();
|
||||||
|
let mut sink = box_imp.resetSinkMap.try_borrow();
|
||||||
|
while sink.is_err() {
|
||||||
|
sink = box_imp.resetSinkMap.try_borrow();
|
||||||
|
}
|
||||||
|
let sink = sink.unwrap();
|
||||||
|
let sink = sink.get(&selected);
|
||||||
|
if sink.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut stream = imp.stream.try_borrow();
|
||||||
|
while stream.is_err() {
|
||||||
|
stream = imp.stream.try_borrow();
|
||||||
|
}
|
||||||
|
let stream = stream.unwrap();
|
||||||
|
let sink = sink.unwrap().0;
|
||||||
|
set_sink_of_input_stream(stream.index, sink);
|
||||||
|
}),
|
||||||
|
);
|
||||||
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();
|
||||||
let mut stream = stream.borrow_mut();
|
let mut stream = stream.try_borrow_mut();
|
||||||
|
while stream.is_err() {
|
||||||
|
stream = imp.stream.try_borrow_mut();
|
||||||
|
}
|
||||||
|
let mut stream = stream.unwrap();
|
||||||
stream.muted = !stream.muted;
|
stream.muted = !stream.muted;
|
||||||
let muted = stream.muted;
|
let muted = stream.muted;
|
||||||
let index = stream.index;
|
let index = stream.index;
|
||||||
|
@ -107,3 +170,18 @@ fn toggle_input_stream_mute(index: u32, muted: bool) -> bool {
|
||||||
}
|
}
|
||||||
res.unwrap().0
|
res.unwrap().0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_sink_of_input_stream(stream: u32, sink: u32) -> bool {
|
||||||
|
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", "SetSinkOfInputStream", (stream, sink));
|
||||||
|
if res.is_err() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
res.unwrap().0
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ pub struct InputStreamEntry {
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub resetVolumeMeter: TemplateChild<ProgressBar>,
|
pub resetVolumeMeter: TemplateChild<ProgressBar>,
|
||||||
pub stream: Arc<RefCell<InputStream>>,
|
pub stream: Arc<RefCell<InputStream>>,
|
||||||
|
pub associatedSink: Arc<RefCell<(u32, String)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
|
|
@ -10,14 +10,14 @@ use adw::{glib, prelude::ListBoxRowExt};
|
||||||
use dbus::blocking::Connection;
|
use dbus::blocking::Connection;
|
||||||
use dbus::Error;
|
use dbus::Error;
|
||||||
use glib::subclass::prelude::ObjectSubclassIsExt;
|
use glib::subclass::prelude::ObjectSubclassIsExt;
|
||||||
use glib::{clone, Propagation, Variant};
|
use glib::{clone, Cast, Propagation, Variant};
|
||||||
use gtk::gio;
|
|
||||||
use gtk::prelude::ActionableExt;
|
use gtk::prelude::ActionableExt;
|
||||||
|
use gtk::{gio, StringObject};
|
||||||
use ReSet_Lib::audio::audio::{InputStream, Sink};
|
use ReSet_Lib::audio::audio::{InputStream, Sink};
|
||||||
|
|
||||||
use super::inputStreamEntry::InputStreamEntry;
|
use super::inputStreamEntry::InputStreamEntry;
|
||||||
use super::sinkBoxImpl;
|
use super::sinkBoxImpl;
|
||||||
use super::sinkEntry::{toggle_sink_mute, SinkEntry};
|
use super::sinkEntry::{set_default_sink, toggle_sink_mute, SinkEntry};
|
||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
pub struct SinkBox(ObjectSubclass<sinkBoxImpl::SinkBox>)
|
pub struct SinkBox(ObjectSubclass<sinkBoxImpl::SinkBox>)
|
||||||
|
@ -51,20 +51,28 @@ impl SinkBox {
|
||||||
pub fn populate_sinks(output_box: Arc<SinkBox>) {
|
pub fn populate_sinks(output_box: Arc<SinkBox>) {
|
||||||
gio::spawn_blocking(move || {
|
gio::spawn_blocking(move || {
|
||||||
let output_box_ref = output_box.clone();
|
let output_box_ref = output_box.clone();
|
||||||
|
let sinks = get_sinks();
|
||||||
{
|
{
|
||||||
let output_box_imp = output_box.imp();
|
let output_box_imp = output_box.imp();
|
||||||
output_box_imp.resetDefaultSink.replace(get_default_sink());
|
output_box_imp.resetDefaultSink.replace(get_default_sink());
|
||||||
|
let list = output_box_imp.resetModelList.borrow_mut();
|
||||||
|
let mut map = output_box_imp.resetSinkMap.borrow_mut();
|
||||||
|
let mut i: u32 = 0;
|
||||||
|
for sink in sinks.iter() {
|
||||||
|
dbg!(sink.clone());
|
||||||
|
list.append(&sink.alias);
|
||||||
|
map.insert(sink.alias.clone(), (sink.index, i, sink.name.clone()));
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let sinks = get_sinks();
|
|
||||||
glib::spawn_future(async move {
|
glib::spawn_future(async move {
|
||||||
glib::idle_add_once(move || {
|
glib::idle_add_once(move || {
|
||||||
// TODO handle default mapping
|
|
||||||
let output_box_ref_slider = output_box.clone();
|
let output_box_ref_slider = output_box.clone();
|
||||||
let output_box_ref_mute = output_box.clone();
|
let output_box_ref_mute = output_box.clone();
|
||||||
{
|
{
|
||||||
let output_box_imp = output_box_ref.imp();
|
let output_box_imp = output_box_ref.imp();
|
||||||
let default_sink = output_box_imp.resetDefaultSink.clone(); // Clone outside closure
|
let default_sink = output_box_imp.resetDefaultSink.clone();
|
||||||
let sink = default_sink.borrow(); //
|
let sink = default_sink.borrow();
|
||||||
|
|
||||||
let volume = sink.volume.first().unwrap_or_else(|| &(0 as u32));
|
let volume = sink.volume.first().unwrap_or_else(|| &(0 as u32));
|
||||||
let fraction = (*volume as f64 / 655.36).round();
|
let fraction = (*volume as f64 / 655.36).round();
|
||||||
|
@ -72,15 +80,48 @@ pub fn populate_sinks(output_box: Arc<SinkBox>) {
|
||||||
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 {
|
||||||
// TODO create sink handler -> currently only allows input streams
|
|
||||||
let mut is_default = false;
|
let mut is_default = false;
|
||||||
if output_box_imp.resetDefaultSink.borrow().name == stream.name {
|
if output_box_imp.resetDefaultSink.borrow().name == stream.name {
|
||||||
is_default = true;
|
is_default = true;
|
||||||
}
|
}
|
||||||
let entry = ListEntry::new(&SinkEntry::new(is_default, output_box_imp.resetDefaultCheckButton.clone(), stream));
|
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);
|
||||||
}
|
}
|
||||||
|
let list = output_box_imp.resetModelList.borrow();
|
||||||
|
output_box_imp.resetSinkDropdown.set_model(Some(&*list));
|
||||||
|
let map = output_box_imp.resetSinkMap.borrow();
|
||||||
|
let name = output_box_imp.resetDefaultSink.borrow();
|
||||||
|
let name = &name.alias;
|
||||||
|
let index = map.get(name);
|
||||||
|
if index.is_some() {
|
||||||
|
output_box_imp
|
||||||
|
.resetSinkDropdown
|
||||||
|
.set_selected(index.unwrap().1);
|
||||||
|
}
|
||||||
|
output_box_imp.resetSinkDropdown.connect_selected_notify(
|
||||||
|
clone!(@weak output_box_imp => move |dropdown| {
|
||||||
|
let selected = dropdown.selected_item();
|
||||||
|
if selected.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let selected = selected.unwrap();
|
||||||
|
let selected = selected.downcast_ref::<StringObject>().unwrap();
|
||||||
|
let selected = selected.string().to_string();
|
||||||
|
|
||||||
|
let sink = output_box_imp.resetSinkMap.borrow();
|
||||||
|
let sink = sink.get(&selected);
|
||||||
|
if sink.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let sink = Arc::new(sink.unwrap().2.clone());
|
||||||
|
set_default_sink(sink);
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
output_box_ref
|
output_box_ref
|
||||||
.imp()
|
.imp()
|
||||||
|
@ -121,13 +162,9 @@ pub fn populate_sinks(output_box: Arc<SinkBox>) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn populate_inputstreams(listeners: Arc<Listeners>, output_box: Arc<SinkBox>) {
|
pub fn populate_inputstreams(_listeners: Arc<Listeners>, output_box: Arc<SinkBox>) {
|
||||||
// TODO add listener
|
// TODO add listener
|
||||||
let output_box_ref = output_box.clone();
|
let output_box_ref = output_box.clone();
|
||||||
// let output_box_ref_listener = output_box.clone();
|
|
||||||
let output_box_imp = output_box.imp();
|
|
||||||
// let sources = output_box_imp.resetSinks.clone();
|
|
||||||
// let output_streams = output_box_imp.resetInputStreams.clone();
|
|
||||||
|
|
||||||
gio::spawn_blocking(move || {
|
gio::spawn_blocking(move || {
|
||||||
let streams = get_input_streams();
|
let streams = get_input_streams();
|
||||||
|
@ -135,7 +172,7 @@ pub fn populate_inputstreams(listeners: Arc<Listeners>, output_box: Arc<SinkBox>
|
||||||
glib::idle_add_once(move || {
|
glib::idle_add_once(move || {
|
||||||
let output_box_imp = output_box_ref.imp();
|
let output_box_imp = output_box_ref.imp();
|
||||||
for stream in streams {
|
for stream in streams {
|
||||||
let entry = ListEntry::new(&InputStreamEntry::new(stream));
|
let entry = ListEntry::new(&InputStreamEntry::new(output_box.clone(), stream));
|
||||||
entry.set_activatable(false);
|
entry.set_activatable(false);
|
||||||
output_box_imp.resetInputStreams.append(&entry);
|
output_box_imp.resetInputStreams.append(&entry);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, Mutex};
|
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, CheckButton};
|
use gtk::{
|
||||||
|
glib, Box, Button, CheckButton, CompositeTemplate, DropDown, Label, StringList, TemplateChild,
|
||||||
|
};
|
||||||
use gtk::{prelude::*, ProgressBar, Scale};
|
use gtk::{prelude::*, ProgressBar, Scale};
|
||||||
use ReSet_Lib::audio::audio::{InputStream, Sink};
|
use ReSet_Lib::audio::audio::{InputStream, Sink};
|
||||||
|
|
||||||
|
@ -18,7 +21,7 @@ pub struct SinkBox {
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub resetSinksRow: TemplateChild<ListEntry>,
|
pub resetSinksRow: TemplateChild<ListEntry>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub resetInputDevice: TemplateChild<DropDown>,
|
pub resetSinkDropdown: TemplateChild<DropDown>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub resetSinkMute: TemplateChild<Button>,
|
pub resetSinkMute: TemplateChild<Button>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
|
@ -37,6 +40,9 @@ pub struct SinkBox {
|
||||||
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>>>,
|
||||||
|
pub resetModelList: Arc<RefCell<StringList>>,
|
||||||
|
// first u32 is the index of the sink, the second the index in the model list
|
||||||
|
pub resetSinkMap: Arc<RefCell<HashMap<String, (u32, u32, String)>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
|
|
@ -24,10 +24,10 @@ impl SinkEntry {
|
||||||
pub fn new(is_default: bool, check_group: Arc<CheckButton>, 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 dropdown
|
// TODO handle events
|
||||||
{
|
{
|
||||||
let imp = obj.imp();
|
let imp = obj.imp();
|
||||||
imp.resetSinkName.set_text(stream.name.clone().as_str());
|
imp.resetSinkName.set_text(stream.alias.clone().as_str());
|
||||||
let name = Arc::new(stream.name.clone());
|
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();
|
||||||
|
@ -49,7 +49,6 @@ impl SinkEntry {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
imp.resetSelectedSink.set_group(Some(&*check_group));
|
imp.resetSelectedSink.set_group(Some(&*check_group));
|
||||||
// check_group.set_group(Some(&*imp.resetSelectedSink));
|
|
||||||
if is_default {
|
if is_default {
|
||||||
imp.resetSelectedSink.set_active(true);
|
imp.resetSelectedSink.set_active(true);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use crate::components::output::sinkEntry;
|
use crate::components::output::sinkEntry;
|
||||||
use gtk::subclass::prelude::*;
|
use gtk::subclass::prelude::*;
|
||||||
use gtk::{glib, Button, CompositeTemplate, DropDown, Label, ProgressBar, Scale, CheckButton};
|
use gtk::{glib, Button, CompositeTemplate, Label, ProgressBar, Scale, CheckButton};
|
||||||
use ReSet_Lib::audio::audio::Sink;
|
use ReSet_Lib::audio::audio::Sink;
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkDropDown" id="resetInputDevice">
|
<object class="GtkDropDown" id="resetSinkDropdown">
|
||||||
<property name="halign">end</property>
|
<property name="halign">end</property>
|
||||||
<property name="hexpand">True</property>
|
<property name="hexpand">True</property>
|
||||||
<property name="valign">center</property>
|
<property name="valign">center</property>
|
||||||
|
|
|
@ -114,7 +114,7 @@
|
||||||
(8,74,"resetListBoxRow","resetSinksRow",73,None,None,None,None,None),
|
(8,74,"resetListBoxRow","resetSinksRow",73,None,None,None,None,None),
|
||||||
(8,75,"GtkBox",None,74,None,None,None,None,None),
|
(8,75,"GtkBox",None,74,None,None,None,None,None),
|
||||||
(8,76,"GtkLabel",None,75,None,None,None,None,None),
|
(8,76,"GtkLabel",None,75,None,None,None,None,None),
|
||||||
(8,77,"GtkDropDown","resetInputDevice",75,None,None,None,1,None),
|
(8,77,"GtkDropDown","resetSinkDropdown",75,None,None,None,1,None),
|
||||||
(8,78,"GtkImage",None,75,None,None,None,2,None),
|
(8,78,"GtkImage",None,75,None,None,None,2,None),
|
||||||
(8,81,"GtkLabel",None,72,None,None,None,1,None),
|
(8,81,"GtkLabel",None,72,None,None,None,1,None),
|
||||||
(8,85,"GtkBox","resetInputStreams",56,None,None,None,4,None),
|
(8,85,"GtkBox","resetInputStreams",56,None,None,None,4,None),
|
||||||
|
|
Loading…
Reference in a new issue