├── .gitignore ├── examples ├── ram.sh └── github.fish ├── src ├── i3 │ ├── mod.rs │ ├── i3.rs │ └── i3_thread.rs ├── cpu │ ├── mod.rs │ ├── cpu.rs │ └── cpu_thread.rs ├── alsa │ ├── mod.rs │ ├── alsa.rs │ └── alsa_thread.rs ├── mpris │ ├── mod.rs │ ├── mpris.rs │ └── mpris_thread.rs ├── config.ron ├── style.css ├── custom.rs ├── clock.rs ├── clock │ └── popover.rs ├── config.rs ├── ewmh │ ├── ewmh.rs │ └── ewmh_helper.rs ├── bar.rs └── main.rs ├── wiki.md ├── Cargo.toml ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /examples/ram.sh: -------------------------------------------------------------------------------- 1 | free -m | grep Mem | awk '{printf("%.0f%",($3/$2)*100)}' -------------------------------------------------------------------------------- /src/i3/mod.rs: -------------------------------------------------------------------------------- 1 | mod i3; 2 | pub mod i3_thread; 3 | 4 | pub use i3::*; 5 | -------------------------------------------------------------------------------- /src/cpu/mod.rs: -------------------------------------------------------------------------------- 1 | mod cpu; 2 | pub mod cpu_thread; 3 | 4 | pub use cpu::*; 5 | -------------------------------------------------------------------------------- /src/alsa/mod.rs: -------------------------------------------------------------------------------- 1 | mod alsa; 2 | pub mod alsa_thread; 3 | 4 | pub use self::alsa::*; 5 | -------------------------------------------------------------------------------- /src/mpris/mod.rs: -------------------------------------------------------------------------------- 1 | mod mpris; 2 | pub mod mpris_thread; 3 | 4 | pub use self::mpris::*; 5 | -------------------------------------------------------------------------------- /examples/github.fish: -------------------------------------------------------------------------------- 1 | set key "GITHUB-KEY" 2 | set len (curl --location --request GET 'https://api.github.com/notifications' \ 3 | --header "Authorization: token $key" | jq length) 4 | 5 | if test $len != 0 6 | echo $len 7 | end -------------------------------------------------------------------------------- /wiki.md: -------------------------------------------------------------------------------- 1 | # YetAnotherBar 2 | 3 | - **#bar_name** (Window) 4 | - **#main_box** (Box) 5 | - (EventBox) 6 | - **#clock** (Label) 7 | - (EventBox) 8 | - **#alsa** (Label) 9 | - .muted 10 | - (EventBox) 11 | - **#mpris** (Label) 12 | - .playing 13 | - **#cpu** (Label) 14 | - **#i3** (Box) 15 | - (Button) * number of workspaces 16 | - .focused 17 | - .urgent 18 | - :hover 19 | - :active 20 | - **#mode** (Label) 21 | 22 | 23 | ![Graph](https://i.imgur.com/SaUEjpB.png) -------------------------------------------------------------------------------- /src/config.ron: -------------------------------------------------------------------------------- 1 | // vim:ft=rust 2 | 3 | Config( 4 | bars: { 5 | "bar-left": ( 6 | monitor: "DP-1", 7 | pos_x: 0, 8 | pos_y: 1000, 9 | modules_left: [ 10 | I3, 11 | ], 12 | modules_right: [ 13 | Cpu, 14 | Mpris, 15 | Alsa, 16 | Clock, 17 | ], 18 | ), 19 | "bar-right": ( 20 | monitor: "HDMI-0", 21 | pos_x: 1920, 22 | pos_y: 1000, 23 | modules_left: [ 24 | I3, 25 | ], 26 | modules_right: [ 27 | Cpu, 28 | Mpris, 29 | Alsa, 30 | Clock, 31 | ], 32 | ), 33 | }, 34 | ) 35 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "yetanotherbar" 3 | version = "0.1.0" 4 | authors = ["Poly "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | gio = "0.14" 9 | gtk = { version="0.14", features=["v3_22"] } 10 | gdk = "0.14" 11 | glib = "0.14" 12 | 13 | relm = "0.22" 14 | relm-derive = "0.22" 15 | 16 | serde = "1.0" 17 | serde_derive = "1.0" 18 | ron = "0.6.0" 19 | 20 | chrono = "0.4" 21 | i3ipc = "0.10.1" 22 | alsa = "0.5.0" 23 | mpris = "1.1.2" 24 | systemstat = "0.1.5" 25 | gtk-layer-shell = { version="0.2.2", features=["v0_5"], optional=true} 26 | 27 | [features] 28 | default=[] 29 | wayland=["gtk-layer-shell"] -------------------------------------------------------------------------------- /src/cpu/cpu.rs: -------------------------------------------------------------------------------- 1 | use gtk::prelude::*; 2 | use relm::Widget; 3 | use relm_derive::{widget, Msg}; 4 | 5 | pub struct Model { 6 | out: String, 7 | } 8 | 9 | #[derive(Msg, Clone)] 10 | pub enum Msg { 11 | Update(String), 12 | } 13 | 14 | #[widget] 15 | impl Widget for Cpu { 16 | fn model() -> Model { 17 | Model { 18 | out: "▁ ▁ ▁ ▁".into(), 19 | } 20 | } 21 | 22 | fn update(&mut self, event: Msg) { 23 | match event { 24 | Msg::Update(s) => self.model.out = s, 25 | } 26 | } 27 | 28 | fn init_view(&mut self) {} 29 | 30 | view! { 31 | gtk::Label { 32 | text: &self.model.out, 33 | widget_name: "cpu" 34 | }, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | border: none; 3 | border-radius: 0; 4 | font-size: 13px; 5 | font-weight: 600; 6 | min-height: 0; 7 | } 8 | 9 | #clock, 10 | #alsa, 11 | #mpris 12 | { 13 | font-size: 15px; 14 | 15 | padding: 0px 10px; 16 | margin: 5px 4px; 17 | color: #ffffff; 18 | border-radius: 10px; 19 | } 20 | #clock { 21 | background-color: #ff0066; 22 | } 23 | #alsa { 24 | background-color: #2ecc71; 25 | color: black; 26 | font-weight: 500; 27 | transition-property: background-color, color; 28 | transition-duration: 0.5s; 29 | } 30 | #alsa.muted{ 31 | background-color: #90b1b1; 32 | } 33 | 34 | #mpris{ 35 | background-color: #90b1b1; 36 | color: #ffffff; 37 | transition-property: background-color, color; 38 | transition-duration: 0.5s; 39 | } 40 | #mpris.playing{ 41 | background-color: #25a75b; 42 | } 43 | #cpu{ 44 | margin: 5px 4px; 45 | color: #424242; 46 | } 47 | 48 | 49 | window,#main_box{ 50 | background: rgba(35, 41, 47, 0.5); 51 | color: #ffffff; 52 | } 53 | 54 | 55 | #i3 #mode{ 56 | margin-left: 15px; 57 | } 58 | #i3 button { 59 | background: unset; 60 | padding: 0 15px; 61 | background-color: transparent; 62 | color: #ffffff; 63 | border-bottom: 4px solid rgba(255, 255, 255, 0.2); 64 | box-shadow: unset; 65 | } 66 | #i3 button.focused { 67 | border-bottom: 4px solid rgba(255, 255, 255, 0.8); 68 | } 69 | #i3 button.urgent { 70 | border-bottom: 4px solid rgb(226, 51, 51); 71 | } 72 | #i3 button:hover { 73 | background: rgba(0, 0, 0, 0.2); 74 | box-shadow: inherit; 75 | border-bottom: 4px solid #ffffff; 76 | } 77 | #i3 button:active { 78 | background: rgb(40,40,40); 79 | } 80 | -------------------------------------------------------------------------------- /src/cpu/cpu_thread.rs: -------------------------------------------------------------------------------- 1 | pub struct CpuThread { 2 | streams: Vec>, 3 | } 4 | 5 | impl CpuThread { 6 | pub fn new() -> Self { 7 | Self { 8 | streams: Vec::new(), 9 | } 10 | } 11 | pub fn push_stream(&mut self, stream: relm::StreamHandle) { 12 | self.streams.push(stream); 13 | } 14 | pub fn should_run(&self) -> bool { 15 | !self.streams.is_empty() 16 | } 17 | pub fn run(self) { 18 | let streams = self.streams; 19 | let (_channel, sender) = relm::Channel::new(move |u: String| { 20 | for s in streams.iter() { 21 | s.emit(super::cpu::Msg::Update(u.clone())); 22 | } 23 | }); 24 | 25 | std::thread::spawn(move || { 26 | use systemstat::{Platform, System}; 27 | 28 | let sys = System::new(); 29 | 30 | loop { 31 | match sys.cpu_load() { 32 | Ok(cpu) => { 33 | std::thread::sleep(std::time::Duration::from_secs(1)); 34 | let cpus = cpu.done().unwrap(); 35 | 36 | let mut load = String::new(); 37 | load += " "; 38 | let list = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█']; 39 | for cpu in cpus { 40 | let cp = (cpu.user + cpu.nice + cpu.system + cpu.interrupt) * 7.0; 41 | 42 | load += &list[cp as usize].to_string(); 43 | load += " "; 44 | } 45 | sender.send(load).expect("cpu_thread send message"); 46 | } 47 | Err(x) => println!("\nCPU load: error: {}", x), 48 | } 49 | } 50 | }); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![YetAnotherBar Baner](https://i.imgur.com/jqUkGuA.png) 2 | 3 | ## Why do we need yet another status bar? 4 | The answer is really simple... we don't, 5 | but I really like the idea of native status bar with CSS support so here you go anyway 6 | 7 | # Installation 8 | On Arch linux you can install it from AUR [yetanotherbar-git](https://aur.archlinux.org/packages/yetanotherbar-git) 9 | 10 | #### Wayland 11 | for Wayland you need `gtk-layer-shell` on your system, and YAB binary built with `wayland` feature flag 12 | 13 | # Example Config 14 | `` ~/.config/YetAnotherBar/config.ron`` 15 | ```rust 16 | Config( 17 | bars: { 18 | "bar-left": ( 19 | monitor: "DP-1", 20 | pos_x: 0, 21 | pos_y: 1000, 22 | modules_left: [ 23 | I3, 24 | Custom(( 25 | name: "custom-ram", 26 | exec: ["sh","/path/to/ram.sh"], 27 | interval: 1000, 28 | )) 29 | ], 30 | modules_right: [ 31 | Cpu, 32 | Mpris, 33 | Alsa, 34 | Clock, 35 | ], 36 | ), 37 | "bar-right": ( 38 | monitor: "HDMI-0", 39 | pos_x: 1920, 40 | pos_y: 1000, 41 | modules_left: [ 42 | I3, 43 | ], 44 | modules_right: [ 45 | Cpu, 46 | Mpris, 47 | Alsa, 48 | Clock, 49 | ], 50 | ), 51 | }, 52 | ) 53 | ``` 54 | `` ~/.config/YetAnotherBar/style.css`` [css](https://github.com/PolyMeilex/YetAnotherBar/blob/master/src/style.css) 55 | For more info about CSS selectors visit [wiki](https://github.com/PolyMeilex/YetAnotherBar/wiki) 56 | ## Result 57 | ![img](https://i.imgur.com/GJ71oye.png) 58 | 59 | ![img](https://i.imgur.com/ECgAEZj.png) 60 | -------------------------------------------------------------------------------- /src/custom.rs: -------------------------------------------------------------------------------- 1 | use std::thread; 2 | use std::time::Duration; 3 | 4 | use gtk::prelude::*; 5 | use gtk::Inhibit; 6 | use relm::Channel; 7 | use relm::{Relm, Widget}; 8 | use relm_derive::{widget, Msg}; 9 | 10 | use crate::config::CustomModule; 11 | 12 | pub struct Model { 13 | config: CustomModule, 14 | text: String, 15 | 16 | _channel: Channel, 17 | } 18 | 19 | #[derive(Msg)] 20 | pub enum Msg { 21 | Click, 22 | TextUpdate(String), 23 | } 24 | 25 | #[widget] 26 | impl Widget for Custom { 27 | fn model(relm: &Relm, config: CustomModule) -> Model { 28 | let stream = relm.stream().clone(); 29 | let (channel, sender) = Channel::new(move |msg| { 30 | stream.emit(msg); 31 | }); 32 | 33 | let c = config.clone(); 34 | thread::spawn(move || loop { 35 | let mut exec = c.exec.clone(); 36 | let d = std::process::Command::new(&exec.remove(0)) 37 | .args(exec) 38 | .output(); 39 | 40 | if let Ok(d) = d { 41 | let text = String::from_utf8(d.stdout).unwrap(); 42 | sender.send(Msg::TextUpdate(text)).expect("send message"); 43 | } 44 | 45 | thread::sleep(Duration::from_millis(c.interval as u64)); 46 | }); 47 | 48 | Model { 49 | config, 50 | text: String::new(), 51 | _channel: channel, 52 | } 53 | } 54 | 55 | fn update(&mut self, event: Msg) { 56 | match event { 57 | Msg::Click => {} 58 | Msg::TextUpdate(s) => { 59 | self.model.text = s; 60 | } 61 | } 62 | } 63 | 64 | fn init_view(&mut self) { 65 | self.widgets.label.set_widget_name(&self.model.config.name); 66 | } 67 | 68 | view! { 69 | gtk::EventBox{ 70 | button_press_event(_,_) => (Msg::Click, Inhibit(false)), 71 | #[name="label"] 72 | gtk::Label { 73 | text: self.model.text.trim(), 74 | }, 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/alsa/alsa.rs: -------------------------------------------------------------------------------- 1 | use gtk::prelude::*; 2 | use gtk::Inhibit; 3 | use relm::{Relm, Widget}; 4 | use relm_derive::{widget, Msg}; 5 | use std::sync::mpsc; 6 | 7 | use super::alsa_thread::AlsaActionEvent; 8 | 9 | pub struct Model { 10 | volume: String, 11 | sender: mpsc::Sender, 12 | } 13 | 14 | #[derive(Msg, Clone)] 15 | pub enum Msg { 16 | Update(f64, i32), 17 | Mute, 18 | VolumeChange(gdk::ScrollDirection), 19 | } 20 | 21 | #[widget] 22 | impl Widget for Alsa { 23 | fn model(_relm: &Relm, sender: mpsc::Sender) -> Model { 24 | Model { 25 | volume: "0%".into(), 26 | sender, 27 | } 28 | } 29 | 30 | fn update(&mut self, event: Msg) { 31 | match event { 32 | Msg::Update(volume, state) => { 33 | let p = volume.round(); 34 | 35 | self.model.volume = p.to_string() + "%"; 36 | 37 | if state == 0 { 38 | self.widgets.gtk_label.style_context().add_class("muted"); 39 | } else { 40 | self.widgets.gtk_label.style_context().remove_class("muted"); 41 | } 42 | } 43 | Msg::Mute => { 44 | self.model.sender.send(AlsaActionEvent::Mute).unwrap(); 45 | } 46 | Msg::VolumeChange(sd) => { 47 | let mult = match sd { 48 | gdk::ScrollDirection::Up => 1, 49 | gdk::ScrollDirection::Down => -1, 50 | _ => return, 51 | }; 52 | self.model 53 | .sender 54 | .send(AlsaActionEvent::VolumeChange(5.0 * mult as f64)) 55 | .unwrap(); 56 | } 57 | } 58 | } 59 | 60 | view! { 61 | gtk::EventBox{ 62 | events: gdk::EventMask::SCROLL_MASK, 63 | button_press_event(_,_) => (Msg::Mute, Inhibit(false)), 64 | scroll_event(_,se) => (Msg::VolumeChange(se.direction()),Inhibit(false)), 65 | 66 | #[name="gtk_label"] 67 | gtk::Label { 68 | text: &self.model.volume, 69 | widget_name: "alsa", 70 | }, 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/mpris/mpris.rs: -------------------------------------------------------------------------------- 1 | use gtk::prelude::*; 2 | use gtk::Inhibit; 3 | use relm::{Relm, Widget}; 4 | use relm_derive::{widget, Msg}; 5 | use std::sync::mpsc; 6 | 7 | use super::mpris_thread; 8 | use mpris_thread::MpscActionEvent; 9 | 10 | pub struct Model { 11 | text: String, 12 | player: Option, 13 | status: Option, 14 | sender: mpsc::Sender, 15 | } 16 | 17 | #[derive(Msg, Clone)] 18 | pub enum Msg { 19 | UpdateLabel, 20 | Player(Option), 21 | PausePlay, 22 | Status(Option), 23 | } 24 | 25 | #[widget] 26 | impl Widget for Mpris { 27 | fn model(_: &Relm, sender: mpsc::Sender) -> Model { 28 | Model { 29 | text: "None".into(), 30 | player: None, 31 | status: None, 32 | sender, 33 | } 34 | } 35 | 36 | fn update(&mut self, event: Msg) { 37 | match event { 38 | Msg::UpdateLabel => { 39 | if let (Some(player), Some(status)) = (&self.model.player, &self.model.status) { 40 | self.model.text = format!("{} : {:?}", player, status); 41 | } else { 42 | self.model.text = "None".into(); 43 | } 44 | } 45 | Msg::Player(s) => self.model.player = s, 46 | Msg::PausePlay => { 47 | self.model.sender.send(MpscActionEvent::PausePlay).unwrap(); 48 | } 49 | Msg::Status(status) => { 50 | self.model.status = status; 51 | 52 | let ctx = self.widgets.gtk_label.style_context(); 53 | 54 | match status { 55 | Some(mpris::PlaybackStatus::Playing) => { 56 | ctx.add_class("playing"); 57 | } 58 | _ => { 59 | ctx.remove_class("playing"); 60 | } 61 | } 62 | } 63 | } 64 | } 65 | 66 | view! { 67 | gtk::EventBox{ 68 | button_press_event(_,_) => (Msg::PausePlay, Inhibit(false)), 69 | 70 | #[name="gtk_label"] 71 | gtk::Label { 72 | text: &self.model.text, 73 | widget_name: "mpris", 74 | }, 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/clock.rs: -------------------------------------------------------------------------------- 1 | use gdk::EventButton; 2 | use gtk::prelude::*; 3 | use gtk::Inhibit; 4 | use relm::Component; 5 | use relm::{Relm, Widget}; 6 | use relm_derive::{widget, Msg}; 7 | 8 | mod popover; 9 | use popover::{PopupMenu, PopupMenuMsg}; 10 | 11 | pub struct Model { 12 | unfolded: bool, 13 | time: String, 14 | 15 | relm: Relm, 16 | 17 | popup_menu: Option>, 18 | } 19 | 20 | #[derive(Msg)] 21 | pub enum Msg { 22 | Tick, 23 | Click(EventButton), 24 | PopoverDone, 25 | } 26 | 27 | #[widget] 28 | impl Widget for Clock { 29 | fn model(relm: &Relm, _: ()) -> Model { 30 | let time = chrono::Local::now(); 31 | Model { 32 | unfolded: false, 33 | time: format!("{}", time.format("%H:%M")), 34 | 35 | relm: relm.clone(), 36 | popup_menu: None, 37 | } 38 | } 39 | 40 | fn update(&mut self, event: Msg) { 41 | match event { 42 | Msg::Click(btn_event) => { 43 | if btn_event.button() == 3 && self.model.popup_menu.is_none() { 44 | self.model.popup_menu = Some(relm::create_component::(( 45 | self.model.relm.stream().clone(), 46 | self.widgets.event_box.clone(), 47 | ))); 48 | } else if btn_event.button() == 1 { 49 | self.model.unfolded = !self.model.unfolded; 50 | self.update(Msg::Tick); 51 | } 52 | } 53 | Msg::Tick => { 54 | let time = chrono::Local::now(); 55 | 56 | if !self.model.unfolded { 57 | self.model.time = format!("{}", time.format("%H:%M")); 58 | } else { 59 | self.model.time = format!("{}", time.format("%Y-%m-%d")); 60 | } 61 | } 62 | Msg::PopoverDone => self.model.popup_menu = None, 63 | } 64 | } 65 | fn subscriptions(&mut self, relm: &Relm) { 66 | relm::interval(relm.stream(), 1000, || Msg::Tick); 67 | } 68 | 69 | view! { 70 | #[name="event_box"] 71 | gtk::EventBox{ 72 | button_press_event(_,event) => (Msg::Click(event.clone()), Inhibit(false)), 73 | gtk::Label { 74 | text: &self.model.time, 75 | widget_name: "clock" 76 | }, 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/clock/popover.rs: -------------------------------------------------------------------------------- 1 | use gtk::prelude::*; 2 | use gtk::EventBox; 3 | use relm::connect; 4 | use relm::Update; 5 | use relm::{Relm, StreamHandle, Widget}; 6 | use relm_derive::Msg; 7 | 8 | use super::Msg as ClockMsg; 9 | 10 | #[derive(Msg)] 11 | pub enum PopupMenuMsg { 12 | Finish, 13 | } 14 | 15 | pub struct PopupMenuModel { 16 | msg_stream: StreamHandle, 17 | relative_to: EventBox, 18 | } 19 | 20 | pub struct PopupMenu { 21 | model: PopupMenuModel, 22 | 23 | popover: gtk::Popover, 24 | } 25 | 26 | impl Update for PopupMenu { 27 | type Model = PopupMenuModel; 28 | type ModelParam = (StreamHandle, EventBox); 29 | type Msg = PopupMenuMsg; 30 | 31 | fn model( 32 | _: &Relm, 33 | (msg_stream, relative_to): (StreamHandle, EventBox), 34 | ) -> PopupMenuModel { 35 | PopupMenuModel { 36 | msg_stream, 37 | relative_to, 38 | } 39 | } 40 | 41 | fn update(&mut self, event: PopupMenuMsg) { 42 | match event { 43 | PopupMenuMsg::Finish => { 44 | self.popover.popdown(); 45 | self.model.msg_stream.emit(ClockMsg::PopoverDone); 46 | } 47 | } 48 | } 49 | } 50 | 51 | impl Widget for PopupMenu { 52 | type Root = gtk::Popover; 53 | 54 | fn init_view(&mut self) { 55 | self.popover.popup(); 56 | } 57 | 58 | fn view(relm: &::relm::Relm, model: Self::Model) -> Self { 59 | let popover = gtk::PopoverBuilder::new() 60 | .position(gtk::PositionType::Top) 61 | .constrain_to(gtk::PopoverConstraint::None) 62 | .relative_to(&model.relative_to) 63 | .build(); 64 | popover.popdown(); 65 | 66 | let vbox = gtk::BoxBuilder::new() 67 | .orientation(gtk::Orientation::Vertical) 68 | .margin(10) 69 | .build(); 70 | popover.set_child(Some(&vbox)); 71 | 72 | let calendar = gtk::CalendarBuilder::new() 73 | .width_request(300) 74 | .height_request(150) 75 | .build(); 76 | vbox.pack_start(&calendar, true, true, 0); 77 | vbox.show_all(); 78 | 79 | connect!( 80 | relm, 81 | popover, 82 | connect_closed(_), 83 | return (Some(PopupMenuMsg::Finish), ()) 84 | ); 85 | 86 | Self { model, popover } 87 | } 88 | 89 | fn root(&self) -> Self::Root { 90 | self.popover.clone() 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use serde_derive::{Deserialize, Serialize}; 2 | use std::collections::BTreeMap; 3 | 4 | #[derive(Clone, Debug, Deserialize, Serialize)] 5 | pub struct Bar { 6 | pub monitor: String, 7 | pub pos_x: i32, 8 | pub pos_y: i32, 9 | pub modules_left: Vec, 10 | pub modules_right: Vec, 11 | } 12 | 13 | #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] 14 | pub struct CustomModule { 15 | pub name: String, 16 | pub exec: Vec, 17 | pub interval: u32, 18 | } 19 | 20 | #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] 21 | pub enum Module { 22 | I3, 23 | Clock, 24 | Alsa, 25 | Mpris, 26 | Cpu, 27 | Custom(CustomModule), 28 | } 29 | 30 | // #[derive(Clone, Debug, Deserialize)] 31 | // pub struct DetailedDep { 32 | // name: String, 33 | // } 34 | 35 | // #[derive(Clone, Debug, Deserialize)] 36 | // #[serde(untagged)] 37 | // pub enum Dep { 38 | // Simple(String), 39 | // Detailed(DetailedDep), 40 | // } 41 | 42 | #[derive(Clone, Debug, Deserialize, Serialize)] 43 | pub struct Config { 44 | pub bars: BTreeMap, 45 | } 46 | 47 | use std::path::PathBuf; 48 | pub fn config_dir() -> Option { 49 | let home = std::env::var_os("HOME").and_then(|h| if h.is_empty() { None } else { Some(h) }); 50 | if let Some(home) = home { 51 | Some(PathBuf::from(home).join(".config")) 52 | } else { 53 | None 54 | } 55 | } 56 | 57 | pub fn get_config() -> (Config, Vec) { 58 | let config_dir = config_dir(); 59 | 60 | let default_config = include_str!("./config.ron"); 61 | let default_style = include_bytes!("./style.css"); 62 | 63 | let (ron_str, style_str) = if let Some(config_dir) = config_dir { 64 | let bar_config_dir = config_dir.join("YetAnotherBar"); 65 | let _ = std::fs::create_dir_all(&bar_config_dir); 66 | let ron_str: String = 67 | if let Ok(file) = std::fs::read_to_string(&bar_config_dir.join("config.ron")) { 68 | file 69 | } else { 70 | default_config.into() 71 | }; 72 | let style_str = if let Ok(file) = std::fs::read(&bar_config_dir.join("style.css")) { 73 | file 74 | } else { 75 | default_style.to_vec() 76 | }; 77 | (ron_str, style_str) 78 | } else { 79 | (default_config.into(), default_style.to_vec()) 80 | }; 81 | 82 | let decoded: Config = ron::from_str(&ron_str).unwrap(); 83 | 84 | (decoded, style_str) 85 | } 86 | -------------------------------------------------------------------------------- /src/ewmh/ewmh.rs: -------------------------------------------------------------------------------- 1 | use gtk::prelude::*; 2 | use gtk::Inhibit; 3 | use relm::{Channel, Relm, Widget}; 4 | use relm_derive::{widget, Msg}; 5 | 6 | use crate::clock::Clock; 7 | use crate::ewmh_helper; 8 | 9 | pub struct Model { 10 | monitor_name: String, 11 | gtk_buttons: Vec, 12 | cur_desktop: String, 13 | } 14 | 15 | #[derive(Msg)] 16 | pub enum Msg { 17 | Update(ewmh_helper::EwmhEvent), 18 | } 19 | 20 | #[widget] 21 | impl Widget for Ewmh { 22 | type ModelParam = String; 23 | 24 | fn model(_: &Relm, monitor_name: String) -> Model { 25 | Model { 26 | monitor_name, 27 | gtk_buttons: Vec::new(), 28 | cur_desktop: String::new(), 29 | } 30 | } 31 | 32 | fn update(&mut self, event: Msg) { 33 | match event { 34 | Msg::Update(ewmh_event) => { 35 | self.model.cur_desktop = ewmh_event 36 | .desktop_names 37 | .get(ewmh_event.current_desktop as usize) 38 | .unwrap() 39 | .clone(); 40 | 41 | for btn in self.model.gtk_buttons.iter() { 42 | btn.destroy(); 43 | } 44 | 45 | for id in 0..ewmh_event.num_desktops as usize { 46 | let m = ewmh_event.desktop_monitors[id].as_ref().unwrap(); 47 | if m.name != self.model.monitor_name { 48 | continue; 49 | } 50 | let btn = gtk::Button::new_with_label(&ewmh_event.desktop_names[id]); 51 | 52 | if ewmh_event.current_desktop as usize == id { 53 | btn.get_style_context().add_class("focused"); 54 | } 55 | 56 | self.gtk_box.add(&btn); 57 | gtk::WidgetExt::show(&btn); 58 | self.model.gtk_buttons.push(btn); 59 | } 60 | } 61 | } 62 | } 63 | fn subscriptions(&mut self, relm: &Relm) { 64 | let stream = relm.stream().clone(); 65 | let (_channel, sender) = Channel::new(move |event: ewmh_helper::EwmhEvent| { 66 | stream.emit(Msg::Update(event)); 67 | }); 68 | 69 | std::thread::spawn(|| ewmh_helper::init(sender)); 70 | } 71 | 72 | fn init_view(&mut self) {} 73 | 74 | view! { 75 | #[name="gtk_box"] 76 | gtk::Box{ 77 | widget_name: "ewmh", 78 | orientation: gtk::Orientation::Horizontal, 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/i3/i3.rs: -------------------------------------------------------------------------------- 1 | use gtk::prelude::*; 2 | use relm::{Relm, Widget}; 3 | use relm_derive::{widget, Msg}; 4 | use std::sync::mpsc; 5 | 6 | use super::i3_thread; 7 | use i3_thread::I3ActionEvent; 8 | 9 | pub struct Model { 10 | monitor_name: String, 11 | gtk_buttons: Vec, 12 | gtk_label: gtk::Label, 13 | sender: mpsc::Sender, 14 | } 15 | 16 | #[derive(Msg, Clone)] 17 | pub enum Msg { 18 | UpdateWorkspaces(Vec), 19 | UpdateMode(String), 20 | } 21 | 22 | #[widget] 23 | impl Widget for I3 { 24 | type ModelParam = String; 25 | 26 | fn model( 27 | _: &Relm, 28 | (monitor_name, sender): (String, mpsc::Sender), 29 | ) -> Model { 30 | Model { 31 | monitor_name, 32 | gtk_buttons: Vec::new(), 33 | gtk_label: gtk::LabelBuilder::new().name("mode").build(), 34 | sender, 35 | } 36 | } 37 | 38 | fn update(&mut self, event: Msg) { 39 | match event { 40 | Msg::UpdateWorkspaces(workspaces) => { 41 | for btn in self.model.gtk_buttons.iter() { 42 | unsafe { btn.destroy() }; 43 | } 44 | 45 | let monitor_name = &self.model.monitor_name; 46 | for ws in workspaces 47 | .into_iter() 48 | .filter(|ws| &ws.output == monitor_name) 49 | { 50 | let btn = gtk::Button::with_label(&ws.name); 51 | 52 | if ws.focused { 53 | btn.style_context().add_class("focused"); 54 | } 55 | if ws.urgent { 56 | btn.style_context().add_class("urgent"); 57 | } 58 | 59 | let sender = self.model.sender.clone(); 60 | btn.connect_clicked(move |_| { 61 | sender 62 | .send(I3ActionEvent::RunCommand(format!("workspace {}", ws.name))) 63 | .unwrap(); 64 | }); 65 | 66 | self.widgets.gtk_box.pack_start(&btn, false, false, 0); 67 | WidgetExt::show(&btn); 68 | self.model.gtk_buttons.push(btn); 69 | } 70 | } 71 | Msg::UpdateMode(mode) => { 72 | if mode != "default" { 73 | self.model.gtk_label.set_text(&mode); 74 | } else { 75 | self.model.gtk_label.set_text(""); 76 | } 77 | } 78 | } 79 | } 80 | fn init_view(&mut self) { 81 | self.widgets 82 | .gtk_box 83 | .pack_end(&self.model.gtk_label, false, false, 5); 84 | } 85 | 86 | view! { 87 | #[name="gtk_box"] 88 | gtk::Box{ 89 | widget_name: "i3", 90 | orientation: gtk::Orientation::Horizontal, 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/alsa/alsa_thread.rs: -------------------------------------------------------------------------------- 1 | use std::sync::mpsc; 2 | 3 | #[derive(Debug)] 4 | pub enum AlsaActionEvent { 5 | Mute, 6 | VolumeChange(f64), 7 | } 8 | 9 | pub struct AlsaThread { 10 | streams: Vec>, 11 | tx: mpsc::Sender, 12 | rx: mpsc::Receiver, 13 | } 14 | 15 | impl AlsaThread { 16 | pub fn new() -> Self { 17 | let (tx, rx) = mpsc::channel::(); 18 | 19 | Self { 20 | streams: Vec::new(), 21 | tx, 22 | rx, 23 | } 24 | } 25 | pub fn sender(&self) -> &mpsc::Sender { 26 | &self.tx 27 | } 28 | pub fn push_stream(&mut self, stream: relm::StreamHandle) { 29 | self.streams.push(stream); 30 | } 31 | pub fn should_run(&self) -> bool { 32 | !self.streams.is_empty() 33 | } 34 | pub fn run(self) { 35 | let streams = self.streams; 36 | let (_channel, sender) = relm::Channel::new(move |msg: super::alsa::Msg| { 37 | for s in streams.iter() { 38 | s.emit(msg.clone()); 39 | } 40 | }); 41 | 42 | let rx = self.rx; 43 | std::thread::spawn(move || { 44 | fn update_event(master: &::alsa::mixer::Selem) -> super::alsa::Msg { 45 | let volume = master 46 | .get_playback_volume(::alsa::mixer::SelemChannelId::FrontLeft) 47 | .unwrap() as f64; 48 | 49 | let (min, max) = master.get_playback_volume_range(); 50 | let volume_devider = max as f64 - min as f64; 51 | 52 | let state = master 53 | .get_playback_switch(::alsa::mixer::SelemChannelId::FrontLeft) 54 | .unwrap(); 55 | super::alsa::Msg::Update((volume / volume_devider) * 100.0, state) 56 | } 57 | 58 | let alsa_mixer = ::alsa::Mixer::new("default", true).unwrap(); 59 | 60 | let master = alsa_mixer 61 | .find_selem(&::alsa::mixer::SelemId::new("Master", 0)) 62 | .unwrap(); 63 | 64 | // Init Event 65 | sender.send(update_event(&master)).expect("alsa send"); 66 | loop { 67 | if alsa_mixer.handle_events().unwrap() == 1 { 68 | sender.send(update_event(&master)).expect("alsa send"); 69 | } 70 | 71 | if let Ok(e) = rx.try_recv() { 72 | match e { 73 | AlsaActionEvent::Mute => { 74 | let state = master 75 | .get_playback_switch(alsa::mixer::SelemChannelId::FrontLeft) 76 | .unwrap(); 77 | if state == 0 { 78 | let _ = master.set_playback_switch_all(1); 79 | } else { 80 | let _ = master.set_playback_switch_all(0); 81 | } 82 | 83 | sender.send(update_event(&master)).expect("alsa send"); 84 | } 85 | AlsaActionEvent::VolumeChange(v) => { 86 | let (min, max) = master.get_playback_volume_range(); 87 | let volume_devider = max as f64 - min as f64; 88 | 89 | let add = (v * volume_devider / 100.0) as i64; 90 | 91 | let mut volume = master 92 | .get_playback_volume(alsa::mixer::SelemChannelId::FrontLeft) 93 | .unwrap(); 94 | 95 | if volume + add > max { 96 | volume = max; 97 | } else { 98 | volume += add; 99 | } 100 | 101 | let _ = master.set_playback_volume_all(volume); 102 | 103 | sender.send(update_event(&master)).expect("alsa send"); 104 | } 105 | } 106 | } 107 | 108 | std::thread::sleep(std::time::Duration::from_millis(100)); 109 | } 110 | }); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/ewmh/ewmh_helper.rs: -------------------------------------------------------------------------------- 1 | use xcb_util::ewmh; 2 | 3 | #[derive(Debug)] 4 | pub struct EwmhEvent { 5 | pub num_desktops: u32, 6 | pub current_desktop: u32, 7 | pub desktop_names: Vec, 8 | pub desktop_monitors: Vec>, 9 | } 10 | 11 | #[derive(Debug, Clone)] 12 | pub struct RandrMonitor { 13 | pub name: String, 14 | pub x: i16, 15 | pub y: i16, 16 | pub w: u16, 17 | pub h: u16, 18 | } 19 | 20 | fn on_change( 21 | ewmh_conn: &ewmh::Connection, 22 | screen_idx: i32, 23 | randr_monitors: &Vec, 24 | ) -> EwmhEvent { 25 | let num_desktops = ewmh::get_number_of_desktops(&ewmh_conn, screen_idx) 26 | .get_reply() 27 | .unwrap(); 28 | 29 | let current_desktop = ewmh::get_current_desktop(&ewmh_conn, screen_idx) 30 | .get_reply() 31 | .unwrap(); 32 | let list = ewmh::get_desktop_names(&ewmh_conn, screen_idx) 33 | .get_reply() 34 | .unwrap(); 35 | let desktop_names: Vec = list.strings().iter().map(|s| s.to_string()).collect(); 36 | 37 | let viewport = ewmh::get_desktop_viewport(&ewmh_conn, screen_idx) 38 | .get_reply() 39 | .unwrap(); 40 | 41 | let desktop_monitors: Vec> = viewport 42 | .desktop_viewports() 43 | .iter() 44 | .map(|t| { 45 | let x = t.x; 46 | let y = t.y; 47 | 48 | let m = randr_monitors 49 | .iter() 50 | .find(|m| m.x as u32 == x && m.y as u32 == y); 51 | if let Some(m) = m { 52 | Some(m.to_owned()) 53 | } else { 54 | None 55 | } 56 | }) 57 | .collect(); 58 | 59 | return EwmhEvent { 60 | num_desktops, 61 | current_desktop, 62 | desktop_names, 63 | desktop_monitors, 64 | }; 65 | } 66 | 67 | pub fn init(sender: relm::Sender) { 68 | let (xcb_conn, screen_idx) = xcb::Connection::connect(None).unwrap(); 69 | 70 | let root_window = xcb_conn 71 | .get_setup() 72 | .roots() 73 | .nth(screen_idx as usize) 74 | .unwrap() 75 | .root(); 76 | 77 | let randr_monitors: Vec = { 78 | let t = xcb::randr::get_screen_resources_current(&xcb_conn, root_window) 79 | .get_reply() 80 | .unwrap(); 81 | let ops = t.outputs(); 82 | 83 | let mut monitors = Vec::new(); 84 | for op in ops.iter() { 85 | let a = xcb::randr::get_output_info(&xcb_conn, *op, xcb::CURRENT_TIME) 86 | .get_reply() 87 | .unwrap(); 88 | let crtc = 89 | xcb::randr::get_crtc_info(&xcb_conn, a.crtc(), xcb::CURRENT_TIME).get_reply(); 90 | 91 | if let Ok(crtc) = crtc { 92 | let name = String::from_utf8(a.name().into()).unwrap(); 93 | let x = crtc.x(); 94 | let y = crtc.y(); 95 | 96 | let w = crtc.width(); 97 | let h = crtc.height(); 98 | 99 | monitors.push(RandrMonitor { name, x, y, w, h }) 100 | } 101 | } 102 | monitors 103 | }; 104 | 105 | let ewmh_conn = ewmh::Connection::connect(xcb_conn).ok().unwrap(); 106 | 107 | let ewmh_conn = std::rc::Rc::new(ewmh_conn); 108 | 109 | let attributes = [(xcb::CW_EVENT_MASK, xcb::EVENT_MASK_PROPERTY_CHANGE)]; 110 | xcb::change_window_attributes(&ewmh_conn, root_window, &attributes); 111 | ewmh_conn.flush(); 112 | 113 | // Initial Update 114 | sender 115 | .send(on_change(&ewmh_conn, screen_idx, &randr_monitors)) 116 | .expect("ewmh send"); 117 | 118 | let properties = [ 119 | ewmh_conn.NUMBER_OF_DESKTOPS(), 120 | ewmh_conn.CURRENT_DESKTOP(), 121 | ewmh_conn.DESKTOP_NAMES(), 122 | ]; 123 | loop { 124 | let event = ewmh_conn.wait_for_event().unwrap(); 125 | 126 | use xcb::xproto::{PropertyNotifyEvent, PROPERTY_NOTIFY}; 127 | if event.response_type() == PROPERTY_NOTIFY { 128 | let event: &PropertyNotifyEvent = unsafe { xcb::cast_event(&event) }; 129 | if properties.iter().any(|p| *p == event.atom()) { 130 | sender 131 | .send(on_change(&ewmh_conn, screen_idx, &randr_monitors)) 132 | .expect("ewmh send"); 133 | } 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/bar.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | use gtk::prelude::*; 4 | use gtk::{ApplicationWindow, Inhibit, WindowType}; 5 | use relm::{connect, Relm, Update, Widget}; 6 | use relm_derive::Msg; 7 | 8 | use crate::ModuleComponent; 9 | 10 | #[derive(Clone)] 11 | pub struct ModelParam { 12 | pub bar_name: String, 13 | pub monitor_name: String, 14 | pub x: i32, 15 | pub y: i32, 16 | pub modules_left: Vec>, 17 | pub modules_right: Vec>, 18 | } 19 | 20 | pub struct Model { 21 | params: ModelParam, 22 | app: gtk::Application, 23 | } 24 | #[derive(Msg)] 25 | pub enum Msg { 26 | Quit, 27 | SetVisual, 28 | } 29 | 30 | pub struct Bar { 31 | gtk_window: ApplicationWindow, 32 | gtk_box: gtk::Box, 33 | model: Model, 34 | } 35 | 36 | impl Widget for Bar { 37 | fn init_view(&mut self) { 38 | for module in self.model.params.modules_left.iter() { 39 | self.gtk_box.pack_start(&module.widget(), false, false, 0); 40 | } 41 | 42 | for module in self.model.params.modules_right.iter().rev() { 43 | self.gtk_box.pack_end(&module.widget(), false, false, 0); 44 | } 45 | 46 | self.gtk_window.show_all(); 47 | } 48 | fn view(relm: &::relm::Relm, model: Self::Model) -> Self { 49 | let gtk_window: ApplicationWindow = gtk::ApplicationWindowBuilder::new() 50 | .application(&model.app) 51 | .type_(WindowType::Toplevel) 52 | .name(&model.params.bar_name) 53 | .type_hint(gdk::WindowTypeHint::Dock) 54 | .decorated(false) 55 | .default_height(35) 56 | .default_width(1920) 57 | .app_paintable(true) 58 | .build(); 59 | 60 | #[cfg(feature = "wayland")] 61 | if gtk_layer_shell::is_supported() { 62 | gtk_layer_shell::init_for_window(>k_window); 63 | gtk_layer_shell::set_layer(>k_window, gtk_layer_shell::Layer::Top); 64 | gtk_layer_shell::auto_exclusive_zone_enable(>k_window); 65 | 66 | gtk_layer_shell::set_anchor(>k_window, gtk_layer_shell::Edge::Left, true); 67 | gtk_layer_shell::set_anchor(>k_window, gtk_layer_shell::Edge::Right, true); 68 | gtk_layer_shell::set_anchor(>k_window, gtk_layer_shell::Edge::Bottom, true); 69 | gtk_layer_shell::set_anchor(>k_window, gtk_layer_shell::Edge::Top, false); 70 | 71 | if let Some(display) = gdk::Display::default() { 72 | if let Some(monitor) = display.monitor_at_point(model.params.x, model.params.y) { 73 | gtk_layer_shell::set_monitor(>k_window, &monitor) 74 | } 75 | } 76 | } 77 | 78 | gtk_window.move_(model.params.x, model.params.y); 79 | 80 | Self::set_visual(>k_window, None); 81 | 82 | let gtk_box = gtk::Box::new(gtk::Orientation::Horizontal, 0); 83 | gtk_box.set_widget_name("main_box"); 84 | gtk_window.add(>k_box); 85 | 86 | connect!( 87 | relm, 88 | gtk_window, 89 | connect_screen_changed(_, _), 90 | return (Some(Msg::SetVisual), ()) 91 | ); 92 | 93 | connect!( 94 | relm, 95 | gtk_window, 96 | connect_delete_event(_, _), 97 | return (Some(Msg::Quit), Inhibit(false)) 98 | ); 99 | 100 | Bar { 101 | gtk_window, 102 | gtk_box, 103 | model, 104 | } 105 | } 106 | type Root = ApplicationWindow; 107 | fn root(&self) -> Self::Root { 108 | self.gtk_window.clone() 109 | } 110 | } 111 | 112 | impl Update for Bar { 113 | type Msg = Msg; 114 | type Model = Model; 115 | type ModelParam = (ModelParam, gtk::Application); 116 | fn update(&mut self, event: Msg) { 117 | match event { 118 | Msg::Quit => gtk::main_quit(), 119 | Msg::SetVisual => Self::set_visual(&self.gtk_window, None), 120 | } 121 | } 122 | fn model(_: &Relm, params: Self::ModelParam) -> Model { 123 | Model { 124 | params: params.0, 125 | app: params.1, 126 | } 127 | } 128 | } 129 | 130 | impl Bar { 131 | fn set_visual(window: &ApplicationWindow, _screen: Option<&gdk::Screen>) { 132 | if let Some(screen) = window.screen() { 133 | if let Some(ref visual) = screen.rgba_visual() { 134 | window.set_visual(Some(visual)); 135 | } 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/mpris/mpris_thread.rs: -------------------------------------------------------------------------------- 1 | use std::sync::mpsc; 2 | 3 | pub enum MpscActionEvent { 4 | PausePlay, 5 | } 6 | 7 | fn find_active(finder: &mpris::PlayerFinder) -> Option { 8 | if let Ok(list) = finder.find_all() { 9 | let mut active_list: Vec = list 10 | .into_iter() 11 | .filter(|p| { 12 | if let Ok(mpris::PlaybackStatus::Playing) = p.get_playback_status() { 13 | true 14 | } else { 15 | false 16 | } 17 | }) 18 | .collect(); 19 | 20 | if !active_list.is_empty() { 21 | Some(active_list.remove(0)) 22 | } else { 23 | finder.find_active().ok() 24 | } 25 | } else { 26 | None 27 | } 28 | } 29 | 30 | pub struct MprisThread { 31 | streams: Vec>, 32 | tx: mpsc::Sender, 33 | rx: mpsc::Receiver, 34 | } 35 | 36 | impl MprisThread { 37 | pub fn new() -> Self { 38 | let (tx, rx) = mpsc::channel::(); 39 | 40 | Self { 41 | streams: Vec::new(), 42 | tx, 43 | rx, 44 | } 45 | } 46 | pub fn sender(&self) -> &mpsc::Sender { 47 | &self.tx 48 | } 49 | pub fn push_stream(&mut self, stream: relm::StreamHandle) { 50 | self.streams.push(stream); 51 | } 52 | pub fn should_run(&self) -> bool { 53 | !self.streams.is_empty() 54 | } 55 | pub fn run(self) { 56 | let streams = self.streams; 57 | 58 | let (_channel, sender) = relm::Channel::new(move |msg: super::mpris::Msg| { 59 | for s in streams.iter() { 60 | s.emit(msg.clone()); 61 | } 62 | }); 63 | 64 | let rx = self.rx; 65 | std::thread::spawn(move || { 66 | let finder = mpris::PlayerFinder::new().expect("Could not connect to D-Bus"); 67 | let mut active_player: Option = finder.find_active().ok(); 68 | 69 | loop { 70 | if let Some(ap) = &active_player { 71 | if !ap.is_running() { 72 | active_player = None; 73 | } 74 | } 75 | 76 | if let Ok(event) = rx.try_recv() { 77 | match event { 78 | MpscActionEvent::PausePlay => { 79 | if let Some(active_player) = &active_player { 80 | let _ = active_player.play_pause(); 81 | } 82 | } 83 | } 84 | } 85 | 86 | if let Some(player) = &active_player { 87 | let status = player.get_playback_status(); 88 | 89 | if let Ok(status) = status { 90 | sender 91 | .send(super::mpris::Msg::Status(Some(status))) 92 | .expect("mpris_thread send"); 93 | sender 94 | .send(super::mpris::Msg::Player(Some( 95 | player.identity().to_string(), 96 | ))) 97 | .expect("mpris_thread send"); 98 | sender 99 | .send(super::mpris::Msg::UpdateLabel) 100 | .expect("mpris_thread send"); 101 | 102 | if let mpris::PlaybackStatus::Paused | mpris::PlaybackStatus::Stopped = 103 | status 104 | { 105 | active_player = find_active(&finder); 106 | } 107 | } else { 108 | active_player = find_active(&finder); 109 | }; 110 | } else { 111 | sender 112 | .send(super::mpris::Msg::Status(None)) 113 | .expect("mpris_thread send"); 114 | sender 115 | .send(super::mpris::Msg::Player(None)) 116 | .expect("mpris_thread send"); 117 | sender 118 | .send(super::mpris::Msg::UpdateLabel) 119 | .expect("mpris_thread send"); 120 | 121 | active_player = finder.find_active().ok(); 122 | } 123 | std::thread::sleep(std::time::Duration::from_millis(100)); 124 | } 125 | }); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/i3/i3_thread.rs: -------------------------------------------------------------------------------- 1 | use std::sync::mpsc; 2 | 3 | #[derive(Debug, Clone)] 4 | pub struct RandrMonitor { 5 | pub name: String, 6 | pub x: i16, 7 | pub y: i16, 8 | pub w: u16, 9 | pub h: u16, 10 | } 11 | #[derive(Debug, Clone)] 12 | pub struct I3Workspace { 13 | pub num: i32, 14 | pub name: String, 15 | pub focused: bool, 16 | pub urgent: bool, 17 | pub output: String, 18 | } 19 | 20 | #[derive(Debug)] 21 | pub enum I3ActionEvent { 22 | RunCommand(String), 23 | } 24 | 25 | fn get_workspaces_event(i3_conn: &mut i3ipc::I3Connection) -> super::i3::Msg { 26 | let workspaces = i3_conn 27 | .get_workspaces() 28 | .expect("i3_thread get_workspaces") 29 | .workspaces; 30 | 31 | let workspaces: Vec = workspaces 32 | .into_iter() 33 | .map(|ws| I3Workspace { 34 | num: ws.num, 35 | name: ws.name, 36 | focused: ws.focused, 37 | urgent: ws.urgent, 38 | output: ws.output, 39 | }) 40 | .collect(); 41 | 42 | super::i3::Msg::UpdateWorkspaces(workspaces) 43 | } 44 | 45 | pub struct I3Thread { 46 | streams: Vec>, 47 | tx: mpsc::Sender, 48 | rx: mpsc::Receiver, 49 | } 50 | 51 | impl I3Thread { 52 | pub fn new() -> Self { 53 | let (tx, rx) = mpsc::channel::(); 54 | 55 | Self { 56 | streams: Vec::new(), 57 | tx, 58 | rx, 59 | } 60 | } 61 | pub fn sender(&self) -> &mpsc::Sender { 62 | &self.tx 63 | } 64 | pub fn push_stream(&mut self, stream: relm::StreamHandle) { 65 | self.streams.push(stream); 66 | } 67 | pub fn should_run(&self) -> bool { 68 | !self.streams.is_empty() 69 | } 70 | pub fn run(self) { 71 | let streams = self.streams; 72 | let (_channel, sender) = relm::Channel::new(move |msg: super::i3::Msg| { 73 | for s in streams.iter() { 74 | s.emit(msg.clone()); 75 | } 76 | }); 77 | 78 | let rx = self.rx; 79 | std::thread::spawn(move || loop { 80 | let i3_conn = i3ipc::I3Connection::connect(); 81 | 82 | let mut i3_conn = if let Ok(i3_conn) = i3_conn { 83 | i3_conn 84 | } else { 85 | std::thread::sleep(std::time::Duration::from_secs(1)); 86 | continue; 87 | }; 88 | 89 | // Initial Update 90 | sender 91 | .send(get_workspaces_event(&mut i3_conn)) 92 | .expect("i3_thread sennder"); 93 | 94 | // Sadly there is no api to get curently active binding 95 | // sender 96 | // .send(i3_conn.get_binding_modes()) 97 | // .expect("i3 sennder"); 98 | 99 | enum ThreadEvent { 100 | I3icpEvent(i3ipc::event::Event), 101 | ActionEvent(I3ActionEvent), 102 | } 103 | let local_sender = { 104 | let sender = sender.clone(); 105 | let (_, local_sender) = relm::Channel::new(move |event: ThreadEvent| { 106 | use i3ipc::event::Event; 107 | 108 | let event = match event { 109 | ThreadEvent::I3icpEvent(event) => match event { 110 | Event::WorkspaceEvent { .. } => get_workspaces_event(&mut i3_conn), 111 | Event::ModeEvent(info) => super::i3::Msg::UpdateMode(info.change), 112 | _ => return, 113 | }, 114 | ThreadEvent::ActionEvent(event) => { 115 | match event { 116 | I3ActionEvent::RunCommand(c) => i3_conn.run_command(&c).unwrap(), 117 | }; 118 | return; 119 | } 120 | }; 121 | sender.send(event).expect("i3_thread sennder"); 122 | }); 123 | local_sender 124 | }; 125 | 126 | let mut listener = i3ipc::I3EventListener::connect().expect("i3_thread listener"); 127 | 128 | let subs = [i3ipc::Subscription::Mode, i3ipc::Subscription::Workspace]; 129 | listener.subscribe(&subs).expect("i3_thread subscribe"); 130 | 131 | let i3_is_running = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true)); 132 | 133 | { 134 | let local_sender = local_sender.clone(); 135 | let i3_is_running = i3_is_running.clone(); 136 | std::thread::spawn(move || { 137 | for event in listener.listen() { 138 | let event = if let Ok(event) = event { 139 | event 140 | } else { 141 | break; 142 | }; 143 | local_sender.send(ThreadEvent::I3icpEvent(event)).unwrap(); 144 | } 145 | i3_is_running.swap(false, std::sync::atomic::Ordering::Relaxed); 146 | }); 147 | } 148 | 149 | while i3_is_running.load(std::sync::atomic::Ordering::Relaxed) { 150 | if let Ok(e) = rx.try_recv() { 151 | local_sender.send(ThreadEvent::ActionEvent(e)).unwrap(); 152 | } 153 | std::thread::sleep(std::time::Duration::from_millis(100)); 154 | } 155 | 156 | // After I3 Crashed or restarted we wait 2s before trying to connect again 157 | std::thread::sleep(std::time::Duration::from_secs(1)); 158 | }); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use gio::{prelude::*, ApplicationFlags}; 2 | use gtk::prelude::*; 3 | 4 | use relm::Component; 5 | 6 | use std::cell::RefCell; 7 | use std::rc::Rc; 8 | 9 | mod config; 10 | 11 | mod bar; 12 | mod clock; 13 | mod custom; 14 | 15 | mod alsa; 16 | use crate::alsa::alsa_thread::AlsaThread; 17 | mod cpu; 18 | use crate::cpu::cpu_thread::CpuThread; 19 | mod i3; 20 | use crate::i3::i3_thread::I3Thread; 21 | mod mpris; 22 | use crate::mpris::mpris_thread::MprisThread; 23 | 24 | use bar::Bar; 25 | 26 | pub enum ModuleComponent { 27 | Clock(Component), 28 | I3(Component), 29 | Alsa(Component), 30 | Mpris(Component), 31 | Cpu(Component), 32 | Custom(Component), 33 | } 34 | 35 | impl ModuleComponent { 36 | fn widget(&self) -> gtk::Widget { 37 | match self { 38 | ModuleComponent::Clock(m) => m.widget().clone().upcast::(), 39 | ModuleComponent::I3(m) => m.widget().clone().upcast::(), 40 | ModuleComponent::Alsa(m) => m.widget().clone().upcast::(), 41 | ModuleComponent::Mpris(m) => m.widget().clone().upcast::(), 42 | ModuleComponent::Cpu(m) => m.widget().clone().upcast::(), 43 | ModuleComponent::Custom(m) => m.widget().clone().upcast::(), 44 | } 45 | } 46 | } 47 | 48 | pub struct Threads { 49 | i3: I3Thread, 50 | alsa: AlsaThread, 51 | mpris: MprisThread, 52 | cpu: CpuThread, 53 | } 54 | 55 | fn main() { 56 | let app = gtk::Application::new( 57 | Some("io.github.polymeilex.yetanotherbar"), 58 | ApplicationFlags::HANDLES_COMMAND_LINE, 59 | ); 60 | 61 | let bars: Rc>> = Default::default(); 62 | 63 | app.connect_command_line(move |app, cli| { 64 | if !cli.is_remote() { 65 | let (config, stylesheet) = config::get_config(); 66 | 67 | let mut bars = bars.borrow_mut(); 68 | 69 | // Stylesheet 70 | { 71 | let style_provider = gtk::CssProvider::new(); 72 | style_provider.load_from_data(&stylesheet).unwrap(); 73 | gtk::StyleContext::add_provider_for_screen( 74 | &gdk::Screen::default().unwrap(), 75 | &style_provider, 76 | gtk::STYLE_PROVIDER_PRIORITY_APPLICATION, 77 | ); 78 | } 79 | 80 | let mut threads = Threads { 81 | i3: I3Thread::new(), 82 | alsa: AlsaThread::new(), 83 | mpris: MprisThread::new(), 84 | cpu: CpuThread::new(), 85 | }; 86 | 87 | // Init Bars From Config 88 | for config_bar in config.bars { 89 | fn match_module( 90 | monitor: String, 91 | module: config::Module, 92 | threads: &mut Threads, 93 | list: &mut Vec>, 94 | ) { 95 | list.push(Rc::new(match module { 96 | config::Module::Clock => { 97 | ModuleComponent::Clock(relm::init::(()).unwrap()) 98 | } 99 | config::Module::I3 => { 100 | let i3 = 101 | relm::init::((monitor, threads.i3.sender().clone())) 102 | .unwrap(); 103 | threads.i3.push_stream(i3.stream().clone()); 104 | 105 | ModuleComponent::I3(i3) 106 | } 107 | config::Module::Alsa => { 108 | let alsa = 109 | relm::init::(threads.alsa.sender().clone()) 110 | .unwrap(); 111 | threads.alsa.push_stream(alsa.stream().clone()); 112 | 113 | ModuleComponent::Alsa(alsa) 114 | } 115 | config::Module::Mpris => { 116 | let mpris = 117 | relm::init::(threads.mpris.sender().clone()) 118 | .unwrap(); 119 | threads.mpris.push_stream(mpris.stream().clone()); 120 | ModuleComponent::Mpris(mpris) 121 | } 122 | config::Module::Cpu => { 123 | let cpu = relm::init::(()).unwrap(); 124 | threads.cpu.push_stream(cpu.stream().clone()); 125 | 126 | ModuleComponent::Cpu(cpu) 127 | } 128 | config::Module::Custom(config) => ModuleComponent::Custom( 129 | relm::init::(config).unwrap(), 130 | ), 131 | })); 132 | } 133 | 134 | let mut param = bar::ModelParam { 135 | bar_name: config_bar.0, 136 | monitor_name: config_bar.1.monitor.clone(), 137 | x: config_bar.1.pos_x, 138 | y: config_bar.1.pos_y, 139 | modules_left: Vec::new(), 140 | modules_right: Vec::new(), 141 | }; 142 | 143 | for module in config_bar.1.modules_left { 144 | match_module( 145 | config_bar.1.monitor.clone(), 146 | module, 147 | &mut threads, 148 | &mut param.modules_left, 149 | ); 150 | } 151 | 152 | for module in config_bar.1.modules_right.clone() { 153 | match_module( 154 | config_bar.1.monitor.clone(), 155 | module, 156 | &mut threads, 157 | &mut param.modules_right, 158 | ); 159 | } 160 | 161 | bars.push(param); 162 | } 163 | 164 | // I3 Thread 165 | if threads.i3.should_run() { 166 | threads.i3.run(); 167 | } 168 | // Alsa Thread 169 | if threads.alsa.should_run() { 170 | threads.alsa.run(); 171 | } 172 | // Mpris Thread 173 | if threads.mpris.should_run() { 174 | threads.mpris.run(); 175 | } 176 | // Cpu Thread 177 | if threads.cpu.should_run() { 178 | threads.cpu.run(); 179 | } 180 | 181 | bars.iter().for_each(|m| { 182 | let _ = relm::init::((m.clone(), app.clone())).unwrap(); 183 | }); 184 | } 185 | 186 | 0 187 | }); 188 | 189 | app.run(); 190 | } 191 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.15.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "e7a2e47a1fbe209ee101dd6d61285226744c6c8d3c21c8dc878ba6cb9f467f3a" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "alsa" 22 | version = "0.5.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "75c4da790adcb2ce5e758c064b4f3ec17a30349f9961d3e5e6c9688b052a9e18" 25 | dependencies = [ 26 | "alsa-sys", 27 | "bitflags", 28 | "libc", 29 | "nix", 30 | ] 31 | 32 | [[package]] 33 | name = "alsa-sys" 34 | version = "0.3.1" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" 37 | dependencies = [ 38 | "libc", 39 | "pkg-config", 40 | ] 41 | 42 | [[package]] 43 | name = "anyhow" 44 | version = "1.0.42" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486" 47 | 48 | [[package]] 49 | name = "arrayvec" 50 | version = "0.5.2" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" 53 | 54 | [[package]] 55 | name = "atk" 56 | version = "0.14.0" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "a83b21d2aa75e464db56225e1bda2dd5993311ba1095acaa8fa03d1ae67026ba" 59 | dependencies = [ 60 | "atk-sys", 61 | "bitflags", 62 | "glib", 63 | "libc", 64 | ] 65 | 66 | [[package]] 67 | name = "atk-sys" 68 | version = "0.14.0" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "badcf670157c84bb8b1cf6b5f70b650fed78da2033c9eed84c4e49b11cbe83ea" 71 | dependencies = [ 72 | "glib-sys", 73 | "gobject-sys", 74 | "libc", 75 | "system-deps", 76 | ] 77 | 78 | [[package]] 79 | name = "autocfg" 80 | version = "1.0.1" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 83 | 84 | [[package]] 85 | name = "backtrace" 86 | version = "0.3.59" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744" 89 | dependencies = [ 90 | "addr2line", 91 | "cc", 92 | "cfg-if", 93 | "libc", 94 | "miniz_oxide", 95 | "object", 96 | "rustc-demangle", 97 | ] 98 | 99 | [[package]] 100 | name = "base64" 101 | version = "0.13.0" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 104 | 105 | [[package]] 106 | name = "bitflags" 107 | version = "1.2.1" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 110 | 111 | [[package]] 112 | name = "bitvec" 113 | version = "0.19.5" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" 116 | dependencies = [ 117 | "funty", 118 | "radium", 119 | "tap", 120 | "wyz", 121 | ] 122 | 123 | [[package]] 124 | name = "byteorder" 125 | version = "1.4.3" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 128 | 129 | [[package]] 130 | name = "bytesize" 131 | version = "1.1.0" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "6c58ec36aac5066d5ca17df51b3e70279f5670a72102f5752cb7e7c856adfc70" 134 | 135 | [[package]] 136 | name = "cairo-rs" 137 | version = "0.14.1" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "a408c13bbc04c3337b94194c1a4d04067097439b79dbc1dcbceba299d828b9ea" 140 | dependencies = [ 141 | "bitflags", 142 | "cairo-sys-rs", 143 | "glib", 144 | "libc", 145 | "thiserror", 146 | ] 147 | 148 | [[package]] 149 | name = "cairo-sys-rs" 150 | version = "0.14.0" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "d7c9c3928781e8a017ece15eace05230f04b647457d170d2d9641c94a444ff80" 153 | dependencies = [ 154 | "glib-sys", 155 | "libc", 156 | "system-deps", 157 | ] 158 | 159 | [[package]] 160 | name = "cc" 161 | version = "1.0.69" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" 164 | 165 | [[package]] 166 | name = "cfg-expr" 167 | version = "0.8.0" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "70a1d12766bbdd5d44caab5df04a9bffec9cd855a1b44b15de5665d70c085f94" 170 | dependencies = [ 171 | "smallvec", 172 | ] 173 | 174 | [[package]] 175 | name = "cfg-if" 176 | version = "1.0.0" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 179 | 180 | [[package]] 181 | name = "chrono" 182 | version = "0.4.19" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 185 | dependencies = [ 186 | "libc", 187 | "num-integer", 188 | "num-traits", 189 | "time", 190 | "winapi", 191 | ] 192 | 193 | [[package]] 194 | name = "darling" 195 | version = "0.4.0" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "2a78af487e4eb8f4421a1770687b328af6bb4494ca93435210678c6eea875c11" 198 | dependencies = [ 199 | "darling_core", 200 | "darling_macro", 201 | ] 202 | 203 | [[package]] 204 | name = "darling_core" 205 | version = "0.4.0" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "b315f49c7b6db3708bca6e6913c194581a44ec619b7a39e131d4dd63733a3698" 208 | dependencies = [ 209 | "ident_case", 210 | "proc-macro2 0.3.8", 211 | "quote 0.5.2", 212 | "syn 0.13.11", 213 | ] 214 | 215 | [[package]] 216 | name = "darling_macro" 217 | version = "0.4.0" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "eb69a38fdeaeaf3db712e1df170de67ee9dfc24fb88ca3e9d21e703ec25a4d8e" 220 | dependencies = [ 221 | "darling_core", 222 | "quote 0.5.2", 223 | "syn 0.13.11", 224 | ] 225 | 226 | [[package]] 227 | name = "dbus" 228 | version = "0.6.5" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "48b5f0f36f1eebe901b0e6bee369a77ed3396334bf3f09abd46454a576f71819" 231 | dependencies = [ 232 | "libc", 233 | "libdbus-sys", 234 | ] 235 | 236 | [[package]] 237 | name = "derive_is_enum_variant" 238 | version = "0.1.1" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "d0ac8859845146979953797f03cc5b282fb4396891807cdb3d04929a88418197" 241 | dependencies = [ 242 | "heck", 243 | "quote 0.3.15", 244 | "syn 0.11.11", 245 | ] 246 | 247 | [[package]] 248 | name = "either" 249 | version = "1.6.1" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 252 | 253 | [[package]] 254 | name = "enum-kinds" 255 | version = "0.4.1" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "d0f21c374dea848c19071b1504ca5ad03c9ad0d03d2e509e68f6623b8fcac4b5" 258 | dependencies = [ 259 | "quote 0.4.2", 260 | "syn 0.12.15", 261 | ] 262 | 263 | [[package]] 264 | name = "error-chain" 265 | version = "0.10.0" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8" 268 | 269 | [[package]] 270 | name = "failure" 271 | version = "0.1.8" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" 274 | dependencies = [ 275 | "backtrace", 276 | "failure_derive", 277 | ] 278 | 279 | [[package]] 280 | name = "failure_derive" 281 | version = "0.1.8" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" 284 | dependencies = [ 285 | "proc-macro2 1.0.28", 286 | "quote 1.0.9", 287 | "syn 1.0.74", 288 | "synstructure", 289 | ] 290 | 291 | [[package]] 292 | name = "field-offset" 293 | version = "0.3.4" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92" 296 | dependencies = [ 297 | "memoffset", 298 | "rustc_version", 299 | ] 300 | 301 | [[package]] 302 | name = "fragile" 303 | version = "1.0.0" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "69a039c3498dc930fe810151a34ba0c1c70b02b8625035592e74432f678591f2" 306 | 307 | [[package]] 308 | name = "from_variants" 309 | version = "0.3.0" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "557a27056175c8ecad545ace83508e10092dc8ae34b313c9ad8c8a72b4390b3f" 312 | dependencies = [ 313 | "from_variants_impl", 314 | ] 315 | 316 | [[package]] 317 | name = "from_variants_impl" 318 | version = "0.3.0" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "fc4f4e9b9f5c806f457759523a6c85826aa261115571d3e635f34d890104fbcd" 321 | dependencies = [ 322 | "darling", 323 | "error-chain", 324 | "quote 0.5.2", 325 | "syn 0.13.11", 326 | ] 327 | 328 | [[package]] 329 | name = "funty" 330 | version = "1.1.0" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" 333 | 334 | [[package]] 335 | name = "futures-channel" 336 | version = "0.3.16" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "74ed2411805f6e4e3d9bc904c95d5d423b89b3b25dc0250aa74729de20629ff9" 339 | dependencies = [ 340 | "futures-core", 341 | ] 342 | 343 | [[package]] 344 | name = "futures-core" 345 | version = "0.3.16" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "af51b1b4a7fdff033703db39de8802c673eb91855f2e0d47dcf3bf2c0ef01f99" 348 | 349 | [[package]] 350 | name = "futures-executor" 351 | version = "0.3.16" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "4d0d535a57b87e1ae31437b892713aee90cd2d7b0ee48727cd11fc72ef54761c" 354 | dependencies = [ 355 | "futures-core", 356 | "futures-task", 357 | "futures-util", 358 | ] 359 | 360 | [[package]] 361 | name = "futures-io" 362 | version = "0.3.16" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "0b0e06c393068f3a6ef246c75cdca793d6a46347e75286933e5e75fd2fd11582" 365 | 366 | [[package]] 367 | name = "futures-task" 368 | version = "0.3.16" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "bbe54a98670017f3be909561f6ad13e810d9a51f3f061b902062ca3da80799f2" 371 | 372 | [[package]] 373 | name = "futures-util" 374 | version = "0.3.16" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "67eb846bfd58e44a8481a00049e82c43e0ccb5d61f8dc071057cb19249dd4d78" 377 | dependencies = [ 378 | "autocfg", 379 | "futures-core", 380 | "futures-task", 381 | "pin-project-lite", 382 | "pin-utils", 383 | "slab", 384 | ] 385 | 386 | [[package]] 387 | name = "gdk" 388 | version = "0.14.0" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | checksum = "679e22651cd15888e7acd01767950edca2ee9fcd6421fbf5b3c3b420d4e88bb0" 391 | dependencies = [ 392 | "bitflags", 393 | "cairo-rs", 394 | "gdk-pixbuf", 395 | "gdk-sys", 396 | "gio", 397 | "glib", 398 | "libc", 399 | "pango", 400 | ] 401 | 402 | [[package]] 403 | name = "gdk-pixbuf" 404 | version = "0.14.0" 405 | source = "registry+https://github.com/rust-lang/crates.io-index" 406 | checksum = "534192cb8f01daeb8fab2c8d4baa8f9aae5b7a39130525779f5c2608e235b10f" 407 | dependencies = [ 408 | "gdk-pixbuf-sys", 409 | "gio", 410 | "glib", 411 | "libc", 412 | ] 413 | 414 | [[package]] 415 | name = "gdk-pixbuf-sys" 416 | version = "0.14.0" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "f097c0704201fbc8f69c1762dc58c6947c8bb188b8ed0bc7e65259f1894fe590" 419 | dependencies = [ 420 | "gio-sys", 421 | "glib-sys", 422 | "gobject-sys", 423 | "libc", 424 | "system-deps", 425 | ] 426 | 427 | [[package]] 428 | name = "gdk-sys" 429 | version = "0.14.0" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "0e091b3d3d6696949ac3b3fb3c62090e5bfd7bd6850bef5c3c5ea701de1b1f1e" 432 | dependencies = [ 433 | "cairo-sys-rs", 434 | "gdk-pixbuf-sys", 435 | "gio-sys", 436 | "glib-sys", 437 | "gobject-sys", 438 | "libc", 439 | "pango-sys", 440 | "pkg-config", 441 | "system-deps", 442 | ] 443 | 444 | [[package]] 445 | name = "gimli" 446 | version = "0.24.0" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" 449 | 450 | [[package]] 451 | name = "gio" 452 | version = "0.14.0" 453 | source = "registry+https://github.com/rust-lang/crates.io-index" 454 | checksum = "86c6823b39d46d22cac2466de261f28d7f049ebc18f7b35296a42c7ed8a88325" 455 | dependencies = [ 456 | "bitflags", 457 | "futures-channel", 458 | "futures-core", 459 | "futures-io", 460 | "gio-sys", 461 | "glib", 462 | "libc", 463 | "once_cell", 464 | "thiserror", 465 | ] 466 | 467 | [[package]] 468 | name = "gio-sys" 469 | version = "0.14.0" 470 | source = "registry+https://github.com/rust-lang/crates.io-index" 471 | checksum = "c0a41df66e57fcc287c4bcf74fc26b884f31901ea9792ec75607289b456f48fa" 472 | dependencies = [ 473 | "glib-sys", 474 | "gobject-sys", 475 | "libc", 476 | "system-deps", 477 | "winapi", 478 | ] 479 | 480 | [[package]] 481 | name = "glib" 482 | version = "0.14.2" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "dbecad7a3a898ee749d491ce2ae0decb0bce9e736f9747bc49159b1cea5d37f4" 485 | dependencies = [ 486 | "bitflags", 487 | "futures-channel", 488 | "futures-core", 489 | "futures-executor", 490 | "futures-task", 491 | "glib-macros", 492 | "glib-sys", 493 | "gobject-sys", 494 | "libc", 495 | "once_cell", 496 | "smallvec", 497 | ] 498 | 499 | [[package]] 500 | name = "glib-macros" 501 | version = "0.14.1" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "2aad66361f66796bfc73f530c51ef123970eb895ffba991a234fcf7bea89e518" 504 | dependencies = [ 505 | "anyhow", 506 | "heck", 507 | "proc-macro-crate", 508 | "proc-macro-error", 509 | "proc-macro2 1.0.28", 510 | "quote 1.0.9", 511 | "syn 1.0.74", 512 | ] 513 | 514 | [[package]] 515 | name = "glib-sys" 516 | version = "0.14.0" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "1c1d60554a212445e2a858e42a0e48cece1bd57b311a19a9468f70376cf554ae" 519 | dependencies = [ 520 | "libc", 521 | "system-deps", 522 | ] 523 | 524 | [[package]] 525 | name = "gobject-sys" 526 | version = "0.14.0" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "aa92cae29759dae34ab5921d73fff5ad54b3d794ab842c117e36cafc7994c3f5" 529 | dependencies = [ 530 | "glib-sys", 531 | "libc", 532 | "system-deps", 533 | ] 534 | 535 | [[package]] 536 | name = "gtk" 537 | version = "0.14.0" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "10ae864e5eab8bc8b6b8544ed259eb02dd61b25323b20e777a77aa289c05fd0c" 540 | dependencies = [ 541 | "atk", 542 | "bitflags", 543 | "cairo-rs", 544 | "field-offset", 545 | "futures-channel", 546 | "gdk", 547 | "gdk-pixbuf", 548 | "gio", 549 | "glib", 550 | "gtk-sys", 551 | "gtk3-macros", 552 | "libc", 553 | "once_cell", 554 | "pango", 555 | "pkg-config", 556 | ] 557 | 558 | [[package]] 559 | name = "gtk-layer-shell" 560 | version = "0.2.2" 561 | source = "registry+https://github.com/rust-lang/crates.io-index" 562 | checksum = "4a106f40f47bf7eb2d0d62313b82e8cb9829c4c6ab4a1087c72c95ae6ed03726" 563 | dependencies = [ 564 | "bitflags", 565 | "gdk", 566 | "glib", 567 | "glib-sys", 568 | "gtk", 569 | "gtk-layer-shell-sys", 570 | "libc", 571 | ] 572 | 573 | [[package]] 574 | name = "gtk-layer-shell-sys" 575 | version = "0.2.3" 576 | source = "registry+https://github.com/rust-lang/crates.io-index" 577 | checksum = "568daf8ab604d183e7fc703d65e3621241dc05b8960022fd94e260aef3ebbf4f" 578 | dependencies = [ 579 | "gdk-sys", 580 | "glib-sys", 581 | "gtk-sys", 582 | "libc", 583 | "system-deps", 584 | ] 585 | 586 | [[package]] 587 | name = "gtk-sys" 588 | version = "0.14.0" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "8c14c8d3da0545785a7c5a120345b3abb534010fb8ae0f2ef3f47c027fba303e" 591 | dependencies = [ 592 | "atk-sys", 593 | "cairo-sys-rs", 594 | "gdk-pixbuf-sys", 595 | "gdk-sys", 596 | "gio-sys", 597 | "glib-sys", 598 | "gobject-sys", 599 | "libc", 600 | "pango-sys", 601 | "system-deps", 602 | ] 603 | 604 | [[package]] 605 | name = "gtk3-macros" 606 | version = "0.14.0" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "21de1da96dc117443fb03c2e270b2d34b7de98d0a79a19bbb689476173745b79" 609 | dependencies = [ 610 | "anyhow", 611 | "heck", 612 | "proc-macro-crate", 613 | "proc-macro-error", 614 | "proc-macro2 1.0.28", 615 | "quote 1.0.9", 616 | "syn 1.0.74", 617 | ] 618 | 619 | [[package]] 620 | name = "heck" 621 | version = "0.3.3" 622 | source = "registry+https://github.com/rust-lang/crates.io-index" 623 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 624 | dependencies = [ 625 | "unicode-segmentation", 626 | ] 627 | 628 | [[package]] 629 | name = "i3ipc" 630 | version = "0.10.1" 631 | source = "registry+https://github.com/rust-lang/crates.io-index" 632 | checksum = "63f3dac00c473fae88cb3114f35312204469a32ffb20874264a5214d6c8c927e" 633 | dependencies = [ 634 | "byteorder", 635 | "log", 636 | "serde", 637 | "serde_json", 638 | ] 639 | 640 | [[package]] 641 | name = "ident_case" 642 | version = "1.0.1" 643 | source = "registry+https://github.com/rust-lang/crates.io-index" 644 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 645 | 646 | [[package]] 647 | name = "itertools" 648 | version = "0.10.1" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" 651 | dependencies = [ 652 | "either", 653 | ] 654 | 655 | [[package]] 656 | name = "itoa" 657 | version = "0.4.7" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" 660 | 661 | [[package]] 662 | name = "lazy_static" 663 | version = "1.4.0" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 666 | 667 | [[package]] 668 | name = "lexical-core" 669 | version = "0.7.6" 670 | source = "registry+https://github.com/rust-lang/crates.io-index" 671 | checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" 672 | dependencies = [ 673 | "arrayvec", 674 | "bitflags", 675 | "cfg-if", 676 | "ryu", 677 | "static_assertions", 678 | ] 679 | 680 | [[package]] 681 | name = "libc" 682 | version = "0.2.98" 683 | source = "registry+https://github.com/rust-lang/crates.io-index" 684 | checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" 685 | 686 | [[package]] 687 | name = "libdbus-sys" 688 | version = "0.2.1" 689 | source = "registry+https://github.com/rust-lang/crates.io-index" 690 | checksum = "dc12a3bc971424edbbf7edaf6e5740483444db63aa8e23d3751ff12a30f306f0" 691 | dependencies = [ 692 | "pkg-config", 693 | ] 694 | 695 | [[package]] 696 | name = "log" 697 | version = "0.4.14" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 700 | dependencies = [ 701 | "cfg-if", 702 | ] 703 | 704 | [[package]] 705 | name = "memchr" 706 | version = "2.3.4" 707 | source = "registry+https://github.com/rust-lang/crates.io-index" 708 | checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" 709 | 710 | [[package]] 711 | name = "memoffset" 712 | version = "0.6.4" 713 | source = "registry+https://github.com/rust-lang/crates.io-index" 714 | checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" 715 | dependencies = [ 716 | "autocfg", 717 | ] 718 | 719 | [[package]] 720 | name = "miniz_oxide" 721 | version = "0.4.4" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" 724 | dependencies = [ 725 | "adler", 726 | "autocfg", 727 | ] 728 | 729 | [[package]] 730 | name = "mpris" 731 | version = "1.1.2" 732 | source = "registry+https://github.com/rust-lang/crates.io-index" 733 | checksum = "818520e449f43cd196bc4fdbd163d4f437f36481c2d4573dca4614bb89e4aef3" 734 | dependencies = [ 735 | "dbus", 736 | "derive_is_enum_variant", 737 | "enum-kinds", 738 | "failure", 739 | "failure_derive", 740 | "from_variants", 741 | ] 742 | 743 | [[package]] 744 | name = "nix" 745 | version = "0.20.0" 746 | source = "registry+https://github.com/rust-lang/crates.io-index" 747 | checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" 748 | dependencies = [ 749 | "bitflags", 750 | "cc", 751 | "cfg-if", 752 | "libc", 753 | ] 754 | 755 | [[package]] 756 | name = "nom" 757 | version = "6.2.1" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6" 760 | dependencies = [ 761 | "bitvec", 762 | "funty", 763 | "lexical-core", 764 | "memchr", 765 | "version_check", 766 | ] 767 | 768 | [[package]] 769 | name = "num-integer" 770 | version = "0.1.44" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 773 | dependencies = [ 774 | "autocfg", 775 | "num-traits", 776 | ] 777 | 778 | [[package]] 779 | name = "num-traits" 780 | version = "0.2.14" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 783 | dependencies = [ 784 | "autocfg", 785 | ] 786 | 787 | [[package]] 788 | name = "object" 789 | version = "0.24.0" 790 | source = "registry+https://github.com/rust-lang/crates.io-index" 791 | checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170" 792 | 793 | [[package]] 794 | name = "once_cell" 795 | version = "1.8.0" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" 798 | 799 | [[package]] 800 | name = "pango" 801 | version = "0.14.0" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "415823a4fb9f1789785cd6e2d2413816f2ecff92380382969aaca9c400e13a19" 804 | dependencies = [ 805 | "bitflags", 806 | "glib", 807 | "libc", 808 | "once_cell", 809 | "pango-sys", 810 | ] 811 | 812 | [[package]] 813 | name = "pango-sys" 814 | version = "0.14.0" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "2367099ca5e761546ba1d501955079f097caa186bb53ce0f718dca99ac1942fe" 817 | dependencies = [ 818 | "glib-sys", 819 | "gobject-sys", 820 | "libc", 821 | "system-deps", 822 | ] 823 | 824 | [[package]] 825 | name = "pest" 826 | version = "2.1.3" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" 829 | dependencies = [ 830 | "ucd-trie", 831 | ] 832 | 833 | [[package]] 834 | name = "pin-project-lite" 835 | version = "0.2.7" 836 | source = "registry+https://github.com/rust-lang/crates.io-index" 837 | checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" 838 | 839 | [[package]] 840 | name = "pin-utils" 841 | version = "0.1.0" 842 | source = "registry+https://github.com/rust-lang/crates.io-index" 843 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 844 | 845 | [[package]] 846 | name = "pkg-config" 847 | version = "0.3.19" 848 | source = "registry+https://github.com/rust-lang/crates.io-index" 849 | checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" 850 | 851 | [[package]] 852 | name = "proc-macro-crate" 853 | version = "1.0.0" 854 | source = "registry+https://github.com/rust-lang/crates.io-index" 855 | checksum = "41fdbd1df62156fbc5945f4762632564d7d038153091c3fcf1067f6aef7cff92" 856 | dependencies = [ 857 | "thiserror", 858 | "toml", 859 | ] 860 | 861 | [[package]] 862 | name = "proc-macro-error" 863 | version = "1.0.4" 864 | source = "registry+https://github.com/rust-lang/crates.io-index" 865 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 866 | dependencies = [ 867 | "proc-macro-error-attr", 868 | "proc-macro2 1.0.28", 869 | "quote 1.0.9", 870 | "syn 1.0.74", 871 | "version_check", 872 | ] 873 | 874 | [[package]] 875 | name = "proc-macro-error-attr" 876 | version = "1.0.4" 877 | source = "registry+https://github.com/rust-lang/crates.io-index" 878 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 879 | dependencies = [ 880 | "proc-macro2 1.0.28", 881 | "quote 1.0.9", 882 | "version_check", 883 | ] 884 | 885 | [[package]] 886 | name = "proc-macro2" 887 | version = "0.2.3" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" 890 | dependencies = [ 891 | "unicode-xid 0.1.0", 892 | ] 893 | 894 | [[package]] 895 | name = "proc-macro2" 896 | version = "0.3.8" 897 | source = "registry+https://github.com/rust-lang/crates.io-index" 898 | checksum = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7" 899 | dependencies = [ 900 | "unicode-xid 0.1.0", 901 | ] 902 | 903 | [[package]] 904 | name = "proc-macro2" 905 | version = "1.0.28" 906 | source = "registry+https://github.com/rust-lang/crates.io-index" 907 | checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" 908 | dependencies = [ 909 | "unicode-xid 0.2.2", 910 | ] 911 | 912 | [[package]] 913 | name = "quote" 914 | version = "0.3.15" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" 917 | 918 | [[package]] 919 | name = "quote" 920 | version = "0.4.2" 921 | source = "registry+https://github.com/rust-lang/crates.io-index" 922 | checksum = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" 923 | dependencies = [ 924 | "proc-macro2 0.2.3", 925 | ] 926 | 927 | [[package]] 928 | name = "quote" 929 | version = "0.5.2" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" 932 | dependencies = [ 933 | "proc-macro2 0.3.8", 934 | ] 935 | 936 | [[package]] 937 | name = "quote" 938 | version = "1.0.9" 939 | source = "registry+https://github.com/rust-lang/crates.io-index" 940 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 941 | dependencies = [ 942 | "proc-macro2 1.0.28", 943 | ] 944 | 945 | [[package]] 946 | name = "radium" 947 | version = "0.5.3" 948 | source = "registry+https://github.com/rust-lang/crates.io-index" 949 | checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" 950 | 951 | [[package]] 952 | name = "relm" 953 | version = "0.22.0" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | checksum = "44b9cf78518ee5f62af9de37a1f7086e14149e014729f80fea1eb120e550b726" 956 | dependencies = [ 957 | "cairo-rs", 958 | "fragile", 959 | "glib", 960 | "glib-sys", 961 | "gobject-sys", 962 | "gtk", 963 | "libc", 964 | "log", 965 | ] 966 | 967 | [[package]] 968 | name = "relm-derive" 969 | version = "0.22.0" 970 | source = "registry+https://github.com/rust-lang/crates.io-index" 971 | checksum = "a9e55abe7290cd8a07780d5a96937f141cfab3b91fa690a73eb8f78830127313" 972 | dependencies = [ 973 | "lazy_static", 974 | "proc-macro2 1.0.28", 975 | "quote 1.0.9", 976 | "syn 1.0.74", 977 | ] 978 | 979 | [[package]] 980 | name = "ron" 981 | version = "0.6.4" 982 | source = "registry+https://github.com/rust-lang/crates.io-index" 983 | checksum = "064ea8613fb712a19faf920022ec8ddf134984f100090764a4e1d768f3827f1f" 984 | dependencies = [ 985 | "base64", 986 | "bitflags", 987 | "serde", 988 | ] 989 | 990 | [[package]] 991 | name = "rustc-demangle" 992 | version = "0.1.20" 993 | source = "registry+https://github.com/rust-lang/crates.io-index" 994 | checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49" 995 | 996 | [[package]] 997 | name = "rustc_version" 998 | version = "0.3.3" 999 | source = "registry+https://github.com/rust-lang/crates.io-index" 1000 | checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" 1001 | dependencies = [ 1002 | "semver", 1003 | ] 1004 | 1005 | [[package]] 1006 | name = "ryu" 1007 | version = "1.0.5" 1008 | source = "registry+https://github.com/rust-lang/crates.io-index" 1009 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 1010 | 1011 | [[package]] 1012 | name = "semver" 1013 | version = "0.11.0" 1014 | source = "registry+https://github.com/rust-lang/crates.io-index" 1015 | checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" 1016 | dependencies = [ 1017 | "semver-parser", 1018 | ] 1019 | 1020 | [[package]] 1021 | name = "semver-parser" 1022 | version = "0.10.2" 1023 | source = "registry+https://github.com/rust-lang/crates.io-index" 1024 | checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" 1025 | dependencies = [ 1026 | "pest", 1027 | ] 1028 | 1029 | [[package]] 1030 | name = "serde" 1031 | version = "1.0.127" 1032 | source = "registry+https://github.com/rust-lang/crates.io-index" 1033 | checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" 1034 | dependencies = [ 1035 | "serde_derive", 1036 | ] 1037 | 1038 | [[package]] 1039 | name = "serde_derive" 1040 | version = "1.0.127" 1041 | source = "registry+https://github.com/rust-lang/crates.io-index" 1042 | checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" 1043 | dependencies = [ 1044 | "proc-macro2 1.0.28", 1045 | "quote 1.0.9", 1046 | "syn 1.0.74", 1047 | ] 1048 | 1049 | [[package]] 1050 | name = "serde_json" 1051 | version = "1.0.66" 1052 | source = "registry+https://github.com/rust-lang/crates.io-index" 1053 | checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127" 1054 | dependencies = [ 1055 | "itoa", 1056 | "ryu", 1057 | "serde", 1058 | ] 1059 | 1060 | [[package]] 1061 | name = "slab" 1062 | version = "0.4.3" 1063 | source = "registry+https://github.com/rust-lang/crates.io-index" 1064 | checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" 1065 | 1066 | [[package]] 1067 | name = "smallvec" 1068 | version = "1.6.1" 1069 | source = "registry+https://github.com/rust-lang/crates.io-index" 1070 | checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" 1071 | 1072 | [[package]] 1073 | name = "static_assertions" 1074 | version = "1.1.0" 1075 | source = "registry+https://github.com/rust-lang/crates.io-index" 1076 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 1077 | 1078 | [[package]] 1079 | name = "strum" 1080 | version = "0.21.0" 1081 | source = "registry+https://github.com/rust-lang/crates.io-index" 1082 | checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" 1083 | 1084 | [[package]] 1085 | name = "strum_macros" 1086 | version = "0.21.1" 1087 | source = "registry+https://github.com/rust-lang/crates.io-index" 1088 | checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" 1089 | dependencies = [ 1090 | "heck", 1091 | "proc-macro2 1.0.28", 1092 | "quote 1.0.9", 1093 | "syn 1.0.74", 1094 | ] 1095 | 1096 | [[package]] 1097 | name = "syn" 1098 | version = "0.11.11" 1099 | source = "registry+https://github.com/rust-lang/crates.io-index" 1100 | checksum = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" 1101 | dependencies = [ 1102 | "quote 0.3.15", 1103 | "synom", 1104 | "unicode-xid 0.0.4", 1105 | ] 1106 | 1107 | [[package]] 1108 | name = "syn" 1109 | version = "0.12.15" 1110 | source = "registry+https://github.com/rust-lang/crates.io-index" 1111 | checksum = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5" 1112 | dependencies = [ 1113 | "proc-macro2 0.2.3", 1114 | "quote 0.4.2", 1115 | "unicode-xid 0.1.0", 1116 | ] 1117 | 1118 | [[package]] 1119 | name = "syn" 1120 | version = "0.13.11" 1121 | source = "registry+https://github.com/rust-lang/crates.io-index" 1122 | checksum = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b" 1123 | dependencies = [ 1124 | "proc-macro2 0.3.8", 1125 | "quote 0.5.2", 1126 | "unicode-xid 0.1.0", 1127 | ] 1128 | 1129 | [[package]] 1130 | name = "syn" 1131 | version = "1.0.74" 1132 | source = "registry+https://github.com/rust-lang/crates.io-index" 1133 | checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" 1134 | dependencies = [ 1135 | "proc-macro2 1.0.28", 1136 | "quote 1.0.9", 1137 | "unicode-xid 0.2.2", 1138 | ] 1139 | 1140 | [[package]] 1141 | name = "synom" 1142 | version = "0.11.3" 1143 | source = "registry+https://github.com/rust-lang/crates.io-index" 1144 | checksum = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" 1145 | dependencies = [ 1146 | "unicode-xid 0.0.4", 1147 | ] 1148 | 1149 | [[package]] 1150 | name = "synstructure" 1151 | version = "0.12.5" 1152 | source = "registry+https://github.com/rust-lang/crates.io-index" 1153 | checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa" 1154 | dependencies = [ 1155 | "proc-macro2 1.0.28", 1156 | "quote 1.0.9", 1157 | "syn 1.0.74", 1158 | "unicode-xid 0.2.2", 1159 | ] 1160 | 1161 | [[package]] 1162 | name = "system-deps" 1163 | version = "3.2.0" 1164 | source = "registry+https://github.com/rust-lang/crates.io-index" 1165 | checksum = "480c269f870722b3b08d2f13053ce0c2ab722839f472863c3e2d61ff3a1c2fa6" 1166 | dependencies = [ 1167 | "anyhow", 1168 | "cfg-expr", 1169 | "heck", 1170 | "itertools", 1171 | "pkg-config", 1172 | "strum", 1173 | "strum_macros", 1174 | "thiserror", 1175 | "toml", 1176 | "version-compare", 1177 | ] 1178 | 1179 | [[package]] 1180 | name = "systemstat" 1181 | version = "0.1.8" 1182 | source = "registry+https://github.com/rust-lang/crates.io-index" 1183 | checksum = "a934f8fe2f893260080fdde71e840b35308f48bf3bd3b261cb24e668c4b48db3" 1184 | dependencies = [ 1185 | "bytesize", 1186 | "chrono", 1187 | "lazy_static", 1188 | "libc", 1189 | "nom", 1190 | "time", 1191 | "winapi", 1192 | ] 1193 | 1194 | [[package]] 1195 | name = "tap" 1196 | version = "1.0.1" 1197 | source = "registry+https://github.com/rust-lang/crates.io-index" 1198 | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" 1199 | 1200 | [[package]] 1201 | name = "thiserror" 1202 | version = "1.0.26" 1203 | source = "registry+https://github.com/rust-lang/crates.io-index" 1204 | checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" 1205 | dependencies = [ 1206 | "thiserror-impl", 1207 | ] 1208 | 1209 | [[package]] 1210 | name = "thiserror-impl" 1211 | version = "1.0.26" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" 1214 | dependencies = [ 1215 | "proc-macro2 1.0.28", 1216 | "quote 1.0.9", 1217 | "syn 1.0.74", 1218 | ] 1219 | 1220 | [[package]] 1221 | name = "time" 1222 | version = "0.1.44" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" 1225 | dependencies = [ 1226 | "libc", 1227 | "wasi", 1228 | "winapi", 1229 | ] 1230 | 1231 | [[package]] 1232 | name = "toml" 1233 | version = "0.5.8" 1234 | source = "registry+https://github.com/rust-lang/crates.io-index" 1235 | checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" 1236 | dependencies = [ 1237 | "serde", 1238 | ] 1239 | 1240 | [[package]] 1241 | name = "ucd-trie" 1242 | version = "0.1.3" 1243 | source = "registry+https://github.com/rust-lang/crates.io-index" 1244 | checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" 1245 | 1246 | [[package]] 1247 | name = "unicode-segmentation" 1248 | version = "1.8.0" 1249 | source = "registry+https://github.com/rust-lang/crates.io-index" 1250 | checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" 1251 | 1252 | [[package]] 1253 | name = "unicode-xid" 1254 | version = "0.0.4" 1255 | source = "registry+https://github.com/rust-lang/crates.io-index" 1256 | checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" 1257 | 1258 | [[package]] 1259 | name = "unicode-xid" 1260 | version = "0.1.0" 1261 | source = "registry+https://github.com/rust-lang/crates.io-index" 1262 | checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 1263 | 1264 | [[package]] 1265 | name = "unicode-xid" 1266 | version = "0.2.2" 1267 | source = "registry+https://github.com/rust-lang/crates.io-index" 1268 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 1269 | 1270 | [[package]] 1271 | name = "version-compare" 1272 | version = "0.0.11" 1273 | source = "registry+https://github.com/rust-lang/crates.io-index" 1274 | checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b" 1275 | 1276 | [[package]] 1277 | name = "version_check" 1278 | version = "0.9.3" 1279 | source = "registry+https://github.com/rust-lang/crates.io-index" 1280 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 1281 | 1282 | [[package]] 1283 | name = "wasi" 1284 | version = "0.10.0+wasi-snapshot-preview1" 1285 | source = "registry+https://github.com/rust-lang/crates.io-index" 1286 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 1287 | 1288 | [[package]] 1289 | name = "winapi" 1290 | version = "0.3.9" 1291 | source = "registry+https://github.com/rust-lang/crates.io-index" 1292 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1293 | dependencies = [ 1294 | "winapi-i686-pc-windows-gnu", 1295 | "winapi-x86_64-pc-windows-gnu", 1296 | ] 1297 | 1298 | [[package]] 1299 | name = "winapi-i686-pc-windows-gnu" 1300 | version = "0.4.0" 1301 | source = "registry+https://github.com/rust-lang/crates.io-index" 1302 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1303 | 1304 | [[package]] 1305 | name = "winapi-x86_64-pc-windows-gnu" 1306 | version = "0.4.0" 1307 | source = "registry+https://github.com/rust-lang/crates.io-index" 1308 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1309 | 1310 | [[package]] 1311 | name = "wyz" 1312 | version = "0.2.0" 1313 | source = "registry+https://github.com/rust-lang/crates.io-index" 1314 | checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" 1315 | 1316 | [[package]] 1317 | name = "yetanotherbar" 1318 | version = "0.1.0" 1319 | dependencies = [ 1320 | "alsa", 1321 | "chrono", 1322 | "gdk", 1323 | "gio", 1324 | "glib", 1325 | "gtk", 1326 | "gtk-layer-shell", 1327 | "i3ipc", 1328 | "mpris", 1329 | "relm", 1330 | "relm-derive", 1331 | "ron", 1332 | "serde", 1333 | "serde_derive", 1334 | "systemstat", 1335 | ] 1336 | --------------------------------------------------------------------------------