Update
This commit is contained in:
parent
9e91cd9289
commit
3f19417f75
@ -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"
|
||||
|
61
src/audio.rs
61
src/audio.rs
@ -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
53
src/errors.rs
Normal 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;
|
||||
},
|
||||
})
|
||||
}
|
48
src/gui.rs
48
src/gui.rs
@ -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: >k::Adjustment, scale: f64) {
|
||||
vol_scale_adj.set_value(scale);
|
||||
}
|
||||
|
||||
pub fn grab_devices(window: >k::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: >k::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,
|
||||
let m_grab_status = device.grab(
|
||||
&gdk_window,
|
||||
GrabOwnership::None,
|
||||
true,
|
||||
BUTTON_PRESS_MASK,
|
||||
None,
|
||||
GDK_CURRENT_TIME as u32);
|
||||
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,
|
||||
let k_grab_status = k_dev.grab(
|
||||
&gdk_window,
|
||||
GrabOwnership::None,
|
||||
true,
|
||||
KEY_PRESS_MASK,
|
||||
None,
|
||||
GDK_CURRENT_TIME as u32);
|
||||
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(());
|
||||
}
|
||||
|
||||
|
45
src/main.rs
45
src/main.rs
@ -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,10 +45,10 @@ 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();
|
||||
@ -53,23 +59,25 @@ fn main() {
|
||||
});
|
||||
}
|
||||
{
|
||||
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() {
|
||||
|
Loading…
Reference in New Issue
Block a user