Add Ctl Socket, iterate on Idling daemon, update sysinfo crate, start on run menu
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,2 +1,7 @@
|
||||
/target
|
||||
/unused/
|
||||
/jmb-bar
|
||||
/perf.data
|
||||
/qodana.yaml
|
||||
/.idea/dictionaries/project.xml
|
||||
/.idea/inspectionProfiles/Project_Default.xml
|
||||
|
||||
1
.idea/jmb-bar.iml
generated
1
.idea/jmb-bar.iml
generated
@@ -4,6 +4,7 @@
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/unused" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
|
||||
135
Cargo.lock
generated
135
Cargo.lock
generated
@@ -98,7 +98,7 @@ dependencies = [
|
||||
"russh",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sysinfo",
|
||||
"sysinfo 0.39.6",
|
||||
"tar",
|
||||
"thiserror 2.0.21",
|
||||
"tokio",
|
||||
@@ -1684,15 +1684,6 @@ version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.34"
|
||||
@@ -2496,7 +2487,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core 0.62.2",
|
||||
"windows-core 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2737,7 +2728,7 @@ dependencies = [
|
||||
"notify",
|
||||
"rustsni",
|
||||
"serde_json",
|
||||
"sysinfo",
|
||||
"sysinfo 0.40.0",
|
||||
"thiserror 2.0.21",
|
||||
"time-format",
|
||||
"tokio",
|
||||
@@ -2748,8 +2739,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "jmb-logger-rs"
|
||||
version = "0.2.1"
|
||||
source = "git+https://github.com/jmb05/jmb-logger-rs#ea000f8c733b7e7854fdb123b509eb484bcec101"
|
||||
version = "0.2.2"
|
||||
source = "git+https://github.com/jmb05/jmb-logger-rs#083f7b96a80ab43e37850735d2367e52c6b7f5b0"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"chrono",
|
||||
@@ -3382,27 +3373,28 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "8.2.0"
|
||||
version = "8.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3"
|
||||
checksum = "82f812702fbc75d35416d3f884e04925be7e9498f4eceea2e24ba34559284674"
|
||||
dependencies = [
|
||||
"bitflags 2.13.2",
|
||||
"fsevent-sys",
|
||||
"inotify",
|
||||
"kqueue",
|
||||
"libc",
|
||||
"log",
|
||||
"mio",
|
||||
"notify-types",
|
||||
"objc2-core-foundation",
|
||||
"objc2-core-services",
|
||||
"walkdir",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify-types"
|
||||
version = "2.1.0"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a"
|
||||
checksum = "0a437a9308232ce794b1e7fdf540d38ea37efc3c73492640c13b4c8568b8f108"
|
||||
dependencies = [
|
||||
"bitflags 2.13.2",
|
||||
]
|
||||
@@ -3553,6 +3545,16 @@ dependencies = [
|
||||
"objc2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-services"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "583300ad934cba24ff5292aee751ecc070f7ca6b39a574cc21b7b5e588e06a0b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-encode"
|
||||
version = "4.1.0"
|
||||
@@ -5349,6 +5351,21 @@ dependencies = [
|
||||
"windows 0.62.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "110e37d98880fd804cd47509b90a8444f7aaaab655ae625e83cd442a8bc2ebf2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"memchr",
|
||||
"ntapi",
|
||||
"objc2-core-foundation",
|
||||
"objc2-io-kit",
|
||||
"objc2-open-directory",
|
||||
"windows 0.62.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration"
|
||||
version = "0.7.0"
|
||||
@@ -6492,15 +6509,6 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.60.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||
dependencies = [
|
||||
"windows-targets 0.53.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
@@ -6534,30 +6542,13 @@ dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.6",
|
||||
"windows_aarch64_msvc 0.52.6",
|
||||
"windows_i686_gnu 0.52.6",
|
||||
"windows_i686_gnullvm 0.52.6",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc 0.52.6",
|
||||
"windows_x86_64_gnu 0.52.6",
|
||||
"windows_x86_64_gnullvm 0.52.6",
|
||||
"windows_x86_64_msvc 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
"windows_aarch64_gnullvm 0.53.1",
|
||||
"windows_aarch64_msvc 0.53.1",
|
||||
"windows_i686_gnu 0.53.1",
|
||||
"windows_i686_gnullvm 0.53.1",
|
||||
"windows_i686_msvc 0.53.1",
|
||||
"windows_x86_64_gnu 0.53.1",
|
||||
"windows_x86_64_gnullvm 0.53.1",
|
||||
"windows_x86_64_msvc 0.53.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-threading"
|
||||
version = "0.1.0"
|
||||
@@ -6588,12 +6579,6 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
@@ -6606,12 +6591,6 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
@@ -6624,24 +6603,12 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
@@ -6654,12 +6621,6 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
@@ -6672,12 +6633,6 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
@@ -6690,12 +6645,6 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
@@ -6708,12 +6657,6 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "1.0.4"
|
||||
@@ -6741,7 +6684,7 @@ dependencies = [
|
||||
"serde",
|
||||
"thiserror 2.0.21",
|
||||
"windows 0.62.2",
|
||||
"windows-core 0.62.2",
|
||||
"windows-core 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
12
Cargo.toml
12
Cargo.toml
@@ -3,6 +3,14 @@ name = "jmb-bar"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[[bin]]
|
||||
name = "jmb-bar"
|
||||
path = "src/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "ctl"
|
||||
path = "src/ctl.rs"
|
||||
|
||||
[dependencies]
|
||||
grass = "0.13.4"
|
||||
gtk = { version = "0.11.5", package = "gtk4", features = ["v4_24"] }
|
||||
@@ -17,8 +25,8 @@ tokio = { version = "1.53.3", features = ["rt", "time", "net", "sync", "rt-multi
|
||||
futures-util = "0.3"
|
||||
serde_json = "1.0.154"
|
||||
crossbeam-channel = "0.5.17"
|
||||
jmb-logger-rs = { git = "https://github.com/jmb05/jmb-logger-rs" }
|
||||
sysinfo = "0.39.6"
|
||||
jmb-logger-rs = { version = "0.2.2", git = "https://github.com/jmb05/jmb-logger-rs" }
|
||||
sysinfo = "0.40.0"
|
||||
all-smi = "0.28.1"
|
||||
rustsni = "0.2.2"
|
||||
thiserror = "2.0.21"
|
||||
|
||||
123
src/backend.rs
123
src/backend.rs
@@ -1,5 +1,6 @@
|
||||
pub mod audio;
|
||||
pub mod brightness_control;
|
||||
mod commands;
|
||||
pub(crate) mod idle;
|
||||
pub(crate) mod json_socket;
|
||||
pub mod network;
|
||||
@@ -9,11 +10,13 @@ pub mod window_manager_hypr;
|
||||
use crate::LOGGER;
|
||||
use crate::backend::audio::{MediaBackend, MediaCommand};
|
||||
use crate::backend::brightness_control::{BrightnessManager, BrightnessMessage};
|
||||
use crate::backend::commands::ControlSocket;
|
||||
use crate::backend::idle::{IdleDaemon, IdleMessage, IdleState};
|
||||
use crate::backend::json_socket::{JsonSocketBackend, State};
|
||||
use crate::backend::network::{NetworkBackendHandle, NetworkCommand, NetworkState};
|
||||
use crate::backend::perf_stats::{Stats, StatsBackend};
|
||||
use crate::backend::window_manager_hypr::{HyprlandComms, WindowManagerEvent};
|
||||
use crate::ctl::ControlCommand;
|
||||
use crossbeam_channel::{Receiver, Sender};
|
||||
use jmb_logger_rs::*;
|
||||
use std::fmt::Debug;
|
||||
@@ -31,7 +34,7 @@ pub trait BackendThread<M: Debug + Clone, D> {
|
||||
if let Err(e) = tx.send(message.clone()) {
|
||||
warn!(
|
||||
&LOGGER,
|
||||
"Error sending message to frontend: {}",
|
||||
"Error sending message to frontend: {} (msg: {message:?})",
|
||||
e.to_string()
|
||||
);
|
||||
}
|
||||
@@ -72,8 +75,20 @@ pub struct Backend {
|
||||
br_registrator: Registrator<BrightnessMessage>,
|
||||
stats_registrator: Registrator<Stats>,
|
||||
media_registrator: Registrator<MediaCommand>,
|
||||
tailscale_registrator: Registrator<State>,
|
||||
netbird_registrator: Registrator<State>,
|
||||
idle_registrator: Registrator<IdleState>,
|
||||
control_registrator: Registrator<ControlCommand>,
|
||||
}
|
||||
|
||||
pub enum ChannelType {
|
||||
Net,
|
||||
Hypr,
|
||||
Br,
|
||||
Stats,
|
||||
Media,
|
||||
Idle,
|
||||
Netbird,
|
||||
Control,
|
||||
}
|
||||
|
||||
impl Backend {
|
||||
@@ -86,6 +101,7 @@ impl Backend {
|
||||
let media_registrator = MediaBackend::start();
|
||||
let tailscale_registrator = JsonSocketBackend::start();
|
||||
let idle_registrator = IdleDaemon::start();
|
||||
let control_registrator = ControlSocket::start();
|
||||
debug!(&LOGGER, "Started Backend threads");
|
||||
Self {
|
||||
hypr_registrator,
|
||||
@@ -93,47 +109,85 @@ impl Backend {
|
||||
br_registrator,
|
||||
stats_registrator,
|
||||
media_registrator,
|
||||
tailscale_registrator,
|
||||
netbird_registrator: tailscale_registrator,
|
||||
idle_registrator,
|
||||
control_registrator,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn subscribe(&self) -> BackendChannels {
|
||||
let (net_rx, net_tx) = NetworkBackendHandle::subscribe(self.net_registrator.clone());
|
||||
let (hypr_rx, _) = HyprlandComms::subscribe(self.hypr_registrator.clone());
|
||||
let (br_rx, br_tx) = BrightnessManager::subscribe(self.br_registrator.clone());
|
||||
let (stats_rx, _) = StatsBackend::subscribe(self.stats_registrator.clone());
|
||||
let (media_rx, media_tx) = MediaBackend::subscribe(self.media_registrator.clone());
|
||||
let (tailscale_rx, _) = JsonSocketBackend::subscribe(self.tailscale_registrator.clone());
|
||||
let (idle_rx, idle_tx) = IdleDaemon::subscribe(self.idle_registrator.clone());
|
||||
BackendChannels {
|
||||
net_rx: Some(net_rx),
|
||||
net_tx,
|
||||
hypr_rx: Some(hypr_rx),
|
||||
br_rx: Some(br_rx),
|
||||
br_tx,
|
||||
stats_rx: Some(stats_rx),
|
||||
media_rx: Some(media_rx),
|
||||
media_tx,
|
||||
tailscale_rx: Some(tailscale_rx),
|
||||
idle_rx: Some(idle_rx),
|
||||
idle_tx,
|
||||
pub fn subscribe(&self, channel_types: &[ChannelType]) -> BackendChannels {
|
||||
let mut channels = BackendChannels::default();
|
||||
for ch_type in channel_types {
|
||||
match ch_type {
|
||||
ChannelType::Net => {
|
||||
let (rx, tx) = NetworkBackendHandle::subscribe(self.net_registrator.clone());
|
||||
channels.net_tx = Some(tx);
|
||||
channels.net_rx = Some(rx);
|
||||
}
|
||||
ChannelType::Hypr => {
|
||||
channels.hypr_rx =
|
||||
Some(HyprlandComms::subscribe(self.hypr_registrator.clone()).0);
|
||||
}
|
||||
ChannelType::Br => {
|
||||
let (rx, tx) = BrightnessManager::subscribe(self.br_registrator.clone());
|
||||
channels.br_rx = Some(rx);
|
||||
channels.br_tx = Some(tx);
|
||||
}
|
||||
ChannelType::Stats => {
|
||||
channels.stats_rx =
|
||||
Some(StatsBackend::subscribe(self.stats_registrator.clone()).0);
|
||||
}
|
||||
ChannelType::Media => {
|
||||
let (rx, tx) = MediaBackend::subscribe(self.media_registrator.clone());
|
||||
channels.media_rx = Some(rx);
|
||||
channels.media_tx = Some(tx);
|
||||
}
|
||||
ChannelType::Idle => {
|
||||
let (rx, tx) = IdleDaemon::subscribe(self.idle_registrator.clone());
|
||||
channels.idle_rx = Some(rx);
|
||||
channels.idle_tx = Some(tx);
|
||||
}
|
||||
ChannelType::Netbird => {
|
||||
channels.netbird_rx =
|
||||
Some(JsonSocketBackend::subscribe(self.netbird_registrator.clone()).0);
|
||||
}
|
||||
ChannelType::Control => {
|
||||
channels.ctl_rx =
|
||||
Some(ControlSocket::subscribe(self.control_registrator.clone()).0);
|
||||
}
|
||||
}
|
||||
}
|
||||
channels
|
||||
}
|
||||
|
||||
pub fn subscribe_all(&self) -> BackendChannels {
|
||||
self.subscribe(&[
|
||||
ChannelType::Net,
|
||||
ChannelType::Idle,
|
||||
ChannelType::Netbird,
|
||||
ChannelType::Br,
|
||||
ChannelType::Stats,
|
||||
ChannelType::Control,
|
||||
ChannelType::Media,
|
||||
ChannelType::Hypr,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BackendChannels {
|
||||
net_rx: Option<Receiver<NetworkState>>,
|
||||
net_tx: UnboundedSender<NetworkCommand>,
|
||||
net_tx: Option<UnboundedSender<NetworkCommand>>,
|
||||
hypr_rx: Option<Receiver<WindowManagerEvent>>,
|
||||
br_rx: Option<Receiver<BrightnessMessage>>,
|
||||
br_tx: Sender<BrightnessMessage>,
|
||||
br_tx: Option<Sender<BrightnessMessage>>,
|
||||
stats_rx: Option<Receiver<Stats>>,
|
||||
media_rx: Option<Receiver<MediaCommand>>,
|
||||
media_tx: Sender<MediaCommand>,
|
||||
tailscale_rx: Option<Receiver<State>>,
|
||||
media_tx: Option<Sender<MediaCommand>>,
|
||||
netbird_rx: Option<Receiver<State>>,
|
||||
idle_rx: Option<Receiver<IdleState>>,
|
||||
idle_tx: Sender<IdleMessage>,
|
||||
idle_tx: Option<Sender<IdleMessage>>,
|
||||
ctl_rx: Option<Receiver<ControlCommand>>,
|
||||
}
|
||||
|
||||
impl BackendChannels {
|
||||
@@ -150,7 +204,7 @@ impl BackendChannels {
|
||||
self.stats_rx.take()
|
||||
}
|
||||
pub fn take_netbird_rx(&mut self) -> Option<Receiver<State>> {
|
||||
self.tailscale_rx.take()
|
||||
self.netbird_rx.take()
|
||||
}
|
||||
pub fn take_media_rx(&mut self) -> Option<Receiver<MediaCommand>> {
|
||||
self.media_rx.take()
|
||||
@@ -158,16 +212,19 @@ impl BackendChannels {
|
||||
pub fn take_idle_rx(&mut self) -> Option<Receiver<IdleState>> {
|
||||
self.idle_rx.take()
|
||||
}
|
||||
pub fn net_tx(&self) -> UnboundedSender<NetworkCommand> {
|
||||
pub fn take_ctl_rx(&mut self) -> Option<Receiver<ControlCommand>> {
|
||||
self.ctl_rx.take()
|
||||
}
|
||||
pub fn net_tx(&self) -> Option<UnboundedSender<NetworkCommand>> {
|
||||
self.net_tx.clone()
|
||||
}
|
||||
pub fn br_tx(&self) -> Sender<BrightnessMessage> {
|
||||
pub fn br_tx(&self) -> Option<Sender<BrightnessMessage>> {
|
||||
self.br_tx.clone()
|
||||
}
|
||||
pub fn media_tx(&self) -> Sender<MediaCommand> {
|
||||
pub fn media_tx(&self) -> Option<Sender<MediaCommand>> {
|
||||
self.media_tx.clone()
|
||||
}
|
||||
pub fn idle_tx(&self) -> Sender<IdleMessage> {
|
||||
pub fn idle_tx(&self) -> Option<Sender<IdleMessage>> {
|
||||
self.idle_tx.clone()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,14 +215,19 @@ impl BackendThread<BrightnessMessage, Sender<BrightnessMessage>> for BrightnessM
|
||||
}
|
||||
});
|
||||
thread::spawn(move || {
|
||||
let mut sleep_dur = 500;
|
||||
loop {
|
||||
thread::sleep(Duration::from_millis(10_000));
|
||||
if sleep_dur < 500 {
|
||||
sleep_dur += 1;
|
||||
}
|
||||
thread::sleep(Duration::from_millis(sleep_dur));
|
||||
let mut messages = vec![];
|
||||
|
||||
for (monitor, data) in
|
||||
&mut instance.lock().expect("Couldn't get lock").display_cache
|
||||
{
|
||||
if data.update() {
|
||||
sleep_dur = 50;
|
||||
messages.push(BrightnessMessage::Value(monitor.clone(), data.value, false));
|
||||
}
|
||||
}
|
||||
|
||||
62
src/backend/commands.rs
Normal file
62
src/backend/commands.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
use crate::LOGGER;
|
||||
use crate::backend::{BackendThread, SimpleBackendThread};
|
||||
use crate::ctl::{ControlCommand, SOCKET_PATH};
|
||||
use crossbeam_channel::{Receiver, Sender};
|
||||
use jmb_logger_rs::*;
|
||||
use std::io::Read;
|
||||
use std::net::Shutdown;
|
||||
use std::os::unix::net::UnixListener;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
pub struct ControlSocket {
|
||||
subscribers: Vec<Sender<ControlCommand>>,
|
||||
}
|
||||
|
||||
impl SimpleBackendThread<ControlCommand> for ControlSocket {
|
||||
fn subscribers(&self) -> &Vec<Sender<ControlCommand>> {
|
||||
&self.subscribers
|
||||
}
|
||||
|
||||
fn init(registration_rx: Receiver<Sender<ControlCommand>>) {
|
||||
let instance = Arc::new(Mutex::new(Self {
|
||||
subscribers: Vec::new(),
|
||||
}));
|
||||
let instance_clone = instance.clone();
|
||||
std::thread::spawn(move || {
|
||||
while let Ok(sender) = registration_rx.recv() {
|
||||
instance_clone.lock().unwrap().subscribers.push(sender);
|
||||
}
|
||||
});
|
||||
std::thread::spawn(move || {
|
||||
if std::fs::metadata(SOCKET_PATH).is_ok() {
|
||||
if let Err(e) = std::fs::remove_file(SOCKET_PATH) {
|
||||
error!(&LOGGER, "Error deleting old socket file: {e}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
let socket = UnixListener::bind(SOCKET_PATH);
|
||||
let Ok(socket) = socket else {
|
||||
error!(&LOGGER, "Error creating socket {}", socket.err().unwrap());
|
||||
return;
|
||||
};
|
||||
|
||||
info!(&LOGGER, "Successfully started control socket");
|
||||
|
||||
loop {
|
||||
if let Ok((mut stream, _addr)) = socket.accept() {
|
||||
info!(&LOGGER, "Socket accepted connection");
|
||||
let mut read = String::new();
|
||||
let res = stream.read_to_string(&mut read);
|
||||
if let Err(e) = res {
|
||||
error!(&LOGGER, "Error reading: {e}");
|
||||
let _ = stream.shutdown(Shutdown::Both);
|
||||
continue;
|
||||
}
|
||||
if let Some(command) = ControlCommand::from_str(&read) {
|
||||
instance.lock().unwrap().publish(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ use nmrs::raw::zbus::interface;
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
use std::time::{Duration, Instant};
|
||||
use tokio::sync::watch;
|
||||
use tokio::time::sleep;
|
||||
use wayland_client::globals::registry_queue_init;
|
||||
@@ -26,7 +26,7 @@ const LEGACY_OBJECT_PATH: &str = "/ScreenSaver";
|
||||
|
||||
struct WlState {
|
||||
idle: Option<bool>,
|
||||
tx: watch::Sender<IdleStateInner>,
|
||||
tx: watch::Sender<bool>,
|
||||
}
|
||||
|
||||
delegate_noop!(WlState: ignore WlSeat);
|
||||
@@ -53,14 +53,18 @@ impl Dispatch<ExtIdleNotificationV1, ()> for WlState {
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
match event {
|
||||
Event::Idled => state.idle = Some(true),
|
||||
Event::Resumed => state.idle = Some(false),
|
||||
Event::Idled => {
|
||||
println!("Idled: {:?}", Instant::now());
|
||||
state.idle = Some(true);
|
||||
}
|
||||
Event::Resumed => {
|
||||
println!("Resumed: {:?}", Instant::now());
|
||||
state.idle = Some(false);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if let Some(idle) = state.idle {
|
||||
state.tx.send_modify(|state| {
|
||||
state.wayland_idle = idle;
|
||||
});
|
||||
state.tx.send_modify(|state| *state = idle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,20 +88,6 @@ struct Inhibitor {
|
||||
_reason: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct IdleStateInner {
|
||||
dimmed: bool,
|
||||
wayland_idle: bool,
|
||||
dbus_inhibited: bool,
|
||||
caffeine: bool,
|
||||
}
|
||||
|
||||
impl IdleStateInner {
|
||||
fn should_dim(&self) -> bool {
|
||||
self.wayland_idle && !self.dbus_inhibited
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum IdleState {
|
||||
Init(Sender<IdleMessage>),
|
||||
@@ -107,20 +97,6 @@ pub enum IdleState {
|
||||
Active,
|
||||
}
|
||||
|
||||
impl From<IdleStateInner> for IdleState {
|
||||
fn from(value: IdleStateInner) -> Self {
|
||||
if value.should_dim() {
|
||||
IdleState::Dimmed
|
||||
} else if value.caffeine {
|
||||
IdleState::Caffeine
|
||||
} else if value.dbus_inhibited {
|
||||
IdleState::Inhibited
|
||||
} else {
|
||||
IdleState::Active
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum IdleMessage {
|
||||
Inhibit,
|
||||
@@ -170,15 +146,10 @@ impl BackendThread<IdleState, Sender<IdleMessage>> for IdleDaemon {
|
||||
}
|
||||
}
|
||||
});
|
||||
let (state_tx, state_rx) = watch::channel(IdleStateInner {
|
||||
dimmed: false,
|
||||
wayland_idle: false,
|
||||
dbus_inhibited: false,
|
||||
caffeine: false,
|
||||
});
|
||||
let tx_clone = state_tx.clone();
|
||||
let (wl_tx, wl_rx) = watch::channel(false);
|
||||
let (dbus_tx, dbus_rx) = watch::channel((false, false));
|
||||
std::thread::spawn(move || {
|
||||
if let Err(err) = Self::start_idle_notifier(tx_clone) {
|
||||
if let Err(err) = Self::start_idle_notifier(wl_tx) {
|
||||
error!(&LOGGER, "Idle Daemon unexpectedly quit, reason: {err}");
|
||||
}
|
||||
});
|
||||
@@ -216,10 +187,10 @@ impl BackendThread<IdleState, Sender<IdleMessage>> for IdleDaemon {
|
||||
.expect("Failed to create Tokio runtime");
|
||||
|
||||
runtime.block_on(async move {
|
||||
let res = IdleDaemon::start_dbus(state_tx).await;
|
||||
let res = IdleDaemon::start_dbus(dbus_tx).await;
|
||||
match res {
|
||||
Ok((_, _)) => {
|
||||
Self::run_idle_timer(instance, state_rx, Duration::from_secs(10)).await;
|
||||
Self::run_idle_timer(instance, wl_rx, dbus_rx).await;
|
||||
}
|
||||
Err(err) => error!(&LOGGER, "Error running D-Bus Screensaver: {err}"),
|
||||
}
|
||||
@@ -228,41 +199,77 @@ impl BackendThread<IdleState, Sender<IdleMessage>> for IdleDaemon {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum IdleStage {
|
||||
Dim,
|
||||
TurnOff,
|
||||
Sleep,
|
||||
}
|
||||
|
||||
impl IdleStage {
|
||||
fn next(self) -> Self {
|
||||
match self {
|
||||
IdleStage::Dim => IdleStage::TurnOff,
|
||||
IdleStage::TurnOff => IdleStage::Sleep,
|
||||
IdleStage::Sleep => IdleStage::Sleep,
|
||||
}
|
||||
}
|
||||
|
||||
fn timeout(self) -> Duration {
|
||||
match self {
|
||||
Self::Dim => Duration::from_secs(20),
|
||||
Self::TurnOff => Duration::from_secs(20),
|
||||
Self::Sleep => Duration::from_secs(20),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IdleDaemon {
|
||||
async fn run_idle_timer(
|
||||
instance: Arc<Mutex<Self>>,
|
||||
mut state_rx: watch::Receiver<IdleStateInner>,
|
||||
timeout: Duration,
|
||||
_instance: Arc<Mutex<Self>>,
|
||||
mut wl_rx: watch::Receiver<bool>,
|
||||
mut dbus_rx: watch::Receiver<(bool, bool)>,
|
||||
) {
|
||||
loop {
|
||||
let mut state = *state_rx.borrow_and_update();
|
||||
instance.lock().unwrap().publish(state.into());
|
||||
|
||||
if !state.should_dim() {
|
||||
if state_rx.changed().await.is_err() {
|
||||
return;
|
||||
}
|
||||
|
||||
continue;
|
||||
if let Err(e) = wl_rx.changed().await {
|
||||
warn!(&LOGGER, "Error getting Wayland idle state {e}");
|
||||
return;
|
||||
}
|
||||
|
||||
tokio::select! {
|
||||
_ = sleep(timeout) => {
|
||||
state.dimmed = true;
|
||||
instance.lock().unwrap().publish(state.into());
|
||||
}
|
||||
result = state_rx.changed() => {
|
||||
if result.is_err() {
|
||||
return;
|
||||
let wl_idle = *wl_rx.borrow_and_update();
|
||||
let dbus_state = *dbus_rx.borrow_and_update();
|
||||
println!("Wayland idle state changed {wl_idle} (DBus state: {dbus_state:?})");
|
||||
if wl_idle && !dbus_state.0 {
|
||||
println!("Going into idle cycle");
|
||||
let mut stage = IdleStage::Dim;
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = sleep(stage.timeout()) => {
|
||||
stage = stage.next();
|
||||
println!("Reached next stage {stage:?}");
|
||||
}
|
||||
res = wl_rx.changed() => {
|
||||
if let Err(e) = res {
|
||||
warn!(&LOGGER, "Error getting Wayland idle state {e}");
|
||||
return;
|
||||
}
|
||||
println!("WL state change");
|
||||
break;
|
||||
}
|
||||
res = dbus_rx.changed() => {
|
||||
if let Err(e) = res {
|
||||
warn!(&LOGGER, "Error getting D-Bus idle state {e}");
|
||||
return;
|
||||
}
|
||||
println!("D-Bus state change");
|
||||
break;
|
||||
}
|
||||
}
|
||||
state.dimmed = false;
|
||||
instance.lock().unwrap().publish(state.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn start_idle_notifier(tx: watch::Sender<IdleStateInner>) -> Result<(), Box<dyn Error>> {
|
||||
fn start_idle_notifier(tx: watch::Sender<bool>) -> Result<(), Box<dyn Error>> {
|
||||
let conn = Connection::connect_to_env()?;
|
||||
let (globals, mut event_queue) = registry_queue_init::<WlState>(&conn)?;
|
||||
let queue_handle = event_queue.handle();
|
||||
@@ -281,7 +288,7 @@ impl IdleDaemon {
|
||||
}
|
||||
|
||||
async fn start_dbus(
|
||||
tx: watch::Sender<IdleStateInner>,
|
||||
tx: watch::Sender<(bool, bool)>,
|
||||
) -> zbus::Result<(ScreenSaver, zbus::connection::Connection)> {
|
||||
let service = ScreenSaver::new(tx);
|
||||
|
||||
@@ -345,11 +352,11 @@ struct ScreenSaver {
|
||||
struct Inner {
|
||||
next_cookie: u32,
|
||||
inhibitors: HashMap<u32, Inhibitor>,
|
||||
tx: watch::Sender<IdleStateInner>,
|
||||
tx: watch::Sender<(bool, bool)>,
|
||||
}
|
||||
|
||||
impl ScreenSaver {
|
||||
fn new(tx: watch::Sender<IdleStateInner>) -> Self {
|
||||
fn new(tx: watch::Sender<(bool, bool)>) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(Mutex::new(Inner {
|
||||
next_cookie: 1,
|
||||
@@ -405,8 +412,8 @@ impl ScreenSaver {
|
||||
);
|
||||
|
||||
inner.tx.send_modify(|state| {
|
||||
state.dbus_inhibited = !inner.inhibitors.is_empty();
|
||||
state.caffeine = caffeine_flag;
|
||||
state.0 = !inner.inhibitors.is_empty();
|
||||
state.1 = caffeine_flag;
|
||||
});
|
||||
Ok(cookie)
|
||||
}
|
||||
@@ -436,8 +443,8 @@ impl ScreenSaver {
|
||||
}
|
||||
}
|
||||
inner.tx.send_modify(|state| {
|
||||
state.dbus_inhibited = !inner.inhibitors.is_empty();
|
||||
state.caffeine = caffeine_flag;
|
||||
state.0 = !inner.inhibitors.is_empty();
|
||||
state.1 = caffeine_flag;
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ const POLL_INTERVAL: u64 = 10_000;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Stats {
|
||||
pub cpu: u8,
|
||||
pub ram: u8,
|
||||
pub cpu: Option<u8>,
|
||||
pub ram: Option<u8>,
|
||||
pub disks: Vec<(String, u8)>,
|
||||
pub gpus: Vec<(String, u8)>,
|
||||
pub battery_charge: u8,
|
||||
@@ -28,8 +28,8 @@ pub struct Stats {
|
||||
|
||||
pub struct StatsBackend {
|
||||
subscribers: Vec<Sender<Stats>>,
|
||||
system: System,
|
||||
disks: Disks,
|
||||
system: Option<System>,
|
||||
disks: Option<Disks>,
|
||||
}
|
||||
|
||||
impl BackendThread<Stats, ()> for StatsBackend {
|
||||
@@ -47,8 +47,8 @@ impl BackendThread<Stats, ()> for StatsBackend {
|
||||
thread::spawn(move || {
|
||||
let mut instance = Self {
|
||||
subscribers: Vec::new(),
|
||||
system: System::new(),
|
||||
disks: Disks::new(),
|
||||
system: System::new().ok(),
|
||||
disks: Disks::new().ok(),
|
||||
};
|
||||
let manager = battery::Manager::new();
|
||||
let smi = AllSmi::new();
|
||||
@@ -58,24 +58,29 @@ impl BackendThread<Stats, ()> for StatsBackend {
|
||||
instance.subscribers.push(tx);
|
||||
}
|
||||
|
||||
instance.system.refresh_cpu_usage();
|
||||
instance.system.refresh_memory();
|
||||
instance.disks.refresh(true);
|
||||
let mut cpu = None;
|
||||
let mut ram = None;
|
||||
if let Some(system) = instance.system.as_mut() {
|
||||
system.refresh_cpu_usage();
|
||||
system.refresh_memory();
|
||||
|
||||
let cpu = instance.system.global_cpu_usage() as u8;
|
||||
let ram =
|
||||
(instance.system.used_memory() * 100 / instance.system.total_memory()) as u8;
|
||||
cpu = Some(system.global_cpu_usage() as u8);
|
||||
ram = Some((system.used_memory() * 100 / system.total_memory()) as u8);
|
||||
}
|
||||
|
||||
let disk_stats: Vec<(String, u8)> = instance
|
||||
.disks
|
||||
.iter()
|
||||
.map(|disk| {
|
||||
let mount_point = disk.mount_point().display().to_string();
|
||||
let used_space = disk.total_space() - disk.available_space();
|
||||
let percentage = (used_space * 100 / disk.total_space()) as u8;
|
||||
(mount_point, percentage)
|
||||
})
|
||||
.collect();
|
||||
let mut disk_stats = Vec::new();
|
||||
if let Some(disks) = instance.disks.as_mut() {
|
||||
disks.refresh(true);
|
||||
disk_stats = disks
|
||||
.iter()
|
||||
.map(|disk| {
|
||||
let mount_point = disk.mount_point().display().to_string();
|
||||
let used_space = disk.total_space() - disk.available_space();
|
||||
let percentage = (used_space * 100 / disk.total_space()) as u8;
|
||||
(mount_point, percentage)
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
|
||||
let mut gpus: Vec<(String, u8)> = Vec::new();
|
||||
if let Ok(smi) = &smi {
|
||||
|
||||
51
src/ctl.rs
Normal file
51
src/ctl.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use jmb_logger_rs::*;
|
||||
use std::env;
|
||||
use std::io::Write;
|
||||
use std::os::unix::net::UnixStream;
|
||||
|
||||
const CTL_LOGGER: Logger = Logger::create_with_custom_format(Level::DEBUG, String::new());
|
||||
pub const SOCKET_PATH: &str = "/run/user/1000/jmb-bar.sock";
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ControlCommand {
|
||||
OpenRunMenu,
|
||||
}
|
||||
|
||||
impl ControlCommand {
|
||||
pub fn from_str(s: &str) -> Option<Self> {
|
||||
match s {
|
||||
"menu" => Some(ControlCommand::OpenRunMenu),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string(self) -> String {
|
||||
match self {
|
||||
ControlCommand::OpenRunMenu => String::from("menu"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
info!(&CTL_LOGGER, "Hello, this is mission control");
|
||||
|
||||
let socket = UnixStream::connect(SOCKET_PATH);
|
||||
let Ok(mut stream) = socket else {
|
||||
error!(
|
||||
&CTL_LOGGER,
|
||||
"Error Connecting to socket: {}",
|
||||
socket.err().unwrap()
|
||||
);
|
||||
error!(&CTL_LOGGER, "Is the bar running?");
|
||||
return;
|
||||
};
|
||||
|
||||
let args: Vec<String> = env::args().collect();
|
||||
|
||||
match args.get(1) {
|
||||
Some(str) if let Some(cmd) = ControlCommand::from_str(str) => stream
|
||||
.write(cmd.to_string().as_bytes())
|
||||
.expect("Error sending message"),
|
||||
_ => 0usize,
|
||||
};
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::backend::Backend;
|
||||
mod backend;
|
||||
mod css;
|
||||
mod ctl;
|
||||
mod ui;
|
||||
|
||||
use glib::clone;
|
||||
@@ -29,6 +30,7 @@ fn main() {
|
||||
let backend = Backend::start();
|
||||
|
||||
app.connect_startup(move |_| {
|
||||
debug!(&LOGGER, "Connect startup");
|
||||
let provider = CssProvider::new();
|
||||
if let Some(css) = css::parse_css() {
|
||||
provider.load_from_string(&css);
|
||||
@@ -46,10 +48,12 @@ fn main() {
|
||||
#[strong]
|
||||
backend,
|
||||
move |app| {
|
||||
debug!(&LOGGER, "Connect activate");
|
||||
trace!(&LOGGER, "Starting bars");
|
||||
ui::create_bars(app, backend.clone());
|
||||
}
|
||||
));
|
||||
|
||||
debug!(&LOGGER, "Running app");
|
||||
app.run();
|
||||
}
|
||||
|
||||
33
src/ui.rs
33
src/ui.rs
@@ -1,7 +1,9 @@
|
||||
use crate::LOGGER;
|
||||
use crate::backend::window_manager_hypr::{HyprlandComms, WindowManagerEvent};
|
||||
use crate::backend::{Backend, BackendChannels};
|
||||
use crate::backend::{Backend, BackendChannels, ChannelType};
|
||||
use crate::ctl::ControlCommand;
|
||||
use crate::ui::action_centre::ActionCentre;
|
||||
use crate::ui::run_menu::RunMenu;
|
||||
use crossbeam_channel::TryRecvError;
|
||||
use glib::ControlFlow;
|
||||
use glib::prelude::Cast;
|
||||
@@ -17,6 +19,7 @@ use std::sync::Mutex;
|
||||
use std::time::Duration;
|
||||
|
||||
mod action_centre;
|
||||
mod run_menu;
|
||||
mod systray;
|
||||
mod title_panel;
|
||||
mod utilities_panel;
|
||||
@@ -27,14 +30,14 @@ pub fn create_bars(app: &Application, backend: Backend) {
|
||||
let display = Display::default().expect("Couldn't find GDK Display");
|
||||
let app_clone = app.clone();
|
||||
let bars: Rc<Mutex<HashMap<u32, ApplicationWindow>>> = Rc::new(Mutex::new(HashMap::new()));
|
||||
let ac_channels = backend.subscribe();
|
||||
let ac_channels = backend.subscribe_all();
|
||||
let action_centre = ActionCentre::create_action_centre(app.clone(), ac_channels);
|
||||
for monitor in 0..display.monitors().n_items() {
|
||||
debug!(&LOGGER, "Opening bar {monitor}");
|
||||
let channels = backend.subscribe();
|
||||
let channels = backend.subscribe_all();
|
||||
bars.lock().expect("Couldn't get active bars").insert(
|
||||
monitor,
|
||||
create_bar(
|
||||
create_and_show_bar(
|
||||
app_clone.clone(),
|
||||
&display,
|
||||
monitor,
|
||||
@@ -43,6 +46,7 @@ pub fn create_bars(app: &Application, backend: Backend) {
|
||||
),
|
||||
);
|
||||
}
|
||||
let backend_clone = backend.clone();
|
||||
display
|
||||
.monitors()
|
||||
.connect_items_changed(move |_list, pos, removed, added| {
|
||||
@@ -55,20 +59,35 @@ pub fn create_bars(app: &Application, backend: Backend) {
|
||||
debug!(&LOGGER, "Detected new monitor: {pos}");
|
||||
let app_clone = app_clone.clone();
|
||||
let action_centre = action_centre.clone();
|
||||
let channels = backend.subscribe();
|
||||
let channels = backend_clone.subscribe_all();
|
||||
let bars = bars.clone();
|
||||
let display = display.clone();
|
||||
glib::idle_add_local_once(move || {
|
||||
bars.lock().expect("Couldn't get active bars").insert(
|
||||
pos,
|
||||
create_bar(app_clone, &display, pos, action_centre, channels),
|
||||
create_and_show_bar(app_clone, &display, pos, action_centre, channels),
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let mut ctl_channel = backend.subscribe(&[ChannelType::Control]);
|
||||
let ctl_rx = ctl_channel.take_ctl_rx().unwrap();
|
||||
let app_clone = app.clone();
|
||||
let menu = RunMenu::create(app_clone);
|
||||
glib::timeout_add_local(Duration::from_millis(100), move || {
|
||||
while let Ok(cmd) = ctl_rx.try_recv() {
|
||||
match cmd {
|
||||
ControlCommand::OpenRunMenu => {
|
||||
menu.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
ControlFlow::Continue
|
||||
});
|
||||
}
|
||||
|
||||
fn create_bar(
|
||||
fn create_and_show_bar(
|
||||
app: Application,
|
||||
display: &Display,
|
||||
monitor_idx: u32,
|
||||
|
||||
@@ -51,7 +51,7 @@ impl ActionCentre {
|
||||
.build();
|
||||
|
||||
window.init_layer_shell();
|
||||
window.set_layer(Layer::Overlay);
|
||||
window.set_layer(Layer::Top);
|
||||
window.set_anchor(Edge::Top, true);
|
||||
window.set_anchor(Edge::Bottom, true);
|
||||
window.set_anchor(Edge::Right, true);
|
||||
@@ -230,7 +230,7 @@ impl ActionCentre {
|
||||
let idx = ((network.signal as f32 / 100.0) * (WIFI_ICONS.len() - 1) as f32 + 0.5) as usize;
|
||||
widget.set_wifi_icon_from_name(WIFI_ICONS[idx]);
|
||||
borrowed_wifi_networks_clone.insert(ssid.clone(), widget.clone());
|
||||
let net_tx = channels.net_tx();
|
||||
let net_tx = channels.net_tx().unwrap();
|
||||
widget.connect_clicked(clone!(
|
||||
#[strong]
|
||||
net_tx,
|
||||
|
||||
77
src/ui/run_menu.rs
Normal file
77
src/ui/run_menu.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
use gtk::prelude::{BoxExt, GtkWindowExt, WidgetExt};
|
||||
use gtk::{Align, Application, ApplicationWindow, Orientation, PolicyType, gdk};
|
||||
use gtk4_layer_shell::{KeyboardMode, Layer, LayerShell};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RunMenu {
|
||||
window: ApplicationWindow,
|
||||
}
|
||||
|
||||
impl RunMenu {
|
||||
pub fn create(application: Application) -> Self {
|
||||
let window = gtk::ApplicationWindow::builder()
|
||||
.application(&application)
|
||||
.title("JmbRunMenu")
|
||||
.default_width(500)
|
||||
.default_height(300)
|
||||
.css_classes(["run-menu"])
|
||||
.build();
|
||||
|
||||
window.init_layer_shell();
|
||||
window.set_layer(Layer::Overlay);
|
||||
window.set_halign(Align::Center);
|
||||
window.set_valign(Align::Center);
|
||||
window.set_size_request(500, 300);
|
||||
window.set_keyboard_mode(KeyboardMode::Exclusive);
|
||||
|
||||
let v_box = gtk::Box::new(Orientation::Vertical, 0);
|
||||
|
||||
let entry = gtk::Entry::new();
|
||||
entry.add_css_class("entry");
|
||||
|
||||
let scrolled = gtk::ScrolledWindow::new();
|
||||
scrolled.set_policy(PolicyType::Never, PolicyType::Automatic);
|
||||
scrolled.set_vexpand(true);
|
||||
scrolled.set_valign(Align::Fill);
|
||||
|
||||
let content_box = gtk::Box::new(Orientation::Vertical, 0);
|
||||
content_box.add_css_class("content-box");
|
||||
|
||||
for _ in 0..10 {
|
||||
let label = gtk::Label::new(Some("Test"));
|
||||
content_box.append(&label);
|
||||
}
|
||||
|
||||
scrolled.set_child(Some(&content_box));
|
||||
|
||||
v_box.append(&entry);
|
||||
v_box.append(&scrolled);
|
||||
|
||||
window.set_child(Some(&v_box));
|
||||
|
||||
let window_clone = window.clone();
|
||||
let instance = Self {
|
||||
window: window_clone,
|
||||
};
|
||||
let instance_clone = instance.clone();
|
||||
let key_controller = gtk::EventControllerKey::new();
|
||||
key_controller.connect_key_pressed(move |_, key, _, _| {
|
||||
if key == gdk::Key::Escape {
|
||||
instance_clone.hide();
|
||||
glib::Propagation::Stop
|
||||
} else {
|
||||
glib::Propagation::Proceed
|
||||
}
|
||||
});
|
||||
window.add_controller(key_controller);
|
||||
instance
|
||||
}
|
||||
|
||||
pub fn hide(&self) {
|
||||
self.window.set_visible(false);
|
||||
}
|
||||
|
||||
pub fn show(&self) {
|
||||
self.window.present();
|
||||
}
|
||||
}
|
||||
@@ -62,20 +62,11 @@ pub fn build(
|
||||
String::new()
|
||||
};
|
||||
let monitor_valid = !monitor.is_empty();
|
||||
println!(
|
||||
"{:?}",
|
||||
monitors
|
||||
.item(monitor_idx)
|
||||
.unwrap()
|
||||
.downcast::<gdk::Monitor>()
|
||||
.unwrap()
|
||||
.connector()
|
||||
);
|
||||
if monitor_valid {
|
||||
let _ = channels
|
||||
.br_tx()
|
||||
.unwrap()
|
||||
.send(BrightnessMessage::Request(monitor.clone()));
|
||||
println!("req");
|
||||
}
|
||||
|
||||
let volume_adjustment = Adjustment::new(60.0, 1.0, 100.0, 1.0, 5.0, 0.0);
|
||||
@@ -85,7 +76,7 @@ pub fn build(
|
||||
volume.imp().second_icon.set_icon_name("bluetooth-symbolic");
|
||||
volume.imp().second_icon.add_child_css_class("bt-icon");
|
||||
|
||||
let media_tx = channels.media_tx();
|
||||
let media_tx = channels.media_tx().unwrap();
|
||||
let changed_progr = Rc::new(Cell::new(false));
|
||||
let changed_progr_clone = changed_progr.clone();
|
||||
volume.connect_value_changed(move |slider, button, _| {
|
||||
@@ -97,7 +88,7 @@ pub fn build(
|
||||
));
|
||||
}
|
||||
});
|
||||
let media_tx = channels.media_tx();
|
||||
let media_tx = channels.media_tx().unwrap();
|
||||
volume.connect_clicked(move |slider, button, _| {
|
||||
if button.is_active() {
|
||||
let _ = media_tx.send(MediaCommand::Cmd(slider.value() as u8, true, false));
|
||||
@@ -110,7 +101,7 @@ pub fn build(
|
||||
let brightness = IconSlider::new(Some(brightness_adjustment));
|
||||
brightness.imp().main_icon.set_font_icon("");
|
||||
|
||||
let br_tx = channels.br_tx();
|
||||
let br_tx = channels.br_tx().unwrap();
|
||||
brightness.connect_value_changed(clone!(
|
||||
#[strong]
|
||||
monitor,
|
||||
@@ -128,7 +119,7 @@ pub fn build(
|
||||
}
|
||||
}
|
||||
));
|
||||
let br_tx = channels.br_tx();
|
||||
let br_tx = channels.br_tx().unwrap();
|
||||
brightness.connect_clicked(clone!(
|
||||
#[strong]
|
||||
monitor,
|
||||
@@ -144,7 +135,7 @@ pub fn build(
|
||||
|
||||
let caffeine_button = Button::with_label(" ");
|
||||
caffeine_button.add_css_class("caffeine");
|
||||
let idle_tx = channels.idle_tx();
|
||||
let idle_tx = channels.idle_tx().unwrap();
|
||||
caffeine_button.connect_clicked(move |button| {
|
||||
if button.has_css_class("on") {
|
||||
let _ = idle_tx.send(IdleMessage::Release);
|
||||
@@ -221,7 +212,7 @@ pub fn build(
|
||||
|
||||
let wg_button = Button::with_label("wg");
|
||||
wg_button.add_css_class("vpn");
|
||||
let net_tx = channels.net_tx();
|
||||
let net_tx = channels.net_tx().unwrap();
|
||||
wg_button.connect_clicked(move |_| {
|
||||
let _ = net_tx.send(NetworkCommand::ToggleVpn(String::from("wg")));
|
||||
});
|
||||
@@ -328,7 +319,7 @@ pub fn build(
|
||||
let netbird_rx = channels.take_netbird_rx().unwrap();
|
||||
let idle_rx = channels.take_idle_rx().unwrap();
|
||||
let monitor_clone = monitor.clone();
|
||||
let br_tx = channels.br_tx();
|
||||
let br_tx = channels.br_tx().unwrap();
|
||||
glib::timeout_add_local(Duration::from_millis(100), move || {
|
||||
while let Ok(command) = media_rx.try_recv() {
|
||||
if let MediaCommand::Cmd(vol, mute, bt) = command {
|
||||
@@ -374,7 +365,6 @@ pub fn build(
|
||||
let _ =
|
||||
br_tx.send(BrightnessMessage::Value(monitor_clone.clone(), 20, true));
|
||||
brightness.set_value(20.0);
|
||||
println!("Dimmed: {monitor_clone}");
|
||||
}
|
||||
caffeine_button.add_css_class("idle");
|
||||
caffeine_button.remove_css_class("inhibit");
|
||||
@@ -474,8 +464,12 @@ pub fn build(
|
||||
vpn_button.remove_css_class("login");
|
||||
}
|
||||
while let Ok(stats) = stats_rx.try_recv() {
|
||||
cpu_label.set_label(&format!("{}%", stats.cpu));
|
||||
ram_label.set_label(&format!("{}%", stats.ram));
|
||||
if let Some(cpu) = stats.cpu {
|
||||
cpu_label.set_label(&format!("{}%", cpu));
|
||||
}
|
||||
if let Some(ram) = stats.ram {
|
||||
ram_label.set_label(&format!("{}%", ram));
|
||||
}
|
||||
for disk in stats.disks {
|
||||
if disk.0.eq("/") {
|
||||
disk_label.set_label(&format!("{}%", disk.1));
|
||||
|
||||
5
style/run_menu.scss
Normal file
5
style/run_menu.scss
Normal file
@@ -0,0 +1,5 @@
|
||||
@use "colors" as *;
|
||||
|
||||
.run-menu {
|
||||
background: $background;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
@use "widgets";
|
||||
@use "bar";
|
||||
@use "action_centre";
|
||||
@use "run_menu";
|
||||
Reference in New Issue
Block a user