├── .gitignore ├── rustfmt.toml ├── img ├── zoom.png └── fullscreen.png ├── src ├── data │ ├── icon.ico │ ├── icon.png │ └── config.yaml ├── logger.rs ├── rainbow.rs ├── config.rs ├── util.rs └── main.rs ├── Cargo.toml ├── LICENSE ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | tab_spaces = 2 -------------------------------------------------------------------------------- /img/zoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keifufu/cute-borders/HEAD/img/zoom.png -------------------------------------------------------------------------------- /img/fullscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keifufu/cute-borders/HEAD/img/fullscreen.png -------------------------------------------------------------------------------- /src/data/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keifufu/cute-borders/HEAD/src/data/icon.ico -------------------------------------------------------------------------------- /src/data/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keifufu/cute-borders/HEAD/src/data/icon.png -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cute-borders" 3 | version = "1.3.1" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | check_elevation = "0.2.4" 8 | lazy_static = "1.4.0" 9 | open = "5.1.4" 10 | planif = "1.0.0" 11 | serde = "1.0.203" 12 | serde_yaml = "0.9.34+deprecated" 13 | tray-icon = "0.14.3" 14 | winapi = { version = "0.3.9", features = ["winuser", "dwmapi", "wincon", "shellapi", "errhandlingapi", "winerror"] } 15 | winreg = "0.52.0" 16 | 17 | [build-dependencies] 18 | winres = "0.1.12" 19 | -------------------------------------------------------------------------------- /src/data/config.yaml: -------------------------------------------------------------------------------- 1 | # Valid colors: 2 | # - hex (e.g., #ffffff for white) 3 | # - default (the default windows 11 border) 4 | # - accent (uses your system's accent color) 5 | # - rainbow (cycles through a smooth transition of colors) 6 | # - transparent (invisible border) 7 | # Invalid colors will be logged to %UserProfile%\.cuteborders\log.txt 8 | # and will default to red. 9 | hide_tray_icon: false 10 | rainbow_speed: 1.0 11 | window_rules: 12 | - match: "Global" 13 | active_border_color: "accent" 14 | inactive_border_color: "transparent" 15 | # Example rules 16 | - match: "Title" 17 | contains: "Mozilla Firefox" 18 | active_border_color: "#c6a0f6" 19 | inactive_border_color: "#ffffff" 20 | - match: "Class" 21 | contains: "MozillaWindowClass" 22 | active_border_color: "#c6a0f6" 23 | inactive_border_color: "#ffffff" 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2024 keifufu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/logger.rs: -------------------------------------------------------------------------------- 1 | use crate::util::get_file; 2 | use lazy_static::lazy_static; 3 | use std::{io::Write, sync::Mutex}; 4 | 5 | lazy_static! { 6 | static ref LOGGER: Mutex = Mutex::new(Logger::new().unwrap()); 7 | } 8 | 9 | pub struct Logger { 10 | file: std::fs::File, 11 | last_message: Option, 12 | } 13 | 14 | impl Logger { 15 | fn new() -> Result { 16 | let file = get_file("log.txt", ""); 17 | Ok(Logger { 18 | file, 19 | last_message: None, 20 | }) 21 | } 22 | 23 | pub fn log(message: &str) { 24 | let mut logger = LOGGER.lock().unwrap(); 25 | 26 | if let Some(ref last_message) = logger.last_message { 27 | if last_message == message { 28 | return; // Don't log the same message again (can't be bothered to do it properly :3) 29 | } 30 | } 31 | 32 | let formatted_message = format!("{}\n", message); 33 | logger 34 | .file 35 | .write_all(formatted_message.as_bytes()) 36 | .expect("Failed to write to log"); 37 | logger.file.flush().expect("Failed to flush log"); 38 | 39 | logger.last_message = Some(message.to_string()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cute-borders 2 | 3 | Makes focused and unfocused window borders have a different border color, configurable per program. 4 | Windows 11 only. 5 | 6 | ## Preview 7 | 8 | ![Zoom](img/zoom.png?raw=true) 9 | ![Fullscreen](img/fullscreen.png?raw=true) 10 | 11 | ## Installing 12 | 13 | - Download `cute-borders.exe` from [GitHub Releases](https://github.com/keifufu/cute-borders/releases/latest) 14 | - Start the executable 15 | - Select "install" in the tray menu 16 | 17 | ## Updating 18 | 19 | Assuming you have previously already installed cute-borders: 20 | - Exit cute-borders 21 | - Download the version of cute-borders you want to update to 22 | - Simply run the executable. It will update automatically and run this version on startup from now on. 23 | 24 | ## Configuration 25 | 26 | The config is located at `%UserProfile%/.cuteborders/config.yaml`. 27 | You can open it via the tray icon > Open config 28 | 29 | Example config: 30 | 31 | ```yaml 32 | hide_tray_icon: false 33 | window_rules: 34 | - match: "Global" 35 | active_border_color: "#c6a0f6" 36 | inactive_border_color: "#ffffff" 37 | # Example rules 38 | # color can either be hex or "transparent" 39 | - match: "Title" 40 | contains: "Mozilla Firefox" 41 | active_border_color: "#c6a0f6" 42 | inactive_border_color: "#ffffff" 43 | - match: "Class" 44 | contains: "MozillaWindowClass" 45 | active_border_color: "#c6a0f6" 46 | inactive_border_color: "#ffffff" 47 | ``` 48 | -------------------------------------------------------------------------------- /src/rainbow.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use std::sync::{Arc, Mutex}; 3 | 4 | use crate::DWMWA_COLOR_DEFAULT; 5 | 6 | lazy_static! { 7 | static ref RAINBOW: Mutex = Mutex::new(Rainbow::new()); 8 | } 9 | 10 | pub struct Rainbow { 11 | color: Arc>, 12 | hue: Arc>, 13 | } 14 | 15 | impl Rainbow { 16 | fn new() -> Self { 17 | let color = Arc::new(Mutex::new(DWMWA_COLOR_DEFAULT)); 18 | let hue = Arc::new(Mutex::new(0.0)); 19 | Rainbow { color, hue } 20 | } 21 | pub fn tick(speed: f32) { 22 | let rainbow = RAINBOW.lock().unwrap(); 23 | let mut hue = rainbow.hue.lock().unwrap(); 24 | let (r, g, b) = hsl_to_rgb(*hue, 1.0, 0.5); 25 | let color_value = 0x00u32 | ((b as u32) << 16) | ((g as u32) << 8) | ((r as u32) << 0); 26 | 27 | let mut color = rainbow.color.lock().unwrap(); 28 | *color = color_value; 29 | *hue = (*hue + speed) % 360.0; 30 | } 31 | pub fn get_color() -> u32 { 32 | let rainbow = RAINBOW.lock().unwrap(); 33 | let color = rainbow.color.lock().unwrap(); 34 | *color 35 | } 36 | } 37 | 38 | fn hsl_to_rgb(h: f32, s: f32, l: f32) -> (u8, u8, u8) { 39 | let c = (1.0 - (2.0 * l - 1.0).abs()) * s; 40 | let x = c * (1.0 - ((h / 60.0) % 2.0 - 1.0).abs()); 41 | let m = l - c / 2.0; 42 | 43 | let (r_prime, g_prime, b_prime) = if 0.0 <= h && h < 60.0 { 44 | (c, x, 0.0) 45 | } else if 60.0 <= h && h < 120.0 { 46 | (x, c, 0.0) 47 | } else if 120.0 <= h && h < 180.0 { 48 | (0.0, c, x) 49 | } else if 180.0 <= h && h < 240.0 { 50 | (0.0, x, c) 51 | } else if 240.0 <= h && h < 300.0 { 52 | (x, 0.0, c) 53 | } else { 54 | (c, 0.0, x) 55 | }; 56 | 57 | let r = ((r_prime + m) * 255.0).round() as u8; 58 | let g = ((g_prime + m) * 255.0).round() as u8; 59 | let b = ((b_prime + m) * 255.0).round() as u8; 60 | 61 | (r, g, b) 62 | } 63 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use std::{io::Read, sync::Mutex}; 2 | 3 | use crate::{logger::Logger, util::get_file}; 4 | use lazy_static::lazy_static; 5 | use serde::{Deserialize, Serialize}; 6 | 7 | const DEFAULT_CONFIG: &str = include_str!("data/config.yaml"); 8 | 9 | lazy_static! { 10 | static ref CONFIG: Mutex = Mutex::new(Config::new()); 11 | } 12 | 13 | #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] 14 | // Maybe support Process later. 15 | // Getting the process name seems annoying. 16 | pub enum RuleMatch { 17 | Global, 18 | Title, 19 | Class, 20 | } 21 | 22 | #[derive(Debug, Serialize, Deserialize, Clone)] 23 | pub struct WindowRule { 24 | #[serde(rename = "match")] 25 | pub rule_match: RuleMatch, 26 | pub contains: Option, 27 | pub active_border_color: String, 28 | pub inactive_border_color: String, 29 | } 30 | 31 | // Some are Options because i cant be bothered handling config upgrades 32 | // if they are not defined we just use the default 33 | #[derive(Debug, Serialize, Deserialize, Clone)] 34 | pub struct Config { 35 | pub hide_tray_icon: Option, 36 | pub rainbow_speed: Option, 37 | pub window_rules: Vec, 38 | } 39 | 40 | impl Config { 41 | fn new() -> Self { 42 | let mut file = get_file("config.yaml", DEFAULT_CONFIG); 43 | let mut contents = String::new(); 44 | match file.read_to_string(&mut contents) { 45 | Ok(..) => {} 46 | Err(err) => { 47 | Logger::log("[ERROR] Failed to read config file"); 48 | Logger::log(&format!("[DEBUG] {:?}", err)); 49 | std::process::exit(1); 50 | } 51 | } 52 | let config: Config = match serde_yaml::from_str(contents.as_str()) { 53 | Ok(config) => config, 54 | Err(err) => { 55 | Logger::log("[ERROR] Failed to parse config file"); 56 | Logger::log(&format!("[DEBUG] {:?}", err)); 57 | std::process::exit(1); 58 | } 59 | }; 60 | 61 | config 62 | } 63 | pub fn reload() { 64 | let mut config = CONFIG.lock().unwrap(); 65 | *config = Self::new(); 66 | } 67 | pub fn get() -> Self { 68 | CONFIG.lock().unwrap().clone() 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | use check_elevation::is_elevated; 2 | use planif::enums::TaskCreationFlags; 3 | use planif::schedule::TaskScheduler; 4 | use planif::schedule_builder::Action; 5 | use planif::schedule_builder::ScheduleBuilder; 6 | use planif::settings::Duration; 7 | use planif::settings::LogonType; 8 | use planif::settings::PrincipalSettings; 9 | use planif::settings::RunLevel; 10 | use planif::settings::Settings; 11 | use std::ffi::CString; 12 | use std::{ 13 | env, 14 | fs::{self, File, OpenOptions}, 15 | io::Write, 16 | path::{Path, PathBuf}, 17 | }; 18 | use winapi::shared::minwindef::BOOL; 19 | use winapi::shared::winerror::SUCCEEDED; 20 | use winapi::um::dwmapi::DwmGetColorizationColor; 21 | use winapi::um::winnt::{KEY_READ, KEY_WRITE}; 22 | use winapi::um::winuser::MessageBoxA; 23 | use winapi::um::winuser::MB_ICONERROR; 24 | use winapi::um::winuser::MB_OK; 25 | use winreg::{enums::HKEY_CURRENT_USER, RegKey}; 26 | 27 | use crate::rainbow::Rainbow; 28 | use crate::{logger::Logger, COLOR_INVALID, DWMWA_COLOR_DEFAULT, DWMWA_COLOR_NONE}; 29 | 30 | pub fn get_file_path(filename: &str) -> String { 31 | let user_profile_path = match std::env::var("USERPROFILE") { 32 | Ok(user_profile_path) => user_profile_path, 33 | Err(err) => { 34 | Logger::log("[ERROR] Failed to find USERPROFILE environment variable"); 35 | Logger::log(&format!("[DEBUG] {:?}", err)); 36 | std::process::exit(1); 37 | } 38 | }; 39 | let dirpath = format!("{}\\.cuteborders", user_profile_path); 40 | let filepath = format!("{}\\{}", dirpath, filename); 41 | 42 | if !Path::new(&dirpath).exists() { 43 | if let Err(err) = fs::create_dir(&dirpath) { 44 | Logger::log(&format!("[ERROR] Failed to create directory: {}", &dirpath)); 45 | Logger::log(&format!("[DEBUG] {:?}", err)); 46 | std::process::exit(1); 47 | } 48 | } 49 | return filepath; 50 | } 51 | 52 | pub fn get_file(filename: &str, default_content: &str) -> std::fs::File { 53 | let filepath = get_file_path(filename); 54 | 55 | if !Path::new(&filepath).exists() { 56 | let mut file = match File::create(&filepath) { 57 | Ok(file) => file, 58 | Err(err) => { 59 | Logger::log(&format!("[ERROR] Failed to create file: {}", &filepath)); 60 | Logger::log(&format!("[DEBUG] {:?}", err)); 61 | std::process::exit(1); 62 | } 63 | }; 64 | 65 | if let Err(err) = file.write_all(default_content.as_bytes()) { 66 | Logger::log(&format!("[ERROR] Failed to write to file: {}", &filepath)); 67 | Logger::log(&format!("[DEBUG] {:?}", err)); 68 | std::process::exit(1); 69 | } 70 | } 71 | 72 | let file = match OpenOptions::new() 73 | .read(true) 74 | .write(true) 75 | .append(true) 76 | .open(&filepath) 77 | { 78 | Ok(file) => file, 79 | Err(err) => { 80 | Logger::log(&format!("[ERROR] Failed to open file: {}", &filepath)); 81 | Logger::log(&format!("[DEBUG] {:?}", err)); 82 | std::process::exit(1); 83 | } 84 | }; 85 | 86 | file 87 | } 88 | 89 | pub fn hex_to_colorref(hex: &str) -> u32 { 90 | if hex == "default" { 91 | return DWMWA_COLOR_DEFAULT; 92 | } 93 | 94 | if hex == "transparent" { 95 | return DWMWA_COLOR_NONE; 96 | } 97 | 98 | if hex == "accent" { 99 | let mut colorization: u32 = 0; 100 | let mut opaqueblend: BOOL = 0; 101 | // should not call this every single fucking time but whatever 102 | let result = unsafe { DwmGetColorizationColor(&mut colorization, &mut opaqueblend) }; 103 | if SUCCEEDED(result) { 104 | let red = (colorization & 0x00FF0000) >> 16; 105 | let green = (colorization & 0x0000FF00) >> 8; 106 | let blue = (colorization & 0x000000FF) >> 0; 107 | let bbggrr = (blue << 16) | (green << 8) | red; 108 | return bbggrr; 109 | } else { 110 | Logger::log(&format!( 111 | "[ERROR] Failed to retrieve accent color: 0x{:08X})", 112 | result 113 | )); 114 | // Not returning COLOR_INVALID here since the config is not invalid, 115 | // instead returning DWMWA_COLOR_DEFAULT to let the system handle it. 116 | return DWMWA_COLOR_DEFAULT; 117 | } 118 | } 119 | 120 | if hex == "rainbow" { 121 | return Rainbow::get_color(); 122 | } 123 | 124 | if hex.len() != 7 || !hex.starts_with('#') { 125 | Logger::log(&format!("[ERROR] Invalid hex: {}", hex)); 126 | return COLOR_INVALID; 127 | } 128 | 129 | let r = u8::from_str_radix(&hex[1..3], 16); 130 | let g = u8::from_str_radix(&hex[3..5], 16); 131 | let b = u8::from_str_radix(&hex[5..7], 16); 132 | 133 | match (r, g, b) { 134 | (Ok(r), Ok(g), Ok(b)) => (b as u32) << 16 | (g as u32) << 8 | r as u32, 135 | _ => { 136 | Logger::log(&format!("[ERROR] Invalid hex: {}", hex)); 137 | COLOR_INVALID 138 | } 139 | } 140 | } 141 | 142 | fn clean_old_registry_key() { 143 | let key = match RegKey::predef(HKEY_CURRENT_USER).open_subkey_with_flags( 144 | "Software\\Microsoft\\Windows\\CurrentVersion\\Run", 145 | KEY_READ | KEY_WRITE, 146 | ) { 147 | Ok(key) => Some(key), 148 | Err(_) => None, 149 | }; 150 | 151 | if let Some(key) = key { 152 | let _ = key.delete_value("cute-borders"); 153 | } 154 | } 155 | 156 | pub fn get_exe_path() -> PathBuf { 157 | let exe_path: PathBuf = match env::current_exe() { 158 | Ok(path) => path, 159 | Err(err) => { 160 | Logger::log("[ERROR] Failed to find own executable path"); 161 | Logger::log(&format!("[DEBUG] {:?}", err)); 162 | std::process::exit(1); 163 | } 164 | }; 165 | 166 | let user_profile_path = match std::env::var("USERPROFILE") { 167 | Ok(user_profile_path) => user_profile_path, 168 | Err(err) => { 169 | Logger::log("[ERROR] Failed to find USERPROFILE environment variable"); 170 | Logger::log(&format!("[DEBUG] {:?}", err)); 171 | std::process::exit(1); 172 | } 173 | }; 174 | get_file_path("cute-borders.exe"); // this creates the folder 175 | let new_exe_path = PathBuf::from(format!( 176 | "{}\\.cuteborders\\cute-borders.exe", 177 | user_profile_path, 178 | )); 179 | 180 | if exe_path != new_exe_path { 181 | if Path::new(&new_exe_path).exists() { 182 | match fs::remove_file(&new_exe_path) { 183 | Ok(_) => {} 184 | Err(_err) => { 185 | unsafe { 186 | let title = CString::new("Failed to update").unwrap(); 187 | let message = CString::new( 188 | "Please close currently running cute-borders to be able to update to this version.", 189 | ) 190 | .unwrap(); 191 | MessageBoxA( 192 | std::ptr::null_mut(), 193 | message.as_ptr(), 194 | title.as_ptr(), 195 | MB_OK | MB_ICONERROR, 196 | ); 197 | } 198 | std::process::exit(1); 199 | } 200 | } 201 | } 202 | 203 | match fs::copy(&exe_path, &new_exe_path) { 204 | Ok(_) => {} 205 | Err(err) => { 206 | Logger::log(&format!( 207 | "[ERROR] Failed to copy file: {} to: {}", 208 | &exe_path.to_string_lossy(), 209 | &new_exe_path.to_string_lossy() 210 | )); 211 | Logger::log(&format!("[DEBUG] {:?}", err)); 212 | std::process::exit(1); 213 | } 214 | } 215 | } 216 | 217 | return new_exe_path; 218 | } 219 | 220 | pub fn set_startup(enabled: bool) -> Result<(), Box> { 221 | clean_old_registry_key(); 222 | let exe_path = get_exe_path(); 223 | let is_elevated = is_elevated().unwrap_or(false); 224 | 225 | if !is_elevated { 226 | return Ok(()); 227 | } 228 | 229 | let ts = TaskScheduler::new()?; 230 | let com = ts.get_com(); 231 | let sb = ScheduleBuilder::new(&com).unwrap(); 232 | 233 | let mut settings = Settings::new(); 234 | settings.stop_if_going_on_batteries = Some(false); 235 | settings.disallow_start_if_on_batteries = Some(false); 236 | settings.enabled = Some(true); 237 | 238 | let action = Action::new("cute-borders-action", &exe_path.to_string_lossy(), "", ""); 239 | 240 | let delay = Duration { 241 | seconds: Some(5), 242 | // see https://github.com/mattrobineau/planif/commit/ac2e7f79ec8de8935c6292d64533a6c7ce37212e 243 | // github has 1.0.1 but crates.io doesnt 244 | hours: Some(0), 245 | ..Default::default() 246 | }; 247 | 248 | sb.create_logon() 249 | .settings(settings)? 250 | .author("keifufu")? 251 | .description("cute-borders startup")? 252 | .principal(PrincipalSettings { 253 | display_name: "".to_string(), 254 | group_id: None, 255 | id: "".to_string(), 256 | logon_type: LogonType::Password, 257 | run_level: RunLevel::Highest, 258 | user_id: None, 259 | })? 260 | .trigger("cute-borders-trigger", enabled)? 261 | .delay(delay)? 262 | .action(action)? 263 | .build()? 264 | .register("cute-borders", TaskCreationFlags::CreateOrUpdate as i32)?; 265 | 266 | Ok(()) 267 | } 268 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![windows_subsystem = "windows"] 2 | #![allow(unused_assignments)] 3 | 4 | use check_elevation::is_elevated; 5 | use config::Config; 6 | use config::RuleMatch; 7 | use logger::Logger; 8 | use rainbow::Rainbow; 9 | use std::ffi::c_ulong; 10 | use std::ffi::OsStr; 11 | use std::ffi::OsString; 12 | use std::os::windows::ffi::OsStrExt; 13 | use std::os::windows::prelude::OsStringExt; 14 | use std::time::Duration; 15 | use tray_icon::menu::Menu; 16 | use tray_icon::menu::MenuEvent; 17 | use tray_icon::menu::MenuId; 18 | use tray_icon::menu::MenuItemBuilder; 19 | use tray_icon::Icon; 20 | use tray_icon::TrayIconBuilder; 21 | use util::get_exe_path; 22 | use util::get_file_path; 23 | use util::hex_to_colorref; 24 | use util::set_startup; 25 | use winapi::ctypes::c_int; 26 | use winapi::ctypes::c_void; 27 | use winapi::shared::minwindef::{BOOL, LPARAM}; 28 | use winapi::shared::windef::HWND; 29 | use winapi::um::dwmapi::DwmSetWindowAttribute; 30 | use winapi::um::shellapi::ShellExecuteExW; 31 | use winapi::um::shellapi::SEE_MASK_NOASYNC; 32 | use winapi::um::shellapi::SEE_MASK_NOCLOSEPROCESS; 33 | use winapi::um::shellapi::SHELLEXECUTEINFOW; 34 | use winapi::um::winuser::EnumWindows; 35 | use winapi::um::winuser::GetClassNameW; 36 | use winapi::um::winuser::GetWindowTextLengthW; 37 | use winapi::um::winuser::GetWindowTextW; 38 | use winapi::um::winuser::WS_EX_TOOLWINDOW; 39 | use winapi::um::winuser::{ 40 | DispatchMessageW, GetForegroundWindow, GetMessageW, IsWindowVisible, TranslateMessage, 41 | GWL_EXSTYLE, 42 | }; 43 | 44 | const DWMWA_BORDER_COLOR: u32 = 34; 45 | const DWMWA_COLOR_DEFAULT: u32 = 0xFFFFFFFF; 46 | const DWMWA_COLOR_NONE: u32 = 0xFFFFFFFE; 47 | const COLOR_INVALID: u32 = 0x000000FF; 48 | 49 | mod config; 50 | mod logger; 51 | mod rainbow; 52 | mod util; 53 | 54 | fn main() { 55 | if let Err(err) = set_startup(true) { 56 | Logger::log("[ERROR] Failed to create or update startup task"); 57 | Logger::log(&format!("[DEBUG] {:?}", err)); 58 | } 59 | 60 | // I will just fucking update everything every 100ms 61 | // I might want to do this properly buuuuut I dont even use this myself. 62 | std::thread::spawn(|| loop { 63 | Rainbow::tick(Config::get().rainbow_speed.unwrap_or(1.0)); 64 | apply_colors(false); 65 | std::thread::sleep(Duration::from_millis(100)); 66 | }); 67 | 68 | let is_elevated = is_elevated().unwrap_or(false); 69 | unsafe { 70 | #[allow(unused_variables)] 71 | let tray_icon; // needs to be in the main scope 72 | if !Config::get().hide_tray_icon.unwrap_or(false) { 73 | let tray_menu_builder = Menu::with_items(&[ 74 | &MenuItemBuilder::new() 75 | .text("Open config") 76 | .enabled(true) 77 | .id(MenuId::new("0")) 78 | .build(), 79 | &MenuItemBuilder::new() 80 | .text("Reload config") 81 | .enabled(true) 82 | .id(MenuId::new("1")) 83 | .build(), 84 | &MenuItemBuilder::new() 85 | .text(if is_elevated { "Uninstall" } else { "Install" }) 86 | .enabled(true) 87 | .id(MenuId::new("2")) 88 | .build(), 89 | &MenuItemBuilder::new() 90 | .text("Exit") 91 | .enabled(true) 92 | .id(MenuId::new("3")) 93 | .build(), 94 | ]); 95 | 96 | let tray_menu = match tray_menu_builder { 97 | Ok(tray_menu) => tray_menu, 98 | Err(err) => { 99 | Logger::log("[ERROR] Failed to build tray icon"); 100 | Logger::log(&format!("[DEBUG] {:?}", err)); 101 | std::process::exit(1); 102 | } 103 | }; 104 | 105 | let icon = match Icon::from_resource(1, Some((64, 64))) { 106 | Ok(icon) => icon, 107 | Err(err) => { 108 | Logger::log("[ERROR] Failed to create icon"); 109 | Logger::log(&format!("[DEBUG] {:?}", err)); 110 | std::process::exit(1); 111 | } 112 | }; 113 | 114 | let tray_icon_builder = TrayIconBuilder::new() 115 | .with_menu(Box::new(tray_menu)) 116 | .with_menu_on_left_click(true) 117 | .with_icon(icon) 118 | .with_tooltip(format!("cute-borders v{}", env!("CARGO_PKG_VERSION"))); 119 | 120 | tray_icon = match tray_icon_builder.build() { 121 | Ok(tray_icon) => tray_icon, 122 | Err(err) => { 123 | Logger::log("[ERROR] Failed to build tray icon"); 124 | Logger::log(&format!("[DEBUG] {:?}", err)); 125 | std::process::exit(1); 126 | } 127 | }; 128 | 129 | MenuEvent::set_event_handler(Some(move |event: MenuEvent| { 130 | if event.id == MenuId::new("0") { 131 | let _ = open::that(get_file_path("config.yaml")); 132 | } else if event.id == MenuId::new("1") { 133 | Config::reload(); 134 | apply_colors(false); 135 | } else if event.id == MenuId::new("2") { 136 | if is_elevated { 137 | if let Err(err) = set_startup(false) { 138 | Logger::log("[ERROR] Failed to create or update startup task"); 139 | Logger::log(&format!("[DEBUG] {:?}", err)); 140 | } 141 | apply_colors(true); 142 | std::process::exit(0); 143 | } else { 144 | let lp_verb: Vec = OsStr::new("runas") 145 | .encode_wide() 146 | .chain(std::iter::once(0)) 147 | .collect(); 148 | let d = get_exe_path(); 149 | let v = d.to_str().unwrap_or_default(); 150 | let lp_file: Vec = OsStr::new(&v) 151 | .encode_wide() 152 | .chain(std::iter::once(0)) 153 | .collect(); 154 | let lp_par: Vec = OsStr::new("") 155 | .encode_wide() 156 | .chain(std::iter::once(0)) 157 | .collect(); 158 | 159 | let mut sei = SHELLEXECUTEINFOW { 160 | cbSize: std::mem::size_of::() as u32, 161 | fMask: SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS, 162 | lpVerb: lp_verb.as_ptr(), 163 | lpFile: lp_file.as_ptr(), 164 | lpParameters: lp_par.as_ptr(), 165 | nShow: 1, 166 | dwHotKey: 0, 167 | hInstApp: std::ptr::null_mut(), 168 | hMonitor: std::ptr::null_mut(), 169 | hProcess: std::ptr::null_mut(), 170 | hkeyClass: std::ptr::null_mut(), 171 | hwnd: std::ptr::null_mut(), 172 | lpClass: std::ptr::null_mut(), 173 | lpDirectory: std::ptr::null_mut(), 174 | lpIDList: std::ptr::null_mut(), 175 | }; 176 | 177 | ShellExecuteExW(&mut sei); 178 | apply_colors(true); 179 | std::process::exit(0); 180 | } 181 | } else if event.id == MenuId::new("3") { 182 | apply_colors(true); 183 | std::process::exit(0); 184 | } 185 | })); 186 | } 187 | 188 | let mut msg = std::mem::zeroed(); 189 | while GetMessageW(&mut msg, std::ptr::null_mut(), 0, 0) != 0 { 190 | TranslateMessage(&msg); 191 | DispatchMessageW(&msg); 192 | } 193 | 194 | apply_colors(true); 195 | } 196 | } 197 | 198 | unsafe extern "system" fn enum_windows_callback(hwnd: HWND, lparam: LPARAM) -> BOOL { 199 | if IsWindowVisible(hwnd) != 0 { 200 | let mut title_buffer: [u16; 512] = [0; 512]; 201 | let text_length = GetWindowTextLengthW(hwnd) + 1; 202 | if text_length > 0 { 203 | GetWindowTextW(hwnd, title_buffer.as_mut_ptr(), text_length as c_int); 204 | } 205 | let title = OsString::from_wide(&title_buffer) 206 | .to_string_lossy() 207 | .into_owned(); 208 | 209 | let ex_style = winapi::um::winuser::GetWindowLongW(hwnd, GWL_EXSTYLE) as c_int; 210 | 211 | let mut class_buffer: [u16; 256] = [0; 256]; 212 | let class_result = GetClassNameW(hwnd, class_buffer.as_mut_ptr(), class_buffer.len() as c_int); 213 | let mut class_name = String::new(); 214 | if class_result > 0 { 215 | class_name = OsString::from_wide(&class_buffer) 216 | .to_string_lossy() 217 | .into_owned(); 218 | } 219 | 220 | // Exclude certain window styles like WS_EX_TOOLWINDOW 221 | if ex_style & (WS_EX_TOOLWINDOW as i32) == 0 { 222 | let visible_windows: &mut Vec<(HWND, String, String)> = 223 | &mut *(lparam as *mut Vec<(HWND, String, String)>); 224 | visible_windows.push((hwnd, title, class_name)); 225 | } 226 | } 227 | 228 | 1 229 | } 230 | 231 | fn get_colors_for_window(_hwnd: HWND, title: String, class: String, reset: bool) -> (u32, u32) { 232 | if reset { 233 | return (DWMWA_COLOR_DEFAULT, DWMWA_COLOR_DEFAULT); 234 | } 235 | 236 | let config = Config::get(); 237 | let mut color_active = COLOR_INVALID; 238 | let mut color_inactive = COLOR_INVALID; 239 | 240 | for rule in config.window_rules.iter() { 241 | match rule.rule_match { 242 | RuleMatch::Global => { 243 | color_active = hex_to_colorref(&rule.active_border_color); 244 | color_inactive = hex_to_colorref(&rule.inactive_border_color); 245 | } 246 | RuleMatch::Title => { 247 | if let Some(contains_str) = &rule.contains { 248 | if title.to_lowercase().contains(&contains_str.to_lowercase()) { 249 | color_active = hex_to_colorref(&rule.active_border_color); 250 | color_inactive = hex_to_colorref(&rule.inactive_border_color); 251 | break; 252 | } 253 | } else { 254 | Logger::log("Expected `contains` on `Match=\"Title\"`"); 255 | } 256 | } 257 | RuleMatch::Class => { 258 | if let Some(contains_str) = &rule.contains { 259 | if class.to_lowercase().contains(&contains_str.to_lowercase()) { 260 | color_active = hex_to_colorref(&rule.active_border_color); 261 | color_inactive = hex_to_colorref(&rule.inactive_border_color); 262 | break; 263 | } 264 | } else { 265 | Logger::log("Expected `contains` on `Match=\"Class\"`"); 266 | } 267 | } 268 | } 269 | } 270 | 271 | (color_active, color_inactive) 272 | } 273 | 274 | fn apply_colors(reset: bool) { 275 | let mut visible_windows: Vec<(HWND, String, String)> = Vec::new(); 276 | unsafe { 277 | EnumWindows( 278 | Some(enum_windows_callback), 279 | &mut visible_windows as *mut _ as LPARAM, 280 | ); 281 | } 282 | 283 | for (hwnd, title, class) in visible_windows { 284 | let (color_active, color_inactive) = get_colors_for_window(hwnd, title, class, reset); 285 | unsafe { 286 | let active = GetForegroundWindow(); 287 | 288 | if active == hwnd { 289 | DwmSetWindowAttribute( 290 | hwnd, 291 | DWMWA_BORDER_COLOR, 292 | &color_active as *const _ as *const c_void, 293 | std::mem::size_of::() as u32, 294 | ); 295 | } else { 296 | DwmSetWindowAttribute( 297 | hwnd, 298 | DWMWA_BORDER_COLOR, 299 | &color_inactive as *const _ as *const c_void, 300 | std::mem::size_of::() as u32, 301 | ); 302 | } 303 | } 304 | } 305 | } 306 | -------------------------------------------------------------------------------- /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 = "adler" 7 | version = "1.0.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 10 | 11 | [[package]] 12 | name = "adler2" 13 | version = "2.0.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 16 | 17 | [[package]] 18 | name = "atk" 19 | version = "0.18.0" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "b4af014b17dd80e8af9fa689b2d4a211ddba6eb583c1622f35d0cb543f6b17e4" 22 | dependencies = [ 23 | "atk-sys", 24 | "glib", 25 | "libc", 26 | ] 27 | 28 | [[package]] 29 | name = "atk-sys" 30 | version = "0.18.0" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "251e0b7d90e33e0ba930891a505a9a35ece37b2dd37a14f3ffc306c13b980009" 33 | dependencies = [ 34 | "glib-sys", 35 | "gobject-sys", 36 | "libc", 37 | "system-deps", 38 | ] 39 | 40 | [[package]] 41 | name = "autocfg" 42 | version = "1.3.0" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 45 | 46 | [[package]] 47 | name = "bitflags" 48 | version = "1.3.2" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 51 | 52 | [[package]] 53 | name = "bitflags" 54 | version = "2.6.0" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 57 | dependencies = [ 58 | "serde", 59 | ] 60 | 61 | [[package]] 62 | name = "block" 63 | version = "0.1.6" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" 66 | 67 | [[package]] 68 | name = "cairo-rs" 69 | version = "0.18.5" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" 72 | dependencies = [ 73 | "bitflags 2.6.0", 74 | "cairo-sys-rs", 75 | "glib", 76 | "libc", 77 | "once_cell", 78 | "thiserror", 79 | ] 80 | 81 | [[package]] 82 | name = "cairo-sys-rs" 83 | version = "0.18.2" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" 86 | dependencies = [ 87 | "glib-sys", 88 | "libc", 89 | "system-deps", 90 | ] 91 | 92 | [[package]] 93 | name = "cfg-expr" 94 | version = "0.15.8" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" 97 | dependencies = [ 98 | "smallvec", 99 | "target-lexicon", 100 | ] 101 | 102 | [[package]] 103 | name = "cfg-if" 104 | version = "1.0.0" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 107 | 108 | [[package]] 109 | name = "check_elevation" 110 | version = "0.2.4" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "34f7310b71e7b968cdadd13480b9e4f2def9f173f67fd7317e8eddb8d7a4ba00" 113 | dependencies = [ 114 | "windows 0.51.1", 115 | ] 116 | 117 | [[package]] 118 | name = "cocoa" 119 | version = "0.25.0" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" 122 | dependencies = [ 123 | "bitflags 1.3.2", 124 | "block", 125 | "cocoa-foundation", 126 | "core-foundation", 127 | "core-graphics", 128 | "foreign-types", 129 | "libc", 130 | "objc", 131 | ] 132 | 133 | [[package]] 134 | name = "cocoa-foundation" 135 | version = "0.1.2" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" 138 | dependencies = [ 139 | "bitflags 1.3.2", 140 | "block", 141 | "core-foundation", 142 | "core-graphics-types", 143 | "libc", 144 | "objc", 145 | ] 146 | 147 | [[package]] 148 | name = "core-foundation" 149 | version = "0.9.4" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 152 | dependencies = [ 153 | "core-foundation-sys", 154 | "libc", 155 | ] 156 | 157 | [[package]] 158 | name = "core-foundation-sys" 159 | version = "0.8.7" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 162 | 163 | [[package]] 164 | name = "core-graphics" 165 | version = "0.23.2" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" 168 | dependencies = [ 169 | "bitflags 1.3.2", 170 | "core-foundation", 171 | "core-graphics-types", 172 | "foreign-types", 173 | "libc", 174 | ] 175 | 176 | [[package]] 177 | name = "core-graphics-types" 178 | version = "0.1.3" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" 181 | dependencies = [ 182 | "bitflags 1.3.2", 183 | "core-foundation", 184 | "libc", 185 | ] 186 | 187 | [[package]] 188 | name = "crc32fast" 189 | version = "1.4.2" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 192 | dependencies = [ 193 | "cfg-if", 194 | ] 195 | 196 | [[package]] 197 | name = "crossbeam-channel" 198 | version = "0.5.13" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" 201 | dependencies = [ 202 | "crossbeam-utils", 203 | ] 204 | 205 | [[package]] 206 | name = "crossbeam-utils" 207 | version = "0.8.20" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 210 | 211 | [[package]] 212 | name = "cute-borders" 213 | version = "1.3.1" 214 | dependencies = [ 215 | "check_elevation", 216 | "lazy_static", 217 | "open", 218 | "planif", 219 | "serde", 220 | "serde_yaml", 221 | "tray-icon", 222 | "winapi", 223 | "winreg", 224 | "winres", 225 | ] 226 | 227 | [[package]] 228 | name = "dirs" 229 | version = "5.0.1" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" 232 | dependencies = [ 233 | "dirs-sys", 234 | ] 235 | 236 | [[package]] 237 | name = "dirs-sys" 238 | version = "0.4.1" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" 241 | dependencies = [ 242 | "libc", 243 | "option-ext", 244 | "redox_users", 245 | "windows-sys 0.48.0", 246 | ] 247 | 248 | [[package]] 249 | name = "dpi" 250 | version = "0.1.1" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" 253 | 254 | [[package]] 255 | name = "equivalent" 256 | version = "1.0.1" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 259 | 260 | [[package]] 261 | name = "fdeflate" 262 | version = "0.3.4" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" 265 | dependencies = [ 266 | "simd-adler32", 267 | ] 268 | 269 | [[package]] 270 | name = "field-offset" 271 | version = "0.3.6" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" 274 | dependencies = [ 275 | "memoffset", 276 | "rustc_version", 277 | ] 278 | 279 | [[package]] 280 | name = "flate2" 281 | version = "1.0.33" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" 284 | dependencies = [ 285 | "crc32fast", 286 | "miniz_oxide 0.8.0", 287 | ] 288 | 289 | [[package]] 290 | name = "foreign-types" 291 | version = "0.5.0" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" 294 | dependencies = [ 295 | "foreign-types-macros", 296 | "foreign-types-shared", 297 | ] 298 | 299 | [[package]] 300 | name = "foreign-types-macros" 301 | version = "0.2.3" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" 304 | dependencies = [ 305 | "proc-macro2", 306 | "quote", 307 | "syn 2.0.77", 308 | ] 309 | 310 | [[package]] 311 | name = "foreign-types-shared" 312 | version = "0.3.1" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" 315 | 316 | [[package]] 317 | name = "futures-channel" 318 | version = "0.3.30" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" 321 | dependencies = [ 322 | "futures-core", 323 | ] 324 | 325 | [[package]] 326 | name = "futures-core" 327 | version = "0.3.30" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" 330 | 331 | [[package]] 332 | name = "futures-executor" 333 | version = "0.3.30" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" 336 | dependencies = [ 337 | "futures-core", 338 | "futures-task", 339 | "futures-util", 340 | ] 341 | 342 | [[package]] 343 | name = "futures-io" 344 | version = "0.3.30" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" 347 | 348 | [[package]] 349 | name = "futures-macro" 350 | version = "0.3.30" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" 353 | dependencies = [ 354 | "proc-macro2", 355 | "quote", 356 | "syn 2.0.77", 357 | ] 358 | 359 | [[package]] 360 | name = "futures-task" 361 | version = "0.3.30" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" 364 | 365 | [[package]] 366 | name = "futures-util" 367 | version = "0.3.30" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" 370 | dependencies = [ 371 | "futures-core", 372 | "futures-macro", 373 | "futures-task", 374 | "pin-project-lite", 375 | "pin-utils", 376 | "slab", 377 | ] 378 | 379 | [[package]] 380 | name = "gdk" 381 | version = "0.18.0" 382 | source = "registry+https://github.com/rust-lang/crates.io-index" 383 | checksum = "f5ba081bdef3b75ebcdbfc953699ed2d7417d6bd853347a42a37d76406a33646" 384 | dependencies = [ 385 | "cairo-rs", 386 | "gdk-pixbuf", 387 | "gdk-sys", 388 | "gio", 389 | "glib", 390 | "libc", 391 | "pango", 392 | ] 393 | 394 | [[package]] 395 | name = "gdk-pixbuf" 396 | version = "0.18.5" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" 399 | dependencies = [ 400 | "gdk-pixbuf-sys", 401 | "gio", 402 | "glib", 403 | "libc", 404 | "once_cell", 405 | ] 406 | 407 | [[package]] 408 | name = "gdk-pixbuf-sys" 409 | version = "0.18.0" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" 412 | dependencies = [ 413 | "gio-sys", 414 | "glib-sys", 415 | "gobject-sys", 416 | "libc", 417 | "system-deps", 418 | ] 419 | 420 | [[package]] 421 | name = "gdk-sys" 422 | version = "0.18.0" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "31ff856cb3386dae1703a920f803abafcc580e9b5f711ca62ed1620c25b51ff2" 425 | dependencies = [ 426 | "cairo-sys-rs", 427 | "gdk-pixbuf-sys", 428 | "gio-sys", 429 | "glib-sys", 430 | "gobject-sys", 431 | "libc", 432 | "pango-sys", 433 | "pkg-config", 434 | "system-deps", 435 | ] 436 | 437 | [[package]] 438 | name = "getrandom" 439 | version = "0.2.15" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 442 | dependencies = [ 443 | "cfg-if", 444 | "libc", 445 | "wasi", 446 | ] 447 | 448 | [[package]] 449 | name = "gio" 450 | version = "0.18.4" 451 | source = "registry+https://github.com/rust-lang/crates.io-index" 452 | checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" 453 | dependencies = [ 454 | "futures-channel", 455 | "futures-core", 456 | "futures-io", 457 | "futures-util", 458 | "gio-sys", 459 | "glib", 460 | "libc", 461 | "once_cell", 462 | "pin-project-lite", 463 | "smallvec", 464 | "thiserror", 465 | ] 466 | 467 | [[package]] 468 | name = "gio-sys" 469 | version = "0.18.1" 470 | source = "registry+https://github.com/rust-lang/crates.io-index" 471 | checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" 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.18.5" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" 485 | dependencies = [ 486 | "bitflags 2.6.0", 487 | "futures-channel", 488 | "futures-core", 489 | "futures-executor", 490 | "futures-task", 491 | "futures-util", 492 | "gio-sys", 493 | "glib-macros", 494 | "glib-sys", 495 | "gobject-sys", 496 | "libc", 497 | "memchr", 498 | "once_cell", 499 | "smallvec", 500 | "thiserror", 501 | ] 502 | 503 | [[package]] 504 | name = "glib-macros" 505 | version = "0.18.5" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" 508 | dependencies = [ 509 | "heck 0.4.1", 510 | "proc-macro-crate 2.0.2", 511 | "proc-macro-error", 512 | "proc-macro2", 513 | "quote", 514 | "syn 2.0.77", 515 | ] 516 | 517 | [[package]] 518 | name = "glib-sys" 519 | version = "0.18.1" 520 | source = "registry+https://github.com/rust-lang/crates.io-index" 521 | checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" 522 | dependencies = [ 523 | "libc", 524 | "system-deps", 525 | ] 526 | 527 | [[package]] 528 | name = "gobject-sys" 529 | version = "0.18.0" 530 | source = "registry+https://github.com/rust-lang/crates.io-index" 531 | checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" 532 | dependencies = [ 533 | "glib-sys", 534 | "libc", 535 | "system-deps", 536 | ] 537 | 538 | [[package]] 539 | name = "gtk" 540 | version = "0.18.1" 541 | source = "registry+https://github.com/rust-lang/crates.io-index" 542 | checksum = "93c4f5e0e20b60e10631a5f06da7fe3dda744b05ad0ea71fee2f47adf865890c" 543 | dependencies = [ 544 | "atk", 545 | "cairo-rs", 546 | "field-offset", 547 | "futures-channel", 548 | "gdk", 549 | "gdk-pixbuf", 550 | "gio", 551 | "glib", 552 | "gtk-sys", 553 | "gtk3-macros", 554 | "libc", 555 | "pango", 556 | "pkg-config", 557 | ] 558 | 559 | [[package]] 560 | name = "gtk-sys" 561 | version = "0.18.0" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "771437bf1de2c1c0b496c11505bdf748e26066bbe942dfc8f614c9460f6d7722" 564 | dependencies = [ 565 | "atk-sys", 566 | "cairo-sys-rs", 567 | "gdk-pixbuf-sys", 568 | "gdk-sys", 569 | "gio-sys", 570 | "glib-sys", 571 | "gobject-sys", 572 | "libc", 573 | "pango-sys", 574 | "system-deps", 575 | ] 576 | 577 | [[package]] 578 | name = "gtk3-macros" 579 | version = "0.18.0" 580 | source = "registry+https://github.com/rust-lang/crates.io-index" 581 | checksum = "c6063efb63db582968fb7df72e1ae68aa6360dcfb0a75143f34fc7d616bad75e" 582 | dependencies = [ 583 | "proc-macro-crate 1.3.1", 584 | "proc-macro-error", 585 | "proc-macro2", 586 | "quote", 587 | "syn 2.0.77", 588 | ] 589 | 590 | [[package]] 591 | name = "hashbrown" 592 | version = "0.14.5" 593 | source = "registry+https://github.com/rust-lang/crates.io-index" 594 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 595 | 596 | [[package]] 597 | name = "heck" 598 | version = "0.4.1" 599 | source = "registry+https://github.com/rust-lang/crates.io-index" 600 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 601 | 602 | [[package]] 603 | name = "heck" 604 | version = "0.5.0" 605 | source = "registry+https://github.com/rust-lang/crates.io-index" 606 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 607 | 608 | [[package]] 609 | name = "indexmap" 610 | version = "2.5.0" 611 | source = "registry+https://github.com/rust-lang/crates.io-index" 612 | checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" 613 | dependencies = [ 614 | "equivalent", 615 | "hashbrown", 616 | ] 617 | 618 | [[package]] 619 | name = "is-docker" 620 | version = "0.2.0" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" 623 | dependencies = [ 624 | "once_cell", 625 | ] 626 | 627 | [[package]] 628 | name = "is-wsl" 629 | version = "0.4.0" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" 632 | dependencies = [ 633 | "is-docker", 634 | "once_cell", 635 | ] 636 | 637 | [[package]] 638 | name = "itoa" 639 | version = "1.0.11" 640 | source = "registry+https://github.com/rust-lang/crates.io-index" 641 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 642 | 643 | [[package]] 644 | name = "keyboard-types" 645 | version = "0.7.0" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" 648 | dependencies = [ 649 | "bitflags 2.6.0", 650 | "serde", 651 | "unicode-segmentation", 652 | ] 653 | 654 | [[package]] 655 | name = "lazy_static" 656 | version = "1.5.0" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 659 | 660 | [[package]] 661 | name = "libappindicator" 662 | version = "0.9.0" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" 665 | dependencies = [ 666 | "glib", 667 | "gtk", 668 | "gtk-sys", 669 | "libappindicator-sys", 670 | "log", 671 | ] 672 | 673 | [[package]] 674 | name = "libappindicator-sys" 675 | version = "0.9.0" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" 678 | dependencies = [ 679 | "gtk-sys", 680 | "libloading", 681 | "once_cell", 682 | ] 683 | 684 | [[package]] 685 | name = "libc" 686 | version = "0.2.158" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" 689 | 690 | [[package]] 691 | name = "libloading" 692 | version = "0.7.4" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" 695 | dependencies = [ 696 | "cfg-if", 697 | "winapi", 698 | ] 699 | 700 | [[package]] 701 | name = "libredox" 702 | version = "0.1.3" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 705 | dependencies = [ 706 | "bitflags 2.6.0", 707 | "libc", 708 | ] 709 | 710 | [[package]] 711 | name = "libxdo" 712 | version = "0.6.0" 713 | source = "registry+https://github.com/rust-lang/crates.io-index" 714 | checksum = "00333b8756a3d28e78def82067a377de7fa61b24909000aeaa2b446a948d14db" 715 | dependencies = [ 716 | "libxdo-sys", 717 | ] 718 | 719 | [[package]] 720 | name = "libxdo-sys" 721 | version = "0.11.0" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "db23b9e7e2b7831bbd8aac0bbeeeb7b68cbebc162b227e7052e8e55829a09212" 724 | dependencies = [ 725 | "libc", 726 | "x11", 727 | ] 728 | 729 | [[package]] 730 | name = "log" 731 | version = "0.4.22" 732 | source = "registry+https://github.com/rust-lang/crates.io-index" 733 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 734 | 735 | [[package]] 736 | name = "malloc_buf" 737 | version = "0.0.6" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" 740 | dependencies = [ 741 | "libc", 742 | ] 743 | 744 | [[package]] 745 | name = "memchr" 746 | version = "2.7.4" 747 | source = "registry+https://github.com/rust-lang/crates.io-index" 748 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 749 | 750 | [[package]] 751 | name = "memoffset" 752 | version = "0.9.1" 753 | source = "registry+https://github.com/rust-lang/crates.io-index" 754 | checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" 755 | dependencies = [ 756 | "autocfg", 757 | ] 758 | 759 | [[package]] 760 | name = "miniz_oxide" 761 | version = "0.7.4" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" 764 | dependencies = [ 765 | "adler", 766 | "simd-adler32", 767 | ] 768 | 769 | [[package]] 770 | name = "miniz_oxide" 771 | version = "0.8.0" 772 | source = "registry+https://github.com/rust-lang/crates.io-index" 773 | checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" 774 | dependencies = [ 775 | "adler2", 776 | ] 777 | 778 | [[package]] 779 | name = "muda" 780 | version = "0.13.5" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "86b959f97c97044e4c96e32e1db292a7d594449546a3c6b77ae613dc3a5b5145" 783 | dependencies = [ 784 | "cocoa", 785 | "crossbeam-channel", 786 | "dpi", 787 | "gtk", 788 | "keyboard-types", 789 | "libxdo", 790 | "objc", 791 | "once_cell", 792 | "png", 793 | "thiserror", 794 | "windows-sys 0.52.0", 795 | ] 796 | 797 | [[package]] 798 | name = "objc" 799 | version = "0.2.7" 800 | source = "registry+https://github.com/rust-lang/crates.io-index" 801 | checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" 802 | dependencies = [ 803 | "malloc_buf", 804 | ] 805 | 806 | [[package]] 807 | name = "once_cell" 808 | version = "1.19.0" 809 | source = "registry+https://github.com/rust-lang/crates.io-index" 810 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 811 | 812 | [[package]] 813 | name = "open" 814 | version = "5.3.0" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "61a877bf6abd716642a53ef1b89fb498923a4afca5c754f9050b4d081c05c4b3" 817 | dependencies = [ 818 | "is-wsl", 819 | "libc", 820 | "pathdiff", 821 | ] 822 | 823 | [[package]] 824 | name = "option-ext" 825 | version = "0.2.0" 826 | source = "registry+https://github.com/rust-lang/crates.io-index" 827 | checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" 828 | 829 | [[package]] 830 | name = "pango" 831 | version = "0.18.3" 832 | source = "registry+https://github.com/rust-lang/crates.io-index" 833 | checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" 834 | dependencies = [ 835 | "gio", 836 | "glib", 837 | "libc", 838 | "once_cell", 839 | "pango-sys", 840 | ] 841 | 842 | [[package]] 843 | name = "pango-sys" 844 | version = "0.18.0" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" 847 | dependencies = [ 848 | "glib-sys", 849 | "gobject-sys", 850 | "libc", 851 | "system-deps", 852 | ] 853 | 854 | [[package]] 855 | name = "pathdiff" 856 | version = "0.2.1" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" 859 | 860 | [[package]] 861 | name = "pin-project-lite" 862 | version = "0.2.14" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 865 | 866 | [[package]] 867 | name = "pin-utils" 868 | version = "0.1.0" 869 | source = "registry+https://github.com/rust-lang/crates.io-index" 870 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 871 | 872 | [[package]] 873 | name = "pkg-config" 874 | version = "0.3.30" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 877 | 878 | [[package]] 879 | name = "planif" 880 | version = "1.0.0" 881 | source = "registry+https://github.com/rust-lang/crates.io-index" 882 | checksum = "7502ee5af341c06aa00593d655d09e4b7126f0e886b80745c218d6dc674e8b21" 883 | dependencies = [ 884 | "windows 0.48.0", 885 | ] 886 | 887 | [[package]] 888 | name = "png" 889 | version = "0.17.13" 890 | source = "registry+https://github.com/rust-lang/crates.io-index" 891 | checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" 892 | dependencies = [ 893 | "bitflags 1.3.2", 894 | "crc32fast", 895 | "fdeflate", 896 | "flate2", 897 | "miniz_oxide 0.7.4", 898 | ] 899 | 900 | [[package]] 901 | name = "proc-macro-crate" 902 | version = "1.3.1" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" 905 | dependencies = [ 906 | "once_cell", 907 | "toml_edit 0.19.15", 908 | ] 909 | 910 | [[package]] 911 | name = "proc-macro-crate" 912 | version = "2.0.2" 913 | source = "registry+https://github.com/rust-lang/crates.io-index" 914 | checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" 915 | dependencies = [ 916 | "toml_datetime", 917 | "toml_edit 0.20.2", 918 | ] 919 | 920 | [[package]] 921 | name = "proc-macro-error" 922 | version = "1.0.4" 923 | source = "registry+https://github.com/rust-lang/crates.io-index" 924 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 925 | dependencies = [ 926 | "proc-macro-error-attr", 927 | "proc-macro2", 928 | "quote", 929 | "syn 1.0.109", 930 | "version_check", 931 | ] 932 | 933 | [[package]] 934 | name = "proc-macro-error-attr" 935 | version = "1.0.4" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 938 | dependencies = [ 939 | "proc-macro2", 940 | "quote", 941 | "version_check", 942 | ] 943 | 944 | [[package]] 945 | name = "proc-macro2" 946 | version = "1.0.86" 947 | source = "registry+https://github.com/rust-lang/crates.io-index" 948 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 949 | dependencies = [ 950 | "unicode-ident", 951 | ] 952 | 953 | [[package]] 954 | name = "quote" 955 | version = "1.0.37" 956 | source = "registry+https://github.com/rust-lang/crates.io-index" 957 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 958 | dependencies = [ 959 | "proc-macro2", 960 | ] 961 | 962 | [[package]] 963 | name = "redox_users" 964 | version = "0.4.6" 965 | source = "registry+https://github.com/rust-lang/crates.io-index" 966 | checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" 967 | dependencies = [ 968 | "getrandom", 969 | "libredox", 970 | "thiserror", 971 | ] 972 | 973 | [[package]] 974 | name = "rustc_version" 975 | version = "0.4.1" 976 | source = "registry+https://github.com/rust-lang/crates.io-index" 977 | checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" 978 | dependencies = [ 979 | "semver", 980 | ] 981 | 982 | [[package]] 983 | name = "ryu" 984 | version = "1.0.18" 985 | source = "registry+https://github.com/rust-lang/crates.io-index" 986 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 987 | 988 | [[package]] 989 | name = "semver" 990 | version = "1.0.23" 991 | source = "registry+https://github.com/rust-lang/crates.io-index" 992 | checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" 993 | 994 | [[package]] 995 | name = "serde" 996 | version = "1.0.209" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" 999 | dependencies = [ 1000 | "serde_derive", 1001 | ] 1002 | 1003 | [[package]] 1004 | name = "serde_derive" 1005 | version = "1.0.209" 1006 | source = "registry+https://github.com/rust-lang/crates.io-index" 1007 | checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" 1008 | dependencies = [ 1009 | "proc-macro2", 1010 | "quote", 1011 | "syn 2.0.77", 1012 | ] 1013 | 1014 | [[package]] 1015 | name = "serde_spanned" 1016 | version = "0.6.7" 1017 | source = "registry+https://github.com/rust-lang/crates.io-index" 1018 | checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" 1019 | dependencies = [ 1020 | "serde", 1021 | ] 1022 | 1023 | [[package]] 1024 | name = "serde_yaml" 1025 | version = "0.9.34+deprecated" 1026 | source = "registry+https://github.com/rust-lang/crates.io-index" 1027 | checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" 1028 | dependencies = [ 1029 | "indexmap", 1030 | "itoa", 1031 | "ryu", 1032 | "serde", 1033 | "unsafe-libyaml", 1034 | ] 1035 | 1036 | [[package]] 1037 | name = "simd-adler32" 1038 | version = "0.3.7" 1039 | source = "registry+https://github.com/rust-lang/crates.io-index" 1040 | checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" 1041 | 1042 | [[package]] 1043 | name = "slab" 1044 | version = "0.4.9" 1045 | source = "registry+https://github.com/rust-lang/crates.io-index" 1046 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1047 | dependencies = [ 1048 | "autocfg", 1049 | ] 1050 | 1051 | [[package]] 1052 | name = "smallvec" 1053 | version = "1.13.2" 1054 | source = "registry+https://github.com/rust-lang/crates.io-index" 1055 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1056 | 1057 | [[package]] 1058 | name = "syn" 1059 | version = "1.0.109" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1062 | dependencies = [ 1063 | "proc-macro2", 1064 | "unicode-ident", 1065 | ] 1066 | 1067 | [[package]] 1068 | name = "syn" 1069 | version = "2.0.77" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" 1072 | dependencies = [ 1073 | "proc-macro2", 1074 | "quote", 1075 | "unicode-ident", 1076 | ] 1077 | 1078 | [[package]] 1079 | name = "system-deps" 1080 | version = "6.2.2" 1081 | source = "registry+https://github.com/rust-lang/crates.io-index" 1082 | checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" 1083 | dependencies = [ 1084 | "cfg-expr", 1085 | "heck 0.5.0", 1086 | "pkg-config", 1087 | "toml 0.8.2", 1088 | "version-compare", 1089 | ] 1090 | 1091 | [[package]] 1092 | name = "target-lexicon" 1093 | version = "0.12.16" 1094 | source = "registry+https://github.com/rust-lang/crates.io-index" 1095 | checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" 1096 | 1097 | [[package]] 1098 | name = "thiserror" 1099 | version = "1.0.63" 1100 | source = "registry+https://github.com/rust-lang/crates.io-index" 1101 | checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" 1102 | dependencies = [ 1103 | "thiserror-impl", 1104 | ] 1105 | 1106 | [[package]] 1107 | name = "thiserror-impl" 1108 | version = "1.0.63" 1109 | source = "registry+https://github.com/rust-lang/crates.io-index" 1110 | checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" 1111 | dependencies = [ 1112 | "proc-macro2", 1113 | "quote", 1114 | "syn 2.0.77", 1115 | ] 1116 | 1117 | [[package]] 1118 | name = "toml" 1119 | version = "0.5.11" 1120 | source = "registry+https://github.com/rust-lang/crates.io-index" 1121 | checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" 1122 | dependencies = [ 1123 | "serde", 1124 | ] 1125 | 1126 | [[package]] 1127 | name = "toml" 1128 | version = "0.8.2" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" 1131 | dependencies = [ 1132 | "serde", 1133 | "serde_spanned", 1134 | "toml_datetime", 1135 | "toml_edit 0.20.2", 1136 | ] 1137 | 1138 | [[package]] 1139 | name = "toml_datetime" 1140 | version = "0.6.3" 1141 | source = "registry+https://github.com/rust-lang/crates.io-index" 1142 | checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" 1143 | dependencies = [ 1144 | "serde", 1145 | ] 1146 | 1147 | [[package]] 1148 | name = "toml_edit" 1149 | version = "0.19.15" 1150 | source = "registry+https://github.com/rust-lang/crates.io-index" 1151 | checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" 1152 | dependencies = [ 1153 | "indexmap", 1154 | "toml_datetime", 1155 | "winnow", 1156 | ] 1157 | 1158 | [[package]] 1159 | name = "toml_edit" 1160 | version = "0.20.2" 1161 | source = "registry+https://github.com/rust-lang/crates.io-index" 1162 | checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" 1163 | dependencies = [ 1164 | "indexmap", 1165 | "serde", 1166 | "serde_spanned", 1167 | "toml_datetime", 1168 | "winnow", 1169 | ] 1170 | 1171 | [[package]] 1172 | name = "tray-icon" 1173 | version = "0.14.3" 1174 | source = "registry+https://github.com/rust-lang/crates.io-index" 1175 | checksum = "3ad8319cca93189ea9ab1b290de0595960529750b6b8b501a399ed1ec3775d60" 1176 | dependencies = [ 1177 | "cocoa", 1178 | "core-graphics", 1179 | "crossbeam-channel", 1180 | "dirs", 1181 | "libappindicator", 1182 | "muda", 1183 | "objc", 1184 | "once_cell", 1185 | "png", 1186 | "thiserror", 1187 | "windows-sys 0.52.0", 1188 | ] 1189 | 1190 | [[package]] 1191 | name = "unicode-ident" 1192 | version = "1.0.12" 1193 | source = "registry+https://github.com/rust-lang/crates.io-index" 1194 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 1195 | 1196 | [[package]] 1197 | name = "unicode-segmentation" 1198 | version = "1.11.0" 1199 | source = "registry+https://github.com/rust-lang/crates.io-index" 1200 | checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" 1201 | 1202 | [[package]] 1203 | name = "unsafe-libyaml" 1204 | version = "0.2.11" 1205 | source = "registry+https://github.com/rust-lang/crates.io-index" 1206 | checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" 1207 | 1208 | [[package]] 1209 | name = "version-compare" 1210 | version = "0.2.0" 1211 | source = "registry+https://github.com/rust-lang/crates.io-index" 1212 | checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" 1213 | 1214 | [[package]] 1215 | name = "version_check" 1216 | version = "0.9.5" 1217 | source = "registry+https://github.com/rust-lang/crates.io-index" 1218 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1219 | 1220 | [[package]] 1221 | name = "wasi" 1222 | version = "0.11.0+wasi-snapshot-preview1" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1225 | 1226 | [[package]] 1227 | name = "winapi" 1228 | version = "0.3.9" 1229 | source = "registry+https://github.com/rust-lang/crates.io-index" 1230 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1231 | dependencies = [ 1232 | "winapi-i686-pc-windows-gnu", 1233 | "winapi-x86_64-pc-windows-gnu", 1234 | ] 1235 | 1236 | [[package]] 1237 | name = "winapi-i686-pc-windows-gnu" 1238 | version = "0.4.0" 1239 | source = "registry+https://github.com/rust-lang/crates.io-index" 1240 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1241 | 1242 | [[package]] 1243 | name = "winapi-x86_64-pc-windows-gnu" 1244 | version = "0.4.0" 1245 | source = "registry+https://github.com/rust-lang/crates.io-index" 1246 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1247 | 1248 | [[package]] 1249 | name = "windows" 1250 | version = "0.48.0" 1251 | source = "registry+https://github.com/rust-lang/crates.io-index" 1252 | checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" 1253 | dependencies = [ 1254 | "windows-targets 0.48.5", 1255 | ] 1256 | 1257 | [[package]] 1258 | name = "windows" 1259 | version = "0.51.1" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" 1262 | dependencies = [ 1263 | "windows-core", 1264 | "windows-targets 0.48.5", 1265 | ] 1266 | 1267 | [[package]] 1268 | name = "windows-core" 1269 | version = "0.51.1" 1270 | source = "registry+https://github.com/rust-lang/crates.io-index" 1271 | checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" 1272 | dependencies = [ 1273 | "windows-targets 0.48.5", 1274 | ] 1275 | 1276 | [[package]] 1277 | name = "windows-sys" 1278 | version = "0.48.0" 1279 | source = "registry+https://github.com/rust-lang/crates.io-index" 1280 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1281 | dependencies = [ 1282 | "windows-targets 0.48.5", 1283 | ] 1284 | 1285 | [[package]] 1286 | name = "windows-sys" 1287 | version = "0.52.0" 1288 | source = "registry+https://github.com/rust-lang/crates.io-index" 1289 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1290 | dependencies = [ 1291 | "windows-targets 0.52.6", 1292 | ] 1293 | 1294 | [[package]] 1295 | name = "windows-targets" 1296 | version = "0.48.5" 1297 | source = "registry+https://github.com/rust-lang/crates.io-index" 1298 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 1299 | dependencies = [ 1300 | "windows_aarch64_gnullvm 0.48.5", 1301 | "windows_aarch64_msvc 0.48.5", 1302 | "windows_i686_gnu 0.48.5", 1303 | "windows_i686_msvc 0.48.5", 1304 | "windows_x86_64_gnu 0.48.5", 1305 | "windows_x86_64_gnullvm 0.48.5", 1306 | "windows_x86_64_msvc 0.48.5", 1307 | ] 1308 | 1309 | [[package]] 1310 | name = "windows-targets" 1311 | version = "0.52.6" 1312 | source = "registry+https://github.com/rust-lang/crates.io-index" 1313 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1314 | dependencies = [ 1315 | "windows_aarch64_gnullvm 0.52.6", 1316 | "windows_aarch64_msvc 0.52.6", 1317 | "windows_i686_gnu 0.52.6", 1318 | "windows_i686_gnullvm", 1319 | "windows_i686_msvc 0.52.6", 1320 | "windows_x86_64_gnu 0.52.6", 1321 | "windows_x86_64_gnullvm 0.52.6", 1322 | "windows_x86_64_msvc 0.52.6", 1323 | ] 1324 | 1325 | [[package]] 1326 | name = "windows_aarch64_gnullvm" 1327 | version = "0.48.5" 1328 | source = "registry+https://github.com/rust-lang/crates.io-index" 1329 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 1330 | 1331 | [[package]] 1332 | name = "windows_aarch64_gnullvm" 1333 | version = "0.52.6" 1334 | source = "registry+https://github.com/rust-lang/crates.io-index" 1335 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1336 | 1337 | [[package]] 1338 | name = "windows_aarch64_msvc" 1339 | version = "0.48.5" 1340 | source = "registry+https://github.com/rust-lang/crates.io-index" 1341 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 1342 | 1343 | [[package]] 1344 | name = "windows_aarch64_msvc" 1345 | version = "0.52.6" 1346 | source = "registry+https://github.com/rust-lang/crates.io-index" 1347 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1348 | 1349 | [[package]] 1350 | name = "windows_i686_gnu" 1351 | version = "0.48.5" 1352 | source = "registry+https://github.com/rust-lang/crates.io-index" 1353 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 1354 | 1355 | [[package]] 1356 | name = "windows_i686_gnu" 1357 | version = "0.52.6" 1358 | source = "registry+https://github.com/rust-lang/crates.io-index" 1359 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1360 | 1361 | [[package]] 1362 | name = "windows_i686_gnullvm" 1363 | version = "0.52.6" 1364 | source = "registry+https://github.com/rust-lang/crates.io-index" 1365 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1366 | 1367 | [[package]] 1368 | name = "windows_i686_msvc" 1369 | version = "0.48.5" 1370 | source = "registry+https://github.com/rust-lang/crates.io-index" 1371 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 1372 | 1373 | [[package]] 1374 | name = "windows_i686_msvc" 1375 | version = "0.52.6" 1376 | source = "registry+https://github.com/rust-lang/crates.io-index" 1377 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1378 | 1379 | [[package]] 1380 | name = "windows_x86_64_gnu" 1381 | version = "0.48.5" 1382 | source = "registry+https://github.com/rust-lang/crates.io-index" 1383 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 1384 | 1385 | [[package]] 1386 | name = "windows_x86_64_gnu" 1387 | version = "0.52.6" 1388 | source = "registry+https://github.com/rust-lang/crates.io-index" 1389 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1390 | 1391 | [[package]] 1392 | name = "windows_x86_64_gnullvm" 1393 | version = "0.48.5" 1394 | source = "registry+https://github.com/rust-lang/crates.io-index" 1395 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 1396 | 1397 | [[package]] 1398 | name = "windows_x86_64_gnullvm" 1399 | version = "0.52.6" 1400 | source = "registry+https://github.com/rust-lang/crates.io-index" 1401 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1402 | 1403 | [[package]] 1404 | name = "windows_x86_64_msvc" 1405 | version = "0.48.5" 1406 | source = "registry+https://github.com/rust-lang/crates.io-index" 1407 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 1408 | 1409 | [[package]] 1410 | name = "windows_x86_64_msvc" 1411 | version = "0.52.6" 1412 | source = "registry+https://github.com/rust-lang/crates.io-index" 1413 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1414 | 1415 | [[package]] 1416 | name = "winnow" 1417 | version = "0.5.40" 1418 | source = "registry+https://github.com/rust-lang/crates.io-index" 1419 | checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" 1420 | dependencies = [ 1421 | "memchr", 1422 | ] 1423 | 1424 | [[package]] 1425 | name = "winreg" 1426 | version = "0.52.0" 1427 | source = "registry+https://github.com/rust-lang/crates.io-index" 1428 | checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" 1429 | dependencies = [ 1430 | "cfg-if", 1431 | "windows-sys 0.48.0", 1432 | ] 1433 | 1434 | [[package]] 1435 | name = "winres" 1436 | version = "0.1.12" 1437 | source = "registry+https://github.com/rust-lang/crates.io-index" 1438 | checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c" 1439 | dependencies = [ 1440 | "toml 0.5.11", 1441 | ] 1442 | 1443 | [[package]] 1444 | name = "x11" 1445 | version = "2.21.0" 1446 | source = "registry+https://github.com/rust-lang/crates.io-index" 1447 | checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" 1448 | dependencies = [ 1449 | "libc", 1450 | "pkg-config", 1451 | ] 1452 | --------------------------------------------------------------------------------