This commit is contained in:
Ospald, Julian 2017-06-28 14:55:38 +02:00
parent 0daff4d6b8
commit 6504c5c5ab
5 changed files with 127 additions and 72 deletions

View File

@ -1,8 +1,9 @@
use gtk; use gtk;
use alsa::card::Card; use alsa::card::Card;
use alsa::mixer::{Mixer, Selem}; use alsa::mixer::{Mixer, SelemId, Selem};
use std::cell::Cell; use audio;
use errors::*;
pub struct AppS { pub struct AppS {
/* we keep this to ensure the lifetime is across the whole application */ /* 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 builder_popup: gtk::Builder,
} }
pub struct AlsaCard<'a> { pub struct AlsaCard {
pub card: Cell<Card>, card: Card,
pub mixer: Cell<Mixer>, mixer: Mixer,
pub selem: Cell<Selem<'a>>, selem_id: SelemId,
} }
impl AlsaCard {
pub fn new(
card_name: Option<String>,
elem_name: Option<String>,
) -> Result<AlsaCard> {
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<f64> {
return audio::get_vol(&self.selem());
}
pub fn has_mute(&self) -> bool {
return audio::has_mute(&self.selem());
}
pub fn get_mute(&self) -> Result<bool> {
return audio::get_mute(&self.selem());
}
pub fn set_mute(&self, mute: bool) -> Result<()> {
return audio::set_mute(&self.selem(), mute);
}
}

View File

@ -23,6 +23,17 @@ pub fn get_alsa_cards() -> alsa::card::Iter {
return alsa::card::Iter::new(); return alsa::card::Iter::new();
} }
pub fn get_alsa_card_by_name(name: String) -> Result<Card> {
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<Mixer> { pub fn get_mixer(card: &Card) -> Result<Mixer> {
return Mixer::new(&format!("hw:{}", card.get_index()), false).cherr(); return Mixer::new(&format!("hw:{}", card.get_index()), false).cherr();
} }
@ -40,9 +51,7 @@ pub fn get_selems(mixer: &Mixer) -> Map<alsa::mixer::Iter, fn(Elem) -> Selem> {
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() let n = selem.get_id().get_name().map(|y| String::from(y))?;
.get_name()
.map(|y| String::from(y))?;
if n == name { if n == name {
return Ok(selem); 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)?; let _ = selem.set_playback_switch_all(!mute as i32)?;
return Ok(()); return Ok(());
} }

View File

@ -23,32 +23,40 @@ pub fn grab_devices(window: &gtk::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 = let m_grab_status = device.grab(
device.grab(&gdk_window, &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!("Could not grab {}", warn!(
device.get_name().unwrap_or(String::from("UNKNOWN DEVICE"))); "Could not grab {}",
device.get_name().unwrap_or(String::from("UNKNOWN DEVICE"))
);
} }
/* Grab the keyboard */ /* Grab the keyboard */
let k_dev = device.get_associated_device() let k_dev = device.get_associated_device().ok_or(
.ok_or("Couldn't get associated device")?; "Couldn't get associated device",
)?;
let k_grab_status = k_dev.grab(&gdk_window, let k_grab_status = k_dev.grab(
GrabOwnership::None, &gdk_window,
true, GrabOwnership::None,
KEY_PRESS_MASK, true,
None, KEY_PRESS_MASK,
GDK_CURRENT_TIME as u32); None,
GDK_CURRENT_TIME as u32,
);
if k_grab_status != GrabStatus::Success { if k_grab_status != GrabStatus::Success {
warn!("Could not grab {}", warn!(
k_dev.get_name().unwrap_or(String::from("UNKNOWN DEVICE"))); "Could not grab {}",
k_dev.get_name().unwrap_or(String::from("UNKNOWN DEVICE"))
);
} }
return Ok(()); return Ok(());

View File

@ -9,15 +9,16 @@ use gtk::prelude::*;
use gdk_sys::GDK_KEY_Escape; use gdk_sys::GDK_KEY_Escape;
use gui; use gui;
use audio;
use app_state::*; use app_state::*;
use errors::*; 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<RefCell<AlsaCard>>) {
init_tray_icon(&appstate); 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(); appstate.builder_popup.get_object("vol_scale").unwrap();
tray_icon.connect_activate(move |_| if popup_window.get_visible() { tray_icon.connect_activate(move |_| if popup_window.get_visible() {
popup_window.hide(); popup_window.hide();
} else { } else {
popup_window.show_now(); popup_window.show_now();
vol_scale.grab_focus(); vol_scale.grab_focus();
try_w!(gui::grab_devices(&popup_window)); try_w!(gui::grab_devices(&popup_window));
}); });
tray_icon.set_visible(true); tray_icon.set_visible(true);
} }
fn init_popup_window(appstate: &AppS) { fn init_popup_window(appstate: &AppS, rc_acard: Rc<RefCell<AlsaCard>>) {
/* popup_window.connect_show */ /* popup_window.connect_show */
{ {
let popup_window: gtk::Window = let popup_window: gtk::Window =
@ -50,17 +51,14 @@ fn init_popup_window(appstate: &AppS) {
let mute_check: gtk::CheckButton = let mute_check: gtk::CheckButton =
appstate.builder_popup.get_object("mute_check").unwrap(); appstate.builder_popup.get_object("mute_check").unwrap();
let card = rc_acard.clone();
popup_window.connect_show(move |_| { popup_window.connect_show(move |_| {
let alsa_card = audio::get_default_alsa_card(); let acard = card.borrow();
let mixer = try_w!(audio::get_mixer(&alsa_card));
let selem = try_w!(audio::get_selem_by_name( let cur_vol = try_w!(acard.vol());
&mixer,
String::from("Master"),
));
let cur_vol = try_w!(audio::get_vol(&selem));
gui::set_slider(&vol_scale_adj, cur_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); update_mute_check(&mute_check, muted);
}); });
} }
@ -70,16 +68,12 @@ fn init_popup_window(appstate: &AppS) {
let mute_check: gtk::CheckButton = let mute_check: gtk::CheckButton =
appstate.builder_popup.get_object("mute_check").unwrap(); appstate.builder_popup.get_object("mute_check").unwrap();
let card = rc_acard.clone();
mute_check.connect_toggled(move |_| { mute_check.connect_toggled(move |_| {
let alsa_card = audio::get_default_alsa_card(); let acard = card.borrow();
let mixer = try_w!(audio::get_mixer(&alsa_card));
let selem = try_w!(audio::get_selem_by_name(
&mixer,
String::from("Master"),
));
let muted = try_w!(audio::get_mute(&selem)); let muted = try_w!(acard.get_mute());
let _ = try_w!(audio::set_mute(&selem, !muted)); let _ = try_w!(acard.set_mute(!muted));
}); });
} }
@ -122,7 +116,7 @@ fn update_mute_check(check_button: &gtk::CheckButton, muted: Result<bool>) {
Ok(val) => { Ok(val) => {
check_button.set_active(val); check_button.set_active(val);
check_button.set_tooltip_text(""); check_button.set_tooltip_text("");
}, }
Err(_) => { Err(_) => {
/* can't figure out whether channel is muted, grey out */ /* can't figure out whether channel is muted, grey out */
check_button.set_active(true); check_button.set_active(true);
@ -131,4 +125,3 @@ fn update_mute_check(check_button: &gtk::CheckButton, muted: Result<bool>) {
} }
} }
} }

View File

@ -14,7 +14,8 @@ extern crate alsa;
use gtk::prelude::*; use gtk::prelude::*;
use gdk_sys::GDK_KEY_Escape; use gdk_sys::GDK_KEY_Escape;
use app_state::*; use app_state::*;
use std::cell::Cell; use std::cell::RefCell;
use std::rc::Rc;
use std::boxed::Box; use std::boxed::Box;
@ -27,26 +28,23 @@ mod gui_callbacks;
mod app_state; mod app_state;
fn main() { fn main() {
gtk::init().unwrap(); gtk::init().unwrap();
let ref apps = AppS { let ref apps = AppS {
status_icon: gtk::StatusIcon::new_from_icon_name("pnmixer"), 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 acard = Rc::new(RefCell::new(
let mixer = audio::get_mixer(&alsa_card).unwrap(); AlsaCard::new(
let selem = audio::get_selem_by_name( Some(String::from("Intel 82801AA-ICH")),
&mixer, Some(String::from("Master")),
String::from("Master"), ).unwrap(),
).unwrap(); ));
let ref acard = AlsaCard {
card: Cell::new(alsa_card),
mixer: Cell::new(mixer),
selem: Cell::new(selem),
};
flexi_logger::LogOptions::new() flexi_logger::LogOptions::new()
.log_to_file(false) .log_to_file(false)
@ -55,7 +53,7 @@ fn main() {
.unwrap_or_else(|e| panic!("Logger initialization failed with {}", e)); .unwrap_or_else(|e| panic!("Logger initialization failed with {}", e));
gui_callbacks::init(apps); gui_callbacks::init(apps, acard);
gtk::main(); gtk::main();
} }