Workspaces on hyprland

This commit is contained in:
2024-07-26 11:22:22 +02:00
parent 48e9418f6d
commit 1f6e33fa75
5 changed files with 98 additions and 30 deletions

23
src/eww.rs Normal file
View File

@ -0,0 +1,23 @@
use eyre::{bail, Context};
/// Update eww bar variable
pub fn update_var(key: &str, value: &str) -> eyre::Result<()> {
println!("eww update {key}={value}");
let output = std::process::Command::new("eww")
.arg("update")
.arg(format!("{key}={value}"))
.output()
.wrap_err("failed to execute 'eww update'")?;
if !output.status.success() {
let stdout = std::str::from_utf8(&output.stdout).unwrap_or("Invalid UTF-8");
let stderr = std::str::from_utf8(&output.stderr).unwrap_or("Invalid UTF-8");
eprintln!("'eww update' stdout: {stdout}");
eprintln!("'eww update' stderr: {stderr}");
bail!("'eww update' failed. See logs.");
}
Ok(())
}

View File

@ -1,16 +1,31 @@
use eyre::{bail, eyre};
use crate::{eww, output, Command};
use eyre::{bail, eyre, Context};
use serde::{de::DeserializeOwned, Deserialize};
use std::str;
use crate::Command;
#[derive(Deserialize)]
struct HyprWorkspace {
name: String,
#[serde(rename = "monitorID")]
monitor_id: u32,
//
// id, windows, monitor, hasfullscreen, lastwindow, lastwindowtitle
}
pub fn handle(command: Command) -> eyre::Result<()> {
match command {
Command::Workspaces {} => {
std::process::Command::new("eww-workspaces")
.status()
.map_err(|e| eyre!("unga bunga: {e}"))?;
println!("{}", get_workspaces()?);
}
Command::SwitchWorkspace { .. } => {
bail!("not supported on Hyprland");
Command::SwitchWorkspace { to } => {
std::process::Command::new("hyprctl")
.args(["dispatch", "workspace"])
.arg(format!("{to}"))
.status()
.map_err(|e| eyre!("hyprctl error: {e}"))?;
eww::update_var("workspaces", &get_workspaces()?)?;
}
Command::KeyboardLayout { .. } => {
bail!("not supported on Hyprland");
@ -19,3 +34,42 @@ pub fn handle(command: Command) -> eyre::Result<()> {
Ok(())
}
fn hyprctl<T: DeserializeOwned>(args: &[&str]) -> eyre::Result<T> {
let workspaces_output = std::process::Command::new("hyprctl")
.args(args)
.arg("-j") // JSON output
.output()
.map_err(|e| eyre!("hyprctl error: {e}"))?;
let workspaces_stdout = str::from_utf8(&workspaces_output.stdout)?;
//let workspaces_stderr = str::from_utf8(&workspaces_output.stderr)?;
if !workspaces_output.status.success() {
bail!("hyprctl error, non-zero exit code");
}
serde_json::from_str(workspaces_stdout).wrap_err("Failed to deserialize output from hyprctl")
}
/// Get a JSON-string containing info about workspaces
fn get_workspaces() -> eyre::Result<String> {
let active_workspace: HyprWorkspace = hyprctl(&["activeworkspace"])?;
let workspaces: Vec<HyprWorkspace> = hyprctl(&["workspaces"])?;
let workspaces: output::Workspaces = workspaces
.into_iter()
.map(|workspace| {
let is_active = workspace.name == active_workspace.name;
(
workspace.name,
output::Workspace {
monitor: workspace.monitor_id,
active: is_active,
},
)
})
.collect();
serde_json::to_string(&workspaces).wrap_err("Failed to serialize workspaces")
}

View File

@ -3,8 +3,10 @@ use once_cell::sync::Lazy;
use serde::Serialize;
use std::env;
mod eww;
mod hyprland;
mod niri;
mod output;
#[derive(Parser)]
struct Opt {

View File

@ -1,6 +1,6 @@
use std::collections::HashMap;
use crate::{Command, Workspace};
use crate::{eww, Command, Workspace};
use eyre::{bail, eyre, Context};
use niri_ipc::{Socket, WorkspaceReferenceArg};
@ -19,7 +19,7 @@ pub fn handle(command: Command) -> eyre::Result<()> {
))?
.map_err(|e| eyre!("niri error: {e}"))?;
update_eww("workspaces", &get_workspaces()?)?;
eww::update_var("workspaces", &get_workspaces()?)?;
}
Command::KeyboardLayout { next: _ } => todo!(),
}
@ -32,27 +32,6 @@ fn open_socket() -> eyre::Result<Socket> {
niri_ipc::Socket::connect().wrap_err("Failed to open niri socket")
}
/// Update eww bar variable
fn update_eww(key: &str, value: &str) -> eyre::Result<()> {
let output = std::process::Command::new("eww")
.arg("update")
.arg(format!("{key}={value}"))
.output()
.wrap_err("failed to execute 'eww update'")?;
if !output.status.success() {
let stdout = std::str::from_utf8(&output.stdout).unwrap_or("Invalid UTF-8");
let stderr = std::str::from_utf8(&output.stderr).unwrap_or("Invalid UTF-8");
eprintln!("'eww update' stdout: {stdout}");
eprintln!("'eww update' stderr: {stderr}");
bail!("'eww update' failed. See logs.");
}
Ok(())
}
/// Get a JSON-string containing info about workspaces
fn get_workspaces() -> eyre::Result<String> {
let socket = open_socket()?;

10
src/output.rs Normal file
View File

@ -0,0 +1,10 @@
use serde::Serialize;
use std::collections::HashMap;
pub type Workspaces = HashMap<String, Workspace>;
#[derive(Clone, Debug, Serialize)]
pub struct Workspace {
pub monitor: u32,
pub active: bool,
}