Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
8694a020b0 |
9 changed files with 1452 additions and 0 deletions
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
bin/
|
||||||
|
result
|
||||||
|
|
||||||
|
|
||||||
|
# Added by cargo
|
||||||
|
|
||||||
|
/target
|
1159
Cargo.lock
generated
Normal file
1159
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
[package]
|
||||||
|
name = "hyprman"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = { version = "4.5.4", features = ["derive"] }
|
||||||
|
homedir = "0.2.1"
|
||||||
|
hyprland = "0.3.13"
|
||||||
|
serde = "1.0.197"
|
||||||
|
serde_json = "1.0.115"
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Daylin Morgan
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
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.
|
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# hyprman
|
||||||
|
|
||||||
|
Utility to output the workspace state to be ingested by `eww`.
|
27
flake.lock
Normal file
27
flake.lock
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1706006310,
|
||||||
|
"narHash": "sha256-nDPz0fj0IFcDhSTlXBU2aixcnGs2Jm4Zcuoj0QtmiXQ=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "b43bb235efeab5324c5e486882ef46749188eee2",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
34
flake.nix
Normal file
34
flake.nix
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{
|
||||||
|
description = "hyprman";
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = inputs @ {
|
||||||
|
self,
|
||||||
|
nixpkgs,
|
||||||
|
}: let
|
||||||
|
inherit (nixpkgs.lib) genAttrs;
|
||||||
|
supportedSystems = ["x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin"];
|
||||||
|
forAllSystems = f: genAttrs supportedSystems (system: f nixpkgs.legacyPackages.${system});
|
||||||
|
in {
|
||||||
|
devShells = forAllSystems (pkgs: {
|
||||||
|
default = pkgs.mkShell {
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
nim
|
||||||
|
];
|
||||||
|
};
|
||||||
|
});
|
||||||
|
packages = forAllSystems (
|
||||||
|
pkgs: {
|
||||||
|
hyprman = pkgs.rustPlatform.buildRustPackage {
|
||||||
|
pname = "hyprman";
|
||||||
|
version = "2023.1001";
|
||||||
|
src = ./.;
|
||||||
|
cargoLock.lockFile = ./Cargo.lock;
|
||||||
|
};
|
||||||
|
default = self.packages.${pkgs.system}.hyprman;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
183
src/main.rs
Normal file
183
src/main.rs
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
use clap::{Parser, Subcommand};
|
||||||
|
use hyprland::{
|
||||||
|
data::{Clients, Monitors},
|
||||||
|
event_listener::EventListenerMutable as EventListener,
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
use serde::Serialize;
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
env,
|
||||||
|
fs::File,
|
||||||
|
io::{self, Read},
|
||||||
|
path::PathBuf,
|
||||||
|
process::Command,
|
||||||
|
thread, time,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
#[command(version, about)]
|
||||||
|
struct Cli {
|
||||||
|
#[command(subcommand)]
|
||||||
|
command: Option<Commands>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Subcommand)]
|
||||||
|
enum Commands {
|
||||||
|
/// watch workspace/client activity and write to stdout
|
||||||
|
Workspace {
|
||||||
|
/// path to icons.json
|
||||||
|
#[arg(short, long)]
|
||||||
|
icons: Option<PathBuf>,
|
||||||
|
},
|
||||||
|
/// reflect monitor changes to eww
|
||||||
|
Monitors {},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Clone)]
|
||||||
|
struct EwwData {
|
||||||
|
id: usize,
|
||||||
|
icon: String,
|
||||||
|
class: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_icons(path: &Option<PathBuf>) -> io::Result<HashMap<String, String>> {
|
||||||
|
|
||||||
|
let icon_path: PathBuf = match path {
|
||||||
|
Some(path) => PathBuf::from(path),
|
||||||
|
None => {
|
||||||
|
(env::var("XDG_CONFIG_DIR").map_or(
|
||||||
|
homedir::get_my_home().unwrap().unwrap().join(".config"),
|
||||||
|
PathBuf::from,
|
||||||
|
))
|
||||||
|
.join("hyprman")
|
||||||
|
.join("icons.json")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut file = File::open(icon_path)?;
|
||||||
|
let mut data = String::new();
|
||||||
|
file.read_to_string(&mut data)?;
|
||||||
|
let icons: HashMap<String, String> = serde_json::from_str(&data)?;
|
||||||
|
Ok(icons)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Monitors {}
|
||||||
|
|
||||||
|
fn get_state(icons: &HashMap<String, String>) -> hyprland::Result<()> {
|
||||||
|
let monitors = Monitors::get()?;
|
||||||
|
let clients = Clients::get()?;
|
||||||
|
|
||||||
|
let mut state: Vec<Vec<EwwData>> = vec![];
|
||||||
|
let mut workspaces: Vec<EwwData> = (1..10)
|
||||||
|
.map(|i| EwwData {
|
||||||
|
id: i,
|
||||||
|
icon: "".to_string(),
|
||||||
|
class: format!("ws-button-{}", i - 1),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for client in clients {
|
||||||
|
let id = client.workspace.id;
|
||||||
|
if id < 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
match icons.get(&client.class) {
|
||||||
|
Some(icon) => workspaces[(id - 1) as usize].icon.push_str(icon),
|
||||||
|
None => workspaces[(id - 1) as usize].icon.push(''),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for workspace in &mut workspaces {
|
||||||
|
if workspace.icon.is_empty() {
|
||||||
|
workspace.icon = "".to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for monitor in monitors {
|
||||||
|
let mut workspaces = workspaces.clone();
|
||||||
|
workspaces[(monitor.active_workspace.id - 1) as usize]
|
||||||
|
.class
|
||||||
|
.push_str(" ws-button-open");
|
||||||
|
state.push(workspaces);
|
||||||
|
}
|
||||||
|
println!("{}", serde_json::to_string(&state)?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn watch_workspaces(icons: &Option<PathBuf>) -> hyprland::Result<()> {
|
||||||
|
let icons = load_icons(icons)?;
|
||||||
|
loop {
|
||||||
|
let delay = time::Duration::from_millis(500);
|
||||||
|
thread::sleep(delay);
|
||||||
|
get_state(&icons)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Eww {}
|
||||||
|
|
||||||
|
enum EwwCommand {
|
||||||
|
Open,
|
||||||
|
Close,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eww {
|
||||||
|
fn call(cmd: EwwCommand, bar: &str) -> io::Result<()> {
|
||||||
|
// give the window time to react
|
||||||
|
|
||||||
|
Command::new("eww")
|
||||||
|
.arg(match cmd {
|
||||||
|
EwwCommand::Open => "open",
|
||||||
|
EwwCommand::Close => "close",
|
||||||
|
})
|
||||||
|
.arg("bar".to_string() + bar)
|
||||||
|
.status()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init() -> hyprland::Result<()> {
|
||||||
|
let monitors = Monitors::get()?;
|
||||||
|
for (i, _) in monitors.enumerate() {
|
||||||
|
Eww::call(EwwCommand::Open, &format!("{}", i))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delay() {
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open(bar: &str) -> io::Result<()> {
|
||||||
|
Eww::delay();
|
||||||
|
Eww::call(EwwCommand::Open, bar)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn close(bar: &str) -> io::Result<()> {
|
||||||
|
Eww::delay();
|
||||||
|
Eww::call(EwwCommand::Close, bar)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn listen_for_monitors() -> hyprland::Result<()> {
|
||||||
|
Eww::init()?;
|
||||||
|
|
||||||
|
let mut event_listener = EventListener::new();
|
||||||
|
event_listener.add_monitor_added_handler(|_, _| Eww::open("1").expect("failed to open bar"));
|
||||||
|
event_listener.add_monitor_removed_handler(|_, _| Eww::close("1").expect("failed to open bar"));
|
||||||
|
event_listener.start_listener()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> hyprland::Result<()> {
|
||||||
|
let cli = Cli::parse();
|
||||||
|
|
||||||
|
if let Some(cmd) = &cli.command {
|
||||||
|
match cmd {
|
||||||
|
Commands::Workspace { icons } => watch_workspaces(icons)?,
|
||||||
|
Commands::Monitors {} => listen_for_monitors()?,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("no command specified see: hyprman help")
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
5
todo.md
Normal file
5
todo.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# hyprman todo's
|
||||||
|
|
||||||
|
- [ ] implement the eww infra to listen and close/open bar's on socket2
|
||||||
|
|
||||||
|
<!-- generated with <3 by daylinmorgan/todo -->
|
Loading…
Reference in a new issue