This commit is contained in:
Julian Ospald 2017-06-30 21:10:33 +02:00
parent 7be3d97d7b
commit f2fcdd3cd7
No known key found for this signature in database
GPG Key ID: 511B62C09D50CD28
6 changed files with 184 additions and 200 deletions

View File

@ -15,15 +15,12 @@ pub struct AppS {
impl AppS {
pub fn new() -> AppS {
let builder_popup = gtk::Builder::new_from_string(include_str!(
"../data/ui/popup-window-vertical.glade"
));
let builder_popup = gtk::Builder::new_from_string(include_str!("../data/ui/popup-window-vertical.glade"));
return AppS {
gui: Gui::new(builder_popup),
acard: Rc::new(RefCell::new(
AlsaCard::new(None, Some(String::from("Master"))).unwrap(),
)),
};
gui: Gui::new(builder_popup),
acard: AlsaCard::new(None, Some(String::from("Master")))
.unwrap(),
};
}
}
@ -37,9 +34,9 @@ pub struct Gui {
impl Gui {
pub fn new(builder: gtk::Builder) -> Gui {
return Gui {
status_icon: gtk::StatusIcon::new_from_icon_name("pnmixer"),
popup_window: PopupWindow::new(builder),
};
status_icon: gtk::StatusIcon::new_from_icon_name("pnmixer"),
popup_window: PopupWindow::new(builder),
};
}
}
@ -55,10 +52,10 @@ pub struct PopupWindow {
impl PopupWindow {
pub fn new(builder: gtk::Builder) -> PopupWindow {
return PopupWindow {
window: builder.get_object("popup_window").unwrap(),
vol_scale_adj: builder.get_object("vol_scale_adj").unwrap(),
vol_scale: builder.get_object("vol_scale").unwrap(),
mute_check: builder.get_object("mute_check").unwrap(),
};
window: builder.get_object("popup_window").unwrap(),
vol_scale_adj: builder.get_object("vol_scale_adj").unwrap(),
vol_scale: builder.get_object("vol_scale").unwrap(),
mute_check: builder.get_object("mute_check").unwrap(),
};
}
}

View File

@ -9,10 +9,11 @@ use libc::c_uint;
use libc::pollfd;
use libc::size_t;
use myalsa::*;
use std::mem;
use std::cell::RefCell;
use std::cell::Ref;
use std::cell::RefCell;
use std::mem;
use std::ptr;
use std::rc::Rc;
use std::u8;
@ -31,10 +32,9 @@ pub struct AlsaCard {
/* 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<Rc<RefCell<AlsaCard>>> {
let card = {
match card_name {
Some(name) => get_alsa_card_by_name(name)?,
@ -42,41 +42,39 @@ 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)?;
let mut acard = AlsaCard {
_cannot_construct: (),
card: card,
mixer: mixer,
selem_id: selem_id,
watch_ids: vec![],
last_action_timestamp: RefCell::new(0),
handlers: RefCell::new(vec![]),
};
let acard = Rc::new(RefCell::new(AlsaCard {
_cannot_construct: (),
card: card,
mixer: mixer,
selem_id: selem_id,
watch_ids: vec![],
last_action_timestamp:
RefCell::new(0),
handlers: RefCell::new(vec![]),
}));
/* TODO: callback is registered here, which must be unregistered
* when the mixer is destroyed!!
* poll descriptors must be unwatched too */
let watch_ids = watch_poll_descriptors(vec_pollfd, &acard);
// acard.watch_ids = watch_ids;
let watch_ids = watch_poll_descriptors(vec_pollfd,
acard.clone().as_ptr());
acard.borrow_mut().watch_ids = watch_ids;
// println!("Watch IDs: {:?}", acard.watch_ids);
println!("Last_Timestamp: {}", acard.last_action_timestamp.borrow());
return Ok(acard);
return Ok(acard.clone());
}
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();
}
@ -89,9 +87,7 @@ impl AlsaCard {
{
let mut rc = self.last_action_timestamp.borrow_mut();
*rc = glib::get_monotonic_time();
println!("glib::get_monotonic_time: {}", glib::get_real_time());
}
println!("Now timestamp: {}", self.last_action_timestamp.borrow());
// TODO invoke handlers, make use of user
return set_vol(&self.selem(), new_vol);
}
@ -116,31 +112,27 @@ impl AlsaCard {
fn on_alsa_event(&self, alsa_event: AlsaEvent) {
// let last: i64 = *Ref::clone(&self.last_action_timestamp.borrow());
// if last != 0 {
// let now: i64 = glib::get_monotonic_time();
// let delay: i64 = now - last;
// if delay < 1000000 {
// println!("Too short: {} and {}", now, last);
// println!("Delay: {}", delay);
// return;
// }
// *self.last_action_timestamp.borrow_mut() = 0;
// }
let last: i64 = *Ref::clone(&self.last_action_timestamp.borrow());
if last != 0 {
let now: i64 = glib::get_monotonic_time();
let delay: i64 = now - last;
if delay < 1000000 {
info!("Delay: {}", delay);
return;
}
*self.last_action_timestamp.borrow_mut() = 0;
}
/* external change */
match alsa_event {
// TODO: invoke handlers with AudioUserUnknown
AlsaEvent::AlsaCardError => println!("AlsaCardError"),
AlsaEvent::AlsaCardDiconnected => println!("AlsaCardDiconnected"),
AlsaEvent::AlsaCardError => info!("AlsaCardError"),
AlsaEvent::AlsaCardDiconnected => info!("AlsaCardDiconnected"),
AlsaEvent::AlsaCardValuesChanged => {
println!("AlsaCardValuesChanged");
self.invoke_handlers(
self::AudioSignal::AudioValuesChanged,
self::AudioUser::AudioUserUnknown,
);
info!("AlsaCardValuesChanged");
self.invoke_handlers(self::AudioSignal::AudioValuesChanged,
self::AudioUser::AudioUserUnknown);
}
}
@ -149,31 +141,18 @@ impl AlsaCard {
fn invoke_handlers(&self, signal: AudioSignal, user: AudioUser) {
let mut vec = vec![1,2,3];
for v in &vec {
println!("Elem: {}", v);
}
let handlers = self.handlers.borrow();
let x: &Vec<Box<Fn(&AlsaCard, AudioSignal, AudioUser)>> = &*handlers;
println!("Vec size: {}", handlers.capacity());
// for handler in x {
// // let unboxed = handler.as_ref();
// // unboxed(&self, signal, user);
// println!("Gogo");
// }
for handler in x {
let unboxed = handler.as_ref();
unboxed(&self, signal, user);
}
}
pub fn connect_handler(
&self,
cb: Box<Fn(&AlsaCard, AudioSignal, AudioUser)>,
) {
println!("Vec size before: {}", self.handlers.borrow().capacity());
pub fn connect_handler(&self,
cb: Box<Fn(&AlsaCard, AudioSignal, AudioUser)>) {
self.handlers.borrow_mut().push(cb);
println!("Vec size after: {}", self.handlers.borrow().capacity());
}
}
@ -206,45 +185,51 @@ pub enum AlsaEvent {
}
fn watch_poll_descriptors(polls: Vec<pollfd>, acard: &AlsaCard) -> Vec<c_uint> {
fn watch_poll_descriptors(polls: Vec<pollfd>,
acard: *mut AlsaCard)
-> Vec<c_uint> {
let mut watch_ids: Vec<c_uint> = vec![];
let acard_ptr =
unsafe { mem::transmute::<&AlsaCard, &glib_sys::gpointer>(acard) };
unsafe { mem::transmute::<*mut AlsaCard, glib_sys::gpointer>(acard) };
for poll in polls {
unsafe {
let gioc: *mut glib_sys::GIOChannel =
glib_sys::g_io_channel_unix_new(poll.fd);
watch_ids.push(glib_sys::g_io_add_watch(
let gioc: *mut glib_sys::GIOChannel =
unsafe { glib_sys::g_io_channel_unix_new(poll.fd) };
let id = unsafe {
glib_sys::g_io_add_watch(
gioc,
glib_sys::GIOCondition::from_bits(
glib_sys::G_IO_IN.bits() | glib_sys::G_IO_ERR.bits(),
).unwrap(),
Some(watch_cb),
*acard_ptr,
));
}
acard_ptr,
)
};
watch_ids.push(id);
unsafe { glib_sys::g_io_channel_unref(gioc) }
}
println!("Handler size in watch_poll_descriptors: {}", acard.handlers.borrow().capacity());
return watch_ids;
}
extern "C" 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 acard =
unsafe { mem::transmute::<&glib_sys::gpointer, &AlsaCard>(&data) };
println!("Handler size in watch_cb: {}", acard.handlers.borrow().capacity());
let mixer = unsafe {
mem::transmute::<&Mixer, &*mut alsa_sys::snd_mixer_t>(&acard.mixer)
};
unsafe { mem::transmute::<glib_sys::gpointer, &AlsaCard>(data) };
unsafe {
alsa_sys::snd_mixer_handle_events(*mixer);
{
let mixer_ptr =
unsafe {
mem::transmute::<&Mixer,
&*mut alsa_sys::snd_mixer_t>(&acard.mixer)
};
unsafe {
alsa_sys::snd_mixer_handle_events(*mixer_ptr);
}
}
if cond == glib_sys::G_IO_ERR {
@ -255,31 +240,27 @@ extern "C" 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");
info!("G_IO_STATUS_AGAIN");
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"),
glib_sys::G_IO_STATUS_NORMAL => info!("G_IO_STATUS_NORMAL"),
glib_sys::G_IO_STATUS_ERROR => info!("G_IO_STATUS_ERROR"),
glib_sys::G_IO_STATUS_EOF => info!("G_IO_STATUS_EOF"),
}
return true as glib_sys::gboolean;
}
// TODO: handle alsa events, pass to 'on_alsa_event'
println!("on_alsa_event triggering");
acard.on_alsa_event(AlsaEvent::AlsaCardValuesChanged);
return true as glib_sys::gboolean;

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(());
}

View File

@ -8,20 +8,20 @@ use ui_tray_icon::*;
pub fn init(appstate: Rc<AppS>) {
let s1 = appstate.clone();
let s2 = appstate.clone();
appstate.acard.borrow().connect_handler(
Box::new(|_, s, u| {
println!("In der closure");
{
let apps = appstate.clone();
appstate.acard.borrow().connect_handler(Box::new(move |a, s, u| {
match (s, u) {
(AudioSignal::AudioValuesChanged, AudioUser::AudioUserUnknown) => {
println!("Gaga");
}
_ => println!("Nix"),
}}),
);
(AudioSignal::AudioValuesChanged,
AudioUser::AudioUserUnknown) => {
println!("External volume change!");
init_tray_icon(s1);
init_popup_window(s2);
}
_ => println!("Nix"),
}
}));
}
init_tray_icon(appstate.clone());
init_popup_window(appstate.clone());
}

View File

@ -23,25 +23,37 @@ pub fn init_popup_window(appstate: Rc<AppS>) {
/* mute_check.connect_toggled */
{
let _appstate = appstate.clone();
let mute_check = &appstate.clone().gui.popup_window.mute_check;
toggle_signal = mute_check.connect_toggled(
move |_| on_mute_check_toggled(&_appstate),
);
let mute_check = &appstate.clone()
.gui
.popup_window
.mute_check;
toggle_signal =
mute_check.connect_toggled(move |_| {
on_mute_check_toggled(&_appstate)
});
}
/* popup_window.connect_show */
{
let _appstate = appstate.clone();
let popup_window = &appstate.clone().gui.popup_window.window;
popup_window.connect_show(
move |w| on_popup_window_show(w, &_appstate, toggle_signal),
);
let popup_window = &appstate.clone()
.gui
.popup_window
.window;
popup_window.connect_show(move |w| {
on_popup_window_show(w,
&_appstate,
toggle_signal)
});
}
/* vol_scale_adj.connect_value_changed */
{
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(
move |_| on_vol_scale_value_changed(&_appstate),
);
@ -50,41 +62,38 @@ pub fn init_popup_window(appstate: Rc<AppS>) {
/* popup_window.connect_event */
{
let _appstate = appstate.clone();
let popup_window = &appstate.clone().gui.popup_window.window;
let popup_window = &appstate.clone()
.gui
.popup_window
.window;
popup_window.connect_event(move |w, e| {
on_popup_window_event(w, e, &_appstate)
});
on_popup_window_event(w, e, &_appstate)
});
}
}
fn on_popup_window_show(
window: &gtk::Window,
appstate: &AppS,
toggle_signal: u64,
) {
fn on_popup_window_show(window: &gtk::Window,
appstate: &AppS,
toggle_signal: u64) {
let acard = appstate.acard.borrow();
let popup_window = &appstate.gui.popup_window;
let cur_vol = try_w!(acard.vol());
println!("Cur vol: {}", cur_vol);
set_slider(&popup_window.vol_scale_adj, cur_vol);
let muted = acard.get_mute();
update_mute_check(&appstate, toggle_signal, muted);
popup_window.vol_scale.grab_focus();
// try_w!(grab_devices(window));
println!("Handler size in on_popup_window_show: {}", acard.handlers.borrow().capacity());
try_w!(grab_devices(window));
}
fn on_popup_window_event(
w: &gtk::Window,
e: &gdk::Event,
appstate: &AppS,
) -> gtk::Inhibit {
fn on_popup_window_event(w: &gtk::Window,
e: &gdk::Event,
appstate: &AppS)
-> gtk::Inhibit {
match gdk::Event::get_event_type(e) {
gdk::EventType::GrabBroken => w.hide(),
gdk::EventType::KeyPress => {
@ -116,7 +125,10 @@ fn on_popup_window_event(
fn on_vol_scale_value_changed(appstate: &AppS) {
let acard = appstate.acard.borrow();
let val = appstate.gui.popup_window.vol_scale.get_value();
let val = appstate.gui
.popup_window
.vol_scale
.get_value();
try_w!(acard.set_vol(val, AudioUserPopup));
}
@ -130,7 +142,9 @@ fn on_mute_check_toggled(appstate: &AppS) {
}
fn update_mute_check(appstate: &AppS, toggle_signal: u64, muted: Result<bool>) {
pub fn update_mute_check(appstate: &AppS,
toggle_signal: u64,
muted: Result<bool>) {
let check_button = &appstate.gui.popup_window.mute_check;
// let check_button_ptr = unsafe {
// mem::transmute::<&gtk::CheckButton, &*mut gobject_sys::GObject>(
@ -185,7 +199,7 @@ fn update_mute_check(appstate: &AppS, toggle_signal: u64, muted: Result<bool>) {
}
fn set_slider(vol_scale_adj: &gtk::Adjustment, scale: f64) {
pub fn set_slider(vol_scale_adj: &gtk::Adjustment, scale: f64) {
vol_scale_adj.set_value(scale);
}
@ -196,40 +210,32 @@ 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

@ -7,9 +7,9 @@ use std::rc::Rc;
pub fn init_tray_icon(appstate: Rc<AppS>) {
let tray_icon = &appstate.clone().gui.status_icon;
tray_icon.connect_activate(
move |_| on_tray_icon_activate(&appstate.clone()),
);
tray_icon.connect_activate(move |_| {
on_tray_icon_activate(&appstate.clone())
});
tray_icon.set_visible(true);
}