reached milestone for active window client
This commit is contained in:
@@ -1,3 +1,10 @@
|
|||||||
|
use daemonize::Daemonize;
|
||||||
|
use libc::wchar_t;
|
||||||
|
use log::{error, info};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use signal_hook::{consts::TERM_SIGNALS, iterator::Signals};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::io::Read;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
env,
|
env,
|
||||||
@@ -10,218 +17,149 @@ use std::{
|
|||||||
thread,
|
thread,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
use std::io::Read;
|
|
||||||
use daemonize::Daemonize;
|
|
||||||
use log::{error, info};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use signal_hook::{consts::TERM_SIGNALS, iterator::Signals};
|
|
||||||
|
|
||||||
/// === Hyprland Event Types and Parsing ===
|
/// === Hyprland Event Types ===
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
#[serde(tag = "event", content = "data")]
|
#[serde(tag = "event", content = "data")]
|
||||||
enum HyprlandEvent {
|
enum HyprlandEvent {
|
||||||
Workspace { workspace_name: String },
|
Workspace {
|
||||||
WorkspaceV2 { workspace_id: u8, workspace_name: String },
|
workspace_name: String,
|
||||||
FocusedMon { monitor_name: String, workspace_name: String },
|
},
|
||||||
FocusedMonV2 { monitor_name: String, workspace_id: u8 },
|
WorkspaceV2 {
|
||||||
ActiveWindow { window_class: String, window_title: String },
|
workspace_id: u8,
|
||||||
ActiveWindowV2 { window_address: String },
|
workspace_name: String,
|
||||||
Fullscreen { status: u8 },
|
},
|
||||||
MonitorRemoved { monitor_name: String },
|
FocusedMon {
|
||||||
MonitorAdded { monitor_name: String },
|
monitor_name: String,
|
||||||
MonitorAddedV2 { monitor_id: u8, monitor_name: String, monitor_description: String },
|
workspace_name: String,
|
||||||
CreateWorkspace { workspace_name: String },
|
},
|
||||||
CreateWorkspaceV2 { workspace_id: u8, workspace_name: String },
|
FocusedMonV2 {
|
||||||
DestroyWorkspace { workspace_name: String },
|
monitor_name: String,
|
||||||
DestroyWorkspaceV2 { workspace_id: u8, workspace_name: String },
|
workspace_id: u8,
|
||||||
MoveWorkspace { workspace_name: String, monitor_name: String },
|
},
|
||||||
MoveWorkspaceV2 { workspace_id: u8, workspace_name: String, monitor_name: String },
|
ActiveWindow {
|
||||||
RenameWorkspace { workspace_id: u8, new_name: String },
|
window_class: String,
|
||||||
ActiveSpecial { workspace_name: String, monitor_name: String },
|
window_title: String,
|
||||||
ActiveLayout { keyboard_name: String, layout_name: String },
|
},
|
||||||
OpenWindow { window_address: String, workspace_name: String, window_class: String, window_title: String },
|
ActiveWindowV2 {
|
||||||
CloseWindow { window_address: String },
|
window_address: String,
|
||||||
MoveWindow { window_address: String, workspace_name: String },
|
},
|
||||||
MoveWindowV2 { window_address: String, workspace_id: u8, workspace_name: String },
|
Fullscreen {
|
||||||
OpenLayer { namespace: String },
|
status: u8,
|
||||||
CloseLayer { namespace: String },
|
},
|
||||||
Submap { submap_name: String },
|
MonitorRemoved {
|
||||||
ChangeFloatingMode { window_address: String, floating: u8 },
|
monitor_name: String,
|
||||||
Urgent { window_address: String },
|
},
|
||||||
Screencast { state: u8, owner: u8 },
|
MonitorAdded {
|
||||||
WindowTitle { window_address: String },
|
monitor_name: String,
|
||||||
WindowTitleV2 { window_address: String, window_title: String },
|
},
|
||||||
ToggleGroup { toggle_status: u8, window_addresses: Vec<String> },
|
MonitorAddedV2 {
|
||||||
MoveIntoGroup { window_address: String },
|
monitor_id: u8,
|
||||||
MoveOutOfGroup { window_address: String },
|
monitor_name: String,
|
||||||
IgnoreGroupLock { value: u8 },
|
monitor_description: String,
|
||||||
LockGroups { value: u8 },
|
},
|
||||||
|
CreateWorkspace {
|
||||||
|
workspace_name: String,
|
||||||
|
},
|
||||||
|
CreateWorkspaceV2 {
|
||||||
|
workspace_id: u8,
|
||||||
|
workspace_name: String,
|
||||||
|
},
|
||||||
|
DestroyWorkspace {
|
||||||
|
workspace_name: String,
|
||||||
|
},
|
||||||
|
DestroyWorkspaceV2 {
|
||||||
|
workspace_id: u8,
|
||||||
|
workspace_name: String,
|
||||||
|
},
|
||||||
|
MoveWorkspace {
|
||||||
|
workspace_name: String,
|
||||||
|
monitor_name: String,
|
||||||
|
},
|
||||||
|
MoveWorkspaceV2 {
|
||||||
|
workspace_id: u8,
|
||||||
|
workspace_name: String,
|
||||||
|
monitor_name: String,
|
||||||
|
},
|
||||||
|
RenameWorkspace {
|
||||||
|
workspace_id: u8,
|
||||||
|
new_name: String,
|
||||||
|
},
|
||||||
|
ActiveSpecial {
|
||||||
|
workspace_name: String,
|
||||||
|
monitor_name: String,
|
||||||
|
},
|
||||||
|
ActiveLayout {
|
||||||
|
keyboard_name: String,
|
||||||
|
layout_name: String,
|
||||||
|
},
|
||||||
|
OpenWindow {
|
||||||
|
window_address: String,
|
||||||
|
workspace_name: String,
|
||||||
|
window_class: String,
|
||||||
|
window_title: String,
|
||||||
|
},
|
||||||
|
CloseWindow {
|
||||||
|
window_address: String,
|
||||||
|
},
|
||||||
|
MoveWindow {
|
||||||
|
window_address: String,
|
||||||
|
workspace_name: String,
|
||||||
|
},
|
||||||
|
MoveWindowV2 {
|
||||||
|
window_address: String,
|
||||||
|
workspace_id: u8,
|
||||||
|
workspace_name: String,
|
||||||
|
},
|
||||||
|
OpenLayer {
|
||||||
|
namespace: String,
|
||||||
|
},
|
||||||
|
CloseLayer {
|
||||||
|
namespace: String,
|
||||||
|
},
|
||||||
|
Submap {
|
||||||
|
submap_name: String,
|
||||||
|
},
|
||||||
|
ChangeFloatingMode {
|
||||||
|
window_address: String,
|
||||||
|
floating: u8,
|
||||||
|
},
|
||||||
|
Urgent {
|
||||||
|
window_address: String,
|
||||||
|
},
|
||||||
|
Screencast {
|
||||||
|
state: u8,
|
||||||
|
owner: u8,
|
||||||
|
},
|
||||||
|
WindowTitle {
|
||||||
|
window_address: String,
|
||||||
|
},
|
||||||
|
WindowTitleV2 {
|
||||||
|
window_address: String,
|
||||||
|
window_title: String,
|
||||||
|
},
|
||||||
|
ToggleGroup {
|
||||||
|
toggle_status: u8,
|
||||||
|
window_addresses: Vec<String>,
|
||||||
|
},
|
||||||
|
MoveIntoGroup {
|
||||||
|
window_address: String,
|
||||||
|
},
|
||||||
|
MoveOutOfGroup {
|
||||||
|
window_address: String,
|
||||||
|
},
|
||||||
|
IgnoreGroupLock {
|
||||||
|
value: u8,
|
||||||
|
},
|
||||||
|
LockGroups {
|
||||||
|
value: u8,
|
||||||
|
},
|
||||||
ConfigReloaded,
|
ConfigReloaded,
|
||||||
Pin { window_address: String, pin_state: u8 },
|
Pin {
|
||||||
}
|
window_address: String,
|
||||||
|
pin_state: u8,
|
||||||
fn parse_event_line(line: &str) -> Result<HyprlandEvent, Box<dyn Error>> {
|
},
|
||||||
let line = line.trim();
|
|
||||||
let mut parts = line.split(">>");
|
|
||||||
let event_name = parts.next().ok_or("Missing event name")?;
|
|
||||||
let data = parts.next().unwrap_or("").trim();
|
|
||||||
|
|
||||||
match event_name {
|
|
||||||
"workspace" => Ok(HyprlandEvent::Workspace { workspace_name: data.to_string() }),
|
|
||||||
"workspacev2" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let workspace_id = fields.next().ok_or("Missing workspace_id")?.parse::<u8>()?;
|
|
||||||
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
|
||||||
Ok(HyprlandEvent::WorkspaceV2 { workspace_id, workspace_name })
|
|
||||||
}
|
|
||||||
"focusedmon" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let monitor_name = fields.next().ok_or("Missing monitor_name")?.to_string();
|
|
||||||
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
|
||||||
Ok(HyprlandEvent::FocusedMon { monitor_name, workspace_name })
|
|
||||||
}
|
|
||||||
"focusedmonv2" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let monitor_name = fields.next().ok_or("Missing monitor_name")?.to_string();
|
|
||||||
let workspace_id = fields.next().ok_or("Missing workspace_id")?.parse::<u8>()?;
|
|
||||||
Ok(HyprlandEvent::FocusedMonV2 { monitor_name, workspace_id })
|
|
||||||
}
|
|
||||||
"activewindow" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let window_class = fields.next().ok_or("Missing window_class")?.to_string();
|
|
||||||
let window_title = fields.next().ok_or("Missing window_title")?.to_string();
|
|
||||||
Ok(HyprlandEvent::ActiveWindow { window_class, window_title })
|
|
||||||
}
|
|
||||||
"activewindowv2" => Ok(HyprlandEvent::ActiveWindowV2 { window_address: data.to_string() }),
|
|
||||||
"fullscreen" => {
|
|
||||||
let status = data.parse::<u8>()?;
|
|
||||||
Ok(HyprlandEvent::Fullscreen { status })
|
|
||||||
}
|
|
||||||
"monitorremoved" => Ok(HyprlandEvent::MonitorRemoved { monitor_name: data.to_string() }),
|
|
||||||
"monitoradded" => Ok(HyprlandEvent::MonitorAdded { monitor_name: data.to_string() }),
|
|
||||||
"monitoraddedv2" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let monitor_id = fields.next().ok_or("Missing monitor_id")?.parse::<u8>()?;
|
|
||||||
let monitor_name = fields.next().ok_or("Missing monitor_name")?.to_string();
|
|
||||||
let monitor_description = fields.next().ok_or("Missing monitor_description")?.to_string();
|
|
||||||
Ok(HyprlandEvent::MonitorAddedV2 { monitor_id, monitor_name, monitor_description })
|
|
||||||
}
|
|
||||||
"createworkspace" => Ok(HyprlandEvent::CreateWorkspace { workspace_name: data.to_string() }),
|
|
||||||
"createworkspacev2" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let workspace_id = fields.next().ok_or("Missing workspace_id")?.parse::<u8>()?;
|
|
||||||
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
|
||||||
Ok(HyprlandEvent::CreateWorkspaceV2 { workspace_id, workspace_name })
|
|
||||||
}
|
|
||||||
"destroyworkspace" => Ok(HyprlandEvent::DestroyWorkspace { workspace_name: data.to_string() }),
|
|
||||||
"destroyworkspacev2" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let workspace_id = fields.next().ok_or("Missing workspace_id")?.parse::<u8>()?;
|
|
||||||
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
|
||||||
Ok(HyprlandEvent::DestroyWorkspaceV2 { workspace_id, workspace_name })
|
|
||||||
}
|
|
||||||
"moveworkspace" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
|
||||||
let monitor_name = fields.next().ok_or("Missing monitor_name")?.to_string();
|
|
||||||
Ok(HyprlandEvent::MoveWorkspace { workspace_name, monitor_name })
|
|
||||||
}
|
|
||||||
"moveworkspacev2" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let workspace_id = fields.next().ok_or("Missing workspace_id")?.parse::<u8>()?;
|
|
||||||
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
|
||||||
let monitor_name = fields.next().ok_or("Missing monitor_name")?.to_string();
|
|
||||||
Ok(HyprlandEvent::MoveWorkspaceV2 { workspace_id, workspace_name, monitor_name })
|
|
||||||
}
|
|
||||||
"renameworkspace" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let workspace_id = fields.next().ok_or("Missing workspace_id")?.parse::<u8>()?;
|
|
||||||
let new_name = fields.next().ok_or("Missing new_name")?.to_string();
|
|
||||||
Ok(HyprlandEvent::RenameWorkspace { workspace_id, new_name })
|
|
||||||
}
|
|
||||||
"activespecial" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
|
||||||
let monitor_name = fields.next().ok_or("Missing monitor_name")?.to_string();
|
|
||||||
Ok(HyprlandEvent::ActiveSpecial { workspace_name, monitor_name })
|
|
||||||
}
|
|
||||||
"activelayout" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let keyboard_name = fields.next().ok_or("Missing keyboard_name")?.to_string();
|
|
||||||
let layout_name = fields.next().ok_or("Missing layout_name")?.to_string();
|
|
||||||
Ok(HyprlandEvent::ActiveLayout { keyboard_name, layout_name })
|
|
||||||
}
|
|
||||||
"openwindow" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let window_address = fields.next().ok_or("Missing window_address")?.to_string();
|
|
||||||
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
|
||||||
let window_class = fields.next().ok_or("Missing window_class")?.to_string();
|
|
||||||
let window_title = fields.next().ok_or("Missing window_title")?.to_string();
|
|
||||||
Ok(HyprlandEvent::OpenWindow { window_address, workspace_name, window_class, window_title })
|
|
||||||
}
|
|
||||||
"closewindow" => Ok(HyprlandEvent::CloseWindow { window_address: data.to_string() }),
|
|
||||||
"movewindow" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let window_address = fields.next().ok_or("Missing window_address")?.to_string();
|
|
||||||
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
|
||||||
Ok(HyprlandEvent::MoveWindow { window_address, workspace_name })
|
|
||||||
}
|
|
||||||
"movewindowv2" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let window_address = fields.next().ok_or("Missing window_address")?.to_string();
|
|
||||||
let workspace_id = fields.next().ok_or("Missing workspace_id")?.parse::<u8>()?;
|
|
||||||
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
|
||||||
Ok(HyprlandEvent::MoveWindowV2 { window_address, workspace_id, workspace_name })
|
|
||||||
}
|
|
||||||
"openlayer" => Ok(HyprlandEvent::OpenLayer { namespace: data.to_string() }),
|
|
||||||
"closelayer" => Ok(HyprlandEvent::CloseLayer { namespace: data.to_string() }),
|
|
||||||
"submap" => Ok(HyprlandEvent::Submap { submap_name: data.to_string() }),
|
|
||||||
"changefloatingmode" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let window_address = fields.next().ok_or("Missing window_address")?.to_string();
|
|
||||||
let floating = fields.next().ok_or("Missing floating")?.parse::<u8>()?;
|
|
||||||
Ok(HyprlandEvent::ChangeFloatingMode { window_address, floating })
|
|
||||||
}
|
|
||||||
"urgent" => Ok(HyprlandEvent::Urgent { window_address: data.to_string() }),
|
|
||||||
"screencast" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let state = fields.next().ok_or("Missing state")?.parse::<u8>()?;
|
|
||||||
let owner = fields.next().ok_or("Missing owner")?.parse::<u8>()?;
|
|
||||||
Ok(HyprlandEvent::Screencast { state, owner })
|
|
||||||
}
|
|
||||||
"windowtitle" => Ok(HyprlandEvent::WindowTitle { window_address: data.to_string() }),
|
|
||||||
"windowtitlev2" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let window_address = fields.next().ok_or("Missing window_address")?.to_string();
|
|
||||||
let window_title = fields.next().ok_or("Missing window_title")?.to_string();
|
|
||||||
Ok(HyprlandEvent::WindowTitleV2 { window_address, window_title })
|
|
||||||
}
|
|
||||||
"togglegroup" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let toggle_status = fields.next().ok_or("Missing toggle_status")?.parse::<u8>()?;
|
|
||||||
let window_addresses: Vec<String> = fields.map(|s| s.to_string()).collect();
|
|
||||||
Ok(HyprlandEvent::ToggleGroup { toggle_status, window_addresses })
|
|
||||||
}
|
|
||||||
"moveintogroup" => Ok(HyprlandEvent::MoveIntoGroup { window_address: data.to_string() }),
|
|
||||||
"moveoutofgroup" => Ok(HyprlandEvent::MoveOutOfGroup { window_address: data.to_string() }),
|
|
||||||
"ignoregrouplock" => {
|
|
||||||
let value = data.parse::<u8>()?;
|
|
||||||
Ok(HyprlandEvent::IgnoreGroupLock { value })
|
|
||||||
}
|
|
||||||
"lockgroups" => {
|
|
||||||
let value = data.parse::<u8>()?;
|
|
||||||
Ok(HyprlandEvent::LockGroups { value })
|
|
||||||
}
|
|
||||||
"configreloaded" => Ok(HyprlandEvent::ConfigReloaded),
|
|
||||||
"pin" => {
|
|
||||||
let mut fields = data.split(',');
|
|
||||||
let window_address = fields.next().ok_or("Missing window_address")?.to_string();
|
|
||||||
let pin_state = fields.next().ok_or("Missing pin_state")?.parse::<u8>()?;
|
|
||||||
Ok(HyprlandEvent::Pin { window_address, pin_state })
|
|
||||||
}
|
|
||||||
_ => Err(format!("Unknown event type: {}", event_name).into()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// === Utility: Extract event type string for filtering ===
|
/// === Utility: Extract event type string for filtering ===
|
||||||
@@ -269,6 +207,316 @@ fn event_type(event: &HyprlandEvent) -> &'static str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// === Hyprland Events parsing ===
|
||||||
|
|
||||||
|
fn parse_event_line(line: &str) -> Result<HyprlandEvent, Box<dyn Error>> {
|
||||||
|
let line = line.trim();
|
||||||
|
let mut parts = line.split(">>");
|
||||||
|
let event_name = parts.next().ok_or("Missing event name")?;
|
||||||
|
let data = parts.next().unwrap_or("").trim();
|
||||||
|
|
||||||
|
match event_name {
|
||||||
|
"workspace" => Ok(HyprlandEvent::Workspace {
|
||||||
|
workspace_name: data.to_string(),
|
||||||
|
}),
|
||||||
|
"workspacev2" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let workspace_id = fields.next().ok_or("Missing workspace_id")?.parse::<u8>()?;
|
||||||
|
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
||||||
|
Ok(HyprlandEvent::WorkspaceV2 {
|
||||||
|
workspace_id,
|
||||||
|
workspace_name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"focusedmon" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let monitor_name = fields.next().ok_or("Missing monitor_name")?.to_string();
|
||||||
|
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
||||||
|
Ok(HyprlandEvent::FocusedMon {
|
||||||
|
monitor_name,
|
||||||
|
workspace_name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"focusedmonv2" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let monitor_name = fields.next().ok_or("Missing monitor_name")?.to_string();
|
||||||
|
let workspace_id = fields.next().ok_or("Missing workspace_id")?.parse::<u8>()?;
|
||||||
|
Ok(HyprlandEvent::FocusedMonV2 {
|
||||||
|
monitor_name,
|
||||||
|
workspace_id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"activewindow" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let window_class = fields.next().ok_or("Missing window_class")?.to_string();
|
||||||
|
let window_title = fields.next().ok_or("Missing window_title")?.to_string();
|
||||||
|
Ok(HyprlandEvent::ActiveWindow {
|
||||||
|
window_class,
|
||||||
|
window_title,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"activewindowv2" => Ok(HyprlandEvent::ActiveWindowV2 {
|
||||||
|
window_address: data.to_string(),
|
||||||
|
}),
|
||||||
|
"fullscreen" => {
|
||||||
|
let status = data.parse::<u8>()?;
|
||||||
|
Ok(HyprlandEvent::Fullscreen { status })
|
||||||
|
}
|
||||||
|
"monitorremoved" => Ok(HyprlandEvent::MonitorRemoved {
|
||||||
|
monitor_name: data.to_string(),
|
||||||
|
}),
|
||||||
|
"monitoradded" => Ok(HyprlandEvent::MonitorAdded {
|
||||||
|
monitor_name: data.to_string(),
|
||||||
|
}),
|
||||||
|
"monitoraddedv2" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let monitor_id = fields.next().ok_or("Missing monitor_id")?.parse::<u8>()?;
|
||||||
|
let monitor_name = fields.next().ok_or("Missing monitor_name")?.to_string();
|
||||||
|
let monitor_description = fields
|
||||||
|
.next()
|
||||||
|
.ok_or("Missing monitor_description")?
|
||||||
|
.to_string();
|
||||||
|
Ok(HyprlandEvent::MonitorAddedV2 {
|
||||||
|
monitor_id,
|
||||||
|
monitor_name,
|
||||||
|
monitor_description,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"createworkspace" => Ok(HyprlandEvent::CreateWorkspace {
|
||||||
|
workspace_name: data.to_string(),
|
||||||
|
}),
|
||||||
|
"createworkspacev2" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let workspace_id = fields.next().ok_or("Missing workspace_id")?.parse::<u8>()?;
|
||||||
|
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
||||||
|
Ok(HyprlandEvent::CreateWorkspaceV2 {
|
||||||
|
workspace_id,
|
||||||
|
workspace_name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"destroyworkspace" => Ok(HyprlandEvent::DestroyWorkspace {
|
||||||
|
workspace_name: data.to_string(),
|
||||||
|
}),
|
||||||
|
"destroyworkspacev2" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let workspace_id = fields.next().ok_or("Missing workspace_id")?.parse::<u8>()?;
|
||||||
|
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
||||||
|
Ok(HyprlandEvent::DestroyWorkspaceV2 {
|
||||||
|
workspace_id,
|
||||||
|
workspace_name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"moveworkspace" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
||||||
|
let monitor_name = fields.next().ok_or("Missing monitor_name")?.to_string();
|
||||||
|
Ok(HyprlandEvent::MoveWorkspace {
|
||||||
|
workspace_name,
|
||||||
|
monitor_name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"moveworkspacev2" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let workspace_id = fields.next().ok_or("Missing workspace_id")?.parse::<u8>()?;
|
||||||
|
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
||||||
|
let monitor_name = fields.next().ok_or("Missing monitor_name")?.to_string();
|
||||||
|
Ok(HyprlandEvent::MoveWorkspaceV2 {
|
||||||
|
workspace_id,
|
||||||
|
workspace_name,
|
||||||
|
monitor_name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"renameworkspace" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let workspace_id = fields.next().ok_or("Missing workspace_id")?.parse::<u8>()?;
|
||||||
|
let new_name = fields.next().ok_or("Missing new_name")?.to_string();
|
||||||
|
Ok(HyprlandEvent::RenameWorkspace {
|
||||||
|
workspace_id,
|
||||||
|
new_name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"activespecial" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
||||||
|
let monitor_name = fields.next().ok_or("Missing monitor_name")?.to_string();
|
||||||
|
Ok(HyprlandEvent::ActiveSpecial {
|
||||||
|
workspace_name,
|
||||||
|
monitor_name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"activelayout" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let keyboard_name = fields.next().ok_or("Missing keyboard_name")?.to_string();
|
||||||
|
let layout_name = fields.next().ok_or("Missing layout_name")?.to_string();
|
||||||
|
Ok(HyprlandEvent::ActiveLayout {
|
||||||
|
keyboard_name,
|
||||||
|
layout_name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"openwindow" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let window_address = fields.next().ok_or("Missing window_address")?.to_string();
|
||||||
|
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
||||||
|
let window_class = fields.next().ok_or("Missing window_class")?.to_string();
|
||||||
|
let window_title = fields.next().ok_or("Missing window_title")?.to_string();
|
||||||
|
Ok(HyprlandEvent::OpenWindow {
|
||||||
|
window_address,
|
||||||
|
workspace_name,
|
||||||
|
window_class,
|
||||||
|
window_title,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"closewindow" => Ok(HyprlandEvent::CloseWindow {
|
||||||
|
window_address: data.to_string(),
|
||||||
|
}),
|
||||||
|
"movewindow" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let window_address = fields.next().ok_or("Missing window_address")?.to_string();
|
||||||
|
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
||||||
|
Ok(HyprlandEvent::MoveWindow {
|
||||||
|
window_address,
|
||||||
|
workspace_name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"movewindowv2" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let window_address = fields.next().ok_or("Missing window_address")?.to_string();
|
||||||
|
let workspace_id = fields.next().ok_or("Missing workspace_id")?.parse::<u8>()?;
|
||||||
|
let workspace_name = fields.next().ok_or("Missing workspace_name")?.to_string();
|
||||||
|
Ok(HyprlandEvent::MoveWindowV2 {
|
||||||
|
window_address,
|
||||||
|
workspace_id,
|
||||||
|
workspace_name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"openlayer" => Ok(HyprlandEvent::OpenLayer {
|
||||||
|
namespace: data.to_string(),
|
||||||
|
}),
|
||||||
|
"closelayer" => Ok(HyprlandEvent::CloseLayer {
|
||||||
|
namespace: data.to_string(),
|
||||||
|
}),
|
||||||
|
"submap" => Ok(HyprlandEvent::Submap {
|
||||||
|
submap_name: data.to_string(),
|
||||||
|
}),
|
||||||
|
"changefloatingmode" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let window_address = fields.next().ok_or("Missing window_address")?.to_string();
|
||||||
|
let floating = fields.next().ok_or("Missing floating")?.parse::<u8>()?;
|
||||||
|
Ok(HyprlandEvent::ChangeFloatingMode {
|
||||||
|
window_address,
|
||||||
|
floating,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"urgent" => Ok(HyprlandEvent::Urgent {
|
||||||
|
window_address: data.to_string(),
|
||||||
|
}),
|
||||||
|
"screencast" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let state = fields.next().ok_or("Missing state")?.parse::<u8>()?;
|
||||||
|
let owner = fields.next().ok_or("Missing owner")?.parse::<u8>()?;
|
||||||
|
Ok(HyprlandEvent::Screencast { state, owner })
|
||||||
|
}
|
||||||
|
"windowtitle" => Ok(HyprlandEvent::WindowTitle {
|
||||||
|
window_address: data.to_string(),
|
||||||
|
}),
|
||||||
|
"windowtitlev2" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let window_address = fields.next().ok_or("Missing window_address")?.to_string();
|
||||||
|
let window_title = fields.next().ok_or("Missing window_title")?.to_string();
|
||||||
|
Ok(HyprlandEvent::WindowTitleV2 {
|
||||||
|
window_address,
|
||||||
|
window_title,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"togglegroup" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let toggle_status = fields
|
||||||
|
.next()
|
||||||
|
.ok_or("Missing toggle_status")?
|
||||||
|
.parse::<u8>()?;
|
||||||
|
let window_addresses: Vec<String> = fields.map(|s| s.to_string()).collect();
|
||||||
|
Ok(HyprlandEvent::ToggleGroup {
|
||||||
|
toggle_status,
|
||||||
|
window_addresses,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"moveintogroup" => Ok(HyprlandEvent::MoveIntoGroup {
|
||||||
|
window_address: data.to_string(),
|
||||||
|
}),
|
||||||
|
"moveoutofgroup" => Ok(HyprlandEvent::MoveOutOfGroup {
|
||||||
|
window_address: data.to_string(),
|
||||||
|
}),
|
||||||
|
"ignoregrouplock" => {
|
||||||
|
let value = data.parse::<u8>()?;
|
||||||
|
Ok(HyprlandEvent::IgnoreGroupLock { value })
|
||||||
|
}
|
||||||
|
"lockgroups" => {
|
||||||
|
let value = data.parse::<u8>()?;
|
||||||
|
Ok(HyprlandEvent::LockGroups { value })
|
||||||
|
}
|
||||||
|
"configreloaded" => Ok(HyprlandEvent::ConfigReloaded),
|
||||||
|
"pin" => {
|
||||||
|
let mut fields = data.split(',');
|
||||||
|
let window_address = fields.next().ok_or("Missing window_address")?.to_string();
|
||||||
|
let pin_state = fields.next().ok_or("Missing pin_state")?.parse::<u8>()?;
|
||||||
|
Ok(HyprlandEvent::Pin {
|
||||||
|
window_address,
|
||||||
|
pin_state,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => Err(format!("Unknown event type: {}", event_name).into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// === Structs for Interaction with Socket1
|
||||||
|
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct Workspace {
|
||||||
|
id: u32,
|
||||||
|
name: String,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
monitor: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
monitor_id: Option<u32>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
windows: Option<u32>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
has_fullscreen: Option<bool>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
last_window: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
last_window_title: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct Client {
|
||||||
|
address: String,
|
||||||
|
mapped: bool,
|
||||||
|
hidden: bool,
|
||||||
|
at: (i32, i32),
|
||||||
|
size: (i32, i32),
|
||||||
|
workspace: Workspace,
|
||||||
|
floating: bool,
|
||||||
|
pseudo: bool,
|
||||||
|
monitor: u8,
|
||||||
|
class: String,
|
||||||
|
title: String,
|
||||||
|
initial_class: String,
|
||||||
|
initial_title: String,
|
||||||
|
pid: u32,
|
||||||
|
xwayland: bool,
|
||||||
|
pinned: bool,
|
||||||
|
fullscreen: i32,
|
||||||
|
fullscreen_client: i32,
|
||||||
|
grouped: Vec<String>,
|
||||||
|
tags: Vec<String>,
|
||||||
|
swallowing: String,
|
||||||
|
#[serde(rename = "focusHistoryID")]
|
||||||
|
focus_history_id: i32,
|
||||||
|
inhibiting_idle: bool,
|
||||||
|
}
|
||||||
|
|
||||||
/// === Client Subscription Infrastructure ===
|
/// === Client Subscription Infrastructure ===
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -316,7 +564,8 @@ fn client_handler(stream: UnixStream, subscriptions: Arc<Mutex<Vec<ClientHandle>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let subscription_line = subscription_line.trim();
|
let subscription_line = subscription_line.trim();
|
||||||
let subscription = if subscription_line.is_empty() || subscription_line.to_lowercase() == "all" {
|
let subscription = if subscription_line.is_empty() || subscription_line.to_lowercase() == "all"
|
||||||
|
{
|
||||||
Subscription::All
|
Subscription::All
|
||||||
} else {
|
} else {
|
||||||
let filters: HashSet<String> = subscription_line
|
let filters: HashSet<String> = subscription_line
|
||||||
@@ -332,7 +581,10 @@ fn client_handler(stream: UnixStream, subscriptions: Arc<Mutex<Vec<ClientHandle>
|
|||||||
|
|
||||||
{
|
{
|
||||||
let mut subs = subscriptions.lock().unwrap();
|
let mut subs = subscriptions.lock().unwrap();
|
||||||
subs.push(ClientHandle { sender: tx, subscription });
|
subs.push(ClientHandle {
|
||||||
|
sender: tx,
|
||||||
|
subscription,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop and write events to the client.
|
// Loop and write events to the client.
|
||||||
@@ -401,9 +653,8 @@ fn hyprland_event_thread(subscriptions: Arc<Mutex<Vec<ClientHandle>>>) {
|
|||||||
fn client_server_thread(client_socket_path: String, subscriptions: Arc<Mutex<Vec<ClientHandle>>>) {
|
fn client_server_thread(client_socket_path: String, subscriptions: Arc<Mutex<Vec<ClientHandle>>>) {
|
||||||
// Remove existing socket file if present.
|
// Remove existing socket file if present.
|
||||||
let _ = fs::remove_file(&client_socket_path);
|
let _ = fs::remove_file(&client_socket_path);
|
||||||
let listener = UnixListener::bind(&client_socket_path).unwrap_or_else(|e| {
|
let listener = UnixListener::bind(&client_socket_path)
|
||||||
panic!("Failed to bind client socket {}: {}", client_socket_path, e)
|
.unwrap_or_else(|e| panic!("Failed to bind client socket {}: {}", client_socket_path, e));
|
||||||
});
|
|
||||||
info!("Client server listening on {}", client_socket_path);
|
info!("Client server listening on {}", client_socket_path);
|
||||||
|
|
||||||
for stream in listener.incoming() {
|
for stream in listener.incoming() {
|
||||||
@@ -418,9 +669,8 @@ fn client_server_thread(client_socket_path: String, subscriptions: Arc<Mutex<Vec
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_socket(socket_path: &str) -> UnixStream {
|
fn create_socket(socket_path: &str) -> UnixStream {
|
||||||
UnixStream::connect(socket_path).unwrap_or_else(|err| {
|
UnixStream::connect(socket_path)
|
||||||
panic!("Could not connect to socket {}: {}", socket_path, err)
|
.unwrap_or_else(|err| panic!("Could not connect to socket {}: {}", socket_path, err))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The main daemon functionality: spawn threads, handle signals, etc.
|
/// The main daemon functionality: spawn threads, handle signals, etc.
|
||||||
@@ -478,7 +728,10 @@ fn run_client(config: &Config, subscription: &str) {
|
|||||||
eprintln!("Failed to send subscription: {}", e);
|
eprintln!("Failed to send subscription: {}", e);
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
println!("Subscribed to '{}' events. Waiting for events...", subscription);
|
println!(
|
||||||
|
"Subscribed to '{}' events. Waiting for events...",
|
||||||
|
subscription
|
||||||
|
);
|
||||||
|
|
||||||
let reader = BufReader::new(stream);
|
let reader = BufReader::new(stream);
|
||||||
for line in reader.lines() {
|
for line in reader.lines() {
|
||||||
@@ -498,64 +751,84 @@ fn run_client(config: &Config, subscription: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_activewindow_client(config: &Config) {
|
/// Prints the active window as json
|
||||||
let hypr_rundir_path = get_hypr_rundir_path();
|
|
||||||
info!("Using hypr runtime directory: {}", hypr_rundir_path);
|
|
||||||
|
|
||||||
let socket1_path = format!("{}/.socket1.sock", hypr_rundir_path);
|
fn run_activewindow_client(config: &Config) {
|
||||||
info!("Using hypr socket2 path: {}", socket1_path);
|
let subscription_line = "activewindowv2,fullscreen,closewindow,movewindow,changefloatingmode,moveintogroup,moveoutofgroup,togglegroup,pin,windowtitle\n";
|
||||||
match UnixStream::connect(&config.client_socket_path) {
|
info!("Using subscription line: {}", subscription_line);
|
||||||
|
let event_reader = match UnixStream::connect(&config.client_socket_path) {
|
||||||
Ok(mut stream) => {
|
Ok(mut stream) => {
|
||||||
let subscription_line = "activewindowv2,openwindow,closewindow,movewindow\n";
|
|
||||||
if let Err(e) = stream.write_all(subscription_line.as_bytes()) {
|
if let Err(e) = stream.write_all(subscription_line.as_bytes()) {
|
||||||
eprintln!("Failed to send subscription: {}", e);
|
eprintln!("Failed to send subscription: {}", e);
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
println!("Successfully connected to daemon.");
|
println!("Successfully connected to daemon.");
|
||||||
match UnixStream::connect(&socket1_path) {
|
BufReader::new(stream)
|
||||||
Ok(mut stream1) => {
|
|
||||||
let query = "activewindow";
|
|
||||||
let reader = BufReader::new(stream);
|
|
||||||
for line in reader.lines() {
|
|
||||||
match line {
|
|
||||||
Ok(msg) => {
|
|
||||||
println!("{}", msg);
|
|
||||||
if let Err(e) = stream1.write_all(query.as_bytes()) {
|
|
||||||
eprintln!("Failed to send query: {}", e);
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
|
||||||
println!("Successfully sent query to daemon.");
|
|
||||||
let mut response = String::new();
|
|
||||||
stream1.read_to_string(&mut response).unwrap();
|
|
||||||
println!("{}", response);
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Error reading from daemon: {}", e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Failed to connect to socket1: {}", e);
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Failed to connect to daemon. Is it running? Error: {}", e);
|
eprintln!("Failed to connect to daemon. Is it running? Error: {}", e);
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
let mut clients = query_socket(QueryModes::Clients);
|
||||||
|
for event_line in event_reader.lines() {
|
||||||
|
let event: HyprlandEvent =
|
||||||
|
serde_json::from_str(&event_line.unwrap()).expect("Failed to parse event");
|
||||||
|
match event {
|
||||||
|
HyprlandEvent::ActiveWindowV2 { window_address } => {
|
||||||
|
if let Some(client) = clients.get(&format!("0x{}", window_address)) {
|
||||||
|
println!("{:#?}", serde_json::to_string(&client).unwrap());
|
||||||
|
} else {
|
||||||
|
clients = query_socket(QueryModes::Clients);
|
||||||
|
if let Some(client) = clients.get(&format!("0x{}", window_address)) {
|
||||||
|
println!("{}", serde_json::to_string(&client).unwrap());
|
||||||
|
} else {
|
||||||
|
eprintln!("Failed to find window address {}", window_address);
|
||||||
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
clients = query_socket(QueryModes::Clients);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum QueryModes {
|
||||||
|
Clients,
|
||||||
|
Workspaces,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// === Helper functions for clients that also query socket1 ===
|
||||||
|
fn query_socket(mode: QueryModes) -> HashMap<String, Client> {
|
||||||
|
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");
|
||||||
|
clients
|
||||||
|
.into_iter()
|
||||||
|
.map(|c| (c.address.clone(), c))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
/// === Daemon Control Functions ===
|
/// === Daemon Control Functions ===
|
||||||
|
|
||||||
fn stop_daemon() -> Result<(), Box<dyn Error>> {
|
fn stop_daemon() -> Result<(), Box<dyn Error>> {
|
||||||
// Compute pid file path from $XDG_RUNTIME_DIR/hyprman/
|
// Compute pid file path from $XDG_RUNTIME_DIR/hyprman/
|
||||||
let xdg_runtime_dir = env::var("XDG_RUNTIME_DIR")
|
let xdg_runtime_dir = env::var("XDG_RUNTIME_DIR").expect("XDG_RUNTIME_DIR not set");
|
||||||
.expect("XDG_RUNTIME_DIR not set");
|
|
||||||
let hyprman_dir = format!("{}/hyprman", xdg_runtime_dir);
|
let hyprman_dir = format!("{}/hyprman", xdg_runtime_dir);
|
||||||
let pid_file_path = format!("{}/hyprman.pid", hyprman_dir);
|
let pid_file_path = format!("{}/hyprman.pid", hyprman_dir);
|
||||||
let pid_str = fs::read_to_string(&pid_file_path)?;
|
let pid_str = fs::read_to_string(&pid_file_path)?;
|
||||||
@@ -585,7 +858,9 @@ fn print_help() {
|
|||||||
println!(" -d, --daemon Run as daemon");
|
println!(" -d, --daemon Run as daemon");
|
||||||
println!(" -r, --restart Restart the daemon");
|
println!(" -r, --restart Restart the daemon");
|
||||||
println!(" -k, --kill Stop the daemon");
|
println!(" -k, --kill Stop the daemon");
|
||||||
println!(" -f, --filter [event] Run in client mode, subscribing to [event] (default: all)");
|
println!(
|
||||||
|
" -f, --filter [event] Run in client mode, subscribing to [event] (default: all)"
|
||||||
|
);
|
||||||
println!(" -h, --help Show this help message");
|
println!(" -h, --help Show this help message");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -600,12 +875,10 @@ fn main() {
|
|||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
// Ensure $XDG_RUNTIME_DIR/hyprman/ exists.
|
// Ensure $XDG_RUNTIME_DIR/hyprman/ exists.
|
||||||
let xdg_runtime_dir = env::var("XDG_RUNTIME_DIR")
|
let xdg_runtime_dir = env::var("XDG_RUNTIME_DIR").expect("XDG_RUNTIME_DIR not set");
|
||||||
.expect("XDG_RUNTIME_DIR not set");
|
|
||||||
let hyprman_dir = format!("{}/hyprman", xdg_runtime_dir);
|
let hyprman_dir = format!("{}/hyprman", xdg_runtime_dir);
|
||||||
if fs::metadata(&hyprman_dir).is_err() {
|
if fs::metadata(&hyprman_dir).is_err() {
|
||||||
fs::create_dir_all(&hyprman_dir)
|
fs::create_dir_all(&hyprman_dir).expect("Failed to create hyprman runtime directory");
|
||||||
.expect("Failed to create hyprman runtime directory");
|
|
||||||
}
|
}
|
||||||
// If the socket path from the config is relative, interpret it relative to hyprman_dir.
|
// If the socket path from the config is relative, interpret it relative to hyprman_dir.
|
||||||
if !config.client_socket_path.starts_with("/") {
|
if !config.client_socket_path.starts_with("/") {
|
||||||
|
Reference in New Issue
Block a user