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>"]
[dependencies]
alsa = "0.1.8"
libc = "0.2.23"
alsa = "^0.1.8"
libc = "^0.2.23"
gdk-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" }
ffi = "0.0.2"
ffi = "^0.0.2"
flexi_logger = "^0.5.1"
log = "0.3.8"
log = "^0.3.8"
error-chain = "^0.10.0"
[dependencies.gtk]
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 std::iter::Map;
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();
}
pub fn get_mixer(card: Card) -> Mixer {
let mixer = Mixer::new(&format!("hw:{}", card.get_index()), false).unwrap();
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_mixer(card: Card) -> Result<Mixer> {
return Mixer::new(&format!("hw:{}", card.get_index()), false).cherr();
}
pub fn get_selem(elem: Elem) -> Selem {
@ -64,6 +35,26 @@ pub fn get_selem(elem: Elem) -> Selem {
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 libc;
use errors::*;
use gtk::prelude::*;
use gdk::DeviceExt;
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);
}
pub fn grab_devices(window: &gtk::Window) {
let m_device = gtk::get_current_event_device();
if m_device.is_none() {
warn!("Couldn't get current device");
return;
}
pub fn grab_devices(window: &gtk::Window) -> Result<()> {
let device = gtk::get_current_event_device().ok_or("No current device")?;
let device = m_device.unwrap();
let gdk_window = window.get_window().unwrap();
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());
warn!(
"Could not grab {}",
device.get_name().unwrap_or(String::from("UNKNOWN DEVICE"))
);
}
/* Grab the keyboard */
let m_k_dev = device.get_associated_device();
if m_k_dev.is_none() {
warn!("Couldn't get associated device");
return;
}
let k_dev = m_k_dev.unwrap();
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())
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]
extern crate log;
#[macro_use]
extern crate error_chain;
extern crate gtk;
extern crate gtk_sys;
extern crate gdk;
@ -19,9 +22,12 @@ use gtk::prelude::*;
use gdk_sys::GDK_KEY_Escape;
#[macro_use]
mod errors;
mod audio;
mod gui;
mod debug;
fn main() {
@ -39,37 +45,39 @@ fn main() {
let builder_popup = gtk::Builder::new_from_string(glade_src);
{
let popup_window: gtk::Window = builder_popup.get_object("popup_window")
.unwrap();
let vol_scale: gtk::Scale = builder_popup.get_object("vol_scale")
.unwrap();
let popup_window: gtk::Window =
builder_popup.get_object("popup_window").unwrap();
let vol_scale: gtk::Scale =
builder_popup.get_object("vol_scale").unwrap();
tray_icon.connect_activate(move |_| if popup_window.get_visible() {
popup_window.hide();
} else {
popup_window.show_now();
vol_scale.grab_focus();
gui::grab_devices(&popup_window);
});
popup_window.hide();
} else {
popup_window.show_now();
vol_scale.grab_focus();
gui::grab_devices(&popup_window);
});
}
{
let popup_window: gtk::Window = builder_popup.get_object("popup_window")
.unwrap();
let vol_scale_adj: gtk::Adjustment = builder_popup.get_object("vol_scale_adj")
.unwrap();
let popup_window: gtk::Window =
builder_popup.get_object("popup_window").unwrap();
let vol_scale_adj: gtk::Adjustment =
builder_popup.get_object("vol_scale_adj").unwrap();
popup_window.connect_show(move |_| {
let alsa_card = audio::get_default_alsa_card();
let mixer = audio::get_mixer(alsa_card);
let selem = audio::get_selem_by_name(&mixer,
String::from("Master"))
.unwrap();
gui::set_slider(&vol_scale_adj, audio::get_vol(selem).unwrap())
let mixer = try_w!(audio::get_mixer(alsa_card));
let selem = try_w!(audio::get_selem_by_name(
&mixer,
String::from("Master"),
));
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")
.unwrap();
let popup_window: gtk::Window =
builder_popup.get_object("popup_window").unwrap();
popup_window.connect_event(move |w, e| {
match gdk::Event::get_event_type(e) {
gdk::EventType::GrabBroken => w.hide(),
@ -80,7 +88,12 @@ fn main() {
}
}
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, _, _) =
gdk::DeviceExt::get_window_at_position(&device);
if window.is_none() {