Update
This commit is contained in:
parent
9e91cd9289
commit
3f19417f75
@ -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"
|
||||||
|
61
src/audio.rs
61
src/audio.rs
@ -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
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 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: >k::Adjustment, scale: f64) {
|
|||||||
vol_scale_adj.set_value(scale);
|
vol_scale_adj.set_value(scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn grab_devices(window: >k::Window) {
|
pub fn grab_devices(window: >k::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(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
45
src/main.rs
45
src/main.rs
@ -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() {
|
||||||
|
Loading…
Reference in New Issue
Block a user