Oops
This commit is contained in:
parent
3096347ae4
commit
a5bfb1e27d
@ -36,14 +36,19 @@ pub struct AlsaCard {
|
|||||||
|
|
||||||
|
|
||||||
impl AlsaCard {
|
impl AlsaCard {
|
||||||
pub fn new(
|
pub fn new(card_name: Option<String>,
|
||||||
card_name: Option<String>,
|
elem_name: Option<String>,
|
||||||
elem_name: Option<String>,
|
cb: Rc<Fn(AlsaEvent)>)
|
||||||
cb: Rc<Fn(AlsaEvent)>,
|
-> Result<Box<AlsaCard>> {
|
||||||
) -> Result<Box<AlsaCard>> {
|
|
||||||
let card = {
|
let card = {
|
||||||
match card_name {
|
match card_name {
|
||||||
Some(name) => get_alsa_card_by_name(name)?,
|
Some(name) => {
|
||||||
|
if name == "(default)" {
|
||||||
|
get_default_alsa_card()
|
||||||
|
} else {
|
||||||
|
get_alsa_card_by_name(name)?
|
||||||
|
}
|
||||||
|
},
|
||||||
None => get_default_alsa_card(),
|
None => get_default_alsa_card(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -51,26 +56,26 @@ impl AlsaCard {
|
|||||||
|
|
||||||
let vec_pollfd = PollDescriptors::get(&mixer)?;
|
let vec_pollfd = PollDescriptors::get(&mixer)?;
|
||||||
|
|
||||||
let selem_id = get_selem_by_name(
|
let selem_id =
|
||||||
&mixer,
|
get_selem_by_name(&mixer,
|
||||||
elem_name.unwrap_or(String::from("Master")),
|
elem_name.unwrap_or(String::from("Master")))
|
||||||
).unwrap()
|
.unwrap()
|
||||||
.get_id();
|
.get_id();
|
||||||
|
|
||||||
let acard = Box::new(AlsaCard {
|
let acard = Box::new(AlsaCard {
|
||||||
_cannot_construct: (),
|
_cannot_construct: (),
|
||||||
card: card,
|
card: card,
|
||||||
mixer: mixer,
|
mixer: mixer,
|
||||||
selem_id: selem_id,
|
selem_id: selem_id,
|
||||||
watch_ids: Cell::new(vec![]),
|
watch_ids: Cell::new(vec![]),
|
||||||
cb: cb,
|
cb: cb,
|
||||||
});
|
});
|
||||||
|
|
||||||
/* TODO: callback is registered here, which must be unregistered
|
/* TODO: callback is registered here, which must be unregistered
|
||||||
* when the card is destroyed!!
|
* when the card is destroyed!!
|
||||||
* poll descriptors must be unwatched too */
|
* poll descriptors must be unwatched too */
|
||||||
let watch_ids =
|
let watch_ids = AlsaCard::watch_poll_descriptors(vec_pollfd,
|
||||||
AlsaCard::watch_poll_descriptors(vec_pollfd, acard.as_ref());
|
acard.as_ref());
|
||||||
acard.watch_ids.set(watch_ids);
|
acard.watch_ids.set(watch_ids);
|
||||||
|
|
||||||
return Ok(acard);
|
return Ok(acard);
|
||||||
@ -83,7 +88,9 @@ impl AlsaCard {
|
|||||||
|
|
||||||
|
|
||||||
pub fn chan_name(&self) -> Result<String> {
|
pub fn chan_name(&self) -> Result<String> {
|
||||||
let n = self.selem_id.get_name().map(|y| String::from(y))?;
|
let n = self.selem_id
|
||||||
|
.get_name()
|
||||||
|
.map(|y| String::from(y))?;
|
||||||
return Ok(n);
|
return Ok(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,9 +119,7 @@ impl AlsaCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let range = selem.get_playback_volume_range();
|
let range = selem.get_playback_volume_range();
|
||||||
selem.set_playback_volume_all(
|
selem.set_playback_volume_all(percent_to_vol(new_vol, range))?;
|
||||||
percent_to_vol(new_vol, range),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -141,10 +146,9 @@ impl AlsaCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn watch_poll_descriptors(
|
fn watch_poll_descriptors(polls: Vec<pollfd>,
|
||||||
polls: Vec<pollfd>,
|
acard: &AlsaCard)
|
||||||
acard: &AlsaCard,
|
-> Vec<c_uint> {
|
||||||
) -> Vec<c_uint> {
|
|
||||||
let mut watch_ids: Vec<c_uint> = vec![];
|
let mut watch_ids: Vec<c_uint> = vec![];
|
||||||
let acard_ptr =
|
let acard_ptr =
|
||||||
unsafe { mem::transmute::<&AlsaCard, glib_sys::gpointer>(acard) };
|
unsafe { mem::transmute::<&AlsaCard, glib_sys::gpointer>(acard) };
|
||||||
@ -201,11 +205,10 @@ impl Drop for AlsaCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" fn watch_cb(
|
extern "C" fn watch_cb(chan: *mut glib_sys::GIOChannel,
|
||||||
chan: *mut glib_sys::GIOChannel,
|
cond: glib_sys::GIOCondition,
|
||||||
cond: glib_sys::GIOCondition,
|
data: glib_sys::gpointer)
|
||||||
data: glib_sys::gpointer,
|
-> glib_sys::gboolean {
|
||||||
) -> glib_sys::gboolean {
|
|
||||||
|
|
||||||
let acard =
|
let acard =
|
||||||
unsafe { mem::transmute::<glib_sys::gpointer, &AlsaCard>(data) };
|
unsafe { mem::transmute::<glib_sys::gpointer, &AlsaCard>(data) };
|
||||||
@ -224,15 +227,14 @@ extern "C" fn watch_cb(
|
|||||||
let mut buf: Vec<u8> = vec![0; 256];
|
let mut buf: Vec<u8> = vec![0; 256];
|
||||||
|
|
||||||
while sread > 0 {
|
while sread > 0 {
|
||||||
let stat: glib_sys::GIOStatus = unsafe {
|
let stat: glib_sys::GIOStatus =
|
||||||
glib_sys::g_io_channel_read_chars(
|
unsafe {
|
||||||
chan,
|
glib_sys::g_io_channel_read_chars(chan,
|
||||||
buf.as_mut_ptr() as *mut u8,
|
buf.as_mut_ptr() as *mut u8,
|
||||||
256,
|
256,
|
||||||
&mut sread as *mut size_t,
|
&mut sread as *mut size_t,
|
||||||
ptr::null_mut(),
|
ptr::null_mut())
|
||||||
)
|
};
|
||||||
};
|
|
||||||
|
|
||||||
match stat {
|
match stat {
|
||||||
glib_sys::G_IO_STATUS_AGAIN => {
|
glib_sys::G_IO_STATUS_AGAIN => {
|
||||||
|
@ -23,22 +23,20 @@ pub struct AppS {
|
|||||||
|
|
||||||
impl AppS {
|
impl AppS {
|
||||||
pub fn new() -> AppS {
|
pub fn new() -> AppS {
|
||||||
let builder_popup_window = gtk::Builder::new_from_string(include_str!(
|
let builder_popup_window =
|
||||||
"../data/ui/popup-window.glade"
|
gtk::Builder::new_from_string(include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/data/ui/popup-window.glade")));
|
||||||
));
|
let builder_popup_menu = gtk::Builder::new_from_string(include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/data/ui/popup-menu.glade")));
|
||||||
let builder_popup_menu = gtk::Builder::new_from_string(
|
|
||||||
include_str!("../data/ui/popup-menu.glade"),
|
|
||||||
);
|
|
||||||
let prefs = RefCell::new(Prefs::new().unwrap());
|
let prefs = RefCell::new(Prefs::new().unwrap());
|
||||||
let gui =
|
let gui =
|
||||||
Gui::new(builder_popup_window, builder_popup_menu, &prefs.borrow());
|
Gui::new(builder_popup_window, builder_popup_menu, &prefs.borrow());
|
||||||
|
|
||||||
return AppS {
|
return AppS {
|
||||||
_cant_construct: (),
|
_cant_construct: (),
|
||||||
gui: gui,
|
gui: gui,
|
||||||
audio: Audio::new(None, Some(String::from("Master"))).unwrap(),
|
audio: Audio::new(None, Some(String::from("Master")))
|
||||||
prefs: prefs,
|
.unwrap(),
|
||||||
};
|
prefs: prefs,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -46,11 +44,9 @@ impl AppS {
|
|||||||
|
|
||||||
pub fn update_tray_icon(&self) -> Result<()> {
|
pub fn update_tray_icon(&self) -> Result<()> {
|
||||||
debug!("Update tray icon!");
|
debug!("Update tray icon!");
|
||||||
return self.gui.tray_icon.update_all(
|
return self.gui.tray_icon.update_all(&self.prefs.borrow(),
|
||||||
&self.prefs.borrow(),
|
&self.audio,
|
||||||
&self.audio,
|
None);
|
||||||
None,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_popup_window(&self) -> Result<()> {
|
pub fn update_popup_window(&self) -> Result<()> {
|
||||||
@ -61,5 +57,4 @@ impl AppS {
|
|||||||
pub fn show_preferences(&self) {
|
pub fn show_preferences(&self) {
|
||||||
// show_prefs_dialog(self);
|
// show_prefs_dialog(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
217
src/audio.rs
217
src/audio.rs
@ -73,10 +73,9 @@ pub struct Audio {
|
|||||||
|
|
||||||
|
|
||||||
impl Audio {
|
impl Audio {
|
||||||
pub fn new(
|
pub fn new(card_name: Option<String>,
|
||||||
card_name: Option<String>,
|
elem_name: Option<String>)
|
||||||
elem_name: Option<String>,
|
-> Result<Audio> {
|
||||||
) -> Result<Audio> {
|
|
||||||
|
|
||||||
let handlers = Handlers::new();
|
let handlers = Handlers::new();
|
||||||
let last_action_timestamp = Rc::new(RefCell::new(0));
|
let last_action_timestamp = Rc::new(RefCell::new(0));
|
||||||
@ -85,8 +84,10 @@ impl Audio {
|
|||||||
let myhandler = handlers.clone();
|
let myhandler = handlers.clone();
|
||||||
let ts = last_action_timestamp.clone();
|
let ts = last_action_timestamp.clone();
|
||||||
Rc::new(move |event| {
|
Rc::new(move |event| {
|
||||||
on_alsa_event(&mut *ts.borrow_mut(), &myhandler.borrow(), event)
|
on_alsa_event(&mut *ts.borrow_mut(),
|
||||||
})
|
&myhandler.borrow(),
|
||||||
|
event)
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let audio = Audio {
|
let audio = Audio {
|
||||||
@ -101,40 +102,44 @@ impl Audio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn switch_acard(
|
pub fn switch_acard(&self,
|
||||||
&self,
|
card_name: Option<String>,
|
||||||
card_name: Option<String>,
|
elem_name: Option<String>,
|
||||||
elem_name: Option<String>,
|
user: AudioUser)
|
||||||
user: AudioUser,
|
-> Result<()> {
|
||||||
) -> Result<()> {
|
|
||||||
debug!("Switching cards");
|
debug!("Switching cards");
|
||||||
debug!(
|
debug!("Old card name: {}",
|
||||||
"Old card name: {}",
|
self.acard
|
||||||
self.acard.borrow().card_name().unwrap()
|
.borrow()
|
||||||
);
|
.card_name()
|
||||||
debug!(
|
.unwrap());
|
||||||
"Old chan name: {}",
|
debug!("Old chan name: {}",
|
||||||
self.acard.borrow().chan_name().unwrap()
|
self.acard
|
||||||
);
|
.borrow()
|
||||||
let cb = self.acard.borrow().cb.clone();
|
.chan_name()
|
||||||
|
.unwrap());
|
||||||
|
let cb = self.acard
|
||||||
|
.borrow()
|
||||||
|
.cb
|
||||||
|
.clone();
|
||||||
{
|
{
|
||||||
let mut ac = self.acard.borrow_mut();
|
let mut ac = self.acard.borrow_mut();
|
||||||
*ac = AlsaCard::new(card_name, elem_name, cb)?;
|
*ac = AlsaCard::new(card_name, elem_name, cb)?;
|
||||||
}
|
}
|
||||||
debug!(
|
debug!("Old card name: {}",
|
||||||
"Old card name: {}",
|
self.acard
|
||||||
self.acard.borrow().card_name().unwrap()
|
.borrow()
|
||||||
);
|
.card_name()
|
||||||
debug!(
|
.unwrap());
|
||||||
"Old chan name: {}",
|
debug!("Old chan name: {}",
|
||||||
self.acard.borrow().chan_name().unwrap()
|
self.acard
|
||||||
);
|
.borrow()
|
||||||
|
.chan_name()
|
||||||
|
.unwrap());
|
||||||
|
|
||||||
invoke_handlers(
|
invoke_handlers(&self.handlers.borrow(),
|
||||||
&self.handlers.borrow(),
|
AudioSignal::CardInitialized,
|
||||||
AudioSignal::CardInitialized,
|
user);
|
||||||
user,
|
|
||||||
);
|
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -167,20 +172,24 @@ impl Audio {
|
|||||||
*rc = glib::get_monotonic_time();
|
*rc = glib::get_monotonic_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(
|
debug!("Setting vol on card {:?} and chan {:?} to {:?} by user {:?}",
|
||||||
"Setting vol on card {:?} and chan {:?} to {:?} by user {:?}",
|
self.acard
|
||||||
self.acard.borrow().card_name().unwrap(),
|
.borrow()
|
||||||
self.acard.borrow().chan_name().unwrap(),
|
.card_name()
|
||||||
new_vol,
|
.unwrap(),
|
||||||
user
|
self.acard
|
||||||
);
|
.borrow()
|
||||||
self.acard.borrow().set_vol(new_vol)?;
|
.chan_name()
|
||||||
|
.unwrap(),
|
||||||
|
new_vol,
|
||||||
|
user);
|
||||||
|
self.acard
|
||||||
|
.borrow()
|
||||||
|
.set_vol(new_vol)?;
|
||||||
|
|
||||||
invoke_handlers(
|
invoke_handlers(&self.handlers.borrow(),
|
||||||
&self.handlers.borrow(),
|
AudioSignal::ValuesChanged,
|
||||||
AudioSignal::ValuesChanged,
|
user);
|
||||||
user,
|
|
||||||
);
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,21 +202,23 @@ impl Audio {
|
|||||||
let old_vol = self.vol()?;
|
let old_vol = self.vol()?;
|
||||||
let new_vol = f64::ceil(old_vol + (self.scroll_step.get() as f64));
|
let new_vol = f64::ceil(old_vol + (self.scroll_step.get() as f64));
|
||||||
|
|
||||||
debug!(
|
debug!("Increase vol on card {:?} and chan {:?} by {:?} to {:?}",
|
||||||
"Increase vol on card {:?} and chan {:?} by {:?} to {:?}",
|
self.acard
|
||||||
self.acard.borrow().card_name().unwrap(),
|
.borrow()
|
||||||
self.acard.borrow().chan_name().unwrap(),
|
.card_name()
|
||||||
(new_vol - old_vol),
|
.unwrap(),
|
||||||
new_vol
|
self.acard
|
||||||
);
|
.borrow()
|
||||||
|
.chan_name()
|
||||||
|
.unwrap(),
|
||||||
|
(new_vol - old_vol),
|
||||||
|
new_vol);
|
||||||
|
|
||||||
self.set_vol(new_vol, user)?;
|
self.set_vol(new_vol, user)?;
|
||||||
|
|
||||||
invoke_handlers(
|
invoke_handlers(&self.handlers.borrow(),
|
||||||
&self.handlers.borrow(),
|
AudioSignal::ValuesChanged,
|
||||||
AudioSignal::ValuesChanged,
|
user);
|
||||||
user,
|
|
||||||
);
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,21 +231,23 @@ impl Audio {
|
|||||||
let old_vol = self.vol()?;
|
let old_vol = self.vol()?;
|
||||||
let new_vol = old_vol - (self.scroll_step.get() as f64);
|
let new_vol = old_vol - (self.scroll_step.get() as f64);
|
||||||
|
|
||||||
debug!(
|
debug!("Decrease vol on card {:?} and chan {:?} by {:?} to {:?}",
|
||||||
"Decrease vol on card {:?} and chan {:?} by {:?} to {:?}",
|
self.acard
|
||||||
self.acard.borrow().card_name().unwrap(),
|
.borrow()
|
||||||
self.acard.borrow().chan_name().unwrap(),
|
.card_name()
|
||||||
(new_vol - old_vol),
|
.unwrap(),
|
||||||
new_vol
|
self.acard
|
||||||
);
|
.borrow()
|
||||||
|
.chan_name()
|
||||||
|
.unwrap(),
|
||||||
|
(new_vol - old_vol),
|
||||||
|
new_vol);
|
||||||
|
|
||||||
self.set_vol(new_vol, user)?;
|
self.set_vol(new_vol, user)?;
|
||||||
|
|
||||||
invoke_handlers(
|
invoke_handlers(&self.handlers.borrow(),
|
||||||
&self.handlers.borrow(),
|
AudioSignal::ValuesChanged,
|
||||||
AudioSignal::ValuesChanged,
|
user);
|
||||||
user,
|
|
||||||
);
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,21 +266,25 @@ impl Audio {
|
|||||||
let mut rc = self.last_action_timestamp.borrow_mut();
|
let mut rc = self.last_action_timestamp.borrow_mut();
|
||||||
*rc = glib::get_monotonic_time();
|
*rc = glib::get_monotonic_time();
|
||||||
|
|
||||||
debug!(
|
debug!("Setting mute to {} on card {:?} and chan {:?} by user {:?}",
|
||||||
"Setting mute to {} on card {:?} and chan {:?} by user {:?}",
|
mute,
|
||||||
mute,
|
self.acard
|
||||||
self.acard.borrow().card_name().unwrap(),
|
.borrow()
|
||||||
self.acard.borrow().chan_name().unwrap(),
|
.card_name()
|
||||||
user
|
.unwrap(),
|
||||||
);
|
self.acard
|
||||||
|
.borrow()
|
||||||
|
.chan_name()
|
||||||
|
.unwrap(),
|
||||||
|
user);
|
||||||
|
|
||||||
self.acard.borrow().set_mute(mute)?;
|
self.acard
|
||||||
|
.borrow()
|
||||||
|
.set_mute(mute)?;
|
||||||
|
|
||||||
invoke_handlers(
|
invoke_handlers(&self.handlers.borrow(),
|
||||||
&self.handlers.borrow(),
|
AudioSignal::ValuesChanged,
|
||||||
AudioSignal::ValuesChanged,
|
user);
|
||||||
user,
|
|
||||||
);
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,16 +301,12 @@ impl Audio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn invoke_handlers(
|
fn invoke_handlers(handlers: &Vec<Box<Fn(AudioSignal, AudioUser)>>,
|
||||||
handlers: &Vec<Box<Fn(AudioSignal, AudioUser)>>,
|
signal: AudioSignal,
|
||||||
signal: AudioSignal,
|
user: AudioUser) {
|
||||||
user: AudioUser,
|
debug!("Invoking handlers for signal {:?} by user {:?}",
|
||||||
) {
|
signal,
|
||||||
debug!(
|
user);
|
||||||
"Invoking handlers for signal {:?} by user {:?}",
|
|
||||||
signal,
|
|
||||||
user
|
|
||||||
);
|
|
||||||
for handler in handlers {
|
for handler in handlers {
|
||||||
let unboxed = handler.as_ref();
|
let unboxed = handler.as_ref();
|
||||||
unboxed(signal, user);
|
unboxed(signal, user);
|
||||||
@ -301,11 +314,9 @@ fn invoke_handlers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn on_alsa_event(
|
fn on_alsa_event(last_action_timestamp: &mut i64,
|
||||||
last_action_timestamp: &mut i64,
|
handlers: &Vec<Box<Fn(AudioSignal, AudioUser)>>,
|
||||||
handlers: &Vec<Box<Fn(AudioSignal, AudioUser)>>,
|
alsa_event: AlsaEvent) {
|
||||||
alsa_event: AlsaEvent,
|
|
||||||
) {
|
|
||||||
let last: i64 = *last_action_timestamp;
|
let last: i64 = *last_action_timestamp;
|
||||||
|
|
||||||
if last != 0 {
|
if last != 0 {
|
||||||
@ -325,11 +336,9 @@ fn on_alsa_event(
|
|||||||
AlsaEvent::AlsaCardDiconnected => debug!("AlsaCardDiconnected"),
|
AlsaEvent::AlsaCardDiconnected => debug!("AlsaCardDiconnected"),
|
||||||
AlsaEvent::AlsaCardValuesChanged => {
|
AlsaEvent::AlsaCardValuesChanged => {
|
||||||
debug!("AlsaCardValuesChanged");
|
debug!("AlsaCardValuesChanged");
|
||||||
invoke_handlers(
|
invoke_handlers(handlers,
|
||||||
handlers,
|
self::AudioSignal::ValuesChanged,
|
||||||
self::AudioSignal::ValuesChanged,
|
self::AudioUser::Unknown);
|
||||||
self::AudioUser::Unknown,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
e => warn!("Unhandled alsa event: {:?}", e),
|
e => warn!("Unhandled alsa event: {:?}", e),
|
||||||
}
|
}
|
||||||
|
65
src/prefs.rs
65
src/prefs.rs
@ -62,16 +62,16 @@ impl From<MiddleClickAction> for i32 {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct DevicePrefs {
|
pub struct DevicePrefs {
|
||||||
pub card: String,
|
pub card: String,
|
||||||
pub channel: String,
|
pub channel: String,
|
||||||
// TODO: normalize volume?
|
// TODO: normalize volume?
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for DevicePrefs {
|
impl Default for DevicePrefs {
|
||||||
fn default() -> DevicePrefs {
|
fn default() -> DevicePrefs {
|
||||||
return DevicePrefs {
|
return DevicePrefs {
|
||||||
card: String::from("(default)"),
|
card: String::from("(default)"),
|
||||||
channel: String::from("Master"),
|
channel: String::from("Master"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,18 +82,18 @@ pub struct ViewPrefs {
|
|||||||
pub draw_vol_meter: bool,
|
pub draw_vol_meter: bool,
|
||||||
pub vol_meter_offset: i32,
|
pub vol_meter_offset: i32,
|
||||||
pub system_theme: bool,
|
pub system_theme: bool,
|
||||||
pub vol_meter_color: VolColor,
|
pub vol_meter_color: VolColor,
|
||||||
// TODO: Display text folume/text volume pos?
|
// TODO: Display text folume/text volume pos?
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ViewPrefs {
|
impl Default for ViewPrefs {
|
||||||
fn default() -> ViewPrefs {
|
fn default() -> ViewPrefs {
|
||||||
return ViewPrefs {
|
return ViewPrefs {
|
||||||
draw_vol_meter: true,
|
draw_vol_meter: true,
|
||||||
vol_meter_offset: 10,
|
vol_meter_offset: 10,
|
||||||
system_theme: true,
|
system_theme: true,
|
||||||
vol_meter_color: VolColor::default(),
|
vol_meter_color: VolColor::default(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,10 +109,10 @@ pub struct VolColor {
|
|||||||
impl Default for VolColor {
|
impl Default for VolColor {
|
||||||
fn default() -> VolColor {
|
fn default() -> VolColor {
|
||||||
return VolColor {
|
return VolColor {
|
||||||
red: 245,
|
red: 245,
|
||||||
green: 180,
|
green: 180,
|
||||||
blue: 0,
|
blue: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,11 +129,11 @@ pub struct BehaviorPrefs {
|
|||||||
impl Default for BehaviorPrefs {
|
impl Default for BehaviorPrefs {
|
||||||
fn default() -> BehaviorPrefs {
|
fn default() -> BehaviorPrefs {
|
||||||
return BehaviorPrefs {
|
return BehaviorPrefs {
|
||||||
vol_control_cmd: None,
|
vol_control_cmd: None,
|
||||||
vol_scroll_step: 5.0,
|
vol_scroll_step: 5.0,
|
||||||
middle_click_action: MiddleClickAction::default(),
|
middle_click_action: MiddleClickAction::default(),
|
||||||
custom_command: None,
|
custom_command: None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,19 +145,19 @@ pub struct NotifyPrefs {
|
|||||||
pub notifcation_timeout: i64,
|
pub notifcation_timeout: i64,
|
||||||
pub notify_mouse_scroll: bool,
|
pub notify_mouse_scroll: bool,
|
||||||
pub notify_popup: bool,
|
pub notify_popup: bool,
|
||||||
pub notify_external: bool,
|
pub notify_external: bool,
|
||||||
// TODO: notify_hotkeys?
|
// TODO: notify_hotkeys?
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for NotifyPrefs {
|
impl Default for NotifyPrefs {
|
||||||
fn default() -> NotifyPrefs {
|
fn default() -> NotifyPrefs {
|
||||||
return NotifyPrefs {
|
return NotifyPrefs {
|
||||||
enable_notifications: true,
|
enable_notifications: true,
|
||||||
notifcation_timeout: 1500,
|
notifcation_timeout: 1500,
|
||||||
notify_mouse_scroll: true,
|
notify_mouse_scroll: true,
|
||||||
notify_popup: true,
|
notify_popup: true,
|
||||||
notify_external: true,
|
notify_external: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ pub struct Prefs {
|
|||||||
pub device_prefs: DevicePrefs,
|
pub device_prefs: DevicePrefs,
|
||||||
pub view_prefs: ViewPrefs,
|
pub view_prefs: ViewPrefs,
|
||||||
pub behavior_prefs: BehaviorPrefs,
|
pub behavior_prefs: BehaviorPrefs,
|
||||||
pub notify_prefs: NotifyPrefs,
|
pub notify_prefs: NotifyPrefs,
|
||||||
// TODO: HotKeys?
|
// TODO: HotKeys?
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,8 +211,8 @@ impl Prefs {
|
|||||||
|
|
||||||
|
|
||||||
pub fn store_config(&self) -> Result<()> {
|
pub fn store_config(&self) -> Result<()> {
|
||||||
let config_path =
|
let config_path = get_xdg_dirs().place_config_file("pnmixer.toml")
|
||||||
get_xdg_dirs().place_config_file("pnmixer.toml").from_err()?;
|
.from_err()?;
|
||||||
|
|
||||||
debug!("Storing config in {:?}", config_path);
|
debug!("Storing config in {:?}", config_path);
|
||||||
|
|
||||||
@ -245,10 +245,9 @@ impl Prefs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Prefs {
|
impl Display for Prefs {
|
||||||
fn fmt(
|
fn fmt(&self,
|
||||||
&self,
|
f: &mut Formatter)
|
||||||
f: &mut Formatter,
|
-> std::result::Result<(), std::fmt::Error> {
|
||||||
) -> std::result::Result<(), std::fmt::Error> {
|
|
||||||
let s = self.to_str();
|
let s = self.to_str();
|
||||||
return write!(f, "{}", s);
|
return write!(f, "{}", s);
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,9 @@ pub fn get_selem_names(mixer: &Mixer) -> Vec<String> {
|
|||||||
|
|
||||||
pub fn get_selem_by_name(mixer: &Mixer, name: String) -> Result<Selem> {
|
pub fn get_selem_by_name(mixer: &Mixer, name: String) -> Result<Selem> {
|
||||||
for selem in get_selems(mixer) {
|
for selem in get_selems(mixer) {
|
||||||
let n = selem.get_id().get_name().map(|y| String::from(y))?;
|
let n = selem.get_id()
|
||||||
|
.get_name()
|
||||||
|
.map(|y| String::from(y))?;
|
||||||
|
|
||||||
if n == name {
|
if n == name {
|
||||||
return Ok(selem);
|
return Ok(selem);
|
||||||
|
26
src/support_cmd.rs
Normal file
26
src/support_cmd.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use errors::*;
|
||||||
|
use glib;
|
||||||
|
use prefs::Prefs;
|
||||||
|
use std::error::Error;
|
||||||
|
use std;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub fn execute_vol_control_command(prefs: &Prefs) -> Result<()> {
|
||||||
|
let m_cmd = prefs.get_avail_vol_control_cmd();
|
||||||
|
|
||||||
|
match m_cmd {
|
||||||
|
Some(ref cmd) => execute_command(cmd.as_str()),
|
||||||
|
None => bail!("No command found"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn execute_command(cmd: &str) -> Result<()> {
|
||||||
|
return glib::spawn_command_line_async(cmd)
|
||||||
|
.map_err(|e| {
|
||||||
|
std::io::Error::new(std::io::ErrorKind::Other,
|
||||||
|
e.description())
|
||||||
|
})
|
||||||
|
.from_err();
|
||||||
|
}
|
@ -21,21 +21,18 @@ pub fn copy_pixbuf(pixbuf: &gdk_pixbuf::Pixbuf) -> gdk_pixbuf::Pixbuf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn pixbuf_new_from_theme(
|
pub fn pixbuf_new_from_theme(icon_name: &str,
|
||||||
icon_name: &str,
|
size: i32,
|
||||||
size: i32,
|
theme: >k::IconTheme)
|
||||||
theme: >k::IconTheme,
|
-> Result<gdk_pixbuf::Pixbuf> {
|
||||||
) -> Result<gdk_pixbuf::Pixbuf> {
|
|
||||||
|
|
||||||
let icon_info = theme
|
let icon_info =
|
||||||
.lookup_icon(icon_name, size, gtk::IconLookupFlags::empty())
|
theme.lookup_icon(icon_name, size, gtk::IconLookupFlags::empty())
|
||||||
.ok_or(format!("Couldn't find icon {}", icon_name))?;
|
.ok_or(format!("Couldn't find icon {}", icon_name))?;
|
||||||
|
|
||||||
debug!(
|
debug!("Loading stock icon {} from {:?}",
|
||||||
"Loading stock icon {} from {:?}",
|
icon_name,
|
||||||
icon_name,
|
icon_info.get_filename().unwrap_or(PathBuf::new()));
|
||||||
icon_info.get_filename().unwrap_or(PathBuf::new())
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: propagate error
|
// TODO: propagate error
|
||||||
let pixbuf = icon_info.load_icon().unwrap();
|
let pixbuf = icon_info.load_icon().unwrap();
|
||||||
@ -47,7 +44,7 @@ pub fn pixbuf_new_from_theme(
|
|||||||
pub fn pixbuf_new_from_file(filename: &str) -> Result<gdk_pixbuf::Pixbuf> {
|
pub fn pixbuf_new_from_file(filename: &str) -> Result<gdk_pixbuf::Pixbuf> {
|
||||||
ensure!(!filename.is_empty(), "Filename is empty");
|
ensure!(!filename.is_empty(), "Filename is empty");
|
||||||
|
|
||||||
let s = format!("./data/pixmaps/{}", filename);
|
let s = format!("{}/data/pixmaps/{}", env!("CARGO_MANIFEST_DIR"), filename);
|
||||||
let path = Path::new(s.as_str());
|
let path = Path::new(s.as_str());
|
||||||
|
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
|
@ -20,18 +20,17 @@ pub struct Gui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Gui {
|
impl Gui {
|
||||||
pub fn new(
|
pub fn new(builder_popup_window: gtk::Builder,
|
||||||
builder_popup_window: gtk::Builder,
|
builder_popup_menu: gtk::Builder,
|
||||||
builder_popup_menu: gtk::Builder,
|
prefs: &Prefs)
|
||||||
prefs: &Prefs,
|
-> Gui {
|
||||||
) -> Gui {
|
|
||||||
return Gui {
|
return Gui {
|
||||||
_cant_construct: (),
|
_cant_construct: (),
|
||||||
tray_icon: TrayIcon::new(prefs).unwrap(),
|
tray_icon: TrayIcon::new(prefs).unwrap(),
|
||||||
popup_window: PopupWindow::new(builder_popup_window),
|
popup_window: PopupWindow::new(builder_popup_window),
|
||||||
popup_menu: PopupMenu::new(builder_popup_menu),
|
popup_menu: PopupMenu::new(builder_popup_menu),
|
||||||
prefs_dialog: RefCell::new(None),
|
prefs_dialog: RefCell::new(None),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,19 +11,17 @@ const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
create_builder_item!(
|
create_builder_item!(PopupMenu,
|
||||||
PopupMenu,
|
menu_window: gtk::Window,
|
||||||
menu_window: gtk::Window,
|
menubar: gtk::MenuBar,
|
||||||
menubar: gtk::MenuBar,
|
menu: gtk::Menu,
|
||||||
menu: gtk::Menu,
|
about_item: gtk::MenuItem,
|
||||||
about_item: gtk::MenuItem,
|
mixer_item: gtk::MenuItem,
|
||||||
mixer_item: gtk::MenuItem,
|
mute_item: gtk::MenuItem,
|
||||||
mute_item: gtk::MenuItem,
|
mute_check: gtk::CheckButton,
|
||||||
mute_check: gtk::CheckButton,
|
prefs_item: gtk::MenuItem,
|
||||||
prefs_item: gtk::MenuItem,
|
quit_item: gtk::MenuItem,
|
||||||
quit_item: gtk::MenuItem,
|
reload_item: gtk::MenuItem);
|
||||||
reload_item: gtk::MenuItem
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -33,15 +31,20 @@ pub fn init_popup_menu(appstate: Rc<AppS>) {
|
|||||||
let apps = appstate.clone();
|
let apps = appstate.clone();
|
||||||
appstate.audio.connect_handler(Box::new(move |s, u| {
|
appstate.audio.connect_handler(Box::new(move |s, u| {
|
||||||
/* skip if window is hidden */
|
/* skip if window is hidden */
|
||||||
if !apps.gui.popup_menu.menu.get_visible() {
|
if !apps.gui
|
||||||
|
.popup_menu
|
||||||
|
.menu
|
||||||
|
.get_visible() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
match (s, u) {
|
match (s, u) {
|
||||||
(AudioSignal::ValuesChanged, _) => {
|
(_, _) => {
|
||||||
let muted = try_w!(apps.audio.get_mute());
|
let muted = try_w!(apps.audio.get_mute());
|
||||||
apps.gui.popup_menu.mute_check.set_active(muted);
|
apps.gui
|
||||||
|
.popup_menu
|
||||||
|
.mute_check
|
||||||
|
.set_active(muted);
|
||||||
}
|
}
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -50,10 +53,16 @@ pub fn init_popup_menu(appstate: Rc<AppS>) {
|
|||||||
/* popup_menu.menu.connect_show */
|
/* popup_menu.menu.connect_show */
|
||||||
{
|
{
|
||||||
let apps = appstate.clone();
|
let apps = appstate.clone();
|
||||||
appstate.gui.popup_menu.menu.connect_show(move |_| {
|
appstate.gui
|
||||||
let muted = try_w!(apps.audio.get_mute());
|
.popup_menu
|
||||||
apps.gui.popup_menu.mute_check.set_active(muted);
|
.menu
|
||||||
});
|
.connect_show(move |_| {
|
||||||
|
let muted = try_w!(apps.audio.get_mute());
|
||||||
|
apps.gui
|
||||||
|
.popup_menu
|
||||||
|
.mute_check
|
||||||
|
.set_active(muted);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,18 +88,27 @@ pub fn init_popup_menu(appstate: Rc<AppS>) {
|
|||||||
{
|
{
|
||||||
let apps = appstate.clone();
|
let apps = appstate.clone();
|
||||||
let about_item = &appstate.gui.popup_menu.about_item;
|
let about_item = &appstate.gui.popup_menu.about_item;
|
||||||
about_item.connect_activate(
|
about_item.connect_activate(move |_| {
|
||||||
move |_| { on_about_item_activate(&apps); },
|
on_about_item_activate(&apps);
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* about_item.connect_activate_link */
|
/* about_item.connect_activate_link */
|
||||||
{
|
{
|
||||||
let apps = appstate.clone();
|
let apps = appstate.clone();
|
||||||
let prefs_item = &appstate.gui.popup_menu.prefs_item;
|
let prefs_item = &appstate.gui.popup_menu.prefs_item;
|
||||||
prefs_item.connect_activate(
|
prefs_item.connect_activate(move |_| {
|
||||||
move |_| { on_prefs_item_activate(&apps); },
|
on_prefs_item_activate(&apps);
|
||||||
);
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* quit_item.connect_activate_link */
|
||||||
|
{
|
||||||
|
let quit_item = &appstate.gui.popup_menu.quit_item;
|
||||||
|
quit_item.connect_activate(|_| {
|
||||||
|
gtk::main_quit();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,4 +157,3 @@ fn on_prefs_item_activate(appstate: &Rc<AppS>) {
|
|||||||
/* TODO: only create if needed */
|
/* TODO: only create if needed */
|
||||||
show_prefs_dialog(appstate);
|
show_prefs_dialog(appstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,14 +28,14 @@ pub struct PopupWindow {
|
|||||||
impl PopupWindow {
|
impl PopupWindow {
|
||||||
pub fn new(builder: gtk::Builder) -> PopupWindow {
|
pub fn new(builder: gtk::Builder) -> PopupWindow {
|
||||||
return PopupWindow {
|
return PopupWindow {
|
||||||
_cant_construct: (),
|
_cant_construct: (),
|
||||||
popup_window: builder.get_object("popup_window").unwrap(),
|
popup_window: builder.get_object("popup_window").unwrap(),
|
||||||
vol_scale_adj: builder.get_object("vol_scale_adj").unwrap(),
|
vol_scale_adj: builder.get_object("vol_scale_adj").unwrap(),
|
||||||
vol_scale: builder.get_object("vol_scale").unwrap(),
|
vol_scale: builder.get_object("vol_scale").unwrap(),
|
||||||
mute_check: builder.get_object("mute_check").unwrap(),
|
mute_check: builder.get_object("mute_check").unwrap(),
|
||||||
mixer_button: builder.get_object("mixer_button").unwrap(),
|
mixer_button: builder.get_object("mixer_button").unwrap(),
|
||||||
toggle_signal: Cell::new(0),
|
toggle_signal: Cell::new(0),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&self, audio: &Audio) -> Result<()> {
|
pub fn update(&self, audio: &Audio) -> Result<()> {
|
||||||
@ -67,10 +67,8 @@ impl PopupWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glib::signal_handler_unblock(
|
glib::signal_handler_unblock(&self.mute_check,
|
||||||
&self.mute_check,
|
self.toggle_signal.get());
|
||||||
self.toggle_signal.get(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +80,10 @@ pub fn init_popup_window(appstate: Rc<AppS>) {
|
|||||||
let apps = appstate.clone();
|
let apps = appstate.clone();
|
||||||
appstate.audio.connect_handler(Box::new(move |s, u| {
|
appstate.audio.connect_handler(Box::new(move |s, u| {
|
||||||
/* skip if window is hidden */
|
/* skip if window is hidden */
|
||||||
if !apps.gui.popup_window.popup_window.get_visible() {
|
if !apps.gui
|
||||||
|
.popup_window
|
||||||
|
.popup_window
|
||||||
|
.get_visible() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
match (s, u) {
|
match (s, u) {
|
||||||
@ -93,14 +94,13 @@ pub fn init_popup_window(appstate: Rc<AppS>) {
|
|||||||
* the slider value reflects the value set by user,
|
* the slider value reflects the value set by user,
|
||||||
* and not the real value reported by the audio system.
|
* and not the real value reported by the audio system.
|
||||||
*/
|
*/
|
||||||
(AudioSignal::ValuesChanged, AudioUser::Popup) => {
|
(_, AudioUser::Popup) => {
|
||||||
apps.gui.popup_window.update_mute_check(&apps.audio);
|
apps.gui.popup_window.update_mute_check(&apps.audio);
|
||||||
}
|
}
|
||||||
/* external change, safe to update slider too */
|
/* external change, safe to update slider too */
|
||||||
(AudioSignal::ValuesChanged, _) => {
|
(_, _) => {
|
||||||
try_w!(apps.gui.popup_window.update(&apps.audio));
|
try_w!(apps.gui.popup_window.update(&apps.audio));
|
||||||
}
|
}
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -109,24 +109,37 @@ pub fn init_popup_window(appstate: Rc<AppS>) {
|
|||||||
/* mute_check.connect_toggled */
|
/* mute_check.connect_toggled */
|
||||||
{
|
{
|
||||||
let _appstate = appstate.clone();
|
let _appstate = appstate.clone();
|
||||||
let mute_check = &appstate.clone().gui.popup_window.mute_check;
|
let mute_check = &appstate.clone()
|
||||||
let toggle_signal = mute_check.connect_toggled(move |_| {
|
.gui
|
||||||
on_mute_check_toggled(&_appstate)
|
.popup_window
|
||||||
});
|
.mute_check;
|
||||||
appstate.gui.popup_window.toggle_signal.set(toggle_signal);
|
let toggle_signal =
|
||||||
|
mute_check.connect_toggled(move |_| {
|
||||||
|
on_mute_check_toggled(&_appstate)
|
||||||
|
});
|
||||||
|
appstate.gui
|
||||||
|
.popup_window
|
||||||
|
.toggle_signal
|
||||||
|
.set(toggle_signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* popup_window.connect_show */
|
/* popup_window.connect_show */
|
||||||
{
|
{
|
||||||
let _appstate = appstate.clone();
|
let _appstate = appstate.clone();
|
||||||
let popup_window = &appstate.clone().gui.popup_window.popup_window;
|
let popup_window = &appstate.clone()
|
||||||
|
.gui
|
||||||
|
.popup_window
|
||||||
|
.popup_window;
|
||||||
popup_window.connect_show(move |_| on_popup_window_show(&_appstate));
|
popup_window.connect_show(move |_| on_popup_window_show(&_appstate));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* vol_scale_adj.connect_value_changed */
|
/* vol_scale_adj.connect_value_changed */
|
||||||
{
|
{
|
||||||
let _appstate = appstate.clone();
|
let _appstate = appstate.clone();
|
||||||
let vol_scale_adj = &appstate.clone().gui.popup_window.vol_scale_adj;
|
let vol_scale_adj = &appstate.clone()
|
||||||
|
.gui
|
||||||
|
.popup_window
|
||||||
|
.vol_scale_adj;
|
||||||
vol_scale_adj.connect_value_changed(
|
vol_scale_adj.connect_value_changed(
|
||||||
move |_| on_vol_scale_value_changed(&_appstate),
|
move |_| on_vol_scale_value_changed(&_appstate),
|
||||||
);
|
);
|
||||||
@ -134,16 +147,25 @@ pub fn init_popup_window(appstate: Rc<AppS>) {
|
|||||||
|
|
||||||
/* popup_window.connect_event */
|
/* popup_window.connect_event */
|
||||||
{
|
{
|
||||||
let popup_window = &appstate.clone().gui.popup_window.popup_window;
|
let popup_window = &appstate.clone()
|
||||||
|
.gui
|
||||||
|
.popup_window
|
||||||
|
.popup_window;
|
||||||
popup_window.connect_event(move |w, e| on_popup_window_event(w, e));
|
popup_window.connect_event(move |w, e| on_popup_window_event(w, e));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mixer_button.connect_clicked */
|
/* mixer_button.connect_clicked */
|
||||||
{
|
{
|
||||||
let apps = appstate.clone();
|
let apps = appstate.clone();
|
||||||
let mixer_button = &appstate.clone().gui.popup_window.mixer_button;
|
let mixer_button = &appstate.clone()
|
||||||
|
.gui
|
||||||
|
.popup_window
|
||||||
|
.mixer_button;
|
||||||
mixer_button.connect_clicked(move |_| {
|
mixer_button.connect_clicked(move |_| {
|
||||||
apps.gui.popup_window.popup_window.hide();
|
apps.gui
|
||||||
|
.popup_window
|
||||||
|
.popup_window
|
||||||
|
.hide();
|
||||||
try_w!(execute_vol_control_command(&apps.prefs.borrow()));
|
try_w!(execute_vol_control_command(&apps.prefs.borrow()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -152,7 +174,10 @@ pub fn init_popup_window(appstate: Rc<AppS>) {
|
|||||||
|
|
||||||
fn on_popup_window_show(appstate: &AppS) {
|
fn on_popup_window_show(appstate: &AppS) {
|
||||||
try_w!(appstate.gui.popup_window.update(&appstate.audio));
|
try_w!(appstate.gui.popup_window.update(&appstate.audio));
|
||||||
appstate.gui.popup_window.vol_scale.grab_focus();
|
appstate.gui
|
||||||
|
.popup_window
|
||||||
|
.vol_scale
|
||||||
|
.grab_focus();
|
||||||
try_w!(grab_devices(&appstate.gui.popup_window.popup_window));
|
try_w!(grab_devices(&appstate.gui.popup_window.popup_window));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +214,10 @@ fn on_popup_window_event(w: >k::Window, e: &gdk::Event) -> gtk::Inhibit {
|
|||||||
fn on_vol_scale_value_changed(appstate: &AppS) {
|
fn on_vol_scale_value_changed(appstate: &AppS) {
|
||||||
let audio = &appstate.audio;
|
let audio = &appstate.audio;
|
||||||
|
|
||||||
let val = appstate.gui.popup_window.vol_scale.get_value();
|
let val = appstate.gui
|
||||||
|
.popup_window
|
||||||
|
.vol_scale
|
||||||
|
.get_value();
|
||||||
|
|
||||||
try_w!(audio.set_vol(val, AudioUser::Popup));
|
try_w!(audio.set_vol(val, AudioUser::Popup));
|
||||||
}
|
}
|
||||||
@ -212,40 +240,32 @@ pub fn grab_devices(window: >k::Window) -> Result<()> {
|
|||||||
let gdk_window = window.get_window().ok_or("No window?!")?;
|
let gdk_window = window.get_window().ok_or("No window?!")?;
|
||||||
|
|
||||||
/* Grab the mouse */
|
/* Grab the mouse */
|
||||||
let m_grab_status = device.grab(
|
let m_grab_status =
|
||||||
&gdk_window,
|
device.grab(&gdk_window,
|
||||||
GrabOwnership::None,
|
GrabOwnership::None,
|
||||||
true,
|
true,
|
||||||
BUTTON_PRESS_MASK,
|
BUTTON_PRESS_MASK,
|
||||||
None,
|
None,
|
||||||
GDK_CURRENT_TIME as u32,
|
GDK_CURRENT_TIME as u32);
|
||||||
);
|
|
||||||
|
|
||||||
if m_grab_status != GrabStatus::Success {
|
if m_grab_status != GrabStatus::Success {
|
||||||
warn!(
|
warn!("Could not grab {}",
|
||||||
"Could not grab {}",
|
device.get_name().unwrap_or(String::from("UNKNOWN DEVICE")));
|
||||||
device.get_name().unwrap_or(String::from("UNKNOWN DEVICE"))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Grab the keyboard */
|
/* Grab the keyboard */
|
||||||
let k_dev = device.get_associated_device().ok_or(
|
let k_dev = device.get_associated_device()
|
||||||
"Couldn't get associated device",
|
.ok_or("Couldn't get associated device")?;
|
||||||
)?;
|
|
||||||
|
|
||||||
let k_grab_status = k_dev.grab(
|
let k_grab_status = k_dev.grab(&gdk_window,
|
||||||
&gdk_window,
|
GrabOwnership::None,
|
||||||
GrabOwnership::None,
|
true,
|
||||||
true,
|
KEY_PRESS_MASK,
|
||||||
KEY_PRESS_MASK,
|
None,
|
||||||
None,
|
GDK_CURRENT_TIME as u32);
|
||||||
GDK_CURRENT_TIME as u32,
|
|
||||||
);
|
|
||||||
if k_grab_status != GrabStatus::Success {
|
if k_grab_status != GrabStatus::Success {
|
||||||
warn!(
|
warn!("Could not grab {}",
|
||||||
"Could not grab {}",
|
k_dev.get_name().unwrap_or(String::from("UNKNOWN DEVICE")));
|
||||||
k_dev.get_name().unwrap_or(String::from("UNKNOWN DEVICE"))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use app_state::*;
|
use app_state::*;
|
||||||
use audio::AudioUser;
|
use audio::{AudioUser, AudioSignal};
|
||||||
use gdk;
|
use gdk;
|
||||||
use gtk::ResponseType;
|
use gtk::ResponseType;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
@ -7,6 +7,7 @@ use gtk;
|
|||||||
use prefs::*;
|
use prefs::*;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use support_alsa::*;
|
use support_alsa::*;
|
||||||
|
use errors::*;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -45,9 +46,7 @@ pub struct PrefsDialog {
|
|||||||
|
|
||||||
impl PrefsDialog {
|
impl PrefsDialog {
|
||||||
pub fn new() -> PrefsDialog {
|
pub fn new() -> PrefsDialog {
|
||||||
let builder = gtk::Builder::new_from_string(
|
let builder = gtk::Builder::new_from_string(include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/data/ui/prefs-dialog.glade")));
|
||||||
include_str!("../data/ui/prefs-dialog.glade"),
|
|
||||||
);
|
|
||||||
let prefs_dialog = PrefsDialog {
|
let prefs_dialog = PrefsDialog {
|
||||||
_cant_construct: (),
|
_cant_construct: (),
|
||||||
prefs_dialog: builder.get_object("prefs_dialog").unwrap(),
|
prefs_dialog: builder.get_object("prefs_dialog").unwrap(),
|
||||||
@ -55,21 +54,17 @@ impl PrefsDialog {
|
|||||||
card_combo: builder.get_object("card_combo").unwrap(),
|
card_combo: builder.get_object("card_combo").unwrap(),
|
||||||
chan_combo: builder.get_object("chan_combo").unwrap(),
|
chan_combo: builder.get_object("chan_combo").unwrap(),
|
||||||
|
|
||||||
vol_meter_draw_check: builder
|
vol_meter_draw_check: builder.get_object("vol_meter_draw_check")
|
||||||
.get_object("vol_meter_draw_check")
|
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
vol_meter_pos_spin: builder
|
vol_meter_pos_spin: builder.get_object("vol_meter_pos_spin")
|
||||||
.get_object("vol_meter_pos_spin")
|
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
vol_meter_color_button: builder
|
vol_meter_color_button: builder.get_object("vol_meter_color_button")
|
||||||
.get_object("vol_meter_color_button")
|
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
system_theme: builder.get_object("system_theme").unwrap(),
|
system_theme: builder.get_object("system_theme").unwrap(),
|
||||||
|
|
||||||
vol_control_entry: builder.get_object("vol_control_entry").unwrap(),
|
vol_control_entry: builder.get_object("vol_control_entry").unwrap(),
|
||||||
scroll_step_spin: builder.get_object("scroll_step_spin").unwrap(),
|
scroll_step_spin: builder.get_object("scroll_step_spin").unwrap(),
|
||||||
middle_click_combo: builder
|
middle_click_combo: builder.get_object("middle_click_combo")
|
||||||
.get_object("middle_click_combo")
|
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
custom_entry: builder.get_object("custom_entry").unwrap(),
|
custom_entry: builder.get_object("custom_entry").unwrap(),
|
||||||
|
|
||||||
@ -88,26 +83,14 @@ impl PrefsDialog {
|
|||||||
|
|
||||||
pub fn from_prefs(&self, prefs: &Prefs) {
|
pub fn from_prefs(&self, prefs: &Prefs) {
|
||||||
/* DevicePrefs */
|
/* DevicePrefs */
|
||||||
|
/* filled on show signal with audio info */
|
||||||
self.card_combo.remove_all();
|
self.card_combo.remove_all();
|
||||||
self.card_combo.append_text(
|
|
||||||
prefs.device_prefs.card.as_str(),
|
|
||||||
);
|
|
||||||
self.card_combo.set_active(0);
|
|
||||||
|
|
||||||
self.chan_combo.remove_all();
|
self.chan_combo.remove_all();
|
||||||
self.chan_combo.append_text(
|
|
||||||
prefs.device_prefs.channel.as_str(),
|
|
||||||
);
|
|
||||||
self.chan_combo.set_active(0);
|
|
||||||
|
|
||||||
/* ViewPrefs */
|
/* ViewPrefs */
|
||||||
self.vol_meter_draw_check.set_active(
|
self.vol_meter_draw_check.set_active(prefs.view_prefs.draw_vol_meter);
|
||||||
prefs.view_prefs.draw_vol_meter,
|
self.vol_meter_pos_spin.set_value(prefs.view_prefs.vol_meter_offset as
|
||||||
);
|
f64);
|
||||||
self.vol_meter_pos_spin.set_value(
|
|
||||||
prefs.view_prefs.vol_meter_offset as
|
|
||||||
f64,
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO don't convert like that
|
// TODO don't convert like that
|
||||||
let rgba = gdk::RGBA {
|
let rgba = gdk::RGBA {
|
||||||
@ -120,17 +103,12 @@ impl PrefsDialog {
|
|||||||
self.system_theme.set_active(prefs.view_prefs.system_theme);
|
self.system_theme.set_active(prefs.view_prefs.system_theme);
|
||||||
|
|
||||||
/* BehaviorPrefs */
|
/* BehaviorPrefs */
|
||||||
self.vol_control_entry.set_text(
|
self.vol_control_entry.set_text(prefs.behavior_prefs
|
||||||
prefs
|
.vol_control_cmd
|
||||||
.behavior_prefs
|
.as_ref()
|
||||||
.vol_control_cmd
|
.unwrap_or(&String::from(""))
|
||||||
.as_ref()
|
.as_str());
|
||||||
.unwrap_or(&String::from(""))
|
self.scroll_step_spin.set_value(prefs.behavior_prefs.vol_scroll_step);
|
||||||
.as_str(),
|
|
||||||
);
|
|
||||||
self.scroll_step_spin.set_value(
|
|
||||||
prefs.behavior_prefs.vol_scroll_step,
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: make sure these values always match, must be a better way
|
// TODO: make sure these values always match, must be a better way
|
||||||
// also check to_prefs()
|
// also check to_prefs()
|
||||||
@ -138,53 +116,38 @@ impl PrefsDialog {
|
|||||||
self.middle_click_combo.append_text("Show Preferences");
|
self.middle_click_combo.append_text("Show Preferences");
|
||||||
self.middle_click_combo.append_text("Volume Control");
|
self.middle_click_combo.append_text("Volume Control");
|
||||||
self.middle_click_combo.append_text("Custom Command (set below)");
|
self.middle_click_combo.append_text("Custom Command (set below)");
|
||||||
self.middle_click_combo.set_active(
|
self.middle_click_combo.set_active(prefs.behavior_prefs
|
||||||
prefs
|
.middle_click_action
|
||||||
.behavior_prefs
|
.into());
|
||||||
.middle_click_action
|
self.custom_entry.set_text(prefs.behavior_prefs
|
||||||
.into(),
|
.custom_command
|
||||||
);
|
.as_ref()
|
||||||
self.custom_entry.set_text(
|
.unwrap_or(&String::from(""))
|
||||||
prefs
|
.as_str());
|
||||||
.behavior_prefs
|
|
||||||
.custom_command
|
|
||||||
.as_ref()
|
|
||||||
.unwrap_or(&String::from(""))
|
|
||||||
.as_str(),
|
|
||||||
);
|
|
||||||
|
|
||||||
/* NotifyPrefs */
|
/* NotifyPrefs */
|
||||||
self.noti_enable_check.set_active(
|
self.noti_enable_check
|
||||||
prefs
|
.set_active(prefs.notify_prefs.enable_notifications);
|
||||||
.notify_prefs
|
self.noti_timeout_spin
|
||||||
.enable_notifications,
|
.set_value(prefs.notify_prefs.notifcation_timeout as f64);
|
||||||
);
|
self.noti_mouse_check
|
||||||
self.noti_timeout_spin.set_value(
|
.set_active(prefs.notify_prefs.notify_mouse_scroll);
|
||||||
prefs.notify_prefs.notifcation_timeout as
|
self.noti_popup_check.set_active(prefs.notify_prefs.notify_popup);
|
||||||
f64,
|
self.noti_ext_check.set_active(prefs.notify_prefs.notify_external);
|
||||||
);
|
|
||||||
self.noti_mouse_check.set_active(
|
|
||||||
prefs.notify_prefs.notify_mouse_scroll,
|
|
||||||
);
|
|
||||||
self.noti_popup_check.set_active(
|
|
||||||
prefs.notify_prefs.notify_popup,
|
|
||||||
);
|
|
||||||
self.noti_ext_check.set_active(
|
|
||||||
prefs.notify_prefs.notify_external,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn to_prefs(&self) -> Prefs {
|
pub fn to_prefs(&self) -> Prefs {
|
||||||
// TODO: remove duplication with default instance
|
// TODO: remove duplication with default instance
|
||||||
let device_prefs = DevicePrefs {
|
let device_prefs =
|
||||||
card: self.card_combo.get_active_text().unwrap_or(
|
DevicePrefs {
|
||||||
String::from("(default)"),
|
card: self.card_combo
|
||||||
),
|
.get_active_text()
|
||||||
channel: self.chan_combo.get_active_text().unwrap_or(
|
.unwrap_or(String::from("(default)")),
|
||||||
String::from("Master"),
|
channel: self.chan_combo
|
||||||
),
|
.get_active_text()
|
||||||
};
|
.unwrap_or(String::from("Master")),
|
||||||
|
};
|
||||||
|
|
||||||
// TODO don't convert like that
|
// TODO don't convert like that
|
||||||
let vol_meter_color = VolColor {
|
let vol_meter_color = VolColor {
|
||||||
@ -200,16 +163,19 @@ impl PrefsDialog {
|
|||||||
vol_meter_color,
|
vol_meter_color,
|
||||||
};
|
};
|
||||||
|
|
||||||
let vol_control_cmd = self.vol_control_entry.get_text().and_then(|x| {
|
let vol_control_cmd =
|
||||||
if x.is_empty() { None } else { Some(x) }
|
self.vol_control_entry.get_text().and_then(|x| if x.is_empty() {
|
||||||
});
|
None
|
||||||
|
} else {
|
||||||
|
Some(x)
|
||||||
|
});
|
||||||
|
|
||||||
let custom_command =
|
let custom_command =
|
||||||
self.custom_entry.get_text().and_then(|x| if x.is_empty() {
|
self.custom_entry.get_text().and_then(|x| if x.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(x)
|
Some(x)
|
||||||
});
|
});
|
||||||
|
|
||||||
let behavior_prefs = BehaviorPrefs {
|
let behavior_prefs = BehaviorPrefs {
|
||||||
vol_control_cmd,
|
vol_control_cmd,
|
||||||
@ -221,25 +187,28 @@ impl PrefsDialog {
|
|||||||
let notify_prefs = NotifyPrefs {
|
let notify_prefs = NotifyPrefs {
|
||||||
enable_notifications: self.noti_enable_check.get_active(),
|
enable_notifications: self.noti_enable_check.get_active(),
|
||||||
notifcation_timeout: self.noti_timeout_spin.get_value_as_int() as
|
notifcation_timeout: self.noti_timeout_spin.get_value_as_int() as
|
||||||
i64,
|
i64,
|
||||||
notify_mouse_scroll: self.noti_mouse_check.get_active(),
|
notify_mouse_scroll: self.noti_mouse_check.get_active(),
|
||||||
notify_popup: self.noti_popup_check.get_active(),
|
notify_popup: self.noti_popup_check.get_active(),
|
||||||
notify_external: self.noti_ext_check.get_active(),
|
notify_external: self.noti_ext_check.get_active(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return Prefs {
|
return Prefs {
|
||||||
device_prefs,
|
device_prefs,
|
||||||
view_prefs,
|
view_prefs,
|
||||||
behavior_prefs,
|
behavior_prefs,
|
||||||
notify_prefs,
|
notify_prefs,
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn show_prefs_dialog(appstate: &Rc<AppS>) {
|
pub fn show_prefs_dialog(appstate: &Rc<AppS>) {
|
||||||
if appstate.gui.prefs_dialog.borrow().is_some() {
|
if appstate.gui
|
||||||
|
.prefs_dialog
|
||||||
|
.borrow()
|
||||||
|
.is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,6 +229,22 @@ pub fn show_prefs_dialog(appstate: &Rc<AppS>) {
|
|||||||
|
|
||||||
/* TODO: do the references get dropped when the dialog window is gone? */
|
/* TODO: do the references get dropped when the dialog window is gone? */
|
||||||
pub fn init_prefs_dialog(appstate: &Rc<AppS>) {
|
pub fn init_prefs_dialog(appstate: &Rc<AppS>) {
|
||||||
|
/* audio.connect_handler */
|
||||||
|
{
|
||||||
|
let apps = appstate.clone();
|
||||||
|
appstate.audio.connect_handler(Box::new(move |s, u| {
|
||||||
|
match (s, u) {
|
||||||
|
(AudioSignal::CardInitialized, _) => (),
|
||||||
|
(AudioSignal::CardCleanedUp, _) => {
|
||||||
|
fill_card_combo(&apps);
|
||||||
|
fill_chan_combo(&apps, None);
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* prefs_dialog.connect_show */
|
/* prefs_dialog.connect_show */
|
||||||
{
|
{
|
||||||
@ -267,11 +252,30 @@ pub fn init_prefs_dialog(appstate: &Rc<AppS>) {
|
|||||||
let m_pd = appstate.gui.prefs_dialog.borrow();
|
let m_pd = appstate.gui.prefs_dialog.borrow();
|
||||||
let pd = m_pd.as_ref().unwrap();
|
let pd = m_pd.as_ref().unwrap();
|
||||||
pd.prefs_dialog.connect_show(
|
pd.prefs_dialog.connect_show(
|
||||||
move |_| { on_prefs_dialog_show(&apps); },
|
move |_| {
|
||||||
|
fill_card_combo(&apps);
|
||||||
|
fill_chan_combo(&apps, None);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prefs_dialog.connect_show */
|
/* card_combo.connect_changed */
|
||||||
|
{
|
||||||
|
let apps = appstate.clone();
|
||||||
|
let m_cc = appstate.gui.prefs_dialog.borrow();
|
||||||
|
let card_combo = &m_cc.as_ref().unwrap().card_combo;
|
||||||
|
|
||||||
|
card_combo.connect_changed(move |_| {
|
||||||
|
let m_cc = apps.gui.prefs_dialog.borrow();
|
||||||
|
let card_combo = &m_cc.as_ref().unwrap().card_combo;
|
||||||
|
let card_name = card_combo
|
||||||
|
.get_active_text().unwrap();
|
||||||
|
fill_chan_combo(&apps, Some(card_name));
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prefs_dialog.connect_response */
|
||||||
{
|
{
|
||||||
let apps = appstate.clone();
|
let apps = appstate.clone();
|
||||||
let m_pd = appstate.gui.prefs_dialog.borrow();
|
let m_pd = appstate.gui.prefs_dialog.borrow();
|
||||||
@ -298,47 +302,33 @@ pub fn init_prefs_dialog(appstate: &Rc<AppS>) {
|
|||||||
// TODO: update popup, tray_icon, hotkeys, notification and audio
|
// TODO: update popup, tray_icon, hotkeys, notification and audio
|
||||||
try_w!(apps.update_tray_icon());
|
try_w!(apps.update_tray_icon());
|
||||||
try_w!(apps.update_popup_window());
|
try_w!(apps.update_popup_window());
|
||||||
|
{
|
||||||
|
let prefs = apps.prefs.borrow();
|
||||||
|
let card = &prefs.device_prefs.card;
|
||||||
|
let channel = &prefs.device_prefs.channel;
|
||||||
|
try_w!(apps.audio.switch_acard(
|
||||||
|
Some(card.clone()),
|
||||||
|
Some(channel.clone()),
|
||||||
|
AudioUser::PrefsWindow));
|
||||||
|
}
|
||||||
let prefs = apps.prefs.borrow_mut();
|
let prefs = apps.prefs.borrow_mut();
|
||||||
try_w!(prefs.store_config());
|
try_w!(prefs.store_config());
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: fix combo box behavior and filling
|
|
||||||
/* DEVICE TAB */
|
|
||||||
|
|
||||||
/* card_combo.connect_changed */
|
|
||||||
{
|
|
||||||
let apps = appstate.clone();
|
|
||||||
let m_cc = appstate.gui.prefs_dialog.borrow();
|
|
||||||
let card_combo = &m_cc.as_ref().unwrap().card_combo;
|
|
||||||
|
|
||||||
// TODO: refill channel combo
|
|
||||||
card_combo.connect_changed(move |_| { on_card_combo_changed(&apps); });
|
|
||||||
}
|
|
||||||
/* card_combo.connect_changed */
|
|
||||||
{
|
|
||||||
let apps = appstate.clone();
|
|
||||||
let m_cc = appstate.gui.prefs_dialog.borrow();
|
|
||||||
let chan_combo = &m_cc.as_ref().unwrap().chan_combo;
|
|
||||||
|
|
||||||
chan_combo.connect_changed(move |_| { on_chan_combo_changed(&apps); });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn on_prefs_dialog_show(appstate: &AppS) {
|
fn fill_card_combo(appstate: &AppS) {
|
||||||
let m_cc = appstate.gui.prefs_dialog.borrow();
|
let m_cc = appstate.gui.prefs_dialog.borrow();
|
||||||
let card_combo = &m_cc.as_ref().unwrap().card_combo;
|
let card_combo = &m_cc.as_ref().unwrap().card_combo;
|
||||||
let m_cc = appstate.gui.prefs_dialog.borrow();
|
card_combo.remove_all();
|
||||||
let chan_combo = &m_cc.as_ref().unwrap().chan_combo;
|
|
||||||
let acard = appstate.audio.acard.borrow();
|
let acard = appstate.audio.acard.borrow();
|
||||||
|
|
||||||
|
|
||||||
/* set card combo */
|
/* set card combo */
|
||||||
let cur_card_name =
|
let cur_card_name = try_w!(acard.card_name(),
|
||||||
try_w!(acard.card_name(), "Can't get current card name!");
|
"Can't get current card name!");
|
||||||
let available_card_names = get_alsa_card_names();
|
let available_card_names = get_alsa_card_names();
|
||||||
|
|
||||||
/* set_active_id doesn't work, so save the index */
|
/* set_active_id doesn't work, so save the index */
|
||||||
@ -353,12 +343,26 @@ fn on_prefs_dialog_show(appstate: &AppS) {
|
|||||||
|
|
||||||
// TODO, block signal?
|
// TODO, block signal?
|
||||||
card_combo.set_active(c_index);
|
card_combo.set_active(c_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn fill_chan_combo(appstate: &AppS, cardname: Option<String>) {
|
||||||
|
let m_cc = appstate.gui.prefs_dialog.borrow();
|
||||||
|
let chan_combo = &m_cc.as_ref().unwrap().chan_combo;
|
||||||
|
chan_combo.remove_all();
|
||||||
|
|
||||||
|
let cur_acard = appstate.audio.acard.borrow();
|
||||||
|
let card = match cardname {
|
||||||
|
Some(name) => {
|
||||||
|
try_w!(get_alsa_card_by_name(name).from_err())
|
||||||
|
},
|
||||||
|
None => cur_acard.as_ref().card,
|
||||||
|
};
|
||||||
|
|
||||||
/* set chan combo */
|
/* set chan combo */
|
||||||
let cur_chan_name = try_w!(acard.chan_name());
|
let cur_chan_name = try_w!(cur_acard.chan_name());
|
||||||
let available_chan_names = get_selem_names(&acard.mixer);
|
let mixer = try_w!(get_mixer(&card));
|
||||||
|
let available_chan_names = get_selem_names(&mixer);
|
||||||
|
|
||||||
/* set_active_id doesn't work, so save the index */
|
/* set_active_id doesn't work, so save the index */
|
||||||
let mut c_index: i32 = -1;
|
let mut c_index: i32 = -1;
|
||||||
@ -375,53 +379,3 @@ fn on_prefs_dialog_show(appstate: &AppS) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn on_card_combo_changed(appstate: &AppS) {
|
|
||||||
let m_cc = appstate.gui.prefs_dialog.borrow();
|
|
||||||
let card_combo = &m_cc.as_ref().unwrap().card_combo;
|
|
||||||
let m_cc = appstate.gui.prefs_dialog.borrow();
|
|
||||||
let chan_combo = &m_cc.as_ref().unwrap().chan_combo;
|
|
||||||
let active_card_item = try_w!(card_combo.get_active_text().ok_or(
|
|
||||||
"No active Card item found",
|
|
||||||
));
|
|
||||||
let active_chan_item = chan_combo.get_active_id();
|
|
||||||
let cur_card_name = {
|
|
||||||
let acard = appstate.audio.acard.borrow();
|
|
||||||
try_w!(acard.card_name(), "Can't get current card name!")
|
|
||||||
};
|
|
||||||
|
|
||||||
if active_card_item != cur_card_name {
|
|
||||||
appstate.audio.switch_acard(
|
|
||||||
Some(cur_card_name),
|
|
||||||
active_chan_item,
|
|
||||||
AudioUser::PrefsWindow,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn on_chan_combo_changed(appstate: &AppS) {
|
|
||||||
let m_cc = appstate.gui.prefs_dialog.borrow();
|
|
||||||
let card_combo = &m_cc.as_ref().unwrap().card_combo;
|
|
||||||
let m_cc = appstate.gui.prefs_dialog.borrow();
|
|
||||||
let chan_combo = &m_cc.as_ref().unwrap().chan_combo;
|
|
||||||
let active_chan_item = try_w!(chan_combo.get_active_text().ok_or(
|
|
||||||
"No active Chan item found",
|
|
||||||
));
|
|
||||||
let cur_card_name = {
|
|
||||||
let acard = appstate.audio.acard.borrow();
|
|
||||||
acard.card_name().ok()
|
|
||||||
};
|
|
||||||
let cur_chan_name = {
|
|
||||||
let acard = appstate.audio.acard.borrow();
|
|
||||||
try_w!(acard.chan_name())
|
|
||||||
};
|
|
||||||
|
|
||||||
if active_chan_item != cur_chan_name {
|
|
||||||
appstate.audio.switch_acard(
|
|
||||||
cur_card_name,
|
|
||||||
Some(active_chan_item),
|
|
||||||
AudioUser::PrefsWindow,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -45,12 +45,12 @@ impl TrayIcon {
|
|||||||
let status_icon = gtk::StatusIcon::new();
|
let status_icon = gtk::StatusIcon::new();
|
||||||
|
|
||||||
return Ok(TrayIcon {
|
return Ok(TrayIcon {
|
||||||
_cant_construct: (),
|
_cant_construct: (),
|
||||||
volmeter,
|
volmeter,
|
||||||
audio_pix: RefCell::new(audio_pix),
|
audio_pix: RefCell::new(audio_pix),
|
||||||
status_icon,
|
status_icon,
|
||||||
icon_size: Cell::new(ICON_MIN_SIZE),
|
icon_size: Cell::new(ICON_MIN_SIZE),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -78,12 +78,11 @@ impl TrayIcon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn update_all(
|
pub fn update_all(&self,
|
||||||
&self,
|
prefs: &Prefs,
|
||||||
prefs: &Prefs,
|
audio: &Audio,
|
||||||
audio: &Audio,
|
m_size: Option<i32>)
|
||||||
m_size: Option<i32>,
|
-> Result<()> {
|
||||||
) -> Result<()> {
|
|
||||||
match m_size {
|
match m_size {
|
||||||
Some(s) => {
|
Some(s) => {
|
||||||
if s < ICON_MIN_SIZE {
|
if s < ICON_MIN_SIZE {
|
||||||
@ -122,37 +121,30 @@ pub struct VolMeter {
|
|||||||
impl VolMeter {
|
impl VolMeter {
|
||||||
pub fn new(prefs: &Prefs) -> VolMeter {
|
pub fn new(prefs: &Prefs) -> VolMeter {
|
||||||
return VolMeter {
|
return VolMeter {
|
||||||
red: prefs.view_prefs.vol_meter_color.red,
|
red: prefs.view_prefs.vol_meter_color.red,
|
||||||
green: prefs.view_prefs.vol_meter_color.green,
|
green: prefs.view_prefs.vol_meter_color.green,
|
||||||
blue: prefs.view_prefs.vol_meter_color.blue,
|
blue: prefs.view_prefs.vol_meter_color.blue,
|
||||||
x_offset_pct: prefs.view_prefs.vol_meter_offset as i64,
|
x_offset_pct: prefs.view_prefs.vol_meter_offset as i64,
|
||||||
y_offset_pct: 10,
|
y_offset_pct: 10,
|
||||||
/* dynamic */
|
/* dynamic */
|
||||||
width: Cell::new(0),
|
width: Cell::new(0),
|
||||||
row: RefCell::new(vec![]),
|
row: RefCell::new(vec![]),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: cache input pixbuf?
|
// TODO: cache input pixbuf?
|
||||||
fn meter_draw(
|
fn meter_draw(&self,
|
||||||
&self,
|
volume: i64,
|
||||||
volume: i64,
|
pixbuf: &gdk_pixbuf::Pixbuf)
|
||||||
pixbuf: &gdk_pixbuf::Pixbuf,
|
-> Result<gdk_pixbuf::Pixbuf> {
|
||||||
) -> Result<gdk_pixbuf::Pixbuf> {
|
|
||||||
|
|
||||||
ensure!(
|
ensure!(pixbuf.get_colorspace() == GDK_COLORSPACE_RGB,
|
||||||
pixbuf.get_colorspace() == GDK_COLORSPACE_RGB,
|
"Invalid colorspace in pixbuf");
|
||||||
"Invalid colorspace in pixbuf"
|
ensure!(pixbuf.get_bits_per_sample() == 8,
|
||||||
);
|
"Invalid bits per sample in pixbuf");
|
||||||
ensure!(
|
|
||||||
pixbuf.get_bits_per_sample() == 8,
|
|
||||||
"Invalid bits per sample in pixbuf"
|
|
||||||
);
|
|
||||||
ensure!(pixbuf.get_has_alpha(), "No alpha channel in pixbuf");
|
ensure!(pixbuf.get_has_alpha(), "No alpha channel in pixbuf");
|
||||||
ensure!(
|
ensure!(pixbuf.get_n_channels() == 4,
|
||||||
pixbuf.get_n_channels() == 4,
|
"Invalid number of channels in pixbuf");
|
||||||
"Invalid number of channels in pixbuf"
|
|
||||||
);
|
|
||||||
|
|
||||||
let i_width = pixbuf.get_width() as i64;
|
let i_width = pixbuf.get_width() as i64;
|
||||||
let i_height = pixbuf.get_height() as i64;
|
let i_height = pixbuf.get_height() as i64;
|
||||||
@ -161,21 +153,16 @@ impl VolMeter {
|
|||||||
|
|
||||||
let vm_width = i_width / 6;
|
let vm_width = i_width / 6;
|
||||||
let x = (self.x_offset_pct as f64 *
|
let x = (self.x_offset_pct as f64 *
|
||||||
((i_width - vm_width) as f64 / 100.0)) as
|
((i_width - vm_width) as f64 / 100.0)) as i64;
|
||||||
i64;
|
ensure!(x >= 0 && (x + vm_width) <= i_width,
|
||||||
ensure!(
|
"x coordinate invalid: {}",
|
||||||
x >= 0 && (x + vm_width) <= i_width,
|
x);
|
||||||
"x coordinate invalid: {}",
|
|
||||||
x
|
|
||||||
);
|
|
||||||
let y = (self.y_offset_pct as f64 * (i_height as f64 / 100.0)) as i64;
|
let y = (self.y_offset_pct as f64 * (i_height as f64 / 100.0)) as i64;
|
||||||
let vm_height =
|
let vm_height =
|
||||||
((i_height - (y * 2)) as f64 * (volume as f64 / 100.0)) as i64;
|
((i_height - (y * 2)) as f64 * (volume as f64 / 100.0)) as i64;
|
||||||
ensure!(
|
ensure!(y >= 0 && (y + vm_height) <= i_height,
|
||||||
y >= 0 && (y + vm_height) <= i_height,
|
"y coordinate invalid: {}",
|
||||||
"y coordinate invalid: {}",
|
y);
|
||||||
y
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Let's check if the icon width changed, in which case we
|
/* Let's check if the icon width changed, in which case we
|
||||||
* must reinit our internal row of pixels.
|
* must reinit our internal row of pixels.
|
||||||
@ -211,9 +198,8 @@ impl VolMeter {
|
|||||||
let p_index = ((row_offset * rowstride) + col_offset) as usize;
|
let p_index = ((row_offset * rowstride) + col_offset) as usize;
|
||||||
|
|
||||||
let row = self.row.borrow();
|
let row = self.row.borrow();
|
||||||
pixels[p_index..p_index + row.len()].copy_from_slice(
|
pixels[p_index..p_index + row.len()]
|
||||||
row.as_ref(),
|
.copy_from_slice(row.as_ref());
|
||||||
);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -311,11 +297,7 @@ impl AudioPix {
|
|||||||
pub fn init_tray_icon(appstate: Rc<AppS>) {
|
pub fn init_tray_icon(appstate: Rc<AppS>) {
|
||||||
let audio = &appstate.audio;
|
let audio = &appstate.audio;
|
||||||
let tray_icon = &appstate.gui.tray_icon;
|
let tray_icon = &appstate.gui.tray_icon;
|
||||||
try_e!(tray_icon.update_all(
|
try_e!(tray_icon.update_all(&appstate.prefs.borrow_mut(), &audio, None));
|
||||||
&appstate.prefs.borrow_mut(),
|
|
||||||
&audio,
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
|
|
||||||
tray_icon.status_icon.set_visible(true);
|
tray_icon.status_icon.set_visible(true);
|
||||||
|
|
||||||
@ -324,10 +306,9 @@ pub fn init_tray_icon(appstate: Rc<AppS>) {
|
|||||||
let apps = appstate.clone();
|
let apps = appstate.clone();
|
||||||
appstate.audio.connect_handler(
|
appstate.audio.connect_handler(
|
||||||
Box::new(move |s, u| match (s, u) {
|
Box::new(move |s, u| match (s, u) {
|
||||||
(AudioSignal::ValuesChanged, _) => {
|
(_, _) => {
|
||||||
try_w!(apps.gui.tray_icon.update_audio(&apps.audio));
|
try_w!(apps.gui.tray_icon.update_audio(&apps.audio));
|
||||||
}
|
},
|
||||||
_ => (),
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -336,14 +317,10 @@ pub fn init_tray_icon(appstate: Rc<AppS>) {
|
|||||||
{
|
{
|
||||||
let apps = appstate.clone();
|
let apps = appstate.clone();
|
||||||
tray_icon.status_icon.connect_size_changed(move |_, size| {
|
tray_icon.status_icon.connect_size_changed(move |_, size| {
|
||||||
try_wr!(
|
try_wr!(apps.gui.tray_icon.update_all(&apps.prefs.borrow_mut(),
|
||||||
apps.gui.tray_icon.update_all(
|
&apps.audio,
|
||||||
&apps.prefs.borrow_mut(),
|
Some(size)),
|
||||||
&apps.audio,
|
false);
|
||||||
Some(size),
|
|
||||||
),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -351,9 +328,9 @@ pub fn init_tray_icon(appstate: Rc<AppS>) {
|
|||||||
/* tray_icon.connect_activate */
|
/* tray_icon.connect_activate */
|
||||||
{
|
{
|
||||||
let apps = appstate.clone();
|
let apps = appstate.clone();
|
||||||
tray_icon.status_icon.connect_activate(
|
tray_icon.status_icon.connect_activate(move |_| {
|
||||||
move |_| on_tray_icon_activate(&apps),
|
on_tray_icon_activate(&apps)
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* tray_icon.connect_scroll_event */
|
/* tray_icon.connect_scroll_event */
|
||||||
@ -402,10 +379,9 @@ fn on_tray_icon_popup_menu(appstate: &AppS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn on_tray_icon_scroll_event(
|
fn on_tray_icon_scroll_event(appstate: &AppS,
|
||||||
appstate: &AppS,
|
event: &gdk::EventScroll)
|
||||||
event: &gdk::EventScroll,
|
-> bool {
|
||||||
) -> bool {
|
|
||||||
|
|
||||||
let scroll_dir: gdk::ScrollDirection = event.get_direction();
|
let scroll_dir: gdk::ScrollDirection = event.get_direction();
|
||||||
match scroll_dir {
|
match scroll_dir {
|
||||||
@ -422,10 +398,9 @@ fn on_tray_icon_scroll_event(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn on_tray_button_release_event(
|
fn on_tray_button_release_event(appstate: &AppS,
|
||||||
appstate: &AppS,
|
event_button: &gdk::EventButton)
|
||||||
event_button: &gdk::EventButton,
|
-> bool {
|
||||||
) -> bool {
|
|
||||||
let button = event_button.get_button();
|
let button = event_button.get_button();
|
||||||
|
|
||||||
if button != 2 {
|
if button != 2 {
|
||||||
@ -441,17 +416,18 @@ fn on_tray_button_release_event(
|
|||||||
match middle_click_action {
|
match middle_click_action {
|
||||||
&MiddleClickAction::ToggleMute => {
|
&MiddleClickAction::ToggleMute => {
|
||||||
try_wr!(audio.toggle_mute(AudioUser::Popup), false);
|
try_wr!(audio.toggle_mute(AudioUser::Popup), false);
|
||||||
},
|
}
|
||||||
&MiddleClickAction::ShowPreferences => (),
|
&MiddleClickAction::ShowPreferences => (),
|
||||||
&MiddleClickAction::VolumeControl => {
|
&MiddleClickAction::VolumeControl => {
|
||||||
try_wr!(execute_vol_control_command(&appstate.prefs.borrow()), false);
|
try_wr!(execute_vol_control_command(&appstate.prefs.borrow()),
|
||||||
},
|
false);
|
||||||
|
}
|
||||||
&MiddleClickAction::CustomCommand => {
|
&MiddleClickAction::CustomCommand => {
|
||||||
match custom_command {
|
match custom_command {
|
||||||
&Some(ref cmd) => try_wr!(execute_command(cmd.as_str()), false),
|
&Some(ref cmd) => try_wr!(execute_command(cmd.as_str()), false),
|
||||||
&None => warn!("No custom command found"),
|
&None => warn!("No custom command found"),
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user