This commit is contained in:
Julian Ospald 2017-06-29 23:35:39 +02:00
parent fb98506fe3
commit de9afc9469
No known key found for this signature in database
GPG Key ID: 511B62C09D50CD28
8 changed files with 116 additions and 102 deletions

View File

@ -9,4 +9,3 @@ pub struct AppS {
pub builder_popup: gtk::Builder,
}

View File

@ -3,12 +3,14 @@ use alsa::mixer::{Mixer, Selem, SelemId};
use alsa::poll::PollDescriptors;
use alsa_sys;
use errors::*;
use glib;
use glib_sys;
use libc::c_uint;
use libc::pollfd;
use libc::size_t;
use myalsa::*;
use std::mem;
use std::cell::RefCell;
use std::ptr;
use std::u8;
@ -21,15 +23,15 @@ pub struct AlsaCard {
pub mixer: Mixer,
pub selem_id: SelemId,
pub watch_ids: Vec<u32>,
last_action_timestamp: RefCell<i64>,
}
/* TODO: AlsaCard cleanup */
impl AlsaCard {
pub fn new(
card_name: Option<String>,
elem_name: Option<String>,
) -> Result<AlsaCard> {
pub fn new(card_name: Option<String>,
elem_name: Option<String>)
-> Result<AlsaCard> {
let card = {
match card_name {
Some(name) => get_alsa_card_by_name(name)?,
@ -37,31 +39,33 @@ impl AlsaCard {
}
};
let mixer = get_mixer(&card)?;
let selem_id = get_selem_by_name(
&mixer,
elem_name.unwrap_or(String::from("Master")),
).unwrap()
.get_id();
let selem_id =
get_selem_by_name(&mixer,
elem_name.unwrap_or(String::from("Master")))
.unwrap()
.get_id();
let vec_pollfd = PollDescriptors::get(&mixer)?;
/* TODO: callback is registered here, which must be unregistered
* when the mixer is destroyed!! */
* when the mixer is destroyed!!
* poll descriptors must be unwatched too */
let watch_ids = watch_poll_descriptors(vec_pollfd, &mixer);
return Ok(AlsaCard {
_cannot_construct: (),
card: card,
mixer: mixer,
selem_id: selem_id,
watch_ids: watch_ids,
});
_cannot_construct: (),
card: card,
mixer: mixer,
selem_id: selem_id,
watch_ids: watch_ids,
last_action_timestamp: RefCell::new(0),
});
}
pub fn selem(&self) -> Selem {
return get_selems(&self.mixer)
.nth(self.selem_id.get_index() as usize)
.unwrap();
.nth(self.selem_id.get_index() as usize)
.unwrap();
}
@ -70,7 +74,10 @@ impl AlsaCard {
}
pub fn set_vol(&self, new_vol: f64) -> Result<()> {
pub fn set_vol(&self, new_vol: f64, user: AudioUser) -> Result<()> {
let mut rc = self.last_action_timestamp.borrow_mut();
*rc = glib::get_real_time();
// TODO invoke handlers, make use of user
return set_vol(&self.selem(), new_vol);
}
@ -85,9 +92,31 @@ impl AlsaCard {
}
pub fn set_mute(&self, mute: bool) -> Result<()> {
pub fn set_mute(&self, mute: bool, user: AudioUser) -> Result<()> {
let mut rc = self.last_action_timestamp.borrow_mut();
*rc = glib::get_real_time();
// TODO invoke handlers, make use of user
return set_mute(&self.selem(), mute);
}
fn on_alsa_event(&self, alsa_event: AlsaEvent) {
let last: i64 = *self.last_action_timestamp.borrow();
let now: i64 = glib::get_monotonic_time();
let delay = now - last;
if delay < 1000000 {
return;
}
/* external change */
match alsa_event {
// TODO: invoke handlers with AudioUserUnknown
AlsaEvent::AlsaCardError => println!("AlsaCardError"),
AlsaEvent::AlsaCardDiconnected => println!("AlsaCardDiconnected"),
AlsaEvent::AlsaCardValuesChanged => println!("AlsaCardValuesChanged"),
}
}
}
@ -108,15 +137,17 @@ enum AudioSignal {
AudioValuesChanged,
}
enum AlsaEvent {
AlsaCardError,
AlsaCardDiconnected,
AlsaCardValuesChanged,
}
fn watch_poll_descriptors(
polls: Vec<pollfd>,
mixer: &Mixer,
) -> Vec<c_uint> {
fn watch_poll_descriptors(polls: Vec<pollfd>, mixer: &Mixer) -> Vec<c_uint> {
let mut watch_ids: Vec<c_uint> = vec![];
let mixer_ptr = unsafe {
mem::transmute::<&Mixer, &*mut alsa_sys::snd_mixer_t>(mixer)
};
let mixer_ptr =
unsafe { mem::transmute::<&Mixer, &*mut alsa_sys::snd_mixer_t>(mixer) };
for poll in polls {
unsafe {
let gioc: *mut glib_sys::GIOChannel =
@ -136,11 +167,10 @@ fn watch_poll_descriptors(
}
extern fn watch_cb(
chan: *mut glib_sys::GIOChannel,
cond: glib_sys::GIOCondition,
data: glib_sys::gpointer,
) -> glib_sys::gboolean {
extern "C" fn watch_cb(chan: *mut glib_sys::GIOChannel,
cond: glib_sys::GIOCondition,
data: glib_sys::gpointer)
-> glib_sys::gboolean {
let mixer = data as *mut alsa_sys::snd_mixer_t;
@ -156,21 +186,20 @@ extern fn watch_cb(
let mut buf: Vec<u8> = vec![0; 256];
while sread > 0 {
let stat: glib_sys::GIOStatus = unsafe {
glib_sys::g_io_channel_read_chars(
chan,
buf.as_mut_ptr() as *mut u8,
256,
&mut sread as *mut size_t,
ptr::null_mut(),
)
};
let stat: glib_sys::GIOStatus =
unsafe {
glib_sys::g_io_channel_read_chars(chan,
buf.as_mut_ptr() as *mut u8,
256,
&mut sread as *mut size_t,
ptr::null_mut())
};
match stat {
glib_sys::G_IO_STATUS_AGAIN => {
println!("G_IO_STATUS_AGAIN");
continue
},
continue;
}
glib_sys::G_IO_STATUS_NORMAL => println!("G_IO_STATUS_NORMAL"),
glib_sys::G_IO_STATUS_ERROR => println!("G_IO_STATUS_ERROR"),
glib_sys::G_IO_STATUS_EOF => println!("G_IO_STATUS_EOF"),
@ -182,4 +211,3 @@ extern fn watch_cb(
return true as glib_sys::gboolean;
}

View File

@ -79,4 +79,3 @@ macro_rules! try_r {
},
});
}

View File

@ -13,6 +13,7 @@ extern crate alsa_sys;
extern crate ffi;
extern crate gdk;
extern crate gdk_sys;
extern crate glib;
extern crate glib_sys;
extern crate gtk;
extern crate gtk_sys;
@ -41,14 +42,12 @@ fn main() {
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 acard = Rc::new(RefCell::new(
AlsaCard::new(None, Some(String::from("Master"))).unwrap(),
));
let acard = Rc::new(RefCell::new(AlsaCard::new(None,
Some(String::from("Master")))
.unwrap()));
flexi_logger::LogOptions::new()
.log_to_file(false)

View File

@ -56,7 +56,9 @@ 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> {
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);
@ -97,9 +99,7 @@ pub fn set_vol(selem: &Selem, new_vol: f64) -> Result<()> {
}
let range = selem.get_playback_volume_range();
selem.set_playback_volume_all(
percent_to_vol(new_vol, range),
)?;
selem.set_playback_volume_all(percent_to_vol(new_vol, range))?;
return Ok(());
}
@ -121,4 +121,3 @@ pub fn set_mute(selem: &Selem, mute: bool) -> Result<()> {
let _ = selem.set_playback_switch_all(!mute as i32)?;
return Ok(());
}

View File

@ -12,4 +12,3 @@ pub fn init<'a>(appstate: &'a AppS, rc_acard: Rc<RefCell<AlsaCard>>) {
init_tray_icon(&appstate);
init_popup_window(&appstate, rc_acard);
}

View File

@ -1,5 +1,6 @@
use app_state::*;
use audio::AlsaCard;
use audio::AudioUser::*;
use errors::*;
use gdk::DeviceExt;
use gdk::{GrabOwnership, GrabStatus, BUTTON_PRESS_MASK, KEY_PRESS_MASK};
@ -43,18 +44,18 @@ pub fn init_popup_window(appstate: &AppS, rc_acard: Rc<RefCell<AlsaCard>>) {
/* vol_scale_adj.connect_value_changed */
{
let vol_scale_adj: Rc<gtk::Adjustment> =
Rc::new(
appstate.builder_popup.get_object("vol_scale_adj").unwrap(),
);
Rc::new(appstate.builder_popup
.get_object("vol_scale_adj")
.unwrap());
let card = rc_acard.clone();
let vol_scale = vol_scale_adj.clone();
vol_scale_adj.connect_value_changed(move |_| {
let acard = card.borrow();
let val = vol_scale.get_value();
let acard = card.borrow();
let val = vol_scale.get_value();
try_w!(acard.set_vol(val));
});
try_w!(acard.set_vol(val, AudioUserPopup));
});
}
/* mute_check.connect_toggled */
@ -64,11 +65,11 @@ pub fn init_popup_window(appstate: &AppS, rc_acard: Rc<RefCell<AlsaCard>>) {
let card = rc_acard.clone();
mute_check.connect_toggled(move |_| {
let acard = card.borrow();
let acard = card.borrow();
let muted = try_w!(acard.get_mute());
let _ = try_w!(acard.set_mute(!muted));
});
let muted = try_w!(acard.get_mute());
let _ = try_w!(acard.set_mute(!muted, AudioUserPopup));
});
}
/* popup_window.connect_event */
@ -133,42 +134,33 @@ fn grab_devices(window: &gtk::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(());
}

View File

@ -12,10 +12,9 @@ pub fn init_tray_icon(appstate: &AppS) {
appstate.builder_popup.get_object("popup_window").unwrap();
tray_icon.connect_activate(move |_| if popup_window.get_visible() {
popup_window.hide();
} else {
popup_window.show_now();
});
popup_window.hide();
} else {
popup_window.show_now();
});
tray_icon.set_visible(true);
}