This commit is contained in:
Ospald, Julian 2017-06-27 15:56:33 +02:00
parent 9e91cd9289
commit 3f19417f75
5 changed files with 154 additions and 90 deletions

View File

@ -4,14 +4,15 @@ version = "0.1.0"
authors = ["Julian Ospald <hasufell@posteo.de>"] authors = ["Julian Ospald <hasufell@posteo.de>"]
[dependencies] [dependencies]
alsa = "0.1.8" alsa = "^0.1.8"
libc = "0.2.23" libc = "^0.2.23"
gdk-sys = { git = "https://github.com/gtk-rs/sys" } gdk-sys = { git = "https://github.com/gtk-rs/sys" }
gtk-sys = { git = "https://github.com/gtk-rs/sys" } gtk-sys = { git = "https://github.com/gtk-rs/sys" }
glib = { git = "https://github.com/gtk-rs/glib.git" } glib = { git = "https://github.com/gtk-rs/glib.git" }
ffi = "0.0.2" ffi = "^0.0.2"
flexi_logger = "^0.5.1" flexi_logger = "^0.5.1"
log = "0.3.8" log = "^0.3.8"
error-chain = "^0.10.0"
[dependencies.gtk] [dependencies.gtk]
git = "https://github.com/gtk-rs/gtk.git" git = "https://github.com/gtk-rs/gtk.git"

View File

@ -7,6 +7,8 @@ use self::alsa::mixer::{Mixer, Selem, Elem};
use alsa::mixer::SelemChannelId::*; use alsa::mixer::SelemChannelId::*;
use std::iter::Map; use std::iter::Map;
use self::libc::c_int; use self::libc::c_int;
use errors::*;
use std::convert::From;
@ -22,39 +24,8 @@ pub fn get_alsa_cards() -> alsa::card::Iter {
return alsa::card::Iter::new(); return alsa::card::Iter::new();
} }
pub fn get_mixer(card: Card) -> Mixer { pub fn get_mixer(card: Card) -> Result<Mixer> {
let mixer = Mixer::new(&format!("hw:{}", card.get_index()), false).unwrap(); return Mixer::new(&format!("hw:{}", card.get_index()), false).cherr();
return mixer;
}
pub fn get_selems(mixer: &Mixer) -> Map<alsa::mixer::Iter, fn(Elem) -> Selem> {
return mixer.iter().map(get_selem);
}
pub fn get_selem_by_name<'a>(mixer: &'a Mixer, name: String) -> Option<Selem> {
for selem in get_selems(mixer) {
let m_name = selem.get_id()
.get_name()
.map(|y| String::from(y))
.ok();
let retval = m_name.map_or(false, |n| { return n == name; });
if retval {
return Some(selem);
}
}
return None;
}
pub fn get_vol(selem: Selem) -> Result<f64, alsa::Error> {
let (min, max) = selem.get_playback_volume_range();
let volume = selem.get_playback_volume(FrontRight).map(|v| {
return ((v - min) as f64) / ((max - min) as f64) * 100.0;
});
return volume;
} }
pub fn get_selem(elem: Elem) -> Selem { pub fn get_selem(elem: Elem) -> Selem {
@ -64,6 +35,26 @@ pub fn get_selem(elem: Elem) -> Selem {
return Selem::new(elem).unwrap(); return Selem::new(elem).unwrap();
} }
// pub fn list_channels(card: Card, hctl: HCtl) -> [str] { pub fn get_selems(mixer: &Mixer) -> Map<alsa::mixer::Iter, fn(Elem) -> Selem> {
return mixer.iter().map(get_selem);
}
// } pub fn get_selem_by_name<'a>(mixer: &'a Mixer, name: String) -> Result<Selem> {
for selem in get_selems(mixer) {
let n = selem.get_id().get_name().map(|y| String::from(y))?;
if n == name {
return Ok(selem);
}
}
bail!("Not found a matching selem named {}", name);
}
pub fn get_vol(selem: Selem) -> Result<f64> {
let (min, max) = selem.get_playback_volume_range();
let volume = selem.get_playback_volume(FrontRight).map(|v| {
return ((v - min) as f64) / ((max - min) as f64) * 100.0;
});
return volume.cherr();
}

53
src/errors.rs Normal file
View File

@ -0,0 +1,53 @@
use alsa;
use std;
use std::convert::From;
error_chain! {
foreign_links {
Alsa(alsa::Error);
}
}
pub trait CHErr {
type Item;
fn cherr(self) -> Result<Self::Item>;
}
impl<A, E: std::error::Error> CHErr for std::result::Result<A, E>
where Error: std::convert::From<E> {
type Item = A;
fn cherr(self) -> Result<Self::Item> {
return self.map_err(From::from);
}
}
#[macro_export]
macro_rules! try_w {
($expr:expr) => {
try_wr!($expr, ())
};
($expr:expr, $fmt:expr, $($arg:tt)+) => {
try_wr!($expr, (), $fmt, $(arg)+)
}
}
#[macro_export]
macro_rules! try_wr {
($expr:expr, $ret:expr) => (match $expr {
std::result::Result::Ok(val) => val,
std::result::Result::Err(err) => {
warn!("{:?}", err);
return $ret;
},
});
($expr:expr, $ret:expr, $fmt:expr, $($arg:tt)+) => (match $expr {
std::result::Result::Ok(val) => val,
std::result::Result::Err(err) => {
warn!("Original error: {:?}", err);
warn!(format!($fmt, $(arg)+));
return $ret;
},
})
}

View File

@ -6,6 +6,8 @@ extern crate glib;
extern crate ffi; extern crate ffi;
extern crate libc; extern crate libc;
use errors::*;
use gtk::prelude::*; use gtk::prelude::*;
use gdk::DeviceExt; use gdk::DeviceExt;
use gdk::{GrabOwnership, GrabStatus, BUTTON_PRESS_MASK, KEY_PRESS_MASK}; use gdk::{GrabOwnership, GrabStatus, BUTTON_PRESS_MASK, KEY_PRESS_MASK};
@ -15,44 +17,48 @@ pub fn set_slider(vol_scale_adj: &gtk::Adjustment, scale: f64) {
vol_scale_adj.set_value(scale); vol_scale_adj.set_value(scale);
} }
pub fn grab_devices(window: &gtk::Window) { pub fn grab_devices(window: &gtk::Window) -> Result<()> {
let m_device = gtk::get_current_event_device(); let device = gtk::get_current_event_device().ok_or("No current device")?;
if m_device.is_none() {
warn!("Couldn't get current device");
return;
}
let device = m_device.unwrap(); let gdk_window = window.get_window().ok_or("No window?!")?;
let gdk_window = window.get_window().unwrap();
/* 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 {}", device.get_name().unwrap()); warn!(
"Could not grab {}",
device.get_name().unwrap_or(String::from("UNKNOWN DEVICE"))
);
} }
/* Grab the keyboard */ /* Grab the keyboard */
let m_k_dev = device.get_associated_device(); let k_dev = device.get_associated_device().ok_or(
if m_k_dev.is_none() { "Couldn't get associated device",
warn!("Couldn't get associated device"); )?;
return;
}
let k_dev = m_k_dev.unwrap();
let k_grab_status = k_dev.grab(&gdk_window, let k_grab_status = k_dev.grab(
&gdk_window,
GrabOwnership::None, GrabOwnership::None,
true, true,
KEY_PRESS_MASK, KEY_PRESS_MASK,
None, None,
GDK_CURRENT_TIME as u32); GDK_CURRENT_TIME as u32,
);
if k_grab_status != GrabStatus::Success { if k_grab_status != GrabStatus::Success {
warn!("Could not grab {}", k_dev.get_name().unwrap()) warn!(
"Could not grab {}",
k_dev.get_name().unwrap_or(String::from("UNKNOWN DEVICE"))
);
} }
return Ok(());
} }

View File

@ -2,6 +2,9 @@ extern crate flexi_logger;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
#[macro_use]
extern crate error_chain;
extern crate gtk; extern crate gtk;
extern crate gtk_sys; extern crate gtk_sys;
extern crate gdk; extern crate gdk;
@ -19,9 +22,12 @@ use gtk::prelude::*;
use gdk_sys::GDK_KEY_Escape; use gdk_sys::GDK_KEY_Escape;
#[macro_use]
mod errors;
mod audio; mod audio;
mod gui; mod gui;
mod debug;
fn main() { fn main() {
@ -39,10 +45,10 @@ fn main() {
let builder_popup = gtk::Builder::new_from_string(glade_src); let builder_popup = gtk::Builder::new_from_string(glade_src);
{ {
let popup_window: gtk::Window = builder_popup.get_object("popup_window") let popup_window: gtk::Window =
.unwrap(); builder_popup.get_object("popup_window").unwrap();
let vol_scale: gtk::Scale = builder_popup.get_object("vol_scale") let vol_scale: gtk::Scale =
.unwrap(); 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();
@ -53,23 +59,25 @@ fn main() {
}); });
} }
{ {
let popup_window: gtk::Window = builder_popup.get_object("popup_window") let popup_window: gtk::Window =
.unwrap(); builder_popup.get_object("popup_window").unwrap();
let vol_scale_adj: gtk::Adjustment = builder_popup.get_object("vol_scale_adj") let vol_scale_adj: gtk::Adjustment =
.unwrap(); builder_popup.get_object("vol_scale_adj").unwrap();
popup_window.connect_show(move |_| { popup_window.connect_show(move |_| {
let alsa_card = audio::get_default_alsa_card(); let alsa_card = audio::get_default_alsa_card();
let mixer = audio::get_mixer(alsa_card); let mixer = try_w!(audio::get_mixer(alsa_card));
let selem = audio::get_selem_by_name(&mixer, let selem = try_w!(audio::get_selem_by_name(
String::from("Master")) &mixer,
.unwrap(); String::from("Master"),
gui::set_slider(&vol_scale_adj, audio::get_vol(selem).unwrap()) ));
let cur_vol = try_w!(audio::get_vol(selem));
gui::set_slider(&vol_scale_adj, cur_vol);
}); });
} }
{ {
let popup_window: gtk::Window = builder_popup.get_object("popup_window") let popup_window: gtk::Window =
.unwrap(); builder_popup.get_object("popup_window").unwrap();
popup_window.connect_event(move |w, e| { popup_window.connect_event(move |w, e| {
match gdk::Event::get_event_type(e) { match gdk::Event::get_event_type(e) {
gdk::EventType::GrabBroken => w.hide(), gdk::EventType::GrabBroken => w.hide(),
@ -80,7 +88,12 @@ fn main() {
} }
} }
gdk::EventType::ButtonPress => { gdk::EventType::ButtonPress => {
let device = gtk::get_current_event_device().unwrap(); let device = try_wr!(
gtk::get_current_event_device().ok_or(
"No current event device!",
),
Inhibit(false)
);
let (window, _, _) = let (window, _, _) =
gdk::DeviceExt::get_window_at_position(&device); gdk::DeviceExt::get_window_at_position(&device);
if window.is_none() { if window.is_none() {