Files
niri/niri-ipc/src/lib.rs
T

727 lines
24 KiB
Rust
Raw Normal View History

//! Types for communicating with niri via IPC.
#![warn(missing_docs)]
use std::collections::HashMap;
2024-02-10 09:33:32 +04:00
use std::str::FromStr;
use serde::{Deserialize, Serialize};
mod socket;
pub use socket::{Socket, SOCKET_PATH_ENV};
/// Request from client to niri.
2024-02-11 09:19:37 +04:00
#[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub enum Request {
/// Request the version string for the running niri instance.
Version,
/// Request information about connected outputs.
Outputs,
2024-03-28 13:45:24 +04:00
/// Request information about the focused window.
FocusedWindow,
2024-02-10 09:33:32 +04:00
/// Perform an action.
Action(Action),
2024-05-05 10:19:47 +04:00
/// Change output configuration temporarily.
///
/// The configuration is changed temporarily and not saved into the config file. If the output
/// configuration subsequently changes in the config file, these temporary changes will be
/// forgotten.
Output {
/// Output name.
output: String,
/// Configuration to apply.
action: OutputAction,
},
2024-05-16 14:30:52 -07:00
/// Request information about workspaces.
Workspaces,
2024-05-22 16:16:03 -07:00
/// Request information about the focused output.
FocusedOutput,
2024-08-25 09:38:45 +03:00
/// Request information about the keyboard layout.
KeyboardLayouts,
/// Respond with an error (for testing error handling).
ReturnError,
}
2024-02-11 09:19:37 +04:00
/// Reply from niri to client.
///
/// Every request gets one reply.
///
/// * If an error had occurred, it will be an `Reply::Err`.
/// * If the request does not need any particular response, it will be
/// `Reply::Ok(Response::Handled)`. Kind of like an `Ok(())`.
/// * Otherwise, it will be `Reply::Ok(response)` with one of the other [`Response`] variants.
pub type Reply = Result<Response, String>;
/// Successful response from niri to client.
#[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub enum Response {
2024-02-11 09:19:37 +04:00
/// A request that does not need a response was handled successfully.
Handled,
/// The version string for the running niri instance.
Version(String),
/// Information about connected outputs.
///
/// Map from connector name to output info.
Outputs(HashMap<String, Output>),
2024-03-28 13:45:24 +04:00
/// Information about the focused window.
FocusedWindow(Option<Window>),
2024-05-05 12:50:18 +04:00
/// Output configuration change result.
OutputConfigChanged(OutputConfigChanged),
2024-05-16 14:30:52 -07:00
/// Information about workspaces.
Workspaces(Vec<Workspace>),
2024-05-22 16:16:03 -07:00
/// Information about the focused output.
FocusedOutput(Option<Output>),
2024-08-25 09:38:45 +03:00
/// Information about the keyboard layout.
KeyboardLayouts(KeyboardLayouts),
}
2024-02-10 09:33:32 +04:00
/// Actions that niri can perform.
// Variants in this enum should match the spelling of the ones in niri-config. Most, but not all,
// variants from niri-config should be present here.
2024-02-11 09:19:37 +04:00
#[derive(Serialize, Deserialize, Debug, Clone)]
2024-02-10 09:33:32 +04:00
#[cfg_attr(feature = "clap", derive(clap::Parser))]
#[cfg_attr(feature = "clap", command(subcommand_value_name = "ACTION"))]
#[cfg_attr(feature = "clap", command(subcommand_help_heading = "Actions"))]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
2024-02-10 09:33:32 +04:00
pub enum Action {
/// Exit niri.
Quit {
/// Skip the "Press Enter to confirm" prompt.
#[cfg_attr(feature = "clap", arg(short, long))]
skip_confirmation: bool,
},
2024-02-10 09:33:32 +04:00
/// Power off all monitors via DPMS.
PowerOffMonitors,
/// Spawn a command.
Spawn {
/// Command to spawn.
#[cfg_attr(feature = "clap", arg(last = true, required = true))]
command: Vec<String>,
},
2024-05-07 22:06:43 +04:00
/// Do a screen transition.
DoScreenTransition {
/// Delay in milliseconds for the screen to freeze before starting the transition.
#[cfg_attr(feature = "clap", arg(short, long))]
delay_ms: Option<u16>,
},
2024-02-10 09:33:32 +04:00
/// Open the screenshot UI.
Screenshot,
/// Screenshot the focused screen.
ScreenshotScreen,
/// Screenshot the focused window.
ScreenshotWindow,
/// Close the focused window.
CloseWindow,
/// Toggle fullscreen on the focused window.
FullscreenWindow,
/// Focus the column to the left.
FocusColumnLeft,
/// Focus the column to the right.
FocusColumnRight,
/// Focus the first column.
FocusColumnFirst,
/// Focus the last column.
FocusColumnLast,
/// Focus the next column to the right, looping if at end.
FocusColumnRightOrFirst,
/// Focus the next column to the left, looping if at start.
FocusColumnLeftOrLast,
/// Focus the window or the monitor above.
FocusWindowOrMonitorUp,
/// Focus the window or the monitor below.
FocusWindowOrMonitorDown,
/// Focus the column or the monitor to the left.
FocusColumnOrMonitorLeft,
/// Focus the column or the monitor to the right.
FocusColumnOrMonitorRight,
2024-02-10 09:33:32 +04:00
/// Focus the window below.
FocusWindowDown,
/// Focus the window above.
FocusWindowUp,
/// Focus the window below or the column to the left.
FocusWindowDownOrColumnLeft,
/// Focus the window below or the column to the right.
FocusWindowDownOrColumnRight,
/// Focus the window above or the column to the left.
FocusWindowUpOrColumnLeft,
/// Focus the window above or the column to the right.
FocusWindowUpOrColumnRight,
2024-02-10 09:33:32 +04:00
/// Focus the window or the workspace above.
FocusWindowOrWorkspaceDown,
/// Focus the window or the workspace above.
FocusWindowOrWorkspaceUp,
/// Move the focused column to the left.
MoveColumnLeft,
/// Move the focused column to the right.
MoveColumnRight,
/// Move the focused column to the start of the workspace.
MoveColumnToFirst,
/// Move the focused column to the end of the workspace.
MoveColumnToLast,
/// Move the focused column to the left or to the monitor to the left.
MoveColumnLeftOrToMonitorLeft,
/// Move the focused column to the right or to the monitor to the right.
MoveColumnRightOrToMonitorRight,
2024-02-10 09:33:32 +04:00
/// Move the focused window down in a column.
MoveWindowDown,
/// Move the focused window up in a column.
MoveWindowUp,
/// Move the focused window down in a column or to the workspace below.
MoveWindowDownOrToWorkspaceDown,
/// Move the focused window up in a column or to the workspace above.
MoveWindowUpOrToWorkspaceUp,
/// Consume or expel the focused window left.
ConsumeOrExpelWindowLeft,
/// Consume or expel the focused window right.
ConsumeOrExpelWindowRight,
/// Consume the window to the right into the focused column.
ConsumeWindowIntoColumn,
/// Expel the focused window from the column.
ExpelWindowFromColumn,
/// Center the focused column on the screen.
CenterColumn,
/// Focus the workspace below.
FocusWorkspaceDown,
/// Focus the workspace above.
FocusWorkspaceUp,
2024-05-11 22:40:30 +02:00
/// Focus a workspace by reference (index or name).
2024-02-10 09:33:32 +04:00
FocusWorkspace {
2024-05-11 22:40:30 +02:00
/// Reference (index or name) of the workspace to focus.
2024-02-10 09:33:32 +04:00
#[cfg_attr(feature = "clap", arg())]
2024-05-11 22:40:30 +02:00
reference: WorkspaceReferenceArg,
2024-02-10 09:33:32 +04:00
},
2024-03-19 14:27:52 +00:00
/// Focus the previous workspace.
FocusWorkspacePrevious,
2024-02-10 09:33:32 +04:00
/// Move the focused window to the workspace below.
MoveWindowToWorkspaceDown,
/// Move the focused window to the workspace above.
MoveWindowToWorkspaceUp,
2024-05-11 22:40:30 +02:00
/// Move the focused window to a workspace by reference (index or name).
2024-02-10 09:33:32 +04:00
MoveWindowToWorkspace {
2024-05-11 22:40:30 +02:00
/// Reference (index or name) of the workspace to move the window to.
2024-02-10 09:33:32 +04:00
#[cfg_attr(feature = "clap", arg())]
2024-05-11 22:40:30 +02:00
reference: WorkspaceReferenceArg,
2024-02-10 09:33:32 +04:00
},
/// Move the focused column to the workspace below.
MoveColumnToWorkspaceDown,
/// Move the focused column to the workspace above.
MoveColumnToWorkspaceUp,
2024-05-11 22:40:30 +02:00
/// Move the focused column to a workspace by reference (index or name).
2024-02-10 09:33:32 +04:00
MoveColumnToWorkspace {
2024-05-11 22:40:30 +02:00
/// Reference (index or name) of the workspace to move the column to.
2024-02-10 09:33:32 +04:00
#[cfg_attr(feature = "clap", arg())]
2024-05-11 22:40:30 +02:00
reference: WorkspaceReferenceArg,
2024-02-10 09:33:32 +04:00
},
/// Move the focused workspace down.
MoveWorkspaceDown,
/// Move the focused workspace up.
MoveWorkspaceUp,
/// Focus the monitor to the left.
FocusMonitorLeft,
/// Focus the monitor to the right.
FocusMonitorRight,
/// Focus the monitor below.
FocusMonitorDown,
/// Focus the monitor above.
FocusMonitorUp,
/// Move the focused window to the monitor to the left.
MoveWindowToMonitorLeft,
/// Move the focused window to the monitor to the right.
MoveWindowToMonitorRight,
/// Move the focused window to the monitor below.
MoveWindowToMonitorDown,
/// Move the focused window to the monitor above.
MoveWindowToMonitorUp,
/// Move the focused column to the monitor to the left.
MoveColumnToMonitorLeft,
/// Move the focused column to the monitor to the right.
MoveColumnToMonitorRight,
/// Move the focused column to the monitor below.
MoveColumnToMonitorDown,
/// Move the focused column to the monitor above.
MoveColumnToMonitorUp,
/// Change the height of the focused window.
SetWindowHeight {
/// How to change the height.
#[cfg_attr(feature = "clap", arg())]
change: SizeChange,
},
2024-05-11 09:33:23 +04:00
/// Reset the height of the focused window back to automatic.
ResetWindowHeight,
2024-02-10 09:33:32 +04:00
/// Switch between preset column widths.
SwitchPresetColumnWidth,
/// Toggle the maximized state of the focused column.
MaximizeColumn,
/// Change the width of the focused column.
SetColumnWidth {
/// How to change the width.
#[cfg_attr(feature = "clap", arg())]
change: SizeChange,
},
/// Switch between keyboard layouts.
SwitchLayout {
/// Layout to switch to.
#[cfg_attr(feature = "clap", arg())]
layout: LayoutSwitchTarget,
},
/// Show the hotkey overlay.
ShowHotkeyOverlay,
/// Move the focused workspace to the monitor to the left.
MoveWorkspaceToMonitorLeft,
/// Move the focused workspace to the monitor to the right.
MoveWorkspaceToMonitorRight,
/// Move the focused workspace to the monitor below.
MoveWorkspaceToMonitorDown,
/// Move the focused workspace to the monitor above.
MoveWorkspaceToMonitorUp,
/// Toggle a debug tint on windows.
ToggleDebugTint,
2024-05-02 17:52:06 +04:00
/// Toggle visualization of render element opaque regions.
DebugToggleOpaqueRegions,
/// Toggle visualization of output damage.
DebugToggleDamage,
2024-02-10 09:33:32 +04:00
}
/// Change in window or column size.
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
2024-02-10 09:33:32 +04:00
pub enum SizeChange {
/// Set the size in logical pixels.
SetFixed(i32),
/// Set the size as a proportion of the working area.
SetProportion(f64),
/// Add or subtract to the current size in logical pixels.
AdjustFixed(i32),
/// Add or subtract to the current size as a proportion of the working area.
AdjustProportion(f64),
}
2024-05-11 22:40:30 +02:00
/// Workspace reference (index or name) to operate on.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
2024-05-11 22:40:30 +02:00
pub enum WorkspaceReferenceArg {
/// Index of the workspace.
Index(u8),
/// Name of the workspace.
Name(String),
}
2024-02-10 09:33:32 +04:00
/// Layout to switch to.
2024-02-11 09:19:37 +04:00
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
2024-02-10 09:33:32 +04:00
pub enum LayoutSwitchTarget {
/// The next configured layout.
Next,
/// The previous configured layout.
Prev,
}
2024-05-05 10:19:47 +04:00
/// Output actions that niri can perform.
// Variants in this enum should match the spelling of the ones in niri-config. Most thigs from
// niri-config should be present here.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[cfg_attr(feature = "clap", derive(clap::Parser))]
#[cfg_attr(feature = "clap", command(subcommand_value_name = "ACTION"))]
#[cfg_attr(feature = "clap", command(subcommand_help_heading = "Actions"))]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
2024-05-05 10:19:47 +04:00
pub enum OutputAction {
/// Turn off the output.
Off,
/// Turn on the output.
On,
/// Set the output mode.
Mode {
/// Mode to set, or "auto" for automatic selection.
///
2024-06-09 10:50:22 +00:00
/// Run `niri msg outputs` to see the available modes.
2024-05-05 10:19:47 +04:00
#[cfg_attr(feature = "clap", arg())]
mode: ModeToSet,
},
/// Set the output scale.
Scale {
2024-05-05 12:39:20 +04:00
/// Scale factor to set, or "auto" for automatic selection.
2024-05-05 10:19:47 +04:00
#[cfg_attr(feature = "clap", arg())]
2024-05-05 12:39:20 +04:00
scale: ScaleToSet,
2024-05-05 10:19:47 +04:00
},
/// Set the output transform.
Transform {
/// Transform to set, counter-clockwise.
#[cfg_attr(feature = "clap", arg())]
transform: Transform,
},
/// Set the output position.
Position {
/// Position to set, or "auto" for automatic selection.
#[cfg_attr(feature = "clap", command(subcommand))]
position: PositionToSet,
},
2024-08-22 18:58:07 +10:00
/// Set the variable refresh rate mode.
2024-05-05 10:19:47 +04:00
Vrr {
2024-08-22 18:58:07 +10:00
/// Variable refresh rate mode to set.
#[cfg_attr(feature = "clap", command(flatten))]
vrr: VrrToSet,
2024-05-05 10:19:47 +04:00
},
}
/// Output mode to set.
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
2024-05-05 10:19:47 +04:00
pub enum ModeToSet {
/// Niri will pick the mode automatically.
Automatic,
/// Specific mode.
Specific(ConfiguredMode),
}
/// Output mode as set in the config file.
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
2024-05-05 10:19:47 +04:00
pub struct ConfiguredMode {
/// Width in physical pixels.
pub width: u16,
/// Height in physical pixels.
pub height: u16,
/// Refresh rate.
pub refresh: Option<f64>,
}
2024-05-05 12:39:20 +04:00
/// Output scale to set.
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
2024-05-05 12:39:20 +04:00
pub enum ScaleToSet {
/// Niri will pick the scale automatically.
Automatic,
/// Specific scale.
Specific(f64),
}
2024-05-05 10:19:47 +04:00
/// Output position to set.
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "clap", derive(clap::Subcommand))]
#[cfg_attr(feature = "clap", command(subcommand_value_name = "POSITION"))]
#[cfg_attr(feature = "clap", command(subcommand_help_heading = "Position Values"))]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
2024-05-05 10:19:47 +04:00
pub enum PositionToSet {
/// Position the output automatically.
#[cfg_attr(feature = "clap", command(name = "auto"))]
Automatic,
/// Set a specific position.
#[cfg_attr(feature = "clap", command(name = "set"))]
Specific(ConfiguredPosition),
}
/// Output position as set in the config file.
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "clap", derive(clap::Args))]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
2024-05-05 10:19:47 +04:00
pub struct ConfiguredPosition {
/// Logical X position.
pub x: i32,
/// Logical Y position.
pub y: i32,
}
2024-08-22 18:58:07 +10:00
/// Output VRR to set.
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "clap", derive(clap::Args))]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub struct VrrToSet {
/// Whether to enable variable refresh rate.
#[cfg_attr(
feature = "clap",
arg(
value_name = "ON|OFF",
action = clap::ArgAction::Set,
value_parser = clap::builder::BoolishValueParser::new(),
hide_possible_values = true,
),
)]
pub vrr: bool,
/// Only enable when the output shows a window matching the variable-refresh-rate window rule.
#[cfg_attr(feature = "clap", arg(long))]
pub on_demand: bool,
}
/// Connected output.
#[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub struct Output {
/// Name of the output.
pub name: String,
/// Textual description of the manufacturer.
pub make: String,
/// Textual description of the model.
pub model: String,
/// Physical width and height of the output in millimeters, if known.
pub physical_size: Option<(u32, u32)>,
/// Available modes for the output.
pub modes: Vec<Mode>,
/// Index of the current mode in [`Self::modes`].
///
/// `None` if the output is disabled.
pub current_mode: Option<usize>,
2024-04-15 22:29:25 +04:00
/// Whether the output supports variable refresh rate.
pub vrr_supported: bool,
/// Whether variable refresh rate is enabled on the output.
pub vrr_enabled: bool,
/// Logical output information.
///
/// `None` if the output is not mapped to any logical output (for example, if it is disabled).
pub logical: Option<LogicalOutput>,
}
/// Output mode.
2024-05-21 22:43:42 +00:00
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub struct Mode {
/// Width in physical pixels.
pub width: u16,
/// Height in physical pixels.
pub height: u16,
/// Refresh rate in millihertz.
pub refresh_rate: u32,
/// Whether this mode is preferred by the monitor.
pub is_preferred: bool,
}
/// Logical output in the compositor's coordinate space.
2024-05-21 22:43:42 +00:00
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub struct LogicalOutput {
/// Logical X position.
pub x: i32,
/// Logical Y position.
pub y: i32,
/// Width in logical pixels.
pub width: u32,
/// Height in logical pixels.
pub height: u32,
/// Scale factor.
pub scale: f64,
/// Transform.
pub transform: Transform,
}
/// Output transform, which goes counter-clockwise.
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
2024-05-05 10:19:47 +04:00
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub enum Transform {
/// Untransformed.
Normal,
/// Rotated by 90°.
#[serde(rename = "90")]
_90,
/// Rotated by 180°.
#[serde(rename = "180")]
_180,
/// Rotated by 270°.
#[serde(rename = "270")]
_270,
/// Flipped horizontally.
Flipped,
/// Rotated by 90° and flipped horizontally.
2024-05-05 10:19:47 +04:00
#[cfg_attr(feature = "clap", value(name("flipped-90")))]
Flipped90,
/// Flipped vertically.
2024-05-05 10:19:47 +04:00
#[cfg_attr(feature = "clap", value(name("flipped-180")))]
Flipped180,
/// Rotated by 270° and flipped horizontally.
2024-05-05 10:19:47 +04:00
#[cfg_attr(feature = "clap", value(name("flipped-270")))]
Flipped270,
}
2024-02-10 09:33:32 +04:00
2024-03-28 13:45:24 +04:00
/// Toplevel window.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
2024-03-28 13:45:24 +04:00
pub struct Window {
/// Title, if set.
pub title: Option<String>,
/// Application ID, if set.
pub app_id: Option<String>,
}
2024-05-05 12:50:18 +04:00
/// Output configuration change result.
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
2024-05-05 12:50:18 +04:00
pub enum OutputConfigChanged {
/// The target output was connected and the change was applied.
Applied,
/// The target output was not found, the change will be applied when it is connected.
OutputWasMissing,
}
2024-05-16 14:30:52 -07:00
/// A workspace.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
2024-05-16 14:30:52 -07:00
pub struct Workspace {
/// Index of the workspace on its monitor.
///
/// This is the same index you can use for requests like `niri msg action focus-workspace`.
pub idx: u8,
/// Optional name of the workspace.
pub name: Option<String>,
/// Name of the output that the workspace is on.
///
/// Can be `None` if no outputs are currently connected.
pub output: Option<String>,
/// Whether the workspace is currently active on its output.
pub is_active: bool,
}
2024-08-25 09:38:45 +03:00
/// Configured keyboard layouts.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
pub struct KeyboardLayouts {
/// XKB names of the configured layouts.
pub names: Vec<String>,
/// Index of the currently active layout in `names`.
pub current_idx: u8,
}
2024-05-11 22:40:30 +02:00
impl FromStr for WorkspaceReferenceArg {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let reference = if let Ok(index) = s.parse::<i32>() {
if let Ok(idx) = u8::try_from(index) {
Self::Index(idx)
} else {
return Err("workspace indexes must be between 0 and 255");
}
} else {
Self::Name(s.to_string())
};
Ok(reference)
}
}
2024-02-10 09:33:32 +04:00
impl FromStr for SizeChange {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.split_once('%') {
Some((value, empty)) => {
if !empty.is_empty() {
return Err("trailing characters after '%' are not allowed");
}
match value.bytes().next() {
Some(b'-' | b'+') => {
let value = value.parse().map_err(|_| "error parsing value")?;
Ok(Self::AdjustProportion(value))
}
Some(_) => {
let value = value.parse().map_err(|_| "error parsing value")?;
Ok(Self::SetProportion(value))
}
None => Err("value is missing"),
}
}
None => {
let value = s;
match value.bytes().next() {
Some(b'-' | b'+') => {
let value = value.parse().map_err(|_| "error parsing value")?;
Ok(Self::AdjustFixed(value))
}
Some(_) => {
let value = value.parse().map_err(|_| "error parsing value")?;
Ok(Self::SetFixed(value))
}
None => Err("value is missing"),
}
}
}
}
}
impl FromStr for LayoutSwitchTarget {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"next" => Ok(Self::Next),
"prev" => Ok(Self::Prev),
_ => Err(r#"invalid layout action, can be "next" or "prev""#),
}
}
}
2024-03-27 17:03:17 +04:00
impl FromStr for Transform {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"normal" => Ok(Self::Normal),
"90" => Ok(Self::_90),
"180" => Ok(Self::_180),
"270" => Ok(Self::_270),
"flipped" => Ok(Self::Flipped),
"flipped-90" => Ok(Self::Flipped90),
"flipped-180" => Ok(Self::Flipped180),
"flipped-270" => Ok(Self::Flipped270),
_ => Err(concat!(
r#"invalid transform, can be "90", "180", "270", "#,
r#""flipped", "flipped-90", "flipped-180" or "flipped-270""#
)),
}
}
}
2024-05-05 10:19:47 +04:00
impl FromStr for ModeToSet {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.eq_ignore_ascii_case("auto") {
return Ok(Self::Automatic);
}
let mode = s.parse()?;
Ok(Self::Specific(mode))
}
}
impl FromStr for ConfiguredMode {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let Some((width, rest)) = s.split_once('x') else {
return Err("no 'x' separator found");
};
let (height, refresh) = match rest.split_once('@') {
Some((height, refresh)) => (height, Some(refresh)),
None => (rest, None),
};
let width = width.parse().map_err(|_| "error parsing width")?;
let height = height.parse().map_err(|_| "error parsing height")?;
let refresh = refresh
.map(str::parse)
.transpose()
.map_err(|_| "error parsing refresh rate")?;
Ok(Self {
width,
height,
refresh,
})
}
}
2024-05-05 12:39:20 +04:00
impl FromStr for ScaleToSet {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.eq_ignore_ascii_case("auto") {
return Ok(Self::Automatic);
}
let scale = s.parse().map_err(|_| "error parsing scale")?;
Ok(Self::Specific(scale))
}
}