hyprshell_exec_lib/
util.rs1use anyhow::Context;
2use core_lib::{Active, ClientId, Warn};
3use hyprland::ctl::{Color, notify, reload};
4use hyprland::data::{Client, Clients, Monitor, Monitors, Workspace};
5use hyprland::dispatch::{Dispatch, DispatchType};
6use hyprland::keyword::Keyword;
7use hyprland::prelude::*;
8use std::sync::{Mutex, OnceLock};
9use tracing::{Level, debug, span, trace, warn};
10
11pub fn get_clients() -> Vec<Client> {
12 Clients::get().map_or(vec![], |clients| clients.to_vec())
13}
14
15pub fn get_monitors() -> Vec<Monitor> {
16 Monitors::get().map_or(vec![], |monitors| monitors.to_vec())
17}
18
19pub fn get_current_monitor() -> Option<Monitor> {
20 Monitor::get_active().ok()
21}
22
23pub fn reload_config() {
24 debug!("Reloading hyprland config");
25 reload::call().warn("Failed to reload hyprland config");
26}
27
28pub fn toast(body: &str) {
29 warn!("toast: {}", body);
30 let _ = notify::call(
31 notify::Icon::Warning,
32 std::time::Duration::from_secs(10),
33 Color::new(255, 0, 0, 255),
34 format!("hyprshell Error: {}", body),
35 );
36}
37
38pub fn apply_keybinds(list: Vec<(&str, String)>) {
39 trace!("Applying binds and submaps");
40 for (a, b) in list {
41 trace!("{}={}", a, b);
42 Keyword::set(a, b).warn("Failed to apply bind and submap");
43 }
44}
45
46pub fn to_client_id(id: &hyprland::shared::Address) -> ClientId {
48 u64::from_str_radix(id.to_string().trim_start_matches("0x"), 16)
49 .expect("Failed to parse client id, this should never happen")
50}
51pub fn to_client_address(id: ClientId) -> hyprland::shared::Address {
53 hyprland::shared::Address::new(format!("{:x}", id))
54}
55
56fn get_prev_follow_mouse() -> &'static Mutex<String> {
57 static PREV_FOLLOW_MOUSE: OnceLock<Mutex<String>> = OnceLock::new();
58 PREV_FOLLOW_MOUSE.get_or_init(|| Mutex::new("".to_string()))
59}
60
61pub fn activate_submap(submap_name: &str) -> anyhow::Result<()> {
62 let _span = span!(Level::TRACE, "submap").entered();
63 if let Ok(follow) = Keyword::get("input:follow_mouse") {
64 get_prev_follow_mouse()
65 .lock()
66 .map(|mut lock| {
67 *lock = follow.value.to_string();
68 })
69 .warn("Failed to store previous follow_mouse value");
70 Keyword::set("input:follow_mouse", "3").warn("Failed to set follow_mouse to 3");
71 };
72 Dispatch::call(DispatchType::Custom("submap", submap_name)).warn("unable to activate submap");
73 debug!("Activated submap: {}", submap_name);
74 Ok(())
75}
76
77pub fn reset_submap() -> anyhow::Result<()> {
78 let _span = span!(Level::TRACE, "submap").entered();
79 Dispatch::call(DispatchType::Custom("submap", "reset")).warn("unable to activate submap");
80 if let Ok(follow) = get_prev_follow_mouse().lock() {
81 Keyword::set("input:follow_mouse", follow.to_string())
82 .warn("Failed to restore previous follow_mouse value");
83 }
84 debug!("reset submap");
85 Ok(())
86}
87
88pub fn get_initial_active() -> anyhow::Result<Active> {
89 let active_client = Client::get_active()?.map(|c| to_client_id(&c.address));
90 let active_ws = Workspace::get_active()?.id;
91 let active_monitor = Monitor::get_active()?.id;
92 Ok(Active {
93 client: active_client,
94 workspace: active_ws,
95 monitor: active_monitor,
96 })
97}
98
99pub fn get_version() -> anyhow::Result<String> {
100 let version = hyprland::data::Version::get()
101 .context("Failed to get version! (hyprland is probably outdated or too new??)")?;
102
103 trace!("hyprland {version:?}");
104
105 Ok(version
106 .version
107 .unwrap_or(version.tag.trim_start_matches('v').to_string()))
108}