diff --git a/src/app_state.rs b/src/app_state.rs index 3b76822c6..1813314f5 100644 --- a/src/app_state.rs +++ b/src/app_state.rs @@ -1,8 +1,9 @@ use gtk; use alsa::card::Card; -use alsa::mixer::{Mixer, Selem}; -use std::cell::Cell; +use alsa::mixer::{Mixer, SelemId, Selem}; +use audio; +use errors::*; pub struct AppS { /* we keep this to ensure the lifetime is across the whole application */ @@ -11,9 +12,56 @@ pub struct AppS { pub builder_popup: gtk::Builder, } -pub struct AlsaCard<'a> { - pub card: Cell, - pub mixer: Cell, - pub selem: Cell>, +pub struct AlsaCard { + card: Card, + mixer: Mixer, + selem_id: SelemId, } +impl AlsaCard { + pub fn new( + card_name: Option, + elem_name: Option, + ) -> Result { + let card = { + match card_name { + Some(name) => audio::get_alsa_card_by_name(name)?, + None => audio::get_default_alsa_card(), + } + }; + let mixer = audio::get_mixer(&card)?; + let selem_id = audio::get_selem_by_name( + &mixer, + elem_name.unwrap_or(String::from("Master")), + ).unwrap() + .get_id(); + + return Ok(AlsaCard { + card: card, + mixer: mixer, + selem_id: selem_id, + }); + } + + pub fn selem(&self) -> Selem { + return audio::get_selems(&self.mixer) + .nth(self.selem_id.get_index() as usize) + .unwrap(); + } + + pub fn vol(&self) -> Result { + return audio::get_vol(&self.selem()); + } + + pub fn has_mute(&self) -> bool { + return audio::has_mute(&self.selem()); + } + + pub fn get_mute(&self) -> Result { + return audio::get_mute(&self.selem()); + } + + pub fn set_mute(&self, mute: bool) -> Result<()> { + return audio::set_mute(&self.selem(), mute); + } +} diff --git a/src/audio.rs b/src/audio.rs index 46914c15c..81097fe9a 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -23,6 +23,17 @@ pub fn get_alsa_cards() -> alsa::card::Iter { return alsa::card::Iter::new(); } +pub fn get_alsa_card_by_name(name: String) -> Result { + for r_card in get_alsa_cards() { + let card = r_card?; + let card_name = card.get_name()?; + if name == card_name { + return Ok(card); + } + } + bail!("Not found a matching card named {}", name); +} + pub fn get_mixer(card: &Card) -> Result { return Mixer::new(&format!("hw:{}", card.get_index()), false).cherr(); } @@ -40,9 +51,7 @@ pub fn get_selems(mixer: &Mixer) -> Map Selem> { pub fn get_selem_by_name(mixer: &Mixer, name: String) -> Result { 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 { return Ok(selem); @@ -74,4 +83,3 @@ pub fn set_mute(selem: &Selem, mute: bool) -> Result<()> { let _ = selem.set_playback_switch_all(!mute as i32)?; return Ok(()); } - diff --git a/src/gui.rs b/src/gui.rs index 9d2a82fbf..8faa90b1f 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -23,32 +23,40 @@ pub fn grab_devices(window: >k::Window) -> Result<()> { let gdk_window = window.get_window().ok_or("No window?!")?; /* Grab the mouse */ - let m_grab_status = - device.grab(&gdk_window, - GrabOwnership::None, - true, - BUTTON_PRESS_MASK, - None, - GDK_CURRENT_TIME as u32); + let m_grab_status = device.grab( + &gdk_window, + GrabOwnership::None, + true, + BUTTON_PRESS_MASK, + None, + GDK_CURRENT_TIME as u32, + ); if m_grab_status != GrabStatus::Success { - warn!("Could not grab {}", - device.get_name().unwrap_or(String::from("UNKNOWN DEVICE"))); + warn!( + "Could not grab {}", + device.get_name().unwrap_or(String::from("UNKNOWN DEVICE")) + ); } /* Grab the keyboard */ - let k_dev = device.get_associated_device() - .ok_or("Couldn't get associated device")?; + let k_dev = device.get_associated_device().ok_or( + "Couldn't get associated device", + )?; - let k_grab_status = k_dev.grab(&gdk_window, - GrabOwnership::None, - true, - KEY_PRESS_MASK, - None, - GDK_CURRENT_TIME as u32); + let k_grab_status = k_dev.grab( + &gdk_window, + GrabOwnership::None, + true, + KEY_PRESS_MASK, + None, + GDK_CURRENT_TIME as u32, + ); if k_grab_status != GrabStatus::Success { - warn!("Could not grab {}", - k_dev.get_name().unwrap_or(String::from("UNKNOWN DEVICE"))); + warn!( + "Could not grab {}", + k_dev.get_name().unwrap_or(String::from("UNKNOWN DEVICE")) + ); } return Ok(()); diff --git a/src/gui_callbacks.rs b/src/gui_callbacks.rs index 847cfcbea..c64e96e3d 100644 --- a/src/gui_callbacks.rs +++ b/src/gui_callbacks.rs @@ -9,15 +9,16 @@ use gtk::prelude::*; use gdk_sys::GDK_KEY_Escape; use gui; -use audio; use app_state::*; use errors::*; +use std::cell::RefCell; +use std::rc::Rc; -pub fn init<'a>(appstate: &'a AppS) { +pub fn init<'a>(appstate: &'a AppS, rc_acard: Rc>) { init_tray_icon(&appstate); - init_popup_window(&appstate); + init_popup_window(&appstate, rc_acard); } @@ -31,16 +32,16 @@ fn init_tray_icon(appstate: &AppS) { appstate.builder_popup.get_object("vol_scale").unwrap(); tray_icon.connect_activate(move |_| if popup_window.get_visible() { - popup_window.hide(); - } else { - popup_window.show_now(); - vol_scale.grab_focus(); - try_w!(gui::grab_devices(&popup_window)); - }); + popup_window.hide(); + } else { + popup_window.show_now(); + vol_scale.grab_focus(); + try_w!(gui::grab_devices(&popup_window)); + }); tray_icon.set_visible(true); } -fn init_popup_window(appstate: &AppS) { +fn init_popup_window(appstate: &AppS, rc_acard: Rc>) { /* popup_window.connect_show */ { let popup_window: gtk::Window = @@ -50,17 +51,14 @@ fn init_popup_window(appstate: &AppS) { let mute_check: gtk::CheckButton = appstate.builder_popup.get_object("mute_check").unwrap(); + let card = rc_acard.clone(); popup_window.connect_show(move |_| { - let alsa_card = audio::get_default_alsa_card(); - let mixer = try_w!(audio::get_mixer(&alsa_card)); - let selem = try_w!(audio::get_selem_by_name( - &mixer, - String::from("Master"), - )); - let cur_vol = try_w!(audio::get_vol(&selem)); + let acard = card.borrow(); + + let cur_vol = try_w!(acard.vol()); gui::set_slider(&vol_scale_adj, cur_vol); - let muted = audio::get_mute(&selem); + let muted = acard.get_mute(); update_mute_check(&mute_check, muted); }); } @@ -70,16 +68,12 @@ fn init_popup_window(appstate: &AppS) { let mute_check: gtk::CheckButton = appstate.builder_popup.get_object("mute_check").unwrap(); + let card = rc_acard.clone(); mute_check.connect_toggled(move |_| { - let alsa_card = audio::get_default_alsa_card(); - let mixer = try_w!(audio::get_mixer(&alsa_card)); - let selem = try_w!(audio::get_selem_by_name( - &mixer, - String::from("Master"), - )); + let acard = card.borrow(); - let muted = try_w!(audio::get_mute(&selem)); - let _ = try_w!(audio::set_mute(&selem, !muted)); + let muted = try_w!(acard.get_mute()); + let _ = try_w!(acard.set_mute(!muted)); }); } @@ -122,7 +116,7 @@ fn update_mute_check(check_button: >k::CheckButton, muted: Result) { Ok(val) => { check_button.set_active(val); check_button.set_tooltip_text(""); - }, + } Err(_) => { /* can't figure out whether channel is muted, grey out */ check_button.set_active(true); @@ -131,4 +125,3 @@ fn update_mute_check(check_button: >k::CheckButton, muted: Result) { } } } - diff --git a/src/main.rs b/src/main.rs index a1ebc2965..4bd9e4460 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,8 @@ extern crate alsa; use gtk::prelude::*; use gdk_sys::GDK_KEY_Escape; use app_state::*; -use std::cell::Cell; +use std::cell::RefCell; +use std::rc::Rc; use std::boxed::Box; @@ -27,26 +28,23 @@ mod gui_callbacks; mod app_state; + fn main() { gtk::init().unwrap(); let ref apps = AppS { status_icon: gtk::StatusIcon::new_from_icon_name("pnmixer"), - builder_popup: gtk::Builder::new_from_string(include_str!("../data/ui/popup-window-vertical.glade")), + builder_popup: gtk::Builder::new_from_string( + include_str!("../data/ui/popup-window-vertical.glade"), + ), }; - let alsa_card = audio::get_default_alsa_card(); - let mixer = audio::get_mixer(&alsa_card).unwrap(); - let selem = audio::get_selem_by_name( - &mixer, - String::from("Master"), - ).unwrap(); - - let ref acard = AlsaCard { - card: Cell::new(alsa_card), - mixer: Cell::new(mixer), - selem: Cell::new(selem), - }; + let acard = Rc::new(RefCell::new( + AlsaCard::new( + Some(String::from("Intel 82801AA-ICH")), + Some(String::from("Master")), + ).unwrap(), + )); flexi_logger::LogOptions::new() .log_to_file(false) @@ -55,7 +53,7 @@ fn main() { .unwrap_or_else(|e| panic!("Logger initialization failed with {}", e)); - gui_callbacks::init(apps); + gui_callbacks::init(apps, acard); gtk::main(); }