Skip to main content

hyprshell_hyprland/
dispatch.rs

1//! # Dispatch module
2//!
3//! This module is used for calling dispatchers and changing keywords
4//!
5//! ## Usage
6//!
7//! ```rust
8//! use hyprland::Result;
9//! use hyprland::dispatch::{Dispatch, DispatchType};
10//! fn main() -> Result<()> {
11//!     Dispatch::call(DispatchType::Exec("kitty"))?;
12//!
13//!    Ok(())
14//! }
15//! ````
16
17use crate::default_instance;
18use crate::dispatch::fmt::*;
19use crate::error::HyprError;
20use crate::shared::*;
21use derive_more::Display;
22use std::string::ToString;
23
24/// This enum is for identifying a window
25#[derive(Debug, Clone, Display)]
26pub enum WindowIdentifier<'a> {
27    /// The address of a window
28    #[display("address:{_0}")]
29    Address(Address),
30    /// A Regular Expression to match the window class (handled by Hyprland)
31    #[display("class:{_0}")]
32    ClassRegularExpression(&'a str),
33    /// The window title
34    #[display("title:{_0}")]
35    Title(&'a str),
36    /// A window tag regex
37    #[display("tag:{_0}")]
38    Tag(&'a str),
39    /// The window's process Id
40    #[display("pid:{_0}")]
41    ProcessId(u32),
42    /// The active window
43    #[display("activewindow")]
44    ActiveWindow,
45    /// The first floating window
46    #[display("floating")]
47    Floating,
48    /// The first tiled window
49    #[display("tiled")]
50    Tiled,
51}
52
53/// This enum holds the fullscreen types
54#[derive(Debug, Clone, Display)]
55pub enum FullscreenType {
56    /// Fills the whole screen
57    #[display("0")]
58    Real,
59    /// Maximizes the window
60    #[display("1")]
61    Maximize,
62    /// Passes no param
63    #[display("")]
64    NoParam,
65}
66
67/// This enum holds the params to the [DispatchType::ToggleFullscreenState] dispatcher
68#[allow(missing_docs)]
69#[derive(Debug, Clone, Copy)]
70pub enum FullscreenState {
71    Current = -1,
72    None = 0,
73    Maximize = 1,
74    Fullscreen = 2,
75    MaximizeFullscreen = 3,
76}
77
78impl std::fmt::Display for FullscreenState {
79    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80        write!(f, "{}", *self as i8)
81    }
82}
83
84/// This enum holds directions, typically used for moving
85#[derive(Debug, Clone, Display)]
86#[allow(missing_docs)]
87pub enum Direction {
88    #[display("u")]
89    Up,
90    #[display("d")]
91    Down,
92    #[display("r")]
93    Right,
94    #[display("l")]
95    Left,
96}
97
98/// This enum is used for resizing and moving windows precisely
99#[derive(Debug, Clone, Display)]
100pub enum Position {
101    /// A delta in pixels
102    #[display("{_0} {_0}")]
103    Delta(i16, i16),
104    /// The exact size in pixels
105    #[display("exact {_0} {_0}")]
106    Exact(i16, i16),
107    /// A delta in window fraction
108    #[display("{_0}% {_0}%")]
109    DeltaFraction(i16, i16),
110    /// The exact size in screen fraction
111    #[display("exact {_0}% {_0}%")]
112    ExactFraction(i16, i16),
113}
114
115/// This enum holds a direction for cycling
116#[allow(missing_docs)]
117#[derive(Debug, Clone, Display)]
118pub enum CycleDirection {
119    #[display("")]
120    Next,
121    #[display("prev")]
122    Previous,
123}
124
125/// This enum holds a direction for switch windows in a group
126#[allow(missing_docs)]
127#[derive(Debug, Clone, Display)]
128pub enum WindowSwitchDirection {
129    #[display("b")]
130    Back,
131    #[display("f")]
132    Forward,
133    #[display("{}", _0)]
134    Index(i32),
135}
136
137/// This enum is used for identifying monitors
138#[derive(Debug, Clone)]
139pub enum MonitorIdentifier<'a> {
140    /// The monitor that is to the specified direction of the active one
141    Direction(Direction),
142    /// The monitor id
143    Id(MonitorId),
144    /// The monitor name
145    Name(&'a str),
146    /// The current monitor
147    Current,
148    /// The workspace relative to the current workspace
149    Relative(i32),
150}
151
152impl std::fmt::Display for MonitorIdentifier<'_> {
153    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154        let out = match self {
155            MonitorIdentifier::Direction(dir) => dir.to_string(),
156            MonitorIdentifier::Id(id) => id.to_string(),
157            MonitorIdentifier::Name(name) => name.to_string(),
158            MonitorIdentifier::Current => "current".to_string(),
159            MonitorIdentifier::Relative(int) => format_relative(*int, ""),
160        };
161        write!(f, "{out}")
162    }
163}
164
165/// This enum holds corners
166#[allow(missing_docs)]
167#[derive(Debug, Clone)]
168pub enum Corner {
169    BottomLeft = 0,
170    BottomRight = 1,
171    TopRight = 2,
172    TopLeft = 3,
173}
174
175/// This enum holds options that are applied to the current workspace
176#[derive(Debug, Clone, Display)]
177pub enum WorkspaceOptions {
178    /// Makes all windows pseudo tiled
179    #[display("allfloat")]
180    AllPseudo,
181    /// Makes all windows float
182    #[display("allpseudo")]
183    AllFloat,
184}
185
186/// This struct holds options for the first empty workspace
187#[derive(Debug, Clone, Copy, PartialEq, Eq)]
188pub struct FirstEmpty {
189    /// If the first empty workspace should be on the monitor
190    pub on_monitor: bool,
191    /// If the first empty workspace should be next
192    pub next: bool,
193}
194
195impl std::fmt::Display for FirstEmpty {
196    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
197        let mut s = String::new();
198        if self.on_monitor {
199            s.push('m');
200        }
201        if self.next {
202            s.push('n');
203        }
204        write!(f, "{s}")
205    }
206}
207
208/// This enum is for identifying workspaces that also includes the special workspace
209#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
210pub enum WorkspaceIdentifierWithSpecial<'a> {
211    /// The workspace Id
212    Id(WorkspaceId),
213    /// The workspace relative to the current workspace
214    #[display("{}", format_relative(*_0, ""))]
215    Relative(i32),
216    /// The workspace on the monitor relative to the current workspace
217    #[display("{}", format_relative(*_0, "m"))]
218    RelativeMonitor(i32),
219    /// The workspace on the monitor relative to the current workspace, including empty workspaces
220    #[display("{}", format_relative(*_0, "r"))]
221    RelativeMonitorIncludingEmpty(i32),
222    /// The open workspace relative to the current workspace
223    #[display("{}", format_relative(*_0, "e"))]
224    RelativeOpen(i32),
225    /// The previous Workspace
226    #[display("previous")]
227    Previous,
228    /// The previous Workspace
229    #[display("previous_per_monitor")]
230    PreviousPerMonitor,
231    /// The first available empty workspace
232    #[display("{}", format!("empty{}", _0))]
233    Empty(FirstEmpty),
234    /// The name of the workspace
235    #[display("name:{_0}")]
236    Name(&'a str),
237    /// The special workspace
238    #[display("special{}", format_special_workspace_ident(_0))]
239    Special(Option<&'a str>),
240}
241
242pub(super) mod fmt {
243    #[inline(always)]
244    pub(super) fn format_special_workspace_ident<'a>(opt: &'a Option<&'a str>) -> String {
245        match opt {
246            Some(o) => ":".to_owned() + o,
247            None => String::new(),
248        }
249    }
250
251    #[inline(always)]
252    pub(super) fn format_relative(int: i32, extra: &'_ str) -> String {
253        if int.is_positive() {
254            format!("{extra}+{int}")
255        } else if int.is_negative() {
256            format!("{extra}-{}", int.abs())
257        } else {
258            "+0".to_owned()
259        }
260    }
261}
262
263/// This enum is for identifying workspaces
264#[derive(Debug, Clone, Copy, PartialEq, Eq)]
265pub enum WorkspaceIdentifier<'a> {
266    /// The workspace Id
267    Id(WorkspaceId),
268    /// The workspace relative to the current workspace
269    Relative(i32),
270    /// The workspace on the monitor relative to the current workspace
271    RelativeMonitor(i32),
272    /// The workspace on the monitor relative to the current workspace, including empty workspaces
273    RelativeMonitorIncludingEmpty(i32),
274    /// The open workspace relative to the current workspace
275    RelativeOpen(i32),
276    /// The previous Workspace
277    Previous,
278    /// The first available empty workspace
279    Empty,
280    /// The name of the workspace
281    Name(&'a str),
282}
283
284impl std::fmt::Display for WorkspaceIdentifier<'_> {
285    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
286        use WorkspaceIdentifier::*;
287        let out = match self {
288            Id(id) => format!("{id}"),
289            Name(name) => format!("name:{name}"),
290            Relative(int) => format_relative(*int, ""),
291            RelativeMonitor(int) => format_relative(*int, "m"),
292            RelativeMonitorIncludingEmpty(int) => format_relative(*int, "r"),
293            RelativeOpen(int) => format_relative(*int, "e"),
294            Previous => "previous".to_string(),
295            Empty => "empty".to_string(),
296        };
297
298        write!(f, "{out}")
299    }
300}
301
302/// This enum is the params to [DispatchType::MoveWindow] dispatcher
303#[derive(Debug, Clone)]
304pub enum WindowMove<'a> {
305    /// Moves the window to a specified monitor
306    Monitor(MonitorIdentifier<'a>),
307    /// Moves the window in a specified direction
308    Direction(Direction),
309}
310
311/// This enum holds the actions that can be applied to a tag
312#[derive(Debug, Clone, Display)]
313#[allow(missing_docs)]
314pub enum TagAction {
315    #[display("+")]
316    Add,
317    #[display("-")]
318    Remove,
319    #[display("")]
320    Toggle,
321}
322
323/// This enum holds the signals
324#[derive(Debug, Clone, Copy)]
325pub enum SignalType {
326    /// Hangup detected on controlling terminal
327    SIGHUP = 1,
328    /// Interrupt from keyboard
329    SIGINT = 2,
330    /// Quit from keyboard
331    SIGQUIT = 3,
332    /// Illegal Instruction
333    SIGILL = 4,
334    /// Trace/breakpoint trap
335    SIGTRAP = 5,
336    /// Abort signal from abort
337    SIGABRT = 6,
338    /// Bus error (bad memory access)
339    SIGBUS = 7,
340    /// Erroneous arithmetic operation
341    SIGFPE = 8,
342    /// Kill signal
343    SIGKILL = 9,
344    /// User-defined signal 1
345    SIGUSR1 = 10,
346    /// Invalid memory reference
347    SIGSEGV = 11,
348    /// User-defined signal 2
349    SIGUSR2 = 12,
350    /// Broken pipe
351    SIGPIPE = 13,
352    /// Timer signal from alarm
353    SIGALRM = 14,
354    /// Termination signal
355    SIGTERM = 15,
356    /// Stack fault on coprocessor
357    SIGSTKFLT = 16,
358    /// Child stopped, terminated, or continued
359    SIGCHLD = 17,
360    /// Continue if stopped
361    SIGCONT = 18,
362    /// Stop process
363    SIGSTOP = 19,
364    /// Stop typed at terminal
365    SIGTSTP = 20,
366    /// Terminal input for background process
367    SIGTTIN = 21,
368    /// Terminal output for background process
369    SIGTTOU = 22,
370    /// Urgent condition on socket
371    SIGURG = 23,
372    /// CPU time limit exceeded
373    SIGXCPU = 24,
374    /// File size limit exceeded
375    SIGXFSZ = 25,
376    /// Virtual alarm clock
377    SIGVTALRM = 26,
378    /// Profiling timer expired
379    SIGPROF = 27,
380    /// Window resize signal
381    SIGWINCH = 28,
382    /// I/O now possible
383    SIGIO = 29,
384    /// Power failure
385    SIGPWR = 30,
386    /// Bad system call
387    SIGSYS = 31,
388}
389
390impl std::fmt::Display for SignalType {
391    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
392        write!(f, "{}", *self as u8)
393    }
394}
395
396#[derive(Debug, Clone, Copy, Display)]
397/// This enum holds the params to the [DispatchType::MoveToRoot] dispatcher
398pub enum MoveToRootParam {
399    /// Maximize the window in its current subtree
400    #[display("")]
401    Stable,
402    /// Swap the window with the other subtree
403    #[display("unstable")]
404    Unstable,
405}
406
407/// This enum holds the zheight variants
408#[derive(Debug, Clone, Copy, Display)]
409pub enum ZOrder {
410    /// Bring the active window to top of the stack
411    #[display("top")]
412    Top,
413    /// Bring the active window to bottom of the stack
414    #[display("bottom")]
415    Bottom,
416}
417
418/// This enum holds the params to the [DispatchType::Submap] dispatcher
419#[derive(Debug, Clone, Copy, Display)]
420pub enum SubmapParam<'a> {
421    /// Go back to global submap
422    #[display("reset")]
423    Reset,
424    /// Go to named submap
425    #[display("{}", _0)]
426    Name(&'a str),
427}
428
429/// This enum holds every dispatcher
430#[derive(Debug, Clone)]
431pub enum DispatchType<'a> {
432    /// This lets you use dispatchers not supported by hyprland-rs yet, please make issues before
433    /// using
434    Custom(
435        /// Name of event
436        &'a str,
437        /// Args
438        &'a str,
439    ),
440    /// This dispatcher changes the current cursor
441    SetCursor(
442        /// The cursor theme
443        &'a str,
444        /// The size
445        u16,
446    ),
447    /// This dispatcher executes a program
448    Exec(&'a str),
449    /// This dispatcher executes a raw shell command ignoring window rules
450    ExecRaw(&'a str),
451    /// This dispatcher passes a keybind to a window when called in a
452    /// keybind, its used for global keybinds. And should **ONLY** be used with keybinds
453    Pass(WindowIdentifier<'a>),
454    /// Executes a Global Shortcut using the GlobalShortcuts portal.
455    Global(&'a str),
456    /// This dispatcher closes the active window/client
457    KillActiveWindow,
458    /// This dispatcher kills the active window/client
459    ForceKillActiveWindow,
460    /// This dispatcher closes the specified window
461    CloseWindow(WindowIdentifier<'a>),
462    /// This dispatcher changes the current workspace
463    Workspace(WorkspaceIdentifierWithSpecial<'a>),
464    /// This dispatcher moves a window (focused if not specified) to a workspace
465    MoveToWorkspace(
466        WorkspaceIdentifierWithSpecial<'a>,
467        Option<WindowIdentifier<'a>>,
468    ),
469    /// This dispatcher moves a window (focused if not specified) to a workspace, without switching to that
470    /// workspace
471    MoveToWorkspaceSilent(
472        WorkspaceIdentifierWithSpecial<'a>,
473        Option<WindowIdentifier<'a>>,
474    ),
475    /// This dispatcher toggles the floating state of a window (current if not specified)
476    ToggleFloating(Option<WindowIdentifier<'a>>),
477    /// This dispatcher floats a window (current if not specified)
478    SetFloating(Option<WindowIdentifier<'a>>),
479    /// This dispatcher tiles a window (current if not specified)
480    SetTiled(Option<WindowIdentifier<'a>>),
481    /// This dispatcher toggles the current window fullscreen state
482    ToggleFullscreen(FullscreenType),
483    /// This dispatcher sets the focused window’s fullscreen mode and the one sent to the client
484    ToggleFullscreenState(FullscreenState, FullscreenState),
485    /// This dispatcher toggles the focused window’s internal
486    /// fullscreen state without altering the geometry
487    ToggleFakeFullscreen,
488    /// This dispatcher sets the DPMS status for all monitors
489    ToggleDPMS(bool, Option<&'a str>),
490    /// This dispatcher toggles pseudo tiling for the current window
491    TogglePseudo,
492    /// This dispatcher pins the active window to all workspaces
493    TogglePin,
494    /// This dispatcher pins the specified window to all workspaces
495    TogglePinWindow(WindowIdentifier<'a>),
496    /// This dispatcher sends a shortcut to the specified window
497    SendShortcut(
498        /// The modifiers
499        &'a [crate::shared::Mod],
500        /// The key, e.g., "A"
501        &'a str,
502        /// The window identifier
503        Option<WindowIdentifier<'a>>,
504    ),
505    /// This dispatcher sends a signal to the active window
506    Signal(SignalType),
507    /// This dispatcher sends a signal to the specified window
508    SignalWindow(WindowIdentifier<'a>, SignalType),
509    /// This dispatcher moves the window focus in a specified direction
510    MoveFocus(Direction),
511    /// This dispatcher moves the current window to a monitor or in a specified direction
512    MoveWindow(WindowMove<'a>),
513    /// This dispatcher centers the active window
514    CenterWindow,
515    /// This dispatcher resizes the active window using a [Position] enum
516    ResizeActive(Position),
517    /// This dispatcher moves the active window using a [Position] enum
518    MoveActive(Position),
519    /// This dispatcher resizes the specified window using a [Position] enum
520    ResizeWindowPixel(Position, WindowIdentifier<'a>),
521    /// This dispatcher moves the specified window using a [Position] enum
522    MoveWindowPixel(Position, WindowIdentifier<'a>),
523    /// This dispatcher cycles windows using a specified direction
524    CycleWindow(CycleDirection),
525    /// This dispatcher swaps the focused window with the window on a workspace using a specified direction
526    SwapNext(CycleDirection),
527    /// This dispatcher swaps windows using a specified direction
528    SwapWindow(Direction),
529    /// Apply tag to current or the first window matching
530    TagWindow(TagAction, &'a str, Option<WindowIdentifier<'a>>),
531    /// This dispatcher focuses a specified window
532    FocusWindow(WindowIdentifier<'a>),
533    /// This dispatcher focuses a specified monitor
534    FocusMonitor(MonitorIdentifier<'a>),
535    /// This dispatcher changed the split ratio
536    ChangeSplitRatio(FloatValue),
537    /// This dispatcher toggle opacity for the current window/client
538    ToggleOpaque,
539    /// This dispatcher moves the cursor to a specified corner of a window
540    MoveCursorToCorner(Corner),
541    /// This dispatcher moves the cursor to a specified position
542    /// (x, y) where x starts from left to right, and y starts from top to bottom
543    MoveCursor(i64, i64),
544    /// This dispatcher applied a option to all windows in a workspace
545    WorkspaceOption(WorkspaceOptions),
546    /// This dispatcher renames a workspace
547    RenameWorkspace(WorkspaceId, Option<&'a str>),
548    /// This exits Hyprland **(DANGEROUS)**
549    Exit,
550    /// This dispatcher forces the renderer to reload
551    ForceRendererReload,
552    /// This dispatcher moves the current workspace to a specified monitor
553    MoveCurrentWorkspaceToMonitor(MonitorIdentifier<'a>),
554    /// This dispatcher moves a specified workspace to a specified monitor
555    MoveWorkspaceToMonitor(WorkspaceIdentifier<'a>, MonitorIdentifier<'a>),
556    /// This dispatcher swaps the active workspaces of two monitors
557    SwapActiveWorkspaces(MonitorIdentifier<'a>, MonitorIdentifier<'a>),
558    /// This dispatcher brings the active window to the top of the stack
559    BringActiveToTop,
560    /// This dispatcher brings the active window to the top or bottom of the stack
561    AlterZOrder(ZOrder, Option<WindowIdentifier<'a>>),
562    /// This toggles the special workspace (AKA scratchpad)
563    ToggleSpecialWorkspace(Option<String>),
564    /// This dispatcher jump to urgent or the last window
565    FocusUrgentOrLast,
566    /// Switch focus from current to previously focused window
567    FocusCurrentOrLast,
568    /// Swallow or Unswallow a window
569    ToggleSwallow,
570    /// Change the current mapping group
571    Submap(SubmapParam<'a>),
572
573    // LAYOUT DISPATCHERS
574    // DWINDLE
575    /// Toggles the split (top/side) of the current window. `preserve_split` must be enabled for toggling to work
576    ToggleSplit,
577    /// Swaps the two halves of the split of the current window
578    SwapSplit,
579    /// One-time override for the split direction (only works on tiled windows)
580    PreSelect(Direction),
581    /// Moves the selected window (active window if unspecified) to the root of its workspace tree
582    MoveToRoot(Option<WindowIdentifier<'a>>, MoveToRootParam),
583
584    // MASTER
585    /// Swaps the current window with master.
586    /// If the current window is the master,
587    /// swaps it with the first child.
588    SwapWithMaster(SwapWithMasterParam),
589    /// Focuses the master window.
590    FocusMaster(FocusMasterParam),
591    /// Focuses the next window respecting the layout
592    CycleNextMaster(MasterLoopParam),
593    /// Focuses the previous window respecting the layout
594    CyclePrevMaster(MasterLoopParam),
595    /// Swaps the focused window with the next window respecting the layout
596    SwapNextMaster(MasterLoopParam),
597    /// Swaps the focused window with the previous window respecting the layout
598    SwapPrevMaster(MasterLoopParam),
599    /// Adds a master to the master side. That will be the active window,
600    /// if it’s not a master, or the first non-master window.
601    AddMaster,
602    /// Removes a master from the master side. That will be the
603    /// active window, if it’s a master, or the last master window.
604    RemoveMaster,
605    /// Sets the orientation for the current workspace to left
606    /// (master area left, slave windows to the right, vertically stacked)
607    OrientationLeft,
608    /// Sets the orientation for the current workspace to right
609    /// (master area right, slave windows to the left, vertically stacked)
610    OrientationRight,
611    /// Sets the orientation for the current workspace to top
612    /// (master area top, slave windows to the bottom, horizontally stacked)
613    OrientationTop,
614    /// Sets the orientation for the current workspace to bottom
615    /// (master area bottom, slave windows to the top, horizontally stacked)
616    OrientationBottom,
617    /// Sets the orientation for the current workspace to center
618    /// (master area center, slave windows alternate to the left and right, vertically stacked)
619    OrientationCenter,
620    /// Cycle to the next orientation for the current workspace (clockwise)
621    OrientationNext,
622    /// Cycle to the previous orientation for the current workspace (counter-clockwise)
623    OrientationPrev,
624    /// Cycle to the next orientation from the provided list, for the current workspace
625    OrientationCycle(OrientationParam),
626    /// Change mfact, the master split ratio
627    Mfact(FloatValue),
628    /// Rotate the next window in stack to be the master, while keeping the focus on master
629    RollNext,
630    /// Rotate the previous window in stack to be the master, while keeping the focus on master
631    RollPrev,
632
633    // Group Dispatchers
634    /// Toggles the current active window into a group
635    ToggleGroup,
636    /// Switches to the next window in a group.
637    ChangeGroupActive(WindowSwitchDirection),
638    /// Locks the groups
639    LockGroups(LockType),
640    /// Locks the currently focused group
641    LockActiveGroup(LockType),
642    /// Moves the active window into a group in a specified direction
643    MoveIntoGroup(Direction),
644    /// Moves the active window into or out of a group in a specified direction
645    MoveWindowOrGroup(Direction),
646    /// Moves the active window out of a group.
647    MoveOutOfGroup,
648    /// Swaps the active window with the next or previous in a group
649    MoveGroupWindow(WindowSwitchDirection),
650    /// Prohibit the active window from becoming or being inserted into group
651    DenyWindowFromGroup(BinaryState),
652    /// Temporarily enable or disable ignore_group_lock
653    SetIgnoreGroupLock(BinaryState),
654}
655
656/// Enum used for options with a binary on/off state
657#[allow(missing_docs)]
658#[derive(Debug, Clone, Copy, Display, PartialEq, Eq, PartialOrd, Ord)]
659pub enum BinaryState {
660    #[display("on")]
661    On,
662    #[display("off")]
663    Off,
664    #[display("toggle")]
665    Toggle,
666}
667
668/// Enum used with [DispatchType::LockGroups], to determine how to lock/unlock
669#[derive(Debug, Clone, Copy, Display, PartialEq, Eq, PartialOrd, Ord)]
670pub enum LockType {
671    /// Lock Group
672    #[display("lock")]
673    Lock,
674    /// Unlock Group
675    #[display("unlock")]
676    Unlock,
677    /// Toggle lock state of Group
678    #[display("toggle")]
679    ToggleLock,
680}
681
682/// Param for [DispatchType::SwapWithMaster] dispatcher
683#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
684pub enum SwapWithMasterParam {
685    /// New focus is the new master window
686    #[display("master")]
687    Master,
688    /// New focus is the new child
689    #[display("child")]
690    Child,
691    /// Keep the focus of the previously focused window
692    #[display("auto")]
693    Auto,
694    /// Noop if master is already focused
695    #[display("ignoremaster")]
696    IgnoreMaster,
697}
698
699/// Param for [DispatchType::FocusMaster] dispatcher
700#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
701pub enum FocusMasterParam {
702    /// Focus stays at master, (even if it was selected before)
703    #[display("master")]
704    Master,
705    /// If the current window is the master, focuses the first child
706    #[display("auto")]
707    Auto,
708    /// If the current window is the master, focuses the previously focused one
709    #[display("previous")]
710    Previous,
711}
712
713/// Param for some master layout dispatchers
714#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
715pub enum MasterLoopParam {
716    /// Allow looping through the pile
717    #[display("loop")]
718    Loop,
719    /// Do not allow looping through the pile
720    #[display("noloop")]
721    NoLoop,
722}
723
724/// Param for [DispatchType::OrientationCycle] dispatcher
725#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
726pub enum OrientationParam {
727    /// Set orientation to left
728    #[display("left")]
729    Left,
730    /// Set orientation to right
731    #[display("right")]
732    Right,
733    /// Set orientation to bottom
734    #[display("bottom")]
735    Bottom,
736    /// Set orientation to top
737    #[display("top")]
738    Top,
739    /// Set orientation to center
740    #[display("center")]
741    Center,
742}
743
744/// Param for split ratio changes
745#[derive(Debug, Clone, Copy, PartialEq, Display)]
746pub enum FloatValue {
747    /// Change relative to current factor
748    #[display("{}", _0)]
749    Relative(f32),
750    /// Set factor to exact value between 0 and 1
751    #[display("exact {}", _0)]
752    Exact(f32),
753}
754
755pub(crate) fn gen_dispatch_str(cmd: DispatchType, dispatch: bool) -> crate::Result<CommandContent> {
756    use DispatchType::*;
757    let sep = if dispatch { " " } else { "," };
758    let string_to_pass = match &cmd {
759        Custom(name, args) => format!("{name}{sep}{args}"),
760        Exec(sh) => format!("exec{sep}{sh}"),
761        ExecRaw(sh) => format!("execr{sep}{sh}"),
762        Pass(win) => format!("pass{sep}{win}"),
763        Global(name) => format!("global{sep}{name}"),
764        KillActiveWindow => "killactive".to_string(),
765        ForceKillActiveWindow => "forcekillactive".to_string(),
766        CloseWindow(win) => format!("closewindow{sep}{win}"),
767        Workspace(work) => format!("workspace{sep}{work}"),
768        MoveToWorkspace(work, Some(win)) => format!("movetoworkspace{sep}{work},{win}"),
769        MoveToWorkspace(work, None) => format!("movetoworkspace{sep}{work}"),
770        MoveToWorkspaceSilent(work, Some(win)) => format!("movetoworkspacesilent{sep}{work},{win}"),
771        MoveToWorkspaceSilent(work, None) => format!("movetoworkspacesilent{sep}{work}"),
772        ToggleFloating(Some(v)) => format!("togglefloating{sep}{v}"),
773        ToggleFloating(None) => "togglefloating".to_string(),
774        SetFloating(Some(v)) => format!("setfloating{sep}{v}"),
775        SetFloating(None) => "setfloating".to_string(),
776        SetTiled(Some(v)) => format!("settiled{sep}{v}"),
777        SetTiled(None) => "settiled".to_string(),
778        ToggleFullscreen(ftype) => format!("fullscreen{sep}{ftype}"),
779        ToggleFullscreenState(int, cl) => format!("fullscreenstate{sep}{int} {cl}"),
780        ToggleFakeFullscreen => "fakefullscreen".to_string(),
781        ToggleDPMS(stat, mon) => {
782            format!(
783                "dpms{sep}{} {}",
784                if *stat { "on" } else { "off" },
785                mon.unwrap_or_default()
786            )
787        }
788        TogglePseudo => "pseudo".to_string(),
789        TogglePin => "pin".to_string(),
790        TogglePinWindow(win) => format!("pin{sep}{win}"),
791        SendShortcut(mods, key, win_opt) => {
792            let mods_str: String = mods.iter().map(|m| m.to_string()).collect();
793            match win_opt {
794                Some(win) => format!("sendshortcut{sep}{mods_str},{key},{win}"),
795                None => format!("sendshortcut{sep}{mods_str},{key},"),
796            }
797        }
798        MoveFocus(dir) => format!("movefocus{sep}{dir}",),
799        MoveWindow(ident) => format!(
800            "movewindow{sep}{}",
801            match ident {
802                WindowMove::Direction(dir) => dir.to_string(),
803                WindowMove::Monitor(mon) => format!("mon:{mon}"),
804            }
805        ),
806        CenterWindow => "centerwindow".to_string(),
807        ResizeActive(pos) => format!("resizeactive{sep}{pos}"),
808        MoveActive(pos) => format!("moveactive {pos}"),
809        ResizeWindowPixel(pos, win) => format!("resizewindowpixel{sep}{pos},{win}"),
810        MoveWindowPixel(pos, win) => format!("movewindowpixel{sep}{pos},{win}"),
811        CycleWindow(dir) => format!("cyclenext{sep}{dir}"),
812        SwapNext(dir) => format!("swapnext{sep}{dir}"),
813        SwapWindow(dir) => format!("swapwindow{sep}{dir}"),
814        TagWindow(act, tag, Some(win)) => format!("tagwindow{sep}{act}{tag} {win}"),
815        TagWindow(act, tag, None) => format!("tagwindow{sep}{act}{tag}"),
816        FocusWindow(win) => format!("focuswindow{sep}{win}"),
817        FocusMonitor(mon) => format!("focusmonitor{sep}{mon}"),
818        ChangeSplitRatio(fv) => format!("splitratio {fv}"),
819        ToggleOpaque => "toggleopaque".to_string(),
820        MoveCursorToCorner(corner) => format!("movecursortocorner{sep}{}", corner.clone() as u8),
821        MoveCursor(x, y) => format!("movecursor{sep}{x} {y}"),
822        WorkspaceOption(opt) => format!("workspaceopt{sep}{opt}"),
823        Exit => "exit".to_string(),
824        ForceRendererReload => "forcerendererreload".to_string(),
825        MoveCurrentWorkspaceToMonitor(mon) => format!("movecurrentworkspacetomonitor{sep}{mon}"),
826        MoveWorkspaceToMonitor(work, mon) => format!("moveworkspacetomonitor{sep}{work} {mon}"),
827        ToggleSpecialWorkspace(Some(name)) => format!("togglespecialworkspace {name}"),
828        ToggleSpecialWorkspace(None) => "togglespecialworkspace".to_string(),
829        RenameWorkspace(id, name) => {
830            format!(
831                "renameworkspace{sep}{id} {}",
832                name.unwrap_or(&id.to_string())
833            )
834        }
835        SwapActiveWorkspaces(mon, mon2) => format!("swapactiveworkspaces{sep}{mon} {mon2}",),
836        BringActiveToTop => "bringactivetotop".to_string(),
837        AlterZOrder(z, Some(win)) => format!("alterzorder{sep}{z},{win}"),
838        AlterZOrder(z, None) => format!("alterzorder{sep}{z}"),
839        SetCursor(theme, size) => format!("{theme} {}", *size),
840        Signal(sig) => format!("signal{sep}{sig}"),
841        SignalWindow(win, sig) => format!("signalwindow{sep}{win},{sig}"),
842        FocusUrgentOrLast => "focusurgentorlast".to_string(),
843        FocusCurrentOrLast => "focuscurrentorlast".to_string(),
844        ToggleSwallow => "toggleswallow".to_string(),
845        ToggleSplit => format!("layoutmsg{sep}togglesplit"),
846        SwapSplit => format!("layoutmsg{sep}swapsplit"),
847        PreSelect(dir) => format!("layoutmsg{sep}preselect {dir}"),
848        MoveToRoot(Some(win), param) => format!("layoutmsg{sep}movetoroot {win} {param}"),
849        MoveToRoot(None, _) => format!("layoutmsg{sep}movetoroot"),
850        Submap(param) => format!("submap{sep}{param}"),
851        SwapWithMaster(param) => format!("layoutmsg{sep}swapwithmaster {param}"),
852        FocusMaster(param) => format!("layoutmsg{sep}focusmaster {param}"),
853        CycleNextMaster(param) => format!("layoutmsg{sep}cyclenext {param}"),
854        CyclePrevMaster(param) => format!("layoutmsg{sep}cycleprev {param}"),
855        SwapNextMaster(param) => format!("layoutmsg{sep}swapnext {param}"),
856        SwapPrevMaster(param) => format!("layoutmsg{sep}swapprev {param}"),
857        AddMaster => format!("layoutmsg{sep}addmaster"),
858        RemoveMaster => format!("layoutmsg{sep}removemaster"),
859        OrientationLeft => format!("layoutmsg{sep}orientationleft"),
860        OrientationRight => format!("layoutmsg{sep}orientationright"),
861        OrientationTop => format!("layoutmsg{sep}orientationtop"),
862        OrientationBottom => format!("layoutmsg{sep}orientationbottom"),
863        OrientationCenter => format!("layoutmsg{sep}orientationcenter"),
864        OrientationNext => format!("layoutmsg{sep}orientationnext"),
865        OrientationPrev => format!("layoutmsg{sep}orientationprev"),
866        OrientationCycle(param) => format!("layoutmsg{sep}orientationcycle {param}"),
867        Mfact(fv) => format!("layoutmsg{sep}mfact {fv}"),
868        RollNext => format!("layoutmsg{sep}rollnext"),
869        RollPrev => format!("layoutmsg{sep}rollprev"),
870        ToggleGroup => "togglegroup".to_string(),
871        ChangeGroupActive(dir) => format!("changegroupactive{sep}{dir}"),
872        LockGroups(how) => format!("lockgroups{sep}{how}"),
873        LockActiveGroup(how) => format!("lockactivegroups{sep}{how}"),
874        MoveIntoGroup(dir) => format!("moveintogroup{sep}{dir}"),
875        MoveWindowOrGroup(dir) => format!("movewindoworgroup{sep}{dir}"),
876        MoveOutOfGroup => "moveoutofgroup".to_string(),
877        MoveGroupWindow(dir) => format!("movegroupwindow{sep}{dir}"),
878        DenyWindowFromGroup(state) => format!("denywindowfromgroup{sep}{state}"),
879        SetIgnoreGroupLock(state) => format!("setignoregrouplock{sep}{state}"),
880    };
881
882    if let SetCursor(_, _) = cmd {
883        Ok(command!(JSON, "setcursor {string_to_pass}"))
884    } else if dispatch {
885        Ok(command!(JSON, "dispatch {string_to_pass}"))
886    } else {
887        Ok(command!(Empty, "{string_to_pass}"))
888    }
889}
890
891/// The struct that provides all dispatching methods
892pub struct Dispatch;
893
894impl Dispatch {
895    /// This function calls a specified dispatcher (blocking)
896    ///
897    /// ```rust
898    /// # use hyprland::Result;
899    /// # fn main() -> Result<()> {
900    /// use hyprland::dispatch::{DispatchType,Dispatch};
901    /// // This is an example of just one dispatcher, there are many more!
902    /// Dispatch::call(DispatchType::Exec("kitty"))
903    /// # }
904    /// ```
905    pub fn call(dispatch_type: DispatchType) -> crate::Result<()> {
906        Self::instance_call(default_instance()?, dispatch_type)
907    }
908
909    /// This function calls a specified dispatcher (blocking)
910    ///
911    /// ```rust
912    /// # use hyprland::Result;
913    /// # fn main() -> Result<()> {
914    /// use hyprland::dispatch::{DispatchType,Dispatch};
915    /// let instance = hyprland::instance::Instance::from_current_env()?;
916    /// // This is an example of just one dispatcher, there are many more!
917    /// Dispatch::instance_call(&instance, DispatchType::Exec("kitty"))
918    /// # }
919    /// ```
920    pub fn instance_call(
921        instance: &crate::instance::Instance,
922        dispatch_type: DispatchType,
923    ) -> crate::Result<()> {
924        let output = instance.write_to_socket(gen_dispatch_str(dispatch_type, true)?);
925        match output {
926            Ok(msg) => match msg.as_str() {
927                "ok" => Ok(()),
928                msg => Err(HyprError::NotOkDispatch(msg.to_string())),
929            },
930            Err(error) => Err(error),
931        }
932    }
933
934    /// This function calls a specified dispatcher (async)
935    ///
936    /// ```rust
937    /// # use hyprland::Result;
938    /// #[tokio::main(flavor = "current_thread")]
939    /// # async fn main() -> Result<()> {
940    /// use hyprland::dispatch::{Dispatch,DispatchType};
941    /// let instance = hyprland::instance::Instance::from_current_env()?;
942    /// // This is an example of just one dispatcher, there are many more!
943    /// Dispatch::call_async(DispatchType::Exec("kitty")).await
944    /// # }
945    /// ```
946    #[cfg(any(feature = "async-lite", feature = "tokio"))]
947    pub async fn call_async(dispatch_type: DispatchType<'_>) -> crate::Result<()> {
948        Self::instance_call_async(default_instance()?, dispatch_type).await
949    }
950
951    /// This function calls a specified dispatcher (async)
952    ///
953    /// ```rust
954    /// # use hyprland::Result;
955    /// #[tokio::main(flavor = "current_thread")]
956    /// # async fn main() -> Result<()> {
957    /// use hyprland::dispatch::{Dispatch,DispatchType};
958    /// let instance = hyprland::instance::Instance::from_current_env()?;
959    /// // This is an example of just one dispatcher, there are many more!
960    /// Dispatch::call_async(DispatchType::Exec("kitty")).await
961    /// # }
962    /// ```
963    #[cfg(any(feature = "async-lite", feature = "tokio"))]
964    pub async fn instance_call_async(
965        instance: &crate::instance::Instance,
966        dispatch_type: DispatchType<'_>,
967    ) -> crate::Result<()> {
968        let output = instance
969            .write_to_socket_async(gen_dispatch_str(dispatch_type, true)?)
970            .await;
971        match output {
972            Ok(msg) => match msg.as_str() {
973                "ok" => Ok(()),
974                msg => Err(HyprError::NotOkDispatch(msg.to_string())),
975            },
976            Err(error) => Err(error),
977        }
978    }
979}
980
981/// Macro abstraction over [Dispatch::call]
982#[macro_export]
983macro_rules! dispatch {
984    (async; $dis:ident) => {
985        $crate::dispatch::Dispatch::call_async($crate::dispatch::DispatchType::$dis)
986    };
987    (async; $dis:ident, $( $arg:expr ), *) => {
988        $crate::dispatch::Dispatch::call_async($crate::dispatch::DispatchType::$dis($($arg), *))
989    };
990    (async; $instance:expr; $dis:ident) => {
991        $crate::dispatch::Dispatch::instance_call_async($instance, $crate::dispatch::DispatchType::$dis)
992    };
993    (async; $instance:expr; $dis:ident, $( $arg:expr ), *) => {
994        $crate::dispatch::Dispatch::instance_call_async($instance, $crate::dispatch::DispatchType::$dis($($arg), *))
995    };
996    ($dis:ident) => {
997        $crate::dispatch::Dispatch::call($crate::dispatch::DispatchType::$dis)
998    };
999    ($dis:ident, $( $arg:expr ), *) => {
1000        $crate::dispatch::Dispatch::call($crate::dispatch::DispatchType::$dis($($arg), *))
1001    };
1002    ($instance:expr; $dis:ident) => {
1003        $crate::dispatch::Dispatch::instance_call($instance, $crate::dispatch::DispatchType::$dis)
1004    };
1005    ($instance:expr; $dis:ident, $( $arg:expr ), *) => {
1006        $crate::dispatch::Dispatch::instance_call($instance, $crate::dispatch::DispatchType::$dis($($arg), *))
1007    };
1008}