swayipc-types-1.0.0/.cargo_vcs_info.json0000644000000001430000000000100136510ustar { "git": { "sha1": "03cb262c418e7c385c2b64245590d89b1f3794dd" }, "path_in_vcs": "types" }swayipc-types-1.0.0/Cargo.toml0000644000000020540000000000100116520ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "swayipc-types" version = "1.0.0" authors = ["Jayce Fayne "] description = "A library containing Type defintions from sway's IPC interface" readme = "README.md" keywords = ["sway", "swaywm", "swayipc", "ipc"] categories = ["network-programming"] license = "MIT" repository = "https://github.com/jaycefayne/swayipc-rs" [dependencies.serde] version = "1.0.132" features = ["derive"] [dependencies.serde_json] version = "1.0.73" [dependencies.thiserror] version = "1.0.30" optional = true [features] default = ["error"] error = ["thiserror"] swayipc-types-1.0.0/Cargo.toml.orig000064400000000000000000000010770072674642500153670ustar 00000000000000[package] name = "swayipc-types" version = "1.0.0" authors = ["Jayce Fayne "] edition = "2018" description = "A library containing Type defintions from sway's IPC interface" license = "MIT" repository = "https://github.com/jaycefayne/swayipc-rs" categories = ["network-programming"] keywords = ["sway", "swaywm", "swayipc","ipc"] readme = "README.md" [dependencies] serde = { version = "1.0.132", features = ["derive"] } serde_json = "1.0.73" thiserror = { version = "1.0.30", optional = true } [features] default = ["error"] error = ["thiserror"]swayipc-types-1.0.0/README.md000064400000000000000000000020240072674642500137500ustar 00000000000000# swayipc-types   [![Action Badge]][actions] [![Version Badge]][crates.io] [![License Badge]][license] [![Docs Badge]][docs] [Version Badge]: https://img.shields.io/crates/v/swayipc-types.svg [crates.io]: https://crates.io/crates/swayipc-types [Action Badge]: https://github.com/JayceFayne/swayipc-rs/workflows/Rust/badge.svg [actions]: https://github.com/JayceFayne/swayipc-rs/actions [License Badge]: https://img.shields.io/crates/l/swayipc-types.svg [license]: https://github.com/JayceFayne/swayipc-rs/blob/master/LICENSE.md [Docs Badge]: https://docs.rs/swayipc-types/badge.svg [docs]: https://docs.rs/swayipc-types A Rust library containing types used to control swaywm through its [IPC interface](https://github.com/swaywm/sway/blob/master/sway/sway-ipc.7.scd). ## Versioning This library targets the latest stable release of [sway](https://github.com/swaywm/sway). ## Contributing If you find any errors in swayipc or just want to add a new feature feel free to [submit a PR](https://github.com/jaycefayne/swayipc-rs/pulls). swayipc-types-1.0.0/src/command.rs000064400000000000000000000022560072674642500152530ustar 00000000000000#[repr(u32)] #[non_exhaustive] #[derive(Debug, PartialEq, Copy, Clone)] pub enum CommandType { RunCommand = 0, GetWorkspaces = 1, Subscribe = 2, GetOutputs = 3, GetTree = 4, GetMarks = 5, GetBarConfig = 6, GetVersion = 7, GetBindingModes = 8, GetConfig = 9, SendTick = 10, Sync = 11, GetBindingState = 12, GetInputs = 100, GetSeats = 101, } impl CommandType { pub fn encode(self) -> Vec { IntoIterator::into_iter(crate::MAGIC) .chain(IntoIterator::into_iter(0_u32.to_ne_bytes())) .chain(IntoIterator::into_iter(u32::from(self).to_ne_bytes())) .collect() } pub fn encode_with>(self, payload: T) -> Vec { let payload = payload.as_ref(); IntoIterator::into_iter(crate::MAGIC) .chain(IntoIterator::into_iter( (payload.len() as u32).to_ne_bytes(), )) .chain(IntoIterator::into_iter(u32::from(self).to_ne_bytes())) .chain(payload.iter().cloned()) .collect() } } impl From for u32 { fn from(value: CommandType) -> Self { value as u32 } } swayipc-types-1.0.0/src/error/command_outcome.rs000064400000000000000000000006470072674642500201410ustar 00000000000000use crate::{CommandOutcome, Error, Fallible}; impl CommandOutcome { pub fn decode(command_outcome: CommandOutcome) -> Fallible<()> { if let Some(error) = command_outcome.error { Err(if error.parse_error { Error::CommandParse(error.message) } else { Error::CommandFailed(error.message) }) } else { Ok(()) } } } swayipc-types-1.0.0/src/error/command_type.rs000064400000000000000000000007030072674642500174400ustar 00000000000000use crate::{CommandType, Error::InvalidCommandType, Fallible}; use serde::de::DeserializeOwned as Deserialize; impl CommandType { pub fn decode(self, (payload_type, payload): (u32, Vec)) -> Fallible { let command_type = u32::from(self); if payload_type != command_type { return Err(InvalidCommandType(payload_type, command_type)); } Ok(serde_json::from_slice(&payload)?) } } swayipc-types-1.0.0/src/error/event.rs000064400000000000000000000020670072674642500161070ustar 00000000000000use crate::{ Error::UnimplementedEvent, Event::{self, *}, Fallible, }; impl Event { pub fn decode((payload_type, payload): (u32, Vec)) -> Fallible { // strip the highest order bit indicating it's an event // since we dont convert to hex we also dont match on the (hex) values written in the sway-ipc docs! let event_type = (payload_type << 1) >> 1; Ok(match event_type { 0 => Workspace(serde_json::from_slice(&payload)?), 2 => Mode(serde_json::from_slice(&payload)?), 3 => Window(serde_json::from_slice(&payload)?), 4 => BarConfigUpdate(serde_json::from_slice(&payload)?), 5 => Binding(serde_json::from_slice(&payload)?), 6 => Shutdown(serde_json::from_slice(&payload)?), 7 => Tick(serde_json::from_slice(&payload)?), 20 => BarStateUpdate(serde_json::from_slice(&payload)?), 21 => Input(serde_json::from_slice(&payload)?), _ => return Err(UnimplementedEvent(event_type, payload)), }) } } swayipc-types-1.0.0/src/error/mod.rs000064400000000000000000000016420072674642500155430ustar 00000000000000mod command_outcome; mod command_type; mod event; use thiserror::Error as ThisError; pub type Fallible = Result; #[non_exhaustive] #[derive(Debug, ThisError)] pub enum Error { #[error(transparent)] Io(#[from] std::io::Error), #[error(transparent)] SerdeJson(#[from] serde_json::Error), #[error("unexpected magic string, expected 'i3-ipc' but got '{}'", String::from_utf8_lossy(.0))] InvalidMagic([u8; 6]), #[error("did receive a reply with type '{0}' but send command with type '{1}'")] InvalidCommandType(u32, u32), #[error("received unimplemented event '{}' with type '{}'", String::from_utf8_lossy(.1), .0)] UnimplementedEvent(u32, Vec), #[error("failed to subscribe to events {0}")] SubscriptionFailed(String), #[error("command failed with '{0}'")] CommandFailed(String), #[error("command could not be parsed '{0}'")] CommandParse(String), } swayipc-types-1.0.0/src/event.rs000064400000000000000000000005120072674642500147470ustar 00000000000000use serde::Serialize; #[non_exhaustive] #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize)] #[serde(rename_all = "snake_case")] pub enum EventType { Workspace, Mode, Window, #[serde(rename = "barconfig_update")] BarConfigUpdate, Binding, Shutdown, Tick, BarStateUpdate, Input, } swayipc-types-1.0.0/src/lib.rs000064400000000000000000000005050072674642500143760ustar 00000000000000#![deny(unsafe_code)] #![deny(rust_2018_idioms)] mod command; #[cfg(feature = "error")] mod error; mod event; mod reply; mod utils; pub use command::CommandType; #[cfg(feature = "error")] pub use error::{Error, Fallible}; pub use event::EventType; pub use reply::*; pub const MAGIC: [u8; 6] = [105, 51, 45, 105, 112, 99]; swayipc-types-1.0.0/src/reply.rs000064400000000000000000000261240072674642500147700ustar 00000000000000use serde::Deserialize; #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct CommandOutcome { pub success: bool, #[serde(flatten)] pub error: Option, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct CommandError { pub parse_error: bool, #[serde(rename = "error")] pub message: String, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct Workspace { pub id: i64, pub num: i32, pub name: String, pub layout: String, pub visible: bool, pub focused: bool, pub urgent: bool, pub representation: Option, pub orientation: String, pub rect: Rect, pub output: String, #[serde(default)] pub focus: Vec, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct Success { pub success: bool, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] pub struct Mode { pub width: i32, pub height: i32, pub refresh: i32, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct Output { pub id: Option, // Sway doesn't give disabled outputs ids pub name: String, pub make: String, pub model: String, pub serial: String, pub active: bool, pub dpms: bool, pub primary: bool, pub scale: Option, pub subpixel_hinting: Option, pub transform: Option, pub current_workspace: Option, #[serde(default)] pub modes: Vec, pub current_mode: Option, pub rect: Rect, #[serde(default)] pub focus: Vec, #[serde(default)] pub focused: bool, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct Libinput { pub send_events: Option, pub tap: Option, pub tap_button_mapping: Option, pub tap_drag: Option, pub tap_drag_lock: Option, pub accel_speed: Option, pub natural_scroll: Option, pub left_handed: Option, pub click_method: Option, pub middle_emulation: Option, pub scroll_method: Option, pub scroll_button: Option, pub dwt: Option, pub calibration_matrix: Option<[f32; 6]>, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] #[serde(rename_all = "snake_case")] pub enum SendEvents { Enabled, Disabled, DisabledOnExternalMouse, } #[derive(Debug, PartialEq, Deserialize)] #[serde(rename_all = "lowercase")] pub enum EnabledOrDisabled { Enabled, Disabled, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] #[serde(rename_all = "snake_case")] pub enum ClickMethod { ButtonAreas, Clickfinger, None, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] #[serde(rename_all = "snake_case")] pub enum ScrollMethod { TwoFinger, Edge, OnButtonDown, None, } #[derive(Debug, PartialEq, Deserialize)] #[serde(rename_all = "lowercase")] pub enum ButtonMapping { LMR, LRM, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct Input { pub identifier: String, pub name: String, pub vendor: i32, pub product: i32, #[serde(rename = "type")] pub input_type: String, pub xkb_active_layout_name: Option, #[serde(default)] pub xkb_layout_names: Vec, pub xkb_active_layout_index: Option, pub libinput: Option, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct Seat { pub name: String, pub capabilities: i32, pub focus: i32, #[serde(default)] pub devices: Vec, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] pub struct Rect { pub x: i32, pub y: i32, pub width: i32, pub height: i32, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] pub struct WindowProperties { pub title: Option, pub instance: Option, pub class: Option, pub window_role: Option, pub transient_for: Option, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] #[serde(rename_all = "lowercase")] pub enum UserIdleInhibitType { Focus, Fullscreen, Open, Visible, None, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] #[serde(rename_all = "lowercase")] pub enum ApplicationIdleInhibitType { Enabled, None, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] pub struct IdleInhibitors { pub application: ApplicationIdleInhibitType, pub user: UserIdleInhibitType, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] #[serde(rename_all = "snake_case")] pub enum NodeType { Root, Output, Workspace, Con, FloatingCon, Dockarea, // i3-specific } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] #[serde(rename_all = "lowercase")] pub enum NodeBorder { Normal, Pixel, Csd, None, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] #[serde(rename_all = "lowercase")] pub enum NodeLayout { SplitH, SplitV, Stacked, Tabbed, Output, Dockarea, // i3-specific None, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] pub struct Node { pub id: i64, pub name: Option, #[serde(rename = "type")] pub node_type: NodeType, pub border: NodeBorder, pub current_border_width: i32, pub layout: NodeLayout, pub percent: Option, pub rect: Rect, pub window_rect: Rect, pub deco_rect: Rect, pub geometry: Rect, pub urgent: bool, pub focused: bool, pub focus: Vec, #[serde(default)] pub nodes: Vec, pub floating_nodes: Vec, pub sticky: bool, pub representation: Option, pub fullscreen_mode: Option, pub app_id: Option, pub pid: Option, pub window: Option, pub num: Option, //workspace number if `node_type` == `NodeType::Workspace` pub window_properties: Option, #[serde(default)] pub marks: Vec, pub inhibit_idle: Option, pub idle_inhibitors: Option, pub shell: Option, pub visible: Option, } #[non_exhaustive] #[derive(Debug, Deserialize)] #[serde(rename_all = "lowercase")] pub struct ColorableBarPart { pub background: String, pub statusline: String, pub separator: String, pub focused_background: String, pub focused_statusline: String, pub focused_separator: String, pub focused_workspace_text: String, pub focused_workspace_bg: String, pub focused_workspace_border: String, pub active_workspace_text: String, pub active_workspace_bg: String, pub active_workspace_border: String, pub inactive_workspace_text: String, pub inactive_workspace_bg: String, pub inactive_workspace_border: String, pub urgent_workspace_text: String, pub urgent_workspace_bg: String, pub urgent_workspace_border: String, pub binding_mode_text: String, pub binding_mode_bg: String, pub binding_mode_border: String, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct BarConfig { pub id: String, pub mode: BarMode, pub position: Position, pub status_command: String, pub font: String, pub workspace_buttons: bool, pub binding_mode_indicator: bool, pub verbose: bool, pub colors: ColorableBarPart, pub gaps: Gaps, pub bar_height: usize, pub status_padding: usize, pub status_edge_padding: usize, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct BindingState { pub name: String, } #[non_exhaustive] #[derive(Debug, Deserialize)] #[serde(rename_all = "lowercase")] pub enum BarMode { Dock, Hide, Invisible, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct Gaps { pub top: usize, pub bottom: usize, pub right: usize, pub left: usize, } #[non_exhaustive] #[derive(Debug, Deserialize)] #[serde(rename_all = "lowercase")] pub enum Position { Bottom, Top, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct Version { pub major: i32, pub minor: i32, pub patch: i32, pub human_readable: String, pub loaded_config_file_name: String, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct Config { pub config: String, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub enum Event { Workspace(Box), Mode(ModeEvent), Window(Box), BarConfigUpdate(Box), Binding(BindingEvent), Shutdown(ShutdownEvent), Tick(TickEvent), BarStateUpdate(BarStateUpdateEvent), Input(Box), } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct InputEvent { pub change: InputChange, pub input: Input, } #[non_exhaustive] #[derive(Debug, Deserialize)] #[serde(rename_all = "snake_case")] pub enum InputChange { Added, Removed, XkbKeymap, XkbLayout, LibinputConfig, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct BarStateUpdateEvent { pub id: String, pub visible_by_modifier: bool, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct TickEvent { pub first: bool, pub payload: String, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct WorkspaceEvent { pub change: WorkspaceChange, pub current: Option, //Only None if WorkspaceChange::Reload pub old: Option, //Only None if WorkspaceChange::Reload } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct ModeEvent { pub change: String, pub pango_markup: bool, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct WindowEvent { pub change: WindowChange, pub container: Node, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct BindingEvent { pub change: BindingChange, pub binding: BindingEventOps, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct BindingEventOps { pub command: String, #[serde(default)] pub event_state_mask: Vec, pub input_code: u8, pub symbol: Option, pub input_type: InputType, } #[non_exhaustive] #[derive(Debug, Deserialize)] pub struct ShutdownEvent { pub change: ShutdownChange, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] #[serde(rename_all = "lowercase")] pub enum WorkspaceChange { Init, Empty, Focus, Move, Rename, Urgent, Reload, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] #[serde(rename_all = "snake_case")] pub enum WindowChange { New, Close, Focus, Title, FullscreenMode, Move, Floating, Urgent, Mark, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] #[serde(rename_all = "lowercase")] pub enum InputType { Keyboard, Mouse, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] #[serde(rename_all = "lowercase")] pub enum BindingChange { Run, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] #[serde(rename_all = "lowercase")] pub enum ShutdownChange { Exit, } #[non_exhaustive] #[derive(Debug, PartialEq, Deserialize)] #[serde(rename_all = "snake_case")] pub enum ShellType { XdgShell, Xwayland, Unknown, } swayipc-types-1.0.0/src/utils/mod.rs000064400000000000000000000000120072674642500155400ustar 00000000000000mod node; swayipc-types-1.0.0/src/utils/node.rs000064400000000000000000000045470072674642500157270ustar 00000000000000use crate::reply::Node; impl Node { pub fn find_as_ref(&self, predicate: fn(&Node) -> bool) -> Option<&Node> { if predicate(self) { return Some(self); } for node in &self.nodes { let node = node.find_as_ref(predicate); if node.is_some() { return node; } } for node in &self.floating_nodes { let node = node.find_as_ref(predicate); if node.is_some() { return node; } } None } pub fn find(self, predicate: fn(&Node) -> bool) -> Option { if predicate(&self) { return Some(self); } let Node { nodes, floating_nodes, .. } = self; for node in nodes { let node = node.find(predicate); if node.is_some() { return node; } } for node in floating_nodes { let node = node.find(predicate); if node.is_some() { return node; } } None } pub fn find_focused_as_ref(&self, predicate: fn(&Node) -> bool) -> Option<&Node> { if predicate(self) { return Some(self); } if self.focus.is_empty() { return None; } let first = self.focus[0]; for node in &self.nodes { if node.id == first { return node.find_focused_as_ref(predicate); } } for node in &self.floating_nodes { if node.id == first { return node.find_focused_as_ref(predicate); } } None } pub fn find_focused(self, predicate: fn(&Node) -> bool) -> Option { if predicate(&self) { return Some(self); } let Node { nodes, floating_nodes, focus, .. } = self; if focus.is_empty() { return None; } let first = focus[0]; for node in nodes { if node.id == first { return node.find_focused(predicate); } } for node in floating_nodes { if node.id == first { return node.find_focused(predicate); } } None } }