use std::thread;
use std::ops::Deref;
use dbus;
use channel::{self, Receiver};
use crate::{error, backlight};
pub struct Interface {
receiver: Receiver<Event>,
}
#[derive(Debug)]
pub enum Event {
Mode(Mode),
Profile(String),
Brightness(f32),
Save,
Stop,
ScreenSaver(bool),
}
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Mode {
Manual,
Desktop,
Window,
Luminance,
Time,
}
impl Default for Mode {
fn default() -> Self {
Mode::Luminance
}
}
impl Mode {
pub fn parse<T: AsRef<str>>(value: T) -> Option<Mode> {
match value.as_ref() {
"manual" => Some(Mode::Manual),
"desktop" => Some(Mode::Desktop),
"window" => Some(Mode::Window),
"luminance" => Some(Mode::Luminance),
"time" => Some(Mode::Time),
_ => None,
}
}
}
impl Interface {
pub fn mode<T: Into<String>>(value: T) -> error::Result<()> {
dbus::Connection::get_private(dbus::BusType::Session)?
.send(dbus::Message::new_method_call(
"meh.rust.Backlight",
"/meh/rust/Backlight",
"meh.rust.Backlight",
"Mode")?
.append1(value.into()))?;
Ok(())
}
pub fn profile<T: Into<String>>(value: T) -> error::Result<()> {
dbus::Connection::get_private(dbus::BusType::Session)?
.send(dbus::Message::new_method_call(
"meh.rust.Backlight",
"/meh/rust/Backlight",
"meh.rust.Backlight",
"Profile")?
.append1(value.into()))?;
Ok(())
}
pub fn brightness(value: f32) -> error::Result<()> {
dbus::Connection::get_private(dbus::BusType::Session)?
.send(dbus::Message::new_method_call(
"meh.rust.Backlight",
"/meh/rust/Backlight",
"meh.rust.Backlight",
"Brightness")?
.append1(f64::from(backlight::clamp(value))))?;
Ok(())
}
pub fn save() -> error::Result<()> {
dbus::Connection::get_private(dbus::BusType::Session)?
.send(dbus::Message::new_method_call(
"meh.rust.Backlight",
"/meh/rust/Backlight",
"meh.rust.Backlight",
"Save")?)?;
Ok(())
}
pub fn stop() -> error::Result<()> {
dbus::Connection::get_private(dbus::BusType::Session)?
.send(dbus::Message::new_method_call(
"meh.rust.Backlight",
"/meh/rust/Backlight",
"meh.rust.Backlight",
"Stop")?)?;
Ok(())
}
pub fn spawn() -> error::Result<Self> {
let (sender, receiver) = channel::bounded(1);
let (g_sender, g_receiver) = channel::unbounded::<error::Result<()>>();
macro_rules! dbus {
(connect system) => (
dbus::Connection::get_private(dbus::BusType::System)
);
(connect session) => (
match dbus::Connection::get_private(dbus::BusType::Session) {
Ok(value) => {
value
}
Err(error) => {
g_sender.send(Err(error.into())).unwrap();
return;
}
}
);
(register $conn:expr, $name:expr) => (
match $conn.register_name($name, dbus::NameFlag::DoNotQueue as u32) {
Ok(dbus::RequestNameReply::Exists) => {
g_sender.send(Err(error::DBus::AlreadyRegistered.into())).unwrap();
return;
}
Err(error) => {
g_sender.send(Err(error.into())).unwrap();
return;
}
Ok(value) => {
value
}
}
);
(watch $conn:expr, $filter:expr) => (
$conn.add_match($filter)
);
(ready) => (
g_sender.send(Ok(())).unwrap();
);
(check) => (
g_receiver.recv().unwrap()
);
(try $body:expr) => (
match $body {
Ok(value) => {
value
}
Err(err) => {
error!("{:?}", err);
return None;
}
}
);
}
macro_rules! cloning {
([$($var:ident),*] $closure:expr) => ({
$(let $var = $var.clone();)*
$closure
});
}
thread::spawn(move || {
let c = dbus!(connect session);
let f = dbus::tree::Factory::new_sync::<()>();
dbus!(register c, "meh.rust.Backlight");
dbus!(watch c, "interface='org.gnome.ScreenSaver',member='ActiveChanged'");
dbus!(ready);
let tree = f.tree(())
.add(f.object_path("/meh/rust/Backlight", ()).introspectable().add(f.interface("meh.rust.Backlight", ())
.add_m(f.method("Mode", (), cloning!([sender] move |m| {
if let Some(value) = m.msg.get1::<String>().and_then(Mode::parse) {
sender.send(Event::Mode(value)).unwrap();
Ok(vec![m.msg.method_return()])
}
else {
Err(dbus::tree::MethodErr::no_arg())
}
})).inarg::<String, _>("mode"))
.add_m(f.method("Profile", (), cloning!([sender] move |m| {
if let Some(value) = m.msg.get1::<String>() {
sender.send(Event::Profile(value)).unwrap();
Ok(vec![m.msg.method_return()])
}
else {
Err(dbus::tree::MethodErr::no_arg())
}
})).inarg::<String, _>("profile"))
.add_m(f.method("Brightness", (), cloning!([sender] move |m| {
if let Some(value) = m.msg.get1::<f64>() {
sender.send(Event::Brightness(value as f32)).unwrap();
Ok(vec![m.msg.method_return()])
}
else {
Err(dbus::tree::MethodErr::no_arg())
}
})).inarg::<f64, _>("value"))
.add_m(f.method("Save", (), cloning!([sender] move |m| {
sender.send(Event::Save).unwrap();
Ok(vec![m.msg.method_return()])
})))
.add_m(f.method("Stop", (), cloning!([sender] move |m| {
sender.send(Event::Stop).unwrap();
Ok(vec![m.msg.method_return()])
})))));
tree.set_registered(&c, true).unwrap();
for item in tree.run(&c, c.iter(1_000_000)) {
if let dbus::ConnectionItem::Signal(m) = item {
match (&*m.interface().unwrap(), &*m.member().unwrap()) {
("org.gnome.ScreenSaver", "ActiveChanged") => {
if let Some(status) = m.get1() {
sender.send(Event::ScreenSaver(status)).unwrap();
}
}
_ => ()
}
}
}
});
dbus!(check)?;
Ok(Interface { receiver })
}
}
impl Deref for Interface {
type Target = Receiver<Event>;
fn deref(&self) -> &Self::Target {
&self.receiver
}
}