use crate::shared::*;
use std::string::ToString;
use derive_more::Display;
#[derive(Debug, Clone)]
pub enum WindowIdentifier<'a> {
Address(Address),
ClassRegularExpression(&'a str),
Title(&'a str),
ProcessId(u32),
}
impl std::fmt::Display for WindowIdentifier<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let out = match self {
WindowIdentifier::Address(addr) => format!("address:{addr}"),
WindowIdentifier::ProcessId(id) => format!("pid:{id}"),
WindowIdentifier::ClassRegularExpression(regex) => regex.to_string(),
WindowIdentifier::Title(title) => format!("title:{title}"),
};
write!(f, "{out}")
}
}
#[derive(Debug, Clone, Display)]
pub enum FullscreenType {
#[display(fmt = "0")]
Real,
#[display(fmt = "1")]
Maximize,
#[display(fmt = "")]
NoParam,
}
#[derive(Debug, Clone, Display)]
#[allow(missing_docs)]
pub enum Direction {
#[display(fmt = "u")]
Up,
#[display(fmt = "d")]
Down,
#[display(fmt = "r")]
Right,
#[display(fmt = "l")]
Left,
}
#[derive(Debug, Clone)]
pub enum Position {
Delta(i16, i16),
Exact(i16, i16),
}
impl std::fmt::Display for Position {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let out = match self {
Position::Delta(x, y) => format!("{x} {y}"),
Position::Exact(w, h) => format!("exact {w} {h}"),
};
write!(f, "{out}")
}
}
#[allow(missing_docs)]
#[derive(Debug, Clone, Display)]
pub enum CycleDirection {
#[display(fmt = "")]
Next,
#[display(fmt = "prev")]
Previous,
}
#[allow(missing_docs)]
#[derive(Debug, Clone, Display)]
pub enum WindowSwitchDirection {
#[display(fmt = "b")]
Back,
#[display(fmt = "f")]
Forward,
}
#[derive(Debug, Clone)]
pub enum MonitorIdentifier<'a> {
Direction(Direction),
Id(u8),
Name(&'a str),
Current,
Relative(i32),
}
impl std::fmt::Display for MonitorIdentifier<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let out = match self {
MonitorIdentifier::Direction(dir) => dir.to_string(),
MonitorIdentifier::Id(id) => id.to_string(),
MonitorIdentifier::Name(name) => name.to_string(),
MonitorIdentifier::Current => "current".to_string(),
MonitorIdentifier::Relative(int) => format_relative(*int, ""),
};
write!(f, "{out}")
}
}
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub enum Corner {
TopRight = 0,
TopLeft = 1,
BottomRight = 2,
BottomLeft = 3,
}
#[derive(Debug, Clone, Display)]
pub enum WorkspaceOptions {
#[display(fmt = "allfloat")]
AllPseudo,
#[display(fmt = "allpseudo")]
AllFloat,
}
#[derive(Debug, Clone)]
pub enum WorkspaceIdentifierWithSpecial<'a> {
Id(WorkspaceId),
Relative(i32),
RelativeMonitor(i32),
RelativeMonitorIncludingEmpty(i32),
RelativeOpen(i32),
Previous,
Empty,
Name(&'a str),
Special(Option<&'a str>),
}
impl std::fmt::Display for WorkspaceIdentifierWithSpecial<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use WorkspaceIdentifierWithSpecial::*;
let out = match self {
Id(id) => format!("{id}"),
Name(name) => format!("name:{name}"),
Relative(int) => format_relative(*int, ""),
RelativeMonitor(int) => format_relative(*int, "m"),
RelativeMonitorIncludingEmpty(int) => format_relative(*int, "r"),
RelativeOpen(int) => format_relative(*int, "e"),
Previous => "previous".to_string(),
Empty => "empty".to_string(),
Special(opt) => match opt {
Some(name) => format!("special:{name}"),
None => "special".to_string(),
},
};
write!(f, "{out}")
}
}
#[derive(Debug, Clone)]
pub enum WorkspaceIdentifier<'a> {
Id(WorkspaceId),
Relative(i32),
RelativeMonitor(i32),
RelativeMonitorIncludingEmpty(i32),
RelativeOpen(i32),
Previous,
Empty,
Name(&'a str),
}
impl std::fmt::Display for WorkspaceIdentifier<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use WorkspaceIdentifier::*;
let out = match self {
Id(id) => format!("{id}"),
Name(name) => format!("name:{name}"),
Relative(int) => format_relative(*int, ""),
RelativeMonitor(int) => format_relative(*int, "m"),
RelativeMonitorIncludingEmpty(int) => format_relative(*int, "r"),
RelativeOpen(int) => format_relative(*int, "e"),
Previous => "previous".to_string(),
Empty => "empty".to_string(),
};
write!(f, "{out}")
}
}
#[derive(Debug, Clone)]
pub enum WindowMove<'a> {
Monitor(MonitorIdentifier<'a>),
Direction(Direction),
}
#[derive(Debug, Clone)]
pub enum DispatchType<'a> {
Custom(
&'a str,
&'a str,
),
SetCursor(
&'a str,
u16,
),
Exec(&'a str),
Pass(WindowIdentifier<'a>),
Global(&'a str),
KillActiveWindow,
CloseWindow(WindowIdentifier<'a>),
Workspace(WorkspaceIdentifierWithSpecial<'a>),
MoveToWorkspace(
WorkspaceIdentifierWithSpecial<'a>,
Option<WindowIdentifier<'a>>,
),
MoveToWorkspaceSilent(
WorkspaceIdentifierWithSpecial<'a>,
Option<WindowIdentifier<'a>>,
),
#[deprecated(since = "0.3.13", note = "use MoveToWorkspace(work, None) instead")]
MoveFocusedWindowToWorkspace(WorkspaceIdentifier<'a>),
#[deprecated(
since = "0.3.13",
note = "use MoveToWorkspaceSilent(work, None) instead"
)]
MoveFocusedWindowToWorkspaceSilent(WorkspaceIdentifier<'a>),
ToggleFloating(Option<WindowIdentifier<'a>>),
ToggleFullscreen(FullscreenType),
ToggleFakeFullscreen,
ToggleDPMS(bool, Option<&'a str>),
TogglePseudo,
TogglePin,
MoveFocus(Direction),
MoveWindow(WindowMove<'a>),
CenterWindow,
ResizeActive(Position),
MoveActive(Position),
ResizeWindowPixel(Position, WindowIdentifier<'a>),
MoveWindowPixel(Position, WindowIdentifier<'a>),
CycleWindow(CycleDirection),
SwapWindow(CycleDirection),
FocusWindow(WindowIdentifier<'a>),
FocusMonitor(MonitorIdentifier<'a>),
ChangeSplitRatio(f32),
ToggleOpaque,
MoveCursorToCorner(Corner),
MoveCursor(i64, i64),
WorkspaceOption(WorkspaceOptions),
RenameWorkspace(WorkspaceId, Option<&'a str>),
Exit,
ForceRendererReload,
MoveCurrentWorkspaceToMonitor(MonitorIdentifier<'a>),
MoveWorkspaceToMonitor(WorkspaceIdentifier<'a>, MonitorIdentifier<'a>),
SwapActiveWorkspaces(MonitorIdentifier<'a>, MonitorIdentifier<'a>),
BringActiveToTop,
ToggleSpecialWorkspace(Option<String>),
FocusUrgentOrLast,
FocusCurrentOrLast,
ToggleSplit,
SwapWithMaster(SwapWithMasterParam),
FocusMaster(FocusMasterParam),
AddMaster,
RemoveMaster,
OrientationLeft,
OrientationRight,
OrientationTop,
OrientationBottom,
OrientationCenter,
OrientationNext,
OrientationPrev,
ToggleGroup,
ChangeGroupActive(WindowSwitchDirection),
LockGroups(LockType),
MoveIntoGroup(Direction),
MoveOutOfGroup,
}
#[derive(Debug, Clone, Copy, Display, PartialEq, Eq, PartialOrd, Ord)]
pub enum LockType {
#[display(fmt = "lock")]
Lock,
#[display(fmt = "unlock")]
Unlock,
#[display(fmt = "toggle")]
ToggleLock,
}
#[derive(Debug, Clone, Display)]
pub enum SwapWithMasterParam {
#[display(fmt = "master")]
Master,
#[display(fmt = "child")]
Child,
#[display(fmt = "auto")]
Auto,
}
#[derive(Debug, Clone, Display)]
pub enum FocusMasterParam {
#[display(fmt = "master")]
Master,
#[display(fmt = "auto")]
Auto,
}
fn format_relative<T: Ord + std::fmt::Display + num_traits::Signed>(
int: T,
extra: &'_ str,
) -> String {
if int.is_positive() {
format!("{extra}+{int}")
} else if int.is_negative() {
format!("{extra}-{int}", int = int.abs())
} else {
"+0".to_string()
}
}
pub(crate) fn gen_dispatch_str(cmd: DispatchType, dispatch: bool) -> crate::Result<CommandContent> {
use DispatchType::*;
let sep = if dispatch { " " } else { "," };
let string_to_pass = match &cmd {
Custom(name, args) => format!("{name}{sep}{args}"),
Exec(sh) => format!("exec{sep}{sh}"),
Pass(win) => format!("pass{sep}{win}"),
Global(name) => format!("global{sep}{name}"),
KillActiveWindow => "killactive".to_string(),
CloseWindow(win) => format!("closewindow{sep}{win}"),
Workspace(work) => format!("workspace{sep}{work}"),
MoveToWorkspace(work, Some(win)) => format!("movetoworkspace{sep}{work},{win}"),
MoveToWorkspace(work, None) => format!("movetoworkspace{sep}{work}"),
MoveToWorkspaceSilent(work, Some(win)) => format!("movetoworkspacesilent{sep}{work},{win}"),
MoveToWorkspaceSilent(work, None) => format!("movetoworkspacesilent{sep}{work}"),
MoveFocusedWindowToWorkspace(work) => format!("movetoworkspace{sep}{work}"),
MoveFocusedWindowToWorkspaceSilent(work) => format!("movetoworkspacesilent{sep}{work}"),
ToggleFloating(Some(v)) => format!("togglefloating{sep}{v}"),
ToggleFloating(None) => "togglefloating".to_string(),
ToggleFullscreen(ftype) => format!("fullscreen{sep}{ftype}"),
ToggleFakeFullscreen => "fakefullscreen".to_string(),
ToggleDPMS(stat, mon) => {
format!(
"dpms{sep}{} {}",
if *stat { "on" } else { "off" },
mon.unwrap_or_default()
)
}
TogglePseudo => "pseudo".to_string(),
TogglePin => "pin".to_string(),
MoveFocus(dir) => format!("movefocus{sep}{dir}",),
MoveWindow(ident) => format!(
"movewindow{sep}{}",
match ident {
WindowMove::Direction(dir) => dir.to_string(),
WindowMove::Monitor(mon) => format!("mon:{mon}"),
}
),
CenterWindow => "centerwindow".to_string(),
ResizeActive(pos) => format!("resizeactive{sep}{pos}"),
MoveActive(pos) => format!("moveactive {pos}"),
ResizeWindowPixel(pos, win) => format!("resizewindowpixel{sep}{pos},{win}"),
MoveWindowPixel(pos, win) => format!("movewindowpixel{sep}{pos},{win}"),
CycleWindow(dir) => format!("cyclenext{sep}{dir}"),
SwapWindow(dir) => format!("swapnext{sep}{dir}"),
FocusWindow(win) => format!("focuswindow{sep}{win}"),
FocusMonitor(mon) => format!("focusmonitor{sep}{mon}"),
ChangeSplitRatio(ratio) => format!("splitratio {ratio}"),
ToggleOpaque => "toggleopaque".to_string(),
MoveCursorToCorner(corner) => format!("movecursortocorner{sep}{}", corner.clone() as u8),
MoveCursor(x, y) => format!("movecursor{sep}{x} {y}"),
WorkspaceOption(opt) => format!("workspaceopt{sep}{opt}"),
Exit => "exit".to_string(),
ForceRendererReload => "forcerendererreload".to_string(),
MoveCurrentWorkspaceToMonitor(mon) => format!("movecurrentworkspacetomonitor{sep}{mon}"),
MoveWorkspaceToMonitor(work, mon) => format!("moveworkspacetomonitor{sep}{work} {mon}"),
ToggleSpecialWorkspace(Some(name)) => format!("togglespecialworkspace {name}"),
ToggleSpecialWorkspace(None) => "togglespecialworkspace".to_string(),
RenameWorkspace(id, name) => {
format!(
"renameworkspace{sep}{id} {}",
name.unwrap_or(&id.to_string())
)
}
SwapActiveWorkspaces(mon, mon2) => format!("swapactiveworkspaces{sep}{mon} {mon2}",),
BringActiveToTop => "bringactivetotop".to_string(),
SetCursor(theme, size) => format!("{theme} {}", *size),
FocusUrgentOrLast => "focusurgentorlast".to_string(),
FocusCurrentOrLast => "focuscurrentorlast".to_string(),
ToggleSplit => "togglesplit".to_string(),
SwapWithMaster(param) => format!("swapwithmaster{sep}{param}"),
FocusMaster(param) => format!("focusmaster{sep}{param}"),
AddMaster => "addmaster".to_string(),
RemoveMaster => "removemaster".to_string(),
OrientationLeft => "orientationleft".to_string(),
OrientationRight => "orientationright".to_string(),
OrientationTop => "orientationtop".to_string(),
OrientationBottom => "orientationbottom".to_string(),
OrientationCenter => "orientationcenter".to_string(),
OrientationNext => "orientationnext".to_string(),
OrientationPrev => "orientationprev".to_string(),
ToggleGroup => "togglegroup".to_string(),
ChangeGroupActive(dir) => format!("changegroupactive{sep}{dir}"),
LockGroups(how) => format!("lockgroups{sep}{how}"),
MoveIntoGroup(dir) => format!("moveintogroup{sep}{dir}"),
MoveOutOfGroup => "moveoutofgroup".to_string(),
};
if let SetCursor(_, _) = cmd {
Ok(command!(JSON, "setcursor {string_to_pass}"))
} else if dispatch {
Ok(command!(JSON, "dispatch {string_to_pass}"))
} else {
Ok(command!(Empty, "{string_to_pass}"))
}
}
pub struct Dispatch;
impl Dispatch {
pub fn call(dispatch_type: DispatchType) -> crate::Result<()> {
let socket_path = get_socket_path(SocketType::Command);
let output = write_to_socket_sync(socket_path, gen_dispatch_str(dispatch_type, true)?);
match output {
Ok(msg) => match msg.as_str() {
"ok" => Ok(()),
msg => Err(HyprError::NotOkDispatch(msg.to_string())),
},
Err(error) => Err(error),
}
}
pub async fn call_async(dispatch_type: DispatchType<'_>) -> crate::Result<()> {
let socket_path = get_socket_path(SocketType::Command);
let output = write_to_socket(socket_path, gen_dispatch_str(dispatch_type, true)?).await;
match output {
Ok(msg) => match msg.as_str() {
"ok" => Ok(()),
msg => Err(HyprError::NotOkDispatch(msg.to_string())),
},
Err(error) => Err(error),
}
}
}
#[macro_export]
macro_rules! dispatch {
($dis:ident, $( $arg:expr ), *) => {
Dispatch::call(DispatchType::$dis($($arg), *))
};
(async; $dis:ident, $( $arg:expr ), *) => {
Dispatch::call_async(DispatchType::$dis($($arg), *))
};
}