From de9afc946904424660e509c1deb0d860f4ae7ec3 Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Thu, 29 Jun 2017 23:35:39 +0200 Subject: [PATCH] Update --- src/app_state.rs | 1 - src/audio.rs | 116 +++++++++++++++++++++++++---------------- src/errors.rs | 1 - src/main.rs | 11 ++-- src/myalsa.rs | 9 ++-- src/ui_entry.rs | 1 - src/ui_popup_window.rs | 70 +++++++++++-------------- src/ui_tray_icon.rs | 9 ++-- 8 files changed, 116 insertions(+), 102 deletions(-) diff --git a/src/app_state.rs b/src/app_state.rs index e3b116b74..113afaedb 100644 --- a/src/app_state.rs +++ b/src/app_state.rs @@ -9,4 +9,3 @@ pub struct AppS { pub builder_popup: gtk::Builder, } - diff --git a/src/audio.rs b/src/audio.rs index d6b010186..7feb71a43 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -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, + last_action_timestamp: RefCell, } /* TODO: AlsaCard cleanup */ impl AlsaCard { - pub fn new( - card_name: Option, - elem_name: Option, - ) -> Result { + pub fn new(card_name: Option, + elem_name: Option) + -> Result { 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, - mixer: &Mixer, -) -> Vec { + +fn watch_poll_descriptors(polls: Vec, mixer: &Mixer) -> Vec { let mut watch_ids: Vec = 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 = 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; } - diff --git a/src/errors.rs b/src/errors.rs index 1f43e62a4..160153f54 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -79,4 +79,3 @@ macro_rules! try_r { }, }); } - diff --git a/src/main.rs b/src/main.rs index 966462cd6..7b46c4cf9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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) diff --git a/src/myalsa.rs b/src/myalsa.rs index 1e59524f2..af5f0e718 100644 --- a/src/myalsa.rs +++ b/src/myalsa.rs @@ -56,7 +56,9 @@ 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); @@ -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(()); } - diff --git a/src/ui_entry.rs b/src/ui_entry.rs index 567e80d2d..7aa4707a7 100644 --- a/src/ui_entry.rs +++ b/src/ui_entry.rs @@ -12,4 +12,3 @@ pub fn init<'a>(appstate: &'a AppS, rc_acard: Rc>) { init_tray_icon(&appstate); init_popup_window(&appstate, rc_acard); } - diff --git a/src/ui_popup_window.rs b/src/ui_popup_window.rs index 9aa2ac1ea..b4dde5559 100644 --- a/src/ui_popup_window.rs +++ b/src/ui_popup_window.rs @@ -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>) { /* vol_scale_adj.connect_value_changed */ { let vol_scale_adj: Rc = - 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>) { 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: >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/ui_tray_icon.rs b/src/ui_tray_icon.rs index 8bbaac863..5f3d64b0e 100644 --- a/src/ui_tray_icon.rs +++ b/src/ui_tray_icon.rs @@ -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); } -