PulseAudio module
This commit is contained in:
Generated
+47
@@ -65,6 +65,15 @@ dependencies = [
|
|||||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dbus"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libdbus-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dlib"
|
name = "dlib"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
@@ -88,6 +97,14 @@ name = "libc"
|
|||||||
version = "0.2.60"
|
version = "0.2.60"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libdbus-sys"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
@@ -97,6 +114,24 @@ dependencies = [
|
|||||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libpulse-binding"
|
||||||
|
version = "2.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libpulse-sys 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libpulse-sys"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "line_drawing"
|
name = "line_drawing"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
@@ -177,6 +212,11 @@ dependencies = [
|
|||||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "0.4.30"
|
version = "0.4.30"
|
||||||
@@ -356,6 +396,8 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"dbus 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libpulse-binding 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"os_pipe 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"os_pipe 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -385,11 +427,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "ce400c638d48ee0e9ab75aef7997609ec57367ccfe1463f21bf53c3eca67bf46"
|
"checksum cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "ce400c638d48ee0e9ab75aef7997609ec57367ccfe1463f21bf53c3eca67bf46"
|
||||||
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
|
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
|
||||||
"checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe"
|
"checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe"
|
||||||
|
"checksum dbus 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "48b5f0f36f1eebe901b0e6bee369a77ed3396334bf3f09abd46454a576f71819"
|
||||||
"checksum dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a"
|
"checksum dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a"
|
||||||
"checksum downcast-rs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b92dfd5c2f75260cbf750572f95d387e7ca0ba5e3fbe9e1a33f23025be020f"
|
"checksum downcast-rs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b92dfd5c2f75260cbf750572f95d387e7ca0ba5e3fbe9e1a33f23025be020f"
|
||||||
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
|
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
|
||||||
"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb"
|
"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb"
|
||||||
|
"checksum libdbus-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "69382cb3be797cfe62ba89ac5e594a0e3022914ff44867ffbcfc03daa24eebd7"
|
||||||
"checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753"
|
"checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753"
|
||||||
|
"checksum libpulse-binding 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7378bffd76492e876a0afb9a016359379a6b5a859fecd039248f76ce719fb"
|
||||||
|
"checksum libpulse-sys 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dcac117c7e9fb50fe162d5fbc6b3818819bd173922f648fae017f913de68520"
|
||||||
"checksum line_drawing 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5cc7ad3d82c845bdb5dde34ffdcc7a5fb4d2996e1e1ee0f19c33bc80e15196b9"
|
"checksum line_drawing 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5cc7ad3d82c845bdb5dde34ffdcc7a5fb4d2996e1e1ee0f19c33bc80e15196b9"
|
||||||
"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
|
"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
|
||||||
"checksum nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4dbdc256eaac2e3bd236d93ad999d3479ef775c863dbda3068c4006a92eec51b"
|
"checksum nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4dbdc256eaac2e3bd236d93ad999d3479ef775c863dbda3068c4006a92eec51b"
|
||||||
@@ -399,6 +445,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
|
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
|
||||||
"checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
|
"checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
|
||||||
"checksum os_pipe 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce1d819d394515aae0530eae02156fedfc98b4f0359bf3048a442be89a95157b"
|
"checksum os_pipe 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce1d819d394515aae0530eae02156fedfc98b4f0359bf3048a442be89a95157b"
|
||||||
|
"checksum pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c1d2cfa5a714db3b5f24f0915e74fcdf91d09d496ba61329705dda7774d2af"
|
||||||
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||||
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
|
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
|
||||||
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||||
|
|||||||
@@ -14,3 +14,5 @@ memmap = "0.7"
|
|||||||
os_pipe = "0.8.1"
|
os_pipe = "0.8.1"
|
||||||
wayland-client = { version = "0.23", features = ["dlopen"] }
|
wayland-client = { version = "0.23", features = ["dlopen"] }
|
||||||
wayland-protocols = { version = "0.23", features = ["client", "unstable_protocols"] }
|
wayland-protocols = { version = "0.23", features = ["client", "unstable_protocols"] }
|
||||||
|
libpulse-binding = { version = "2.6.0"}
|
||||||
|
dbus = "0.6"
|
||||||
|
|||||||
+2
-2
@@ -3,12 +3,13 @@ use crate::color::Color;
|
|||||||
use crate::draw::{draw_bar, draw_text, ROBOTO_REGULAR};
|
use crate::draw::{draw_bar, draw_text, ROBOTO_REGULAR};
|
||||||
use crate::module::{Input, ModuleImpl};
|
use crate::module::{Input, ModuleImpl};
|
||||||
|
|
||||||
use chrono::{DateTime, Local};
|
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::{Error, ErrorKind};
|
use std::io::{Error, ErrorKind};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use chrono::{DateTime, Local};
|
||||||
|
|
||||||
pub struct Backlight {
|
pub struct Backlight {
|
||||||
device_path: PathBuf,
|
device_path: PathBuf,
|
||||||
cur_brightness: u64,
|
cur_brightness: u64,
|
||||||
@@ -111,7 +112,6 @@ impl ModuleImpl for Backlight {
|
|||||||
)?;
|
)?;
|
||||||
draw_bar(
|
draw_bar(
|
||||||
&mut buf.subdimensions((128, 0, 384, 24)),
|
&mut buf.subdimensions((128, 0, 384, 24)),
|
||||||
bg,
|
|
||||||
&Color::new(1.0, 1.0, 1.0, 1.0),
|
&Color::new(1.0, 1.0, 1.0, 1.0),
|
||||||
384,
|
384,
|
||||||
24,
|
24,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::buffer::Buffer;
|
|||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::draw::{draw_text, DEJAVUSANS_MONO, ROBOTO_REGULAR};
|
use crate::draw::{draw_text, DEJAVUSANS_MONO, ROBOTO_REGULAR};
|
||||||
use crate::module::{Input, ModuleImpl};
|
use crate::module::{Input, ModuleImpl};
|
||||||
|
|
||||||
use chrono::{Date, DateTime, Datelike, Local};
|
use chrono::{Date, DateTime, Datelike, Local};
|
||||||
|
|
||||||
pub struct Calendar {
|
pub struct Calendar {
|
||||||
|
|||||||
+20
-2
@@ -2,14 +2,31 @@ use crate::buffer::Buffer;
|
|||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::draw::{draw_text, draw_text_fixed_width, ROBOTO_REGULAR};
|
use crate::draw::{draw_text, draw_text_fixed_width, ROBOTO_REGULAR};
|
||||||
use crate::module::{Input, ModuleImpl};
|
use crate::module::{Input, ModuleImpl};
|
||||||
use chrono::{DateTime, Datelike, Local, Timelike};
|
|
||||||
|
use std::sync::mpsc::Sender;
|
||||||
|
|
||||||
|
use chrono::{DateTime, Datelike, Duration, Local, Timelike};
|
||||||
|
|
||||||
pub struct Clock {
|
pub struct Clock {
|
||||||
cur_time: DateTime<Local>,
|
cur_time: DateTime<Local>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clock {
|
impl Clock {
|
||||||
pub fn new() -> Clock {
|
pub fn new(ch: Sender<bool>) -> Clock {
|
||||||
|
std::thread::spawn(move || loop {
|
||||||
|
let n = Local::now();
|
||||||
|
let target = (n + Duration::seconds(60))
|
||||||
|
.with_second(0)
|
||||||
|
.unwrap()
|
||||||
|
.with_nanosecond(0)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let d = target - n;
|
||||||
|
|
||||||
|
std::thread::sleep(d.to_std().unwrap());
|
||||||
|
ch.send(true).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
Clock {
|
Clock {
|
||||||
cur_time: Local::now(),
|
cur_time: Local::now(),
|
||||||
}
|
}
|
||||||
@@ -60,6 +77,7 @@ impl ModuleImpl for Clock {
|
|||||||
|| force
|
|| force
|
||||||
{
|
{
|
||||||
self.cur_time = time.clone();
|
self.cur_time = time.clone();
|
||||||
|
println!("UPDATE");
|
||||||
Ok(true)
|
Ok(true)
|
||||||
} else {
|
} else {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
|
|||||||
+4
-4
@@ -58,9 +58,9 @@ impl Color {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_argb8888(&self) -> u32 {
|
pub fn as_argb8888(&self) -> u32 {
|
||||||
((255.0 * self.opacity) as u32) << 24
|
((255.0 * self.opacity) as u32 & 0xFF) << 24
|
||||||
| ((255.0 * self.red) as u32) << 16
|
| ((255.0 * self.red) as u32 & 0xFF) << 16
|
||||||
| ((255.0 * self.green) as u32) << 8
|
| ((255.0 * self.green) as u32 & 0xFF) << 8
|
||||||
| ((255.0 * self.red) as u32)
|
| ((255.0 * self.blue) as u32 & 0xFF)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-2
@@ -102,9 +102,27 @@ pub fn draw_text_fixed_width(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn draw_box(
|
||||||
|
buf: &mut Buffer,
|
||||||
|
c: &Color,
|
||||||
|
dim: (u32, u32),
|
||||||
|
) -> Result<(), ::std::io::Error> {
|
||||||
|
let mut buf = buf.subdimensions((0, 0, dim.0, dim.1));
|
||||||
|
|
||||||
|
for x in 0..dim.0 {
|
||||||
|
buf.put((x, 0), c);
|
||||||
|
buf.put((x, dim.1 - 1), c);
|
||||||
|
}
|
||||||
|
for y in 0..dim.1 {
|
||||||
|
buf.put((0, y), c);
|
||||||
|
buf.put((dim.0 - 1, y), c);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn draw_bar(
|
pub fn draw_bar(
|
||||||
buf: &mut Buffer,
|
buf: &mut Buffer,
|
||||||
background_color: &Color,
|
|
||||||
color: &Color,
|
color: &Color,
|
||||||
length: u32,
|
length: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
@@ -118,7 +136,7 @@ pub fn draw_bar(
|
|||||||
}
|
}
|
||||||
for y in 0..height {
|
for y in 0..height {
|
||||||
for x in 0..fill_pos {
|
for x in 0..fill_pos {
|
||||||
buf.put((x, y), &background_color.blend(color, 1.0));
|
buf.put((x, y), color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+34
-32
@@ -1,12 +1,13 @@
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
|
use std::sync::mpsc::{channel, Sender};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use nix::poll::{poll, PollFd, PollFlags};
|
use nix::poll::{poll, PollFd, PollFlags};
|
||||||
use os_pipe::pipe;
|
use os_pipe::pipe;
|
||||||
|
|
||||||
use chrono::{Duration as ChronoDuration, Local, Timelike};
|
use chrono::{Local};
|
||||||
|
|
||||||
use smithay_client_toolkit::keyboard::{
|
use smithay_client_toolkit::keyboard::{
|
||||||
map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatKind,
|
map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatKind,
|
||||||
@@ -26,6 +27,7 @@ mod clock;
|
|||||||
mod color;
|
mod color;
|
||||||
mod draw;
|
mod draw;
|
||||||
mod module;
|
mod module;
|
||||||
|
mod sound;
|
||||||
|
|
||||||
use crate::backlight::Backlight;
|
use crate::backlight::Backlight;
|
||||||
use crate::buffer::Buffer;
|
use crate::buffer::Buffer;
|
||||||
@@ -33,6 +35,8 @@ use crate::calendar::Calendar;
|
|||||||
use crate::clock::Clock;
|
use crate::clock::Clock;
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::module::{Input, Module};
|
use crate::module::{Input, Module};
|
||||||
|
use crate::sound::PulseAudio;
|
||||||
|
use crate::draw::draw_box;
|
||||||
|
|
||||||
enum Cmd {
|
enum Cmd {
|
||||||
Exit,
|
Exit,
|
||||||
@@ -62,6 +66,8 @@ impl App {
|
|||||||
|
|
||||||
let (buf_x, buf_y) = self.dimensions;
|
let (buf_x, buf_y) = self.dimensions;
|
||||||
|
|
||||||
|
let bg = Color::new(0.0, 0.0, 0.0, 0.9);
|
||||||
|
|
||||||
// resize the pool if relevant
|
// resize the pool if relevant
|
||||||
|
|
||||||
pool.resize((4 * buf_x * buf_y) as usize)
|
pool.resize((4 * buf_x * buf_y) as usize)
|
||||||
@@ -69,16 +75,16 @@ impl App {
|
|||||||
|
|
||||||
let mmap = pool.mmap();
|
let mmap = pool.mmap();
|
||||||
let mut buf = Buffer::new(mmap, self.dimensions);
|
let mut buf = Buffer::new(mmap, self.dimensions);
|
||||||
let mut margin_buf = buf.subdimensions((20, 20, buf_x - 40, buf_y - 40));
|
|
||||||
|
|
||||||
let bg = Color::new(0.0, 0.0, 0.0, 0.9);
|
|
||||||
|
|
||||||
let mut damage = vec![];
|
let mut damage = vec![];
|
||||||
for module in self.modules.iter() {
|
|
||||||
if module.update(&time, force)? {
|
{
|
||||||
let mut b = &mut margin_buf.subdimensions(module.get_bounds());
|
let mut margin_buf = buf.subdimensions((20, 20, buf_x - 40, buf_y - 40));
|
||||||
let mut d = module.draw(&mut b, &bg, &time)?;
|
for module in self.modules.iter() {
|
||||||
damage.append(&mut d);
|
if module.update(&time, force)? {
|
||||||
|
let mut b = &mut margin_buf.subdimensions(module.get_bounds());
|
||||||
|
let mut d = module.draw(&mut b, &bg, &time)?;
|
||||||
|
damage.append(&mut d);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +140,21 @@ impl App {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(dimensions: (u32, u32)) -> App {
|
fn new(dimensions: (u32, u32), tx: Sender<bool>) -> App {
|
||||||
|
let mut modules = vec![
|
||||||
|
Module::new(Box::new(Clock::new(tx.clone())), (0, 0, 720, 320)),
|
||||||
|
Module::new(Box::new(Calendar::new()), (0, 384, 1280, 344)),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut vert_off = 0;
|
||||||
|
if let Ok(m) = Backlight::new() {
|
||||||
|
modules.push(Module::new(Box::new(m), (720, vert_off, 512, 32)));
|
||||||
|
vert_off += 32;
|
||||||
|
}
|
||||||
|
if let Ok(m) = PulseAudio::new(tx.clone()) {
|
||||||
|
modules.push(Module::new(Box::new(m), (720, vert_off, 512, 32)));
|
||||||
|
}
|
||||||
|
|
||||||
let cmd_queue = Arc::new(Mutex::new(VecDeque::new()));
|
let cmd_queue = Arc::new(Mutex::new(VecDeque::new()));
|
||||||
|
|
||||||
let (display, mut event_queue) = Display::connect_to_env().unwrap();
|
let (display, mut event_queue) = Display::connect_to_env().unwrap();
|
||||||
@@ -263,7 +283,6 @@ impl App {
|
|||||||
surface.commit();
|
surface.commit();
|
||||||
event_queue.sync_roundtrip().unwrap();
|
event_queue.sync_roundtrip().unwrap();
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Cursor processing
|
// Cursor processing
|
||||||
//
|
//
|
||||||
@@ -354,15 +373,6 @@ impl App {
|
|||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut modules = vec![
|
|
||||||
Module::new(Box::new(Clock::new()), (0, 0, 720, 320)),
|
|
||||||
Module::new(Box::new(Calendar::new()), (0, 384, 1280, 344)),
|
|
||||||
];
|
|
||||||
|
|
||||||
if let Ok(m) = Backlight::new() {
|
|
||||||
modules.push(Module::new(Box::new(m), (720, 0, 512, 32)));
|
|
||||||
}
|
|
||||||
|
|
||||||
event_queue.sync_roundtrip().unwrap();
|
event_queue.sync_roundtrip().unwrap();
|
||||||
|
|
||||||
App {
|
App {
|
||||||
@@ -379,21 +389,13 @@ impl App {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let (mut rx_pipe, mut tx_pipe) = pipe().unwrap();
|
let (mut rx_pipe, mut tx_pipe) = pipe().unwrap();
|
||||||
|
let (tx_draw, rx_draw) = channel();
|
||||||
|
|
||||||
let mut app = App::new((1320u32, 784u32));
|
let mut app = App::new((1320u32, 784u32), tx_draw);
|
||||||
|
|
||||||
let worker_queue = app.cmd_queue();
|
let worker_queue = app.cmd_queue();
|
||||||
std::thread::spawn(move || loop {
|
std::thread::spawn(move || loop {
|
||||||
let n = Local::now();
|
rx_draw.recv().unwrap();
|
||||||
let target = (n + ChronoDuration::seconds(60))
|
|
||||||
.with_second(0)
|
|
||||||
.unwrap()
|
|
||||||
.with_nanosecond(0)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let d = target - n;
|
|
||||||
|
|
||||||
std::thread::sleep(d.to_std().unwrap());
|
|
||||||
worker_queue.lock().unwrap().push_back(Cmd::Draw);
|
worker_queue.lock().unwrap().push_back(Cmd::Draw);
|
||||||
tx_pipe.write_all(&[0x1]).unwrap();
|
tx_pipe.write_all(&[0x1]).unwrap();
|
||||||
});
|
});
|
||||||
|
|||||||
+515
@@ -0,0 +1,515 @@
|
|||||||
|
use crate::buffer::Buffer;
|
||||||
|
use crate::color::Color;
|
||||||
|
use crate::draw::{draw_bar, draw_text, ROBOTO_REGULAR};
|
||||||
|
use crate::module::{Input, ModuleImpl};
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::cmp::{max, min};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::mpsc::{channel, Sender};
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
use chrono::{DateTime, Local};
|
||||||
|
|
||||||
|
use libpulse_binding::callbacks::ListResult;
|
||||||
|
use libpulse_binding::context::{
|
||||||
|
flags, introspect::ServerInfo, introspect::SinkInfo, subscribe::subscription_masks,
|
||||||
|
subscribe::Facility, subscribe::Operation as SubscribeOperation, Context, State as PulseState,
|
||||||
|
};
|
||||||
|
use libpulse_binding::mainloop::standard::IterateResult;
|
||||||
|
use libpulse_binding::mainloop::standard::Mainloop;
|
||||||
|
use libpulse_binding::proplist::{properties, Proplist};
|
||||||
|
use libpulse_binding::volume::{ChannelVolumes, VOLUME_MAX, VOLUME_NORM};
|
||||||
|
|
||||||
|
struct PulseAudioConnection {
|
||||||
|
mainloop: Rc<RefCell<Mainloop>>,
|
||||||
|
context: Rc<RefCell<Context>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct PulseAudioSinkInfo {
|
||||||
|
volume: ChannelVolumes,
|
||||||
|
mute: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PulseAudioClient {
|
||||||
|
sender: Sender<PulseAudioClientRequest>,
|
||||||
|
default_sink: String,
|
||||||
|
sinks: HashMap<String, PulseAudioSinkInfo>,
|
||||||
|
listener: Sender<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PulseAudioClientRequest {
|
||||||
|
GetDefaultDevice(Option<Sender<bool>>),
|
||||||
|
GetSinkInfoByIndex(Option<Sender<bool>>, u32),
|
||||||
|
GetSinkInfoByName(Option<Sender<bool>>, String),
|
||||||
|
SetSinkVolumeByName(Option<Sender<bool>>, String, ChannelVolumes),
|
||||||
|
SetSinkMuteByName(Option<Sender<bool>>, String, bool),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PulseAudioSoundDevice {
|
||||||
|
client: Arc<Mutex<PulseAudioClient>>,
|
||||||
|
name: Option<String>,
|
||||||
|
volume: Option<ChannelVolumes>,
|
||||||
|
volume_avg: u32,
|
||||||
|
muted: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PulseAudioConnection {
|
||||||
|
fn new() -> Result<Self, ::std::io::Error> {
|
||||||
|
let mut proplist = Proplist::new().unwrap();
|
||||||
|
proplist
|
||||||
|
.sets(properties::APPLICATION_NAME, "wldash")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mainloop = Rc::new(RefCell::new(Mainloop::new().unwrap()));
|
||||||
|
|
||||||
|
let context = Rc::new(RefCell::new(
|
||||||
|
Context::new_with_proplist(mainloop.borrow().deref(), "wldash_context", &proplist)
|
||||||
|
.unwrap(),
|
||||||
|
));
|
||||||
|
|
||||||
|
context
|
||||||
|
.borrow_mut()
|
||||||
|
.connect(None, flags::NOFLAGS, None)
|
||||||
|
.map_err(|_e| {
|
||||||
|
::std::io::Error::new(
|
||||||
|
::std::io::ErrorKind::Other,
|
||||||
|
"unable to connect to pulseaudio context",
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let mut connection = PulseAudioConnection { mainloop, context };
|
||||||
|
|
||||||
|
// Wait for context to be ready
|
||||||
|
loop {
|
||||||
|
connection.iterate(false)?;
|
||||||
|
match connection.context.borrow().get_state() {
|
||||||
|
PulseState::Ready => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
PulseState::Failed | PulseState::Terminated => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(connection)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iterate(&mut self, blocking: bool) -> Result<(), ::std::io::Error> {
|
||||||
|
match self.mainloop.borrow_mut().iterate(blocking) {
|
||||||
|
IterateResult::Quit(_) | IterateResult::Err(_) => Err(::std::io::Error::new(
|
||||||
|
::std::io::ErrorKind::Other,
|
||||||
|
"unable to iterate pulseaudio state",
|
||||||
|
)),
|
||||||
|
IterateResult::Success(_) => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PulseAudioClient {
|
||||||
|
fn new(listener: Sender<bool>) -> Result<Arc<Mutex<Self>>, ::std::io::Error> {
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
|
||||||
|
let client = Arc::new(Mutex::new(PulseAudioClient {
|
||||||
|
sender: tx,
|
||||||
|
default_sink: "@DEFAULT_SINK@".to_string(),
|
||||||
|
sinks: HashMap::new(),
|
||||||
|
listener: listener,
|
||||||
|
}));
|
||||||
|
|
||||||
|
let cl1 = client.clone();
|
||||||
|
let (tx1, rx1) = channel();
|
||||||
|
thread::spawn(move || {
|
||||||
|
let mut conn = match PulseAudioConnection::new() {
|
||||||
|
Ok(v) => {
|
||||||
|
tx1.send(true).unwrap();
|
||||||
|
v
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
tx1.send(false).unwrap();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// make sure mainloop dispatched everything
|
||||||
|
for _ in 0..10 {
|
||||||
|
conn.iterate(false).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let cl11 = cl1.clone();
|
||||||
|
let cl12 = cl1.clone();
|
||||||
|
let cl13 = cl1.clone();
|
||||||
|
match rx.recv() {
|
||||||
|
Err(_) => {}
|
||||||
|
Ok(req) => {
|
||||||
|
let mut introspector = conn.context.borrow_mut().introspect();
|
||||||
|
|
||||||
|
match req {
|
||||||
|
PulseAudioClientRequest::GetDefaultDevice(s) => {
|
||||||
|
introspector.get_server_info(move |info| {
|
||||||
|
let _res = cl11.lock().unwrap().server_info_callback(info);
|
||||||
|
if let Some(s) = &s {
|
||||||
|
s.send(true).unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
PulseAudioClientRequest::GetSinkInfoByIndex(s, index) => {
|
||||||
|
introspector.get_sink_info_by_index(index, move |res| {
|
||||||
|
cl12.lock().unwrap().sink_info_callback(res);
|
||||||
|
if let Some(s) = &s {
|
||||||
|
s.send(true).unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
PulseAudioClientRequest::GetSinkInfoByName(s, name) => {
|
||||||
|
introspector.get_sink_info_by_name(&name, move |res| {
|
||||||
|
cl13.lock().unwrap().sink_info_callback(res);
|
||||||
|
if let Some(s) = &s {
|
||||||
|
s.send(true).unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
PulseAudioClientRequest::SetSinkVolumeByName(s, name, volumes) => {
|
||||||
|
introspector.set_sink_volume_by_name(&name, &volumes, None);
|
||||||
|
if let Some(s) = &s {
|
||||||
|
s.send(true).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PulseAudioClientRequest::SetSinkMuteByName(s, name, mute) => {
|
||||||
|
introspector.set_sink_mute_by_name(&name, mute, None);
|
||||||
|
if let Some(s) = &s {
|
||||||
|
s.send(true).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// send request and receive response
|
||||||
|
conn.iterate(true).unwrap();
|
||||||
|
conn.iterate(true).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if !rx1.recv().unwrap() {
|
||||||
|
return Err(::std::io::Error::new(
|
||||||
|
::std::io::ErrorKind::Other,
|
||||||
|
"unable to start pulseaudio thread",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// subscribe
|
||||||
|
let cl2 = client.clone();
|
||||||
|
let (tx2, rx2) = channel();
|
||||||
|
thread::spawn(move || {
|
||||||
|
let conn = match PulseAudioConnection::new() {
|
||||||
|
Ok(v) => {
|
||||||
|
tx2.send(true).unwrap();
|
||||||
|
v
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
tx2.send(false).unwrap();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// subcribe for events
|
||||||
|
conn.context
|
||||||
|
.borrow_mut()
|
||||||
|
.set_subscribe_callback(Some(Box::new(move |facility, operation, index| {
|
||||||
|
cl2.lock()
|
||||||
|
.unwrap()
|
||||||
|
.subscribe_callback(facility, operation, index)
|
||||||
|
})));
|
||||||
|
conn.context.borrow_mut().subscribe(
|
||||||
|
subscription_masks::SERVER | subscription_masks::SINK,
|
||||||
|
|_| {},
|
||||||
|
);
|
||||||
|
|
||||||
|
conn.mainloop.borrow_mut().run().unwrap();
|
||||||
|
});
|
||||||
|
if !rx2.recv().unwrap() {
|
||||||
|
return Err(::std::io::Error::new(
|
||||||
|
::std::io::ErrorKind::Other,
|
||||||
|
"unable to start pulseaudio thread",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(client)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send(&self, request: PulseAudioClientRequest) -> Result<(), ::std::io::Error> {
|
||||||
|
let res = self.sender.send(request).map_err(|_e| {
|
||||||
|
::std::io::Error::new(
|
||||||
|
::std::io::ErrorKind::Other,
|
||||||
|
"unable to send pulseaudio request",
|
||||||
|
)
|
||||||
|
});
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn server_info_callback(&mut self, server_info: &ServerInfo) {
|
||||||
|
match server_info.default_sink_name.clone() {
|
||||||
|
None => {}
|
||||||
|
Some(default_sink) => {
|
||||||
|
self.default_sink = default_sink.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sink_info_callback(&mut self, result: ListResult<&SinkInfo>) {
|
||||||
|
match result {
|
||||||
|
ListResult::End | ListResult::Error => {}
|
||||||
|
ListResult::Item(sink_info) => {
|
||||||
|
match sink_info.name.clone() {
|
||||||
|
None => {}
|
||||||
|
Some(name) => {
|
||||||
|
let info = PulseAudioSinkInfo {
|
||||||
|
volume: sink_info.volume,
|
||||||
|
mute: sink_info.mute,
|
||||||
|
};
|
||||||
|
self.sinks.insert(name.into(), info);
|
||||||
|
self.listener.send(true).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subscribe_callback(
|
||||||
|
&self,
|
||||||
|
facility: Option<Facility>,
|
||||||
|
_operation: Option<SubscribeOperation>,
|
||||||
|
index: u32,
|
||||||
|
) {
|
||||||
|
match facility {
|
||||||
|
None => {}
|
||||||
|
Some(facility) => match facility {
|
||||||
|
Facility::Server => {
|
||||||
|
let _ = self.send(PulseAudioClientRequest::GetDefaultDevice(None));
|
||||||
|
}
|
||||||
|
Facility::Sink => {
|
||||||
|
let _ = self.send(PulseAudioClientRequest::GetSinkInfoByIndex(None, index));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PulseAudioSoundDevice {
|
||||||
|
fn new(listener: Sender<bool>) -> Result<Arc<Mutex<Self>>, ::std::io::Error> {
|
||||||
|
let client = PulseAudioClient::new(listener)?;
|
||||||
|
let cl = client.clone();
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
{
|
||||||
|
let cl = client.lock().unwrap();
|
||||||
|
cl.send(PulseAudioClientRequest::GetDefaultDevice(Some(tx)))?;
|
||||||
|
}
|
||||||
|
rx.recv().unwrap();
|
||||||
|
let name = {
|
||||||
|
let cl = client.lock().unwrap();
|
||||||
|
cl.default_sink.to_string()
|
||||||
|
};
|
||||||
|
let device = Arc::new(Mutex::new(PulseAudioSoundDevice {
|
||||||
|
client: cl,
|
||||||
|
name: Some(name.to_string()),
|
||||||
|
volume: None,
|
||||||
|
volume_avg: 0,
|
||||||
|
muted: false,
|
||||||
|
}));
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
{
|
||||||
|
let cl = client.lock().unwrap();
|
||||||
|
cl.send(PulseAudioClientRequest::GetSinkInfoByName(Some(tx), name))?;
|
||||||
|
}
|
||||||
|
rx.recv().unwrap();
|
||||||
|
device.lock().unwrap().get_info()?;
|
||||||
|
|
||||||
|
Ok(device)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> String {
|
||||||
|
self.name
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| self.client.lock().unwrap().default_sink.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_volume(&mut self, volume: ChannelVolumes) {
|
||||||
|
self.volume = Some(volume);
|
||||||
|
self.volume_avg = (volume.avg().0 as f32 / VOLUME_NORM.0 as f32 * 100.0).round() as u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn volume(&self) -> u32 {
|
||||||
|
self.volume_avg
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_info(&mut self) -> Result<(), ::std::io::Error> {
|
||||||
|
let sink_info = match self.client.lock().unwrap().sinks.get(&self.name()) {
|
||||||
|
None => return Ok(()),
|
||||||
|
Some(sink_info) => (*sink_info).clone(),
|
||||||
|
};
|
||||||
|
self.update_volume(sink_info.volume);
|
||||||
|
self.muted = sink_info.mute;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_volume(&mut self, step: f32) -> Result<(), ::std::io::Error> {
|
||||||
|
let mut volume = match self.volume {
|
||||||
|
Some(volume) => volume,
|
||||||
|
None => {
|
||||||
|
return Err(::std::io::Error::new(
|
||||||
|
::std::io::ErrorKind::Other,
|
||||||
|
"unable to set volume",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// apply step to volumes
|
||||||
|
let step = (step * VOLUME_NORM.0 as f32 / 100.0).round() as i32;
|
||||||
|
for vol in volume.values.iter_mut() {
|
||||||
|
vol.0 = min(max(0, vol.0 as i32 + step) as u32, VOLUME_MAX.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update volumes
|
||||||
|
self.update_volume(volume);
|
||||||
|
self.client
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.send(PulseAudioClientRequest::SetSinkVolumeByName(
|
||||||
|
None,
|
||||||
|
self.name(),
|
||||||
|
volume,
|
||||||
|
))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggle(&mut self) -> Result<(), ::std::io::Error> {
|
||||||
|
self.muted = !self.muted;
|
||||||
|
self.client
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.send(PulseAudioClientRequest::SetSinkMuteByName(
|
||||||
|
None,
|
||||||
|
self.name(),
|
||||||
|
self.muted,
|
||||||
|
))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PulseAudio {
|
||||||
|
device: Arc<Mutex<PulseAudioSoundDevice>>,
|
||||||
|
dirty: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PulseAudio {
|
||||||
|
pub fn new(listener: Sender<bool>) -> Result<Arc<Mutex<PulseAudio>>, ::std::io::Error> {
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
let device = PulseAudioSoundDevice::new(tx)?;
|
||||||
|
let d = device.clone();
|
||||||
|
let pa = Arc::new(Mutex::new(PulseAudio {
|
||||||
|
device: device,
|
||||||
|
dirty: true,
|
||||||
|
}));
|
||||||
|
let p = pa.clone();
|
||||||
|
std::thread::spawn(move|| loop {
|
||||||
|
rx.recv().unwrap();
|
||||||
|
d.lock().unwrap().get_info().unwrap();
|
||||||
|
p.lock().unwrap().dirty = true;
|
||||||
|
listener.send(true).unwrap();
|
||||||
|
});
|
||||||
|
Ok(pa)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleImpl for Arc<Mutex<PulseAudio>> {
|
||||||
|
fn draw(
|
||||||
|
&self,
|
||||||
|
buf: &mut Buffer,
|
||||||
|
bg: &Color,
|
||||||
|
_time: &DateTime<Local>,
|
||||||
|
) -> Result<Vec<(i32, i32, i32, i32)>, ::std::io::Error> {
|
||||||
|
let s = self.lock().unwrap();
|
||||||
|
buf.memset(bg);
|
||||||
|
draw_text(
|
||||||
|
ROBOTO_REGULAR,
|
||||||
|
&mut buf.subdimensions((0, 0, 128, 24)),
|
||||||
|
bg,
|
||||||
|
&Color::new(1.0, 1.0, 1.0, 1.0),
|
||||||
|
24.0,
|
||||||
|
"volume",
|
||||||
|
)?;
|
||||||
|
let vol = if s.device.lock().unwrap().muted { 0.0 } else { (s.device.lock().unwrap().volume() as f32) / 100.0 };
|
||||||
|
draw_bar(
|
||||||
|
&mut buf.subdimensions((128, 0, 384, 24)),
|
||||||
|
&Color::new(1.0, 1.0, 1.0, 1.0),
|
||||||
|
384,
|
||||||
|
24,
|
||||||
|
vol,
|
||||||
|
)?;
|
||||||
|
if vol > 1.0 {
|
||||||
|
draw_bar(
|
||||||
|
&mut buf.subdimensions((128, 0, 384, 24)),
|
||||||
|
&Color::new(0.75, 0.25, 0.25, 1.0),
|
||||||
|
384,
|
||||||
|
24,
|
||||||
|
vol - 1.0,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
if vol > 2.0 {
|
||||||
|
draw_bar(
|
||||||
|
&mut buf.subdimensions((128, 0, 384, 24)),
|
||||||
|
&Color::new(0.50, 0.10, 0.10, 1.0),
|
||||||
|
384,
|
||||||
|
24,
|
||||||
|
vol - 2.0,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Ok(vec![buf.get_signed_bounds()])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, _time: &DateTime<Local>, force: bool) -> Result<bool, ::std::io::Error> {
|
||||||
|
let mut s = self.lock().unwrap();
|
||||||
|
if s.dirty || force {
|
||||||
|
s.dirty = false;
|
||||||
|
Ok(true)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input(&mut self, input: Input) {
|
||||||
|
match input {
|
||||||
|
Input::Scroll {
|
||||||
|
pos: _pos,
|
||||||
|
x: _x,
|
||||||
|
y,
|
||||||
|
} => {
|
||||||
|
let mut s = self.lock().unwrap();
|
||||||
|
s
|
||||||
|
.device
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.set_volume((y * -1.0) as f32 / 8.0)
|
||||||
|
.unwrap();
|
||||||
|
s.dirty = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
Input::Click { pos: _pos, button } => match button {
|
||||||
|
273 => {
|
||||||
|
let mut s = self.lock().unwrap();
|
||||||
|
s.device.lock().unwrap().toggle().unwrap();
|
||||||
|
s.dirty = true;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user