Goofin'
Some checks failed
/ check (push) Failing after 2m6s

This commit is contained in:
Daniel Flanagan 2025-01-22 11:56:29 -06:00
parent 7df555a756
commit 07c9950cb8
8 changed files with 353 additions and 23 deletions

View file

@ -1,34 +1,38 @@
#!/usr/bin/env bash
# TODO: we're mixing bash arrays and not-arrays - get it together
declare -A OCCUPIED
declare -A ACTIVE
declare -A FOCUSED
#define icons for workspaces 1-9
ic=(1 2 3 4 5 6 7 8 9)
spaces=(1 2 3 4 5 6 7 8 9)
icons=(1 2 3 4 5 6 7 8 9)
occ() { export o"$1"="occupied"; }
unocc() { unset -v o"$1"; }
occupy() { export OCCUPIED["$1"]=occupied; }
unoccupy() { unset "OCCUPIED[$1]"; }
active() { export a"$1"="active"; }
unactive() { unset -v a"$1"; }
activate() { export ACTIVE["$1"]=active; }
deactivate() { unset "ACTIVE[$1]"; }
focus() { export f"$1"="focused"; }
unfocus() { unset -v f"$1"; }
focus() { export FOCUSED["$1"]=focused; }
unfocus() { unset "FOCUSED[$1]"; }
workspaces() {
for num in 1 2 3 4 5 6 7 8 9; do
unfocus $num
unactive $num
unocc $num
for s in "${spaces[@]}"; do
unfocus "$s"
deactivate "$s"
unoccupy "$s"
done
# TODO: avoid recomputing these each time and actually listen to the events?
mons_json=$(hyprctl monitors -j)
for num in $(hyprctl workspaces -j | jq -r '.[] | select(.windows > 0) | .id'); do
occ "$num"
occupy "$num"
done
for num in $(echo "$mons_json" | jq -r '.[].activeWorkspace.id'); do
active "$num"
activate "$num"
done
for num in $(echo "$mons_json" | jq -r '.[] | select(.focused) | .activeWorkspace.id'); do
@ -38,21 +42,23 @@ workspaces() {
# TODO: would be nice to have monitors' workspaces show up in left-to-right
# order as laid out in physical/pixel space
# this would make glancing at the workspace indicator more intuitive
#
# TODO: might be nice to exclude certain windows as counting towards "occupation" such as xwaylandvideobridge or w/e
#
# NOTE: maybe I can group workspaces by their monitor with some mechanism for "unassigned" workspace to show up by a "primary" monitor
# render eww widget
echo "(eventbox :onscroll \"echo {} | sed -e 's/up/-1/g' -e 's/down/+1/g' | xargs hyprctl dispatch workspace\" \
(box :class \"workspaces\" :orientation \"h\" :spacing 0 :space-evenly \"true\" \
(button :onclick \"hyprctl dispatch workspace 1\" :onrightclick \"hyprctl dispatch workspace 1\" :class \"workspace $a1 $o1 $f1\" \"${ic[0]}\") \
(button :onclick \"hyprctl dispatch workspace 2\" :onrightclick \"hyprctl dispatch workspace 2\" :class \"workspace $a2 $o2 $f2\" \"${ic[1]}\") \
(button :onclick \"hyprctl dispatch workspace 3\" :onrightclick \"hyprctl dispatch workspace 3\" :class \"workspace $a3 $o3 $f3\" \"${ic[2]}\") \
(button :onclick \"hyprctl dispatch workspace 4\" :onrightclick \"hyprctl dispatch workspace 4\" :class \"workspace $a4 $o4 $f4\" \"${ic[3]}\") \
(button :onclick \"hyprctl dispatch workspace 5\" :onrightclick \"hyprctl dispatch workspace 5\" :class \"workspace $a5 $o5 $f5\" \"${ic[4]}\") \
(button :onclick \"hyprctl dispatch workspace 6\" :onrightclick \"hyprctl dispatch workspace 6\" :class \"workspace $a6 $o6 $f6\" \"${ic[5]}\") \
(button :onclick \"hyprctl dispatch workspace 7\" :onrightclick \"hyprctl dispatch workspace 7\" :class \"workspace $a7 $o7 $f7\" \"${ic[6]}\") \
(button :onclick \"hyprctl dispatch workspace 8\" :onrightclick \"hyprctl dispatch workspace 8\" :class \"workspace $a8 $o8 $f8\" \"${ic[7]}\") \
(button :onclick \"hyprctl dispatch workspace 9\" :onrightclick \"hyprctl dispatch workspace 9\" :class \"workspace $a9 $o9 $f9\" \"${ic[8]}\") \
(button :onclick \"hyprctl dispatch workspace 1\" :onrightclick \"hyprctl dispatch workspace 1\" :class \"workspace ${ACTIVE[1]} ${OCCUPIED[1]} ${FOCUSED[1]}\" \"${icons[0]}\") \
(button :onclick \"hyprctl dispatch workspace 2\" :onrightclick \"hyprctl dispatch workspace 2\" :class \"workspace ${ACTIVE[2]} ${OCCUPIED[2]} ${FOCUSED[2]}\" \"${icons[1]}\") \
(button :onclick \"hyprctl dispatch workspace 3\" :onrightclick \"hyprctl dispatch workspace 3\" :class \"workspace ${ACTIVE[3]} ${OCCUPIED[3]} ${FOCUSED[3]}\" \"${icons[2]}\") \
(button :onclick \"hyprctl dispatch workspace 4\" :onrightclick \"hyprctl dispatch workspace 4\" :class \"workspace ${ACTIVE[4]} ${OCCUPIED[4]} ${FOCUSED[4]}\" \"${icons[3]}\") \
(button :onclick \"hyprctl dispatch workspace 5\" :onrightclick \"hyprctl dispatch workspace 5\" :class \"workspace ${ACTIVE[5]} ${OCCUPIED[5]} ${FOCUSED[5]}\" \"${icons[4]}\") \
(button :onclick \"hyprctl dispatch workspace 6\" :onrightclick \"hyprctl dispatch workspace 6\" :class \"workspace ${ACTIVE[6]} ${OCCUPIED[6]} ${FOCUSED[6]}\" \"${icons[5]}\") \
(button :onclick \"hyprctl dispatch workspace 7\" :onrightclick \"hyprctl dispatch workspace 7\" :class \"workspace ${ACTIVE[7]} ${OCCUPIED[7]} ${FOCUSED[7]}\" \"${icons[6]}\") \
(button :onclick \"hyprctl dispatch workspace 8\" :onrightclick \"hyprctl dispatch workspace 8\" :class \"workspace ${ACTIVE[8]} ${OCCUPIED[8]} ${FOCUSED[8]}\" \"${icons[7]}\") \
(button :onclick \"hyprctl dispatch workspace 9\" :onrightclick \"hyprctl dispatch workspace 9\" :class \"workspace ${ACTIVE[9]} ${OCCUPIED[9]} ${FOCUSED[9]}\" \"${icons[8]}\") \
) \
)"
}

View file

@ -0,0 +1,2 @@
./target
./result

View file

@ -0,0 +1,20 @@
{pkgs ? import <nixpkgs> {}}: let
# lock = builtins.fromJSON (builtins.readFile ../../../../../flake.lock);
# nixpkgsRev = lock.nodes.nixpkgs.locked.rev;
# pkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/${nixpkgsRev}.tar.gz") {};
pname = "hyprland-workspaces-eww";
version = "1.0.0";
src = ./src;
in
pkgs.rustPlatform.buildRustPackage {
inherit pname version src;
cargoHash = "sha256-6Wl3cOIxlPJjzEuzNhCBZJXayL8runQfAxPruvzh2Vc=";
# cargoHash = pkgs.lib.fakeHash;
checkType = "release";
postBuild = ''
# pushd target/*/release
# ls -la
# ${pkgs.upx}/bin/upx --best --lzma hyprland-workspaces-eww
# popd
'';
}

View file

@ -0,0 +1 @@
target

View file

@ -0,0 +1,96 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "hyprland-workspaces-eww"
version = "0.1.0"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "itoa"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "proc-macro2"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "serde"
version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "2.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"

View file

@ -0,0 +1,19 @@
[package]
name = "hyprland-workspaces-eww"
version = "0.1.0"
edition = "2021"
[[bin]]
name = "hyprland-workspaces-eww"
path = "./main.rs"
[dependencies]
serde = "1.0.217"
serde_json = "1.0.137"
[profile.release]
strip = true
opt-level = "z"
lto = true
codegen-units = 1
panic = "abort"

View file

@ -0,0 +1,186 @@
mod workspace {
pub struct Workspace {
id: usize,
icon: char,
pub is_active: bool,
pub is_occupied: bool,
pub is_focused: bool,
}
impl Workspace {
pub fn new(id: usize) -> Self {
Self {
id,
icon: id.to_string().chars().next().unwrap_or('?'),
is_active: false,
is_occupied: false,
is_focused: false,
}
}
pub fn id(&self) -> usize {
return self.id;
}
pub fn icon(&self) -> char {
return self.icon;
}
pub fn clear_states(&mut self) {
self.is_active = false;
self.is_occupied = false;
self.is_focused = false;
}
}
}
mod eww {}
mod hypr {
pub mod hyprland {
pub mod workspace {
pub type Id = usize;
pub type Name = String;
}
pub mod socket2 {
use super::workspace;
use std::{error::Error, fmt::Display, num::ParseIntError, str::FromStr};
#[derive(Debug)]
pub enum Event {
Workspace(workspace::Id),
Exit(),
WorkspaceV2(String, String),
}
#[derive(Debug)]
pub enum EventParseError {
UnknownEventType(String),
MissingParameters(String),
InvalidParameters(String, String),
ParseIntError(ParseIntError),
}
impl From<ParseIntError> for EventParseError {
fn from(value: ParseIntError) -> Self {
Self::ParseIntError(value)
}
}
impl Error for EventParseError {}
impl Display for EventParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
EventParseError::UnknownEventType(event_type) => {
write!(f, "unknown event type: {event_type}")
}
EventParseError::MissingParameters(event_type) => {
write!(f, "missing parameters for event type: {event_type}")
}
EventParseError::ParseIntError(err) => {
write!(f, "error parsing integer: {err}")
}
EventParseError::InvalidParameters(event_type, params) => {
write!(
f,
"invalid parameters for event type {event_type}: {params}"
)
}
}
}
}
impl FromStr for Event {
type Err = EventParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (event_type, rest): (&str, Option<&str>) = s
.find(">>")
.map(|n| {
let (a, b) = s.split_at(n);
(a, Option::Some(&b[2..]))
})
.unwrap_or((s, Option::None));
match (event_type, rest) {
("workspace", None) => {
Err(EventParseError::MissingParameters(event_type.to_string()))
}
("workspace", Some(workspace)) => Ok(Event::Workspace(workspace.parse()?)),
("workspacev2", Some(args)) => {
let args: (String, String) = args
.split_once(',')
.map(|(a, b)| (a.to_string(), b.to_string()))
.ok_or(EventParseError::InvalidParameters(
event_type.to_string(),
args.to_string(),
))?;
Ok(Event::WorkspaceV2(args.0, args.1))
}
("exit", _) => Ok(Event::Exit()),
_ => Err(EventParseError::UnknownEventType(event_type.to_string())),
}
}
}
}
}
}
use hypr::hyprland::socket2::Event;
use std::{
collections::HashMap,
env,
error::Error,
io::{BufRead, BufReader},
os::unix::net::UnixStream,
};
use workspace::Workspace;
fn main() -> Result<(), Box<dyn Error>> {
let mut workspaces: HashMap<usize, Workspace> =
(1..=9).map(|n| (n, Workspace::new(n))).collect();
let path = format!(
"{}/hypr/{}/.socket2.sock",
env::var("XDG_RUNTIME_DIR")?,
env::var("HYPRLAND_INSTANCE_SIGNATURE")?
);
eprintln!("opening {}", path);
let stream = UnixStream::connect(&path)?;
let event_lines = BufReader::new(stream).lines();
for l in event_lines.into_iter() {
match l?.parse::<Event>() {
Ok(e) => match e {
Event::Workspace(i) => match workspaces.get_mut(&i) {
Some(related_workspace) => {
eprintln!(
"setting workspace {} (id: {}) as active",
related_workspace.icon(),
related_workspace.id()
);
related_workspace.is_active = true
}
None => {
eprintln!("event for untracked workspace {}", i);
}
},
Event::Exit() => break,
other => {
eprintln!("unhandled event: {:?}", other);
}
},
Err(e) => eprintln!("error parsing event: {}", e),
}
render(&workspaces)?;
}
Ok(())
}
fn render(workspaces: &HashMap<usize, Workspace>) -> Result<(), Box<dyn Error>> {
Ok(())
}

View file

@ -27,7 +27,7 @@
programs.hyprland = {
enable = true;
};
environment.systemPackages = with pkgs; [hyprpaper xwaylandvideobridge socat];
environment.systemPackages = with pkgs; [hyprpaper xwaylandvideobridge netcat-openbsd];
programs.hyprland = {
package = flakeInputs.hyprland.packages.${pkgs.system}.hyprland;