diff --git a/Cargo.lock b/Cargo.lock index 9630139a6f..d9a555ceee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -253,7 +253,7 @@ dependencies = [ "i3ipc 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "inotify 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libpulse-binding 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libpulse-binding 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "maildir 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -324,19 +324,20 @@ dependencies = [ [[package]] name = "libpulse-binding" -version = "2.2.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "libpulse-sys 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (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.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -794,8 +795,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" "checksum libdbus-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8720f9274907052cb50313f91201597868da9d625f8dd125f2aca5bddb7e83a1" -"checksum libpulse-binding 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "94cf8d18cd66838e8a2d049ea3b3ae6942e88ad007c2d593def703a1e7470e52" -"checksum libpulse-sys 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a5e1843312173214a21c7f7dabd0e2de467033355ed57366f64aadb2a288f47b" +"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 log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum maildir 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "83d9b449b6ff23db5eda044963296380c74941ac9480fc629840d7405e436c73" diff --git a/src/blocks/sound.rs b/src/blocks/sound.rs index 34b9fde47f..e9661ea631 100644 --- a/src/blocks/sound.rs +++ b/src/blocks/sound.rs @@ -33,7 +33,17 @@ use pulse::mainloop::standard::Mainloop; #[cfg(feature = "pulseaudio")] use pulse::callbacks::ListResult; #[cfg(feature = "pulseaudio")] -use pulse::context::{Context, flags, State as PulseState, introspect::SinkInfo, introspect::ServerInfo, subscribe::Facility, subscribe::Operation as SubscribeOperation, subscribe::subscription_masks}; +use pulse::context::{ + Context, + flags, + State as PulseState, + introspect::SinkInfo, + introspect::SourceInfo, + introspect::ServerInfo, + subscribe::Facility, + subscribe::Operation as SubscribeOperation, + subscribe::subscription_masks +}; #[cfg(feature = "pulseaudio")] use pulse::proplist::{properties, Proplist}; #[cfg(feature = "pulseaudio")] @@ -181,6 +191,7 @@ struct PulseAudioClient { #[cfg(feature = "pulseaudio")] struct PulseAudioSoundDevice { name: Option, + direction: Direction, volume: Option, volume_avg: u32, muted: bool, @@ -193,22 +204,37 @@ struct PulseAudioSinkInfo { mute: bool, } +#[cfg(feature = "pulseaudio")] +#[derive(Debug)] +struct PulseAudioSourceInfo { + volume: ChannelVolumes, + mute: bool, +} + #[cfg(feature = "pulseaudio")] #[derive(Debug)] enum PulseAudioClientRequest { - GetDefaultDevice, + GetDefaultSink, GetSinkInfoByIndex(u32), GetSinkInfoByName(String), SetSinkVolumeByName(String, ChannelVolumes), SetSinkMuteByName(String, bool), + GetDefaultSource, + GetSourceInfoByIndex(u32), + GetSourceInfoByName(String), + SetSourceVolumeByName(String, ChannelVolumes), + SetSourceMuteByName(String, bool), } #[cfg(feature = "pulseaudio")] lazy_static! { - static ref PULSEAUDIO_CLIENT: Result = PulseAudioClient::new(); + static ref PULSEAUDIO_CLIENT_SINK: Result = PulseAudioClient::new(Direction::Output); + static ref PULSEAUDIO_CLIENT_SOURCE: Result = PulseAudioClient::new(Direction::Input); static ref PULSEAUDIO_EVENT_LISTENER: Mutex>> = Mutex::new(HashMap::new()); static ref PULSEAUDIO_DEFAULT_SINK: Mutex = Mutex::new("@DEFAULT_SINK@".into()); static ref PULSEAUDIO_SINKS: Mutex> = Mutex::new(HashMap::new()); + static ref PULSEAUDIO_DEFAULT_SOURCE: Mutex = Mutex::new("@DEFAULT_SOURCE@".into()); + static ref PULSEAUDIO_SOURCES: Mutex> = Mutex::new(HashMap::new()); } #[cfg(feature = "pulseaudio")] @@ -273,7 +299,7 @@ impl PulseAudioConnection { #[cfg(feature = "pulseaudio")] impl PulseAudioClient { - fn new() -> Result { + fn new(direction: Direction) -> Result { let (send_req, recv_req) = async(); let (send_result, recv_result) = sync(0); let send_result2 = send_result.clone(); @@ -318,8 +344,8 @@ impl PulseAudioClient { let mut introspector = connection.context.borrow_mut().introspect(); match req { - PulseAudioClientRequest::GetDefaultDevice => { - introspector.get_server_info(PulseAudioClient::server_info_callback); + PulseAudioClientRequest::GetDefaultSink => { + introspector.get_server_info(PulseAudioClient::server_info_callback_sink); }, PulseAudioClientRequest::GetSinkInfoByIndex(index) => { introspector.get_sink_info_by_index(index, PulseAudioClient::sink_info_callback); @@ -333,6 +359,21 @@ impl PulseAudioClient { PulseAudioClientRequest::SetSinkMuteByName(name, mute) => { introspector.set_sink_mute_by_name(&name, mute, None); }, + PulseAudioClientRequest::GetDefaultSource => { + introspector.get_server_info(PulseAudioClient::server_info_callback_source); + }, + PulseAudioClientRequest::GetSourceInfoByIndex(index) => { + introspector.get_source_info_by_index(index, PulseAudioClient::source_info_callback); + }, + PulseAudioClientRequest::GetSourceInfoByName(name) => { + introspector.get_source_info_by_name(&name, PulseAudioClient::source_info_callback); + }, + PulseAudioClientRequest::SetSourceVolumeByName(name, volumes) => { + introspector.set_source_volume_by_name(&name, &volumes, None); + }, + PulseAudioClientRequest::SetSourceMuteByName(name, mute) => { + introspector.set_source_mute_by_name(&name, mute, None); + }, }; // send request and receive response @@ -347,14 +388,27 @@ impl PulseAudioClient { // subscribe thread::spawn(move || { let connection = new_connection(send_result2); - + // subcribe for events - connection.context.borrow_mut().set_subscribe_callback(Some(Box::new(PulseAudioClient::subscribe_callback))); - connection.context.borrow_mut().subscribe( - subscription_masks::SERVER | - subscription_masks::SINK, - |_| { } - ); + match direction { + Direction::Input => { + connection.context.borrow_mut().set_subscribe_callback(Some(Box::new(PulseAudioClient::subscribe_callback_source))); + connection.context.borrow_mut().subscribe( + subscription_masks::SERVER | + subscription_masks::SOURCE, + |_| { } + ); + } + Direction::Output => { + connection.context.borrow_mut().set_subscribe_callback(Some(Box::new(PulseAudioClient::subscribe_callback_sink))); + connection.context.borrow_mut().subscribe( + subscription_masks::SERVER | + subscription_masks::SINK, + |_| { } + ); + } + } + connection.mainloop.borrow_mut().run().unwrap(); }); @@ -366,21 +420,48 @@ impl PulseAudioClient { } fn send(request: PulseAudioClientRequest) -> Result<()> { - match PULSEAUDIO_CLIENT.as_ref() { - Ok(client) => { - client.sender.send(request); - Ok(()) - }, - Err(err) => { - Err(BlockError( - "sound".into(), - format!("pulseaudio connection failed with error: {}", err), - )) + match request { + PulseAudioClientRequest::GetDefaultSink | + PulseAudioClientRequest::GetSinkInfoByIndex(_) | + PulseAudioClientRequest::GetSinkInfoByName(_) | + PulseAudioClientRequest::SetSinkMuteByName(_, _) | + PulseAudioClientRequest::SetSinkVolumeByName(_, _) => { + match PULSEAUDIO_CLIENT_SINK.as_ref() { + Ok(client) => { + client.sender.send(request); + Ok(()) + }, + Err(err) => { + Err(BlockError( + "sound".into(), + format!("pulseaudio connection failed with error: {}", err), + )) + } + } + } + PulseAudioClientRequest::GetDefaultSource | + PulseAudioClientRequest::GetSourceInfoByIndex(_) | + PulseAudioClientRequest::GetSourceInfoByName(_) | + PulseAudioClientRequest::SetSourceMuteByName(_, _) | + PulseAudioClientRequest::SetSourceVolumeByName(_, _) => { + match PULSEAUDIO_CLIENT_SOURCE.as_ref() { + Ok(client) => { + client.sender.send(request); + Ok(()) + }, + Err(err) => { + Err(BlockError( + "sound".into(), + format!("pulseaudio connection failed with error: {}", err), + )) + } + } } } + } - fn server_info_callback(server_info: &ServerInfo) { + fn server_info_callback_sink(server_info: &ServerInfo) { match server_info.default_sink_name.clone() { None => {}, Some(default_sink) => { @@ -390,6 +471,16 @@ impl PulseAudioClient { } } + fn server_info_callback_source(server_info: &ServerInfo) { + match server_info.default_source_name.clone() { + None => {}, + Some(default_source) => { + *PULSEAUDIO_DEFAULT_SOURCE.lock().unwrap() = default_source.into(); + PulseAudioClient::send_update_event(); + } + } + } + fn sink_info_callback<'r, 's>(result: ListResult<&'r SinkInfo>) { match result { ListResult::End | @@ -410,12 +501,32 @@ impl PulseAudioClient { } } - fn subscribe_callback(facility: Option, _operation: Option, index: u32) { + fn source_info_callback<'r, 's>(result: ListResult<&'r SourceInfo>) { + match result { + ListResult::End | + ListResult::Error => { }, + ListResult::Item(source_info) => { + match source_info.name.clone() { + None => {}, + Some(name) => { + let info = PulseAudioSourceInfo { + volume: source_info.volume, + mute: source_info.mute, + }; + PULSEAUDIO_SOURCES.lock().unwrap().insert(name.into(), info); + PulseAudioClient::send_update_event(); + } + } + }, + } + } + + fn subscribe_callback_sink(facility: Option, _operation: Option, index: u32) { match facility { None => { }, Some(facility) => match facility { Facility::Server => { - let _ = PulseAudioClient::send(PulseAudioClientRequest::GetDefaultDevice); + let _ = PulseAudioClient::send(PulseAudioClientRequest::GetDefaultSink); }, Facility::Sink => { let _ = PulseAudioClient::send(PulseAudioClientRequest::GetSinkInfoByIndex(index)); @@ -425,6 +536,21 @@ impl PulseAudioClient { } } + fn subscribe_callback_source(facility: Option, _operation: Option, index: u32) { + match facility { + None => { }, + Some(facility) => match facility { + Facility::Server => { + let _ = PulseAudioClient::send(PulseAudioClientRequest::GetDefaultSource); + }, + Facility::Source => { + let _ = PulseAudioClient::send(PulseAudioClientRequest::GetSourceInfoByIndex(index)); + }, + _ => { } + } + } + } + fn send_update_event() { for (id, tx_update_request) in &*PULSEAUDIO_EVENT_LISTENER.lock().unwrap() { tx_update_request.send(Task { @@ -437,26 +563,49 @@ impl PulseAudioClient { #[cfg(feature = "pulseaudio")] impl PulseAudioSoundDevice { - fn new() -> Result { - PulseAudioClient::send(PulseAudioClientRequest::GetDefaultDevice)?; + fn new(direction: Direction) -> Result { + match direction { + Direction::Input => { + PulseAudioClient::send(PulseAudioClientRequest::GetDefaultSource)?; + } + Direction::Output => { + PulseAudioClient::send(PulseAudioClientRequest::GetDefaultSink)?; + } + } let device = PulseAudioSoundDevice { name: None, + direction: direction, volume: None, volume_avg: 0, muted: false, }; - PulseAudioClient::send(PulseAudioClientRequest::GetSinkInfoByName(device.name()))?; + match direction { + Direction::Input => { + PulseAudioClient::send(PulseAudioClientRequest::GetSourceInfoByName(device.name()))?; + } + Direction::Output => { + PulseAudioClient::send(PulseAudioClientRequest::GetSinkInfoByName(device.name()))?; + } + } Ok(device) } - fn with_name(name: String) -> Result { - PulseAudioClient::send(PulseAudioClientRequest::GetSinkInfoByName(name.clone()))?; + fn with_name(name: String, direction: Direction) -> Result { + match direction { + Direction::Input => { + PulseAudioClient::send(PulseAudioClientRequest::GetSourceInfoByName(name.clone()))?; + } + Direction::Output => { + PulseAudioClient::send(PulseAudioClientRequest::GetSinkInfoByName(name.clone()))?; + } + } Ok(PulseAudioSoundDevice { name: Some(name), + direction: direction, volume: None, volume_avg: 0, muted: false, @@ -464,7 +613,15 @@ impl PulseAudioSoundDevice { } fn name(&self) -> String { - self.name.clone().unwrap_or_else(|| PULSEAUDIO_DEFAULT_SINK.lock().unwrap().clone()) + match self.direction { + Direction::Input => { + self.name.clone().unwrap_or_else(|| PULSEAUDIO_DEFAULT_SOURCE.lock().unwrap().clone()) + } + Direction::Output => { + self.name.clone().unwrap_or_else(|| PULSEAUDIO_DEFAULT_SINK.lock().unwrap().clone()) + } + } + } fn volume(&mut self, volume: ChannelVolumes) { @@ -479,14 +636,28 @@ impl SoundDevice for PulseAudioSoundDevice { fn muted(&self) -> bool { self.muted } fn get_info(&mut self) -> Result<()> { - match PULSEAUDIO_SINKS.lock().unwrap().get(&self.name()) { - None => {}, - Some(sink_info) => { - self.volume(sink_info.volume); - self.muted = sink_info.mute; + match self.direction { + Direction::Input => { + match PULSEAUDIO_SOURCES.lock().unwrap().get(&self.name()) { + None => {}, + Some(source_info) => { + self.volume(source_info.volume); + self.muted = source_info.mute; + } + } + } + Direction::Output => { + match PULSEAUDIO_SINKS.lock().unwrap().get(&self.name()) { + None => {}, + Some(sink_info) => { + self.volume(sink_info.volume); + self.muted = sink_info.mute; + } + } } } + Ok(()) } @@ -504,14 +675,30 @@ impl SoundDevice for PulseAudioSoundDevice { // update volumes self.volume(volume); - PulseAudioClient::send(PulseAudioClientRequest::SetSinkVolumeByName(self.name(), volume))?; + match self.direction { + Direction::Input => { + PulseAudioClient::send(PulseAudioClientRequest::SetSourceVolumeByName(self.name(), volume))?; + } + Direction::Output => { + PulseAudioClient::send(PulseAudioClientRequest::SetSinkVolumeByName(self.name(), volume))?; + } + } + Ok(()) } fn toggle(&mut self) -> Result<()> { self.muted = !self.muted; - PulseAudioClient::send(PulseAudioClientRequest::SetSinkMuteByName(self.name(), self.muted))?; + match self.direction { + Direction::Input => { + PulseAudioClient::send(PulseAudioClientRequest::SetSourceMuteByName(self.name(), self.muted))?; + } + Direction::Output => { + PulseAudioClient::send(PulseAudioClientRequest::SetSinkMuteByName(self.name(), self.muted))?; + } + } + Ok(()) } @@ -527,6 +714,7 @@ pub struct Sound { text: ButtonWidget, id: String, device: Box, + direction: Direction, step_width: u32, config: Config, on_click: Option, @@ -539,6 +727,10 @@ pub struct SoundConfig { #[serde(default = "SoundDriver::default")] pub driver: SoundDriver, + /// whether the this block specifies an audio input or output + #[serde(default = "Direction::default")] + pub direction: Direction, + /// ALSA / PulseAudio sound device name #[serde(default = "SoundConfig::default_name")] pub name: Option, @@ -566,6 +758,19 @@ impl Default for SoundDriver { } } +#[derive(Deserialize, Copy, Clone, Debug)] +#[serde(rename_all = "lowercase")] +pub enum Direction { + Input, + Output, +} + +impl Default for Direction { + fn default() -> Self { + Direction::Output + } +} + impl SoundConfig { fn default_name() -> Option { None @@ -584,25 +789,51 @@ impl Sound { fn display(&mut self) -> Result<()> { self.device.get_info()?; - if self.device.muted() { - self.text.set_icon("volume_empty"); - self.text.set_text( - self.config - .icons - .get("volume_muted") - .block_error("sound", "cannot find icon")? - .to_owned(), - ); - self.text.set_state(State::Warning); - } else { - let volume = self.device.volume(); - self.text.set_icon(match volume { - 0...20 => "volume_empty", - 21...70 => "volume_half", - _ => "volume_full", - }); - self.text.set_text(format!("{:02}%", volume)); - self.text.set_state(State::Idle); + match self.direction { + Direction::Input => { + if self.device.muted() { + self.text.set_icon("mic_muted"); + self.text.set_text( + self.config + .icons + .get("crossed") + .block_error("sound", "cannot find icon")? + .to_owned(), + ); + self.text.set_state(State::Warning); + } else { + let volume = self.device.volume(); + self.text.set_icon(match volume { + 0...20 => "mic_empty", + 21...70 => "mic_half", + _ => "mic_full", + }); + self.text.set_text(format!("{:02}%", volume)); + self.text.set_state(State::Idle); + } + } + Direction::Output => { + if self.device.muted() { + self.text.set_icon("volume_muted"); + self.text.set_text( + self.config + .icons + .get("crossed") + .block_error("sound", "cannot find icon")? + .to_owned(), + ); + self.text.set_state(State::Warning); + } else { + let volume = self.device.volume(); + self.text.set_icon(match volume { + 0...20 => "volume_empty", + 21...70 => "volume_half", + _ => "volume_full", + }); + self.text.set_text(format!("{:02}%", volume)); + self.text.set_state(State::Idle); + } + } } Ok(()) @@ -627,25 +858,35 @@ impl ConfigBlock for Sound { #[cfg(feature = "pulseaudio")] SoundDriver::Auto | SoundDriver::PulseAudio => match block_config.name.clone() { - None => PulseAudioSoundDevice::new(), - Some(name) => PulseAudioSoundDevice::with_name(name) + None => PulseAudioSoundDevice::new(block_config.direction), + Some(name) => PulseAudioSoundDevice::with_name(name, block_config.direction) }, _ => Err(BlockError( "sound".into(), "PulseAudio feature or driver disabled".into(), )) }; - + // prefere PulseAudio if available and selected, fallback to ALSA let device: Box = match pulseaudio_device { Ok(dev) => Box::new(dev), - Err(_) => Box::new(AlsaSoundDevice::new(block_config.name.unwrap_or_else(|| "Master".into()))?) + Err(_) => { + match block_config.direction { + Direction::Input => { + Box::new(AlsaSoundDevice::new(block_config.name.unwrap_or_else(|| "Capture".into()))?) + } + Direction::Output => { + Box::new(AlsaSoundDevice::new(block_config.name.unwrap_or_else(|| "Master".into()))?) + } + } + } }; let mut sound = Self { text: ButtonWidget::new(config.clone(), &id).with_icon("volume_empty"), id: id.clone(), - device, + device: device, + direction: block_config.direction, step_width: step_width, config: config, on_click: block_config.on_click, diff --git a/src/blocks/xrandr.rs b/src/blocks/xrandr.rs index 14fcc5579f..1e2c1e3ce3 100644 --- a/src/blocks/xrandr.rs +++ b/src/blocks/xrandr.rs @@ -186,20 +186,32 @@ impl Xrandr { fn display(&mut self) -> Result<()> { if let Some(m) = self.monitors.get(self.current_idx) { let brightness_str = m.brightness.to_string(); + let brightness_icon = self.config + .icons + .get("backlight_full") + .block_error("xrandr", "cannot find icon")? + .to_owned(); + let resolution_icon = self.config + .icons + .get("size") + .block_error("xrandr", "cannot find icon")? + .to_owned(); let values = map!("{display}" => m.name.clone(), + "{brightness_icon}" => brightness_icon, "{brightness}" => brightness_str, - "{resolution}" => m.resolution.clone()); + "{resolution}" => m.resolution.clone(), + "{resolution_icon}" => resolution_icon); self.text.set_icon("xrandr"); let format_str: &str; if self.resolution { if self.icons { - format_str = "{display} \u{f185} {brightness} \u{f096} {resolution}"; + format_str = "{display} {brightness_icon}{brightness} {resolution_icon}{resolution}"; } else { format_str = "{display}: {brightness} [{resolution}]"; } } else if self.icons { - format_str = "{display} \u{f185} {brightness}"; + format_str = "{display} {brightness_icon} {brightness}"; } else { format_str = "{display}: {brightness}"; } diff --git a/src/icons.rs b/src/icons.rs index c60f164f01..1ee6059aa1 100755 --- a/src/icons.rs +++ b/src/icons.rs @@ -2,140 +2,208 @@ use std::collections::HashMap as Map; lazy_static! { pub static ref NONE: Map = map_to_owned! { - "" => "", - "time" => " ", - "music" => " ", - "music_play" => ">", - "music_pause" => "||", - "music_next" => " > ", - "music_prev" => " < ", - "cogs" => " LOAD ", - "memory_mem" => " MEM ", - "memory_swap" => " SWAP ", - "cpu" => " CPU ", - "bat" => " BAT ", - "bat_full" => " FULL ", - "bat_charging" => " CHG ", - "bat_discharging" => " DCG ", - "update" => " UPD ", - "toggle_off" => " OFF ", - "toggle_on" => " ON ", - "volume_full" => " VOL ", - "volume_half" => " VOL ", - "volume_empty" => " VOL ", + "" => "", + "time" => " ", + "music" => " ", + "music_play" => ">", + "music_pause" => "||", + "music_next" => " > ", + "music_prev" => " < ", + "cogs" => " LOAD ", + "memory_mem" => " MEM ", + "memory_swap" => " SWAP ", + "cpu" => " CPU ", + "bat" => " BAT ", + "bat_full" => " FULL ", + "bat_charging" => " CHG ", + "bat_discharging" => " DCG ", + "update" => " UPD ", + "toggle_off" => " OFF ", + "toggle_on" => " ON ", + "volume_full" => " VOL ", + "volume_half" => " VOL ", + "volume_empty" => " VOL ", // This icon has no spaces around it because it is manually set as text. (sound.rs) - "volume_muted" => "MUTED", - "thermometer" => " TEMP ", - "xrandr" => " SCREEN ", - "net_up" => " UP ", - "net_down" => " DOWN ", - "net_wireless" => " WLAN ", - "net_wired" => " ETH ", - "ping" => " PING ", - "backlight_empty" => " BRIGHT ", + "volume_muted" => "MUTED", + "thermometer" => " TEMP ", + "xrandr" => " SCREEN ", + "net_up" => " UP ", + "net_down" => " DOWN ", + "net_wireless" => " WLAN ", + "net_wired" => " ETH ", + "ping" => " PING ", + "backlight_empty" => " BRIGHT ", "backlight_partial1" => " BRIGHT ", "backlight_partial2" => " BRIGHT ", "backlight_partial3" => " BRIGHT ", - "backlight_full" => " BRIGHT ", - "weather_sun" => " SUNNY ", - "weather_snow" => " SNOW ", - "weather_thunder" => " STORM ", - "weather_clouds" => " CLOUDY ", - "weather_rain" => " RAIN ", - "weather_default" => " WEATHER ", - "uptime" => " UP ", - "gpu" => " GPU ", - "mail" => " " + "backlight_full" => " BRIGHT ", + "weather_sun" => " SUNNY ", + "weather_snow" => " SNOW ", + "weather_thunder" => " STORM ", + "weather_clouds" => " CLOUDY ", + "weather_rain" => " RAIN ", + "weather_default" => " WEATHER ", + "uptime" => " UP ", + "gpu" => " GPU ", + "mail" => " " }; pub static ref AWESOME: Map = map_to_owned! { - "" => "", - "time" => " \u{f017} ", - "music" => " \u{f001} ", - "music_play" => " \u{f04b} ", - "music_pause" => " \u{f04c} ", - "music_next" => " \u{f061} ", - "music_prev" => " \u{f060} ", - "cogs" => " \u{f085} ", - "memory_mem" => " \u{f2db} ", - "memory_swap" => " \u{f0a0} ", - "cpu" => " \u{f0e4} ", - "bat" => " \u{f242} ", - "bat_full" => " \u{f240} ", - "bat_charging" => " \u{f1e6} ", - "bat_discharging" => " \u{f242} ", - "update" => " \u{f062} ", - "toggle_off" => " \u{f204} ", - "toggle_on" => " \u{f205} ", - "volume_full" => " \u{f028} ", - "volume_half" => " \u{f027} ", - "volume_empty" => " \u{f026} ", + "" => "", + "time" => " \u{f017} ", + "music" => " \u{f001} ", + "music_play" => " \u{f04b} ", + "music_pause" => " \u{f04c} ", + "music_next" => " \u{f061} ", + "music_prev" => " \u{f060} ", + "cogs" => " \u{f085} ", + "memory_mem" => " \u{f2db} ", + "memory_swap" => " \u{f0a0} ", + "cpu" => " \u{f0e4} ", + "bat" => " \u{f242} ", + "bat_full" => " \u{f240} ", + "bat_charging" => " \u{f1e6} ", + "bat_discharging" => " \u{f242} ", + "update" => " \u{f062} ", + "toggle_off" => " \u{f204} ", + "toggle_on" => " \u{f205} ", // This icon has no spaces around it because it is manually set as text. (sound.rs) - "volume_muted" => "\u{f00d}", - "thermometer" => " \u{f2c8} ", - "xrandr" => " \u{f26c} ", - "net_up" => " \u{2b06} ", - "net_down" => " \u{2b07} ", - "net_wireless" => " \u{f1eb} ", - "net_wired" => " \u{f0ac} ", - "ping" => " \u{21ba} ", - "backlight_empty" => " \u{1f315} ", + "crossed" => "\u{f00d}", + "volume_full" => " \u{f028} ", + "volume_half" => " \u{f027} ", + "volume_empty" => " \u{f026} ", + "volume_muted" => " \u{f026} ", + "mic_full" => " \u{f130} ", + "mic_half" => " \u{f130} ", + "mic_empty" => " \u{f130} ", + "mic_muted" => " \u{f131} ", + "thermometer" => " \u{f2c8} ", + "xrandr" => " \u{f26c} ", + "net_up" => " \u{2b06} ", + "net_down" => " \u{2b07} ", + "net_wireless" => " \u{f1eb} ", + "net_wired" => " \u{f0ac} ", + "ping" => " \u{21ba} ", + "backlight_empty" => " \u{1f315} ", "backlight_partial1" => " \u{1f314} ", "backlight_partial2" => " \u{1f313} ", "backlight_partial3" => " \u{1f312} ", - "backlight_full" => " \u{1f311} ", - "weather_sun" => " \u{f185} ", - "weather_snow" => " \u{f2dc} ", - "weather_thunder" => " \u{f0e7} ", - "weather_clouds" => " \u{f0c2} ", - "weather_rain" => " \u{f043} ", + "backlight_full" => " \u{1f311} ", + "size" => " \u{f065} ", + "weather_sun" => " \u{f185} ", + "weather_snow" => " \u{f2dc} ", + "weather_thunder" => " \u{f0e7} ", + "weather_clouds" => " \u{f0c2} ", + "weather_rain" => " \u{f043} ", // Cloud symbol as default - "weather_default" => " \u{f0c2} ", + "weather_default" => " \u{f0c2} ", // Same as time symbol. - "uptime" => " \u{f017} ", - "gpu" => " \u{f26c} ", - "mail" => " \u{f0e0} " + "uptime" => " \u{f017} ", + "gpu" => " \u{f26c} ", + "mail" => " \u{f0e0} " + }; + + pub static ref AWESOME_5: Map = map_to_owned! { + "" => "", + "time" => " \u{f017} ", + "music" => " \u{f001} ", + "music_play" => " \u{f04b} ", + "music_pause" => " \u{f04c} ", + "music_next" => " \u{f061} ", + "music_prev" => " \u{f060} ", + "cogs" => " \u{f085} ", + "memory_mem" => " \u{f2db} ", + "memory_swap" => " \u{f0a0} ", + "cpu" => " \u{f3fd} ", + "bat" => " \u{f242} ", + "bat_full" => " \u{f240} ", + "bat_charging" => " \u{f1e6} ", + "bat_discharging" => " \u{f242} ", + "update" => " \u{f062} ", + "toggle_off" => " \u{f204} ", + "toggle_on" => " \u{f205} ", + // This icon has no spaces around it because it is manually set as text. (sound.rs) + "crossed" => "\u{f00d}", + "volume_full" => " \u{f028} ", + "volume_half" => " \u{f027} ", + "volume_empty" => " \u{f026} ", + "volume_muted" => " \u{f026} ", + "mic_full" => " \u{f130} ", + "mic_half" => " \u{f130} ", + "mic_empty" => " \u{f130} ", + "mic_muted" => " \u{f131} ", + "thermometer" => " \u{f2c8} ", + "xrandr" => " \u{f26c} ", + "net_up" => " \u{2b06} ", + "net_down" => " \u{2b07} ", + "net_wireless" => " \u{f1eb} ", + "net_wired" => " \u{f0ac} ", + "ping" => " \u{21ba} ", + "backlight_empty" => " \u{f0eb} ", + "backlight_partial1" => " \u{f0eb} ", + "backlight_partial2" => " \u{f0eb} ", + "backlight_partial3" => " \u{f0eb} ", + "backlight_full" => " \u{f0eb} ", + "size" => " \u{f065} ", + "weather_sun" => " \u{f185} ", + "weather_snow" => " \u{f2dc} ", + "weather_thunder" => " \u{f0e7} ", + "weather_clouds" => " \u{f0c2} ", + "weather_rain" => " \u{f043} ", + // Cloud symbol as default + "weather_default" => " \u{f0c2} ", + // Same as time symbol. + "uptime" => " \u{f017} ", + "gpu" => " \u{f26c} ", + "mail" => " \u{f0e0} " }; pub static ref MATERIAL: Map = map_to_owned! { - "" => "", - "time" => " \u{e192} ", - "music" => " \u{e405} ", - "music_play" => " \u{e037} ", - "music_pause" => " \u{e034} ", - "music_next" => " \u{e044} ", - "music_prev" => " \u{e045} ", - "cogs" => " \u{e8b8} ", - "memory_mem" => " \u{e322} ", - "memory_swap" => " \u{e8d4} ", - "cpu" => " \u{e640} ", - "bat" => " \u{e1a5} ", - "bat_full" => " \u{e1a4} ", - "bat_charging" => " \u{e1a3} ", - "bat_discharging" => " \u{e19c} ", - "update" => " \u{e8d7} ", - "toggle_off" => " \u{e836} ", - "toggle_on" => " \u{e837} ", - "volume_full" => " \u{e050} ", - "volume_half" => " \u{e04d} ", - "volume_empty" => " \u{e04e} ", + "" => "", + "time" => " \u{e192} ", + "music" => " \u{e405} ", + "music_play" => " \u{e037} ", + "music_pause" => " \u{e034} ", + "music_next" => " \u{e044} ", + "music_prev" => " \u{e045} ", + "cogs" => " \u{e8b8} ", + "memory_mem" => " \u{e322} ", + "memory_swap" => " \u{e8d4} ", + "cpu" => " \u{e640} ", + "bat" => " \u{e1a5} ", + "bat_full" => " \u{e1a4} ", + "bat_charging" => " \u{e1a3} ", + "bat_discharging" => " \u{e19c} ", + "update" => " \u{e8d7} ", + "toggle_off" => " \u{e836} ", + "toggle_on" => " \u{e837} ", // This icon has no spaces around it because it is manually set as text. (sound.rs) - "volume_muted" => "\u{e04f}", - "thermometer" => " \u{f2c8} ", // TODO - "xrandr" => " \u{e31e} ", + "crossed" => "\u{e04f}", + "volume_full" => " \u{e050} ", + "volume_half" => " \u{e04d} ", + "volume_empty" => " \u{e04e} ", + "volume_muted" => " \u{e04e} ", + "volume_full" => " \u{e029} ", + "volume_half" => " \u{e029} ", + "volume_empty" => " \u{e02a} ", + "volume_muted" => " \u{e02b} ", + "thermometer" => " \u{f2c8} ", // TODO + "xrandr" => " \u{e31e} ", + "size" => " \u{e56b} ", // Same as time symbol. - "uptime" => " \u{e192} ", - "gpu" => " \u{e333} ", - "mail" => " \u{e0be} " + "uptime" => " \u{e192} ", + "gpu" => " \u{e333} ", + "mail" => " \u{e0be} " }; } pub fn get_icons(name: &str) -> Option> { match name { - "material" => Some(MATERIAL.clone()), - "awesome" => Some(AWESOME.clone()), - "none" => Some(NONE.clone()), - _ => None, + "material" => Some(MATERIAL.clone()), + "awesome" => Some(AWESOME.clone()), + "awesome 5" => Some(AWESOME_5.clone()), + "none" => Some(NONE.clone()), + _ => None, } } diff --git a/src/util.rs b/src/util.rs index bc2cc0a5ad..bbd5ca2b5b 100644 --- a/src/util.rs +++ b/src/util.rs @@ -197,7 +197,7 @@ impl FormatTemplate { let s_as_bytes = s.clone().into_bytes(); //valid var tokens: {} containing any amount of alphanumericals - let re = Regex::new(r"\{[a-zA-Z0-9]+?\}") + let re = Regex::new(r"\{[_a-zA-Z0-9]+?\}") .internal_error("util", "invalid regex")?; let mut token_vec: Vec = vec![];