Compare commits
10 Commits
ba91e4e58c
...
main
Author | SHA1 | Date | |
---|---|---|---|
5d7e571994 | |||
9f0763b255 | |||
e4fccb4e28 | |||
c2f36ffc27 | |||
423ebd763a | |||
d830d7c6b7 | |||
5f4eaa031d | |||
7c530b612d | |||
fdbbc04c5d | |||
50776e1104 |
@@ -1,5 +1,4 @@
|
||||
use daemonize::Daemonize;
|
||||
use libc::wchar_t;
|
||||
use log::{error, info};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use signal_hook::{consts::TERM_SIGNALS, iterator::Signals};
|
||||
@@ -472,9 +471,11 @@ fn parse_event_line(line: &str) -> Result<HyprlandEvent, Box<dyn Error>> {
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct Workspace {
|
||||
id: u32,
|
||||
id: u8,
|
||||
name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
active: Option<bool>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
monitor: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
monitor_id: Option<u32>,
|
||||
@@ -728,7 +729,7 @@ fn run_client(config: &Config, subscription: &str) {
|
||||
eprintln!("Failed to send subscription: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
println!(
|
||||
info!(
|
||||
"Subscribed to '{}' events. Waiting for events...",
|
||||
subscription
|
||||
);
|
||||
@@ -754,32 +755,26 @@ fn run_client(config: &Config, subscription: &str) {
|
||||
/// Prints the active window as json
|
||||
|
||||
fn run_activewindow_client(config: &Config) {
|
||||
let subscription_line = "activewindowv2,fullscreen,closewindow,movewindow,changefloatingmode,moveintogroup,moveoutofgroup,togglegroup,pin,windowtitle\n";
|
||||
let subscription_line = String::from(
|
||||
"activewindowv2,fullscreen,closewindow,movewindow,changefloatingmode,moveintogroup,moveoutofgroup,togglegroup,pin,windowtitle\n",
|
||||
);
|
||||
info!("Using subscription line: {}", subscription_line);
|
||||
let event_reader = match UnixStream::connect(&config.client_socket_path) {
|
||||
Ok(mut stream) => {
|
||||
if let Err(e) = stream.write_all(subscription_line.as_bytes()) {
|
||||
eprintln!("Failed to send subscription: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
println!("Successfully connected to daemon.");
|
||||
BufReader::new(stream)
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Failed to connect to daemon. Is it running? Error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
let mut clients = query_socket(QueryModes::Clients);
|
||||
let event_reader = connect_unix_socket(config, subscription_line);
|
||||
let mut clients = query_clients();
|
||||
print_empty_client();
|
||||
for event_line in event_reader.lines() {
|
||||
let event_line = event_line.unwrap();
|
||||
info!("Read eventline: {}", event_line.clone());
|
||||
let event: HyprlandEvent =
|
||||
serde_json::from_str(&event_line.unwrap()).expect("Failed to parse event");
|
||||
serde_json::from_str(&event_line).expect("Failed to parse event");
|
||||
info!("Parsed event: {}", serde_json::to_string(&event.clone()).unwrap());
|
||||
match event {
|
||||
HyprlandEvent::ActiveWindowV2 { window_address } => {
|
||||
if window_address != "" {
|
||||
if let Some(client) = clients.get(&format!("0x{}", window_address)) {
|
||||
println!("{:#?}", serde_json::to_string(&client).unwrap());
|
||||
println!("{}", serde_json::to_string(&client).unwrap());
|
||||
} else {
|
||||
clients = query_socket(QueryModes::Clients);
|
||||
clients = query_clients();
|
||||
if let Some(client) = clients.get(&format!("0x{}", window_address)) {
|
||||
println!("{}", serde_json::to_string(&client).unwrap());
|
||||
} else {
|
||||
@@ -787,42 +782,166 @@ fn run_activewindow_client(config: &Config) {
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
info!("No active window.");
|
||||
print_empty_client();
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
clients = query_socket(QueryModes::Clients);
|
||||
clients = query_clients();
|
||||
let active_client = query_active_client();
|
||||
println!("{}", serde_json::to_string(&active_client).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum QueryModes {
|
||||
Clients,
|
||||
Workspaces,
|
||||
}
|
||||
/// Prints the workspaces as json highlighting the active one
|
||||
|
||||
fn run_workspaces_client(config: &Config) {
|
||||
let subscription_line = String::from(
|
||||
"workspacev2,focusedmonv2,createworkspacev2,destoryworkspacev2,moveworkspacev2,renameworkspace,activespecial,openwindow,closewindow\n",
|
||||
);
|
||||
info!("Using subscription line: {}", subscription_line);
|
||||
let event_reader = connect_unix_socket(config, subscription_line);
|
||||
let mut workspaces = query_workspaces();
|
||||
let serialized = serde_json::to_string(&workspaces).expect("Failed to serialize workspaces");
|
||||
println!("{}", serialized);
|
||||
for event_line in event_reader.lines() {
|
||||
let event: HyprlandEvent =
|
||||
serde_json::from_str(&event_line.unwrap()).expect("Failed to parse event");
|
||||
let mut active_id: u8 = 0;
|
||||
match event {
|
||||
HyprlandEvent::WorkspaceV2 { workspace_id, .. }
|
||||
| HyprlandEvent::FocusedMonV2 { workspace_id, .. } => {
|
||||
active_id = workspace_id;
|
||||
}
|
||||
_ => {
|
||||
workspaces = query_workspaces();
|
||||
if active_id < 1 {
|
||||
active_id = query_active_workspace().id;
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut workspaces_tmp = workspaces.clone();
|
||||
workspaces_tmp.sort_by(|a, b| a.id.cmp(&b.id));
|
||||
let workspace = workspaces_tmp
|
||||
.iter_mut()
|
||||
.find(|w| w.id == active_id)
|
||||
.unwrap();
|
||||
workspace.active = Some(true);
|
||||
let serialized =
|
||||
serde_json::to_string(&workspaces_tmp).expect("Failed to serialize workspaces");
|
||||
println!("{}", serialized);
|
||||
}
|
||||
}
|
||||
/// === Helper functions for clients that also query socket1 ===
|
||||
fn query_socket(mode: QueryModes) -> HashMap<String, Client> {
|
||||
|
||||
fn connect_unix_socket(config: &Config, subscription_line: String) -> BufReader<UnixStream> {
|
||||
match UnixStream::connect(&config.client_socket_path) {
|
||||
Ok(mut stream) => {
|
||||
if let Err(e) = stream.write_all(subscription_line.as_bytes()) {
|
||||
eprintln!("Failed to send subscription: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
info!("Successfully connected to daemon.");
|
||||
BufReader::new(stream)
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Failed to connect to daemon. Is it running? Error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_empty_client() -> Client {
|
||||
Client {
|
||||
address: "".to_string(),
|
||||
mapped: false,
|
||||
hidden: false,
|
||||
at: (0, 0),
|
||||
size: (0, 0),
|
||||
workspace: Workspace {
|
||||
id: 0,
|
||||
name: "".to_string(),
|
||||
active: None,
|
||||
monitor: None,
|
||||
monitor_id: None,
|
||||
windows: None,
|
||||
has_fullscreen: None,
|
||||
last_window: None,
|
||||
last_window_title: None,
|
||||
},
|
||||
floating: false,
|
||||
pseudo: false,
|
||||
monitor: 0,
|
||||
class: "".to_string(),
|
||||
title: "".to_string(),
|
||||
initial_class: "".to_string(),
|
||||
initial_title: "".to_string(),
|
||||
pid: 0,
|
||||
xwayland: false,
|
||||
pinned: false,
|
||||
fullscreen: 0,
|
||||
fullscreen_client: 0,
|
||||
grouped: vec![],
|
||||
tags: vec![],
|
||||
swallowing: "".to_string(),
|
||||
focus_history_id: 0,
|
||||
inhibiting_idle: false,
|
||||
}
|
||||
}
|
||||
fn print_empty_client(){
|
||||
let client = create_empty_client();
|
||||
println!("{}", serde_json::to_string(&client).unwrap());
|
||||
}
|
||||
|
||||
fn query_socket(query: &str) -> String {
|
||||
info!("Using query: {}", query);
|
||||
let hypr_rundir_path = get_hypr_rundir_path();
|
||||
info!("Using hypr runtime directory: {}", hypr_rundir_path);
|
||||
let socket_path = format!("{}/.socket.sock", hypr_rundir_path);
|
||||
info!("Using hypr socket1 path: {}", socket_path);
|
||||
let query = match mode {
|
||||
QueryModes::Clients => "j/clients",
|
||||
QueryModes::Workspaces => "j/workspaces",
|
||||
};
|
||||
info!("Using query: {}", query);
|
||||
let mut stream = create_socket(&socket_path);
|
||||
stream.write_all(query.as_bytes()).unwrap();
|
||||
let mut response = String::new();
|
||||
stream.read_to_string(&mut response).unwrap();
|
||||
let clients: Vec<Client> = serde_json::from_str(&response).expect("Failed to parse response");
|
||||
info!("Successfully queried {} active clients", clients.len());
|
||||
stream.flush().expect("Failed to flush stream");
|
||||
response
|
||||
}
|
||||
fn query_active_client() -> Client {
|
||||
let query = "j/activewindow";
|
||||
let response = query_socket(query);
|
||||
if response != "{}" {
|
||||
serde_json::from_str(&response).unwrap_or_else(|e| {
|
||||
eprintln!("Failed to parse active window: {}", e);
|
||||
std::process::exit(1);
|
||||
})
|
||||
} else {
|
||||
info!("Active window is empty.");
|
||||
create_empty_client()
|
||||
}
|
||||
}
|
||||
fn query_clients() -> HashMap<String, Client> {
|
||||
let query = "j/clients";
|
||||
let response = query_socket(query);
|
||||
let clients: Vec<Client> =
|
||||
serde_json::from_str(&response).expect("Failed to parse clients response");
|
||||
clients
|
||||
.into_iter()
|
||||
.map(|c| (c.address.clone(), c))
|
||||
.collect()
|
||||
}
|
||||
fn query_active_workspace() -> Workspace {
|
||||
let query = "j/activeworkspace";
|
||||
let response = query_socket(query);
|
||||
serde_json::from_str(&response).expect("Failed to parse active window response")
|
||||
}
|
||||
fn query_workspaces() -> Vec<Workspace> {
|
||||
let query = "j/workspaces";
|
||||
let response = query_socket(query);
|
||||
serde_json::from_str(&response).expect("Failed to parse response")
|
||||
}
|
||||
|
||||
/// === Daemon Control Functions ===
|
||||
|
||||
@@ -854,14 +973,20 @@ fn restart_daemon() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
/// Print usage help text.
|
||||
fn print_help() {
|
||||
println!("Usage:");
|
||||
println!(" -d, --daemon Run as daemon");
|
||||
println!(" -r, --restart Restart the daemon");
|
||||
println!(" -k, --kill Stop the daemon");
|
||||
println!("Usage: hyprman [OPTIONS]");
|
||||
println!();
|
||||
println!("Options:");
|
||||
println!(" -d, --daemon Run Hyprman as a daemon.");
|
||||
println!(" -r, --restart Restart the running daemon.");
|
||||
println!(" -k, --kill Stop the running daemon.");
|
||||
println!(" -f, --filter [FILTER] Run client mode with a subscription filter (default: all).");
|
||||
println!(" -a, --activewindow Run client mode to track active window changes.");
|
||||
println!(" -w, --workspaces Run client mode to track workspace events.");
|
||||
println!(" -h, --help Show this help message.");
|
||||
println!();
|
||||
println!(
|
||||
" -f, --filter [event] Run in client mode, subscribing to [event] (default: all)"
|
||||
"If no options are provided, Hyprman runs in client mode with the 'all' subscription."
|
||||
);
|
||||
println!(" -h, --help Show this help message");
|
||||
}
|
||||
|
||||
/// === Main Entry Point: Mode Selection Based on Command‑Line Arguments ===
|
||||
@@ -938,6 +1063,9 @@ fn main() {
|
||||
"-a" | "--activewindow" => {
|
||||
run_activewindow_client(&config);
|
||||
}
|
||||
"-w" | "--workspaces" => {
|
||||
run_workspaces_client(&config);
|
||||
}
|
||||
"-h" | "--help" => {
|
||||
print_help();
|
||||
}
|
||||
|
Reference in New Issue
Block a user