diff --git a/src/bin/swayr.rs b/src/bin/swayr.rs
index c98fa85..0052e94 100644
--- a/src/bin/swayr.rs
+++ b/src/bin/swayr.rs
@@ -4,6 +4,7 @@
extern crate clap;
use clap::Clap;
use swayr::client;
+use swayr::ipc;
/// Windows are sorted urgent first, then windows in LRU order, focused window
/// last. Licensed under the GPLv3 (or later).
@@ -15,10 +16,12 @@ use swayr::client;
)]
struct Opts {
#[clap(subcommand)]
- command: client::SwayrCommand,
+ command: ipc::SwayrCommand,
}
fn main() {
let opts: Opts = Opts::parse();
- client::exec_swayr_cmd(&opts.command);
+ if let Err(err) = client::send_swayr_cmd(opts.command) {
+ eprintln!("Could not send command: {}", err);
+ }
}
diff --git a/src/client.rs b/src/client.rs
index 8257b00..8a7d5b8 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -1,323 +1,13 @@
-//! Functions and data structures of the swayr client.
+extern crate serde_json;
-use crate::con;
+use crate::ipc;
use crate::util;
-
-use clap::Clap;
-use std::fmt;
-
-use swayipc as s;
-use swayipc::reply as r;
-
-#[derive(Clap, Debug)]
-pub enum SwayrCommand {
- /// Switch to next urgent window (if any) or to last recently used window.
- SwitchToUrgentOrLRUWindow,
- /// Focus the selected window
- SwitchWindow,
- /// Focus the next window.
- NextWindow,
- /// Focus the previous window.
- PrevWindow,
- /// Quit the selected window
- QuitWindow,
- /// Switch to the selected workspace
- SwitchWorkspace,
- /// Switch to the selected workspace or focus the selected window
- SwitchWorkspaceOrWindow,
- /// Quit all windows of selected workspace or the selected window
- QuitWorkspaceOrWindow,
- /// Select and execute a swaymsg command
- ExecuteSwaymsgCommand,
- /// Select and execute a swayr command
- ExecuteSwayrCommand,
-}
-
-impl fmt::Display for SwayrCommand {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
- write!(f, "{:?}", self)
- }
-}
-
-pub fn exec_swayr_cmd(cmd: &SwayrCommand) {
- match cmd {
- SwayrCommand::SwitchToUrgentOrLRUWindow => {
- switch_to_urgent_or_lru_window()
- }
- SwayrCommand::SwitchWindow => switch_window(),
- SwayrCommand::NextWindow => {
- focus_next_window_in_direction(Direction::Forward)
- }
- SwayrCommand::PrevWindow => {
- focus_next_window_in_direction(Direction::Backward)
- }
- SwayrCommand::QuitWindow => quit_window(),
- SwayrCommand::SwitchWorkspace => switch_workspace(),
- SwayrCommand::SwitchWorkspaceOrWindow => switch_workspace_or_window(),
- SwayrCommand::QuitWorkspaceOrWindow => quit_workspace_or_window(),
- SwayrCommand::ExecuteSwaymsgCommand => exec_swaymsg_command(),
- SwayrCommand::ExecuteSwayrCommand => {
- if let Some(c) = util::wofi_select(
- "Select swayr command",
- &[
- SwayrCommand::ExecuteSwaymsgCommand,
- SwayrCommand::QuitWindow,
- SwayrCommand::QuitWorkspaceOrWindow,
- SwayrCommand::SwitchWindow,
- SwayrCommand::SwitchWorkspace,
- SwayrCommand::SwitchWorkspaceOrWindow,
- SwayrCommand::SwitchToUrgentOrLRUWindow,
- SwayrCommand::NextWindow,
- SwayrCommand::PrevWindow,
- ],
- ) {
- exec_swayr_cmd(c);
- }
- }
- }
-}
-
-fn focus_window_by_id(id: i64) {
- util::swaymsg(&[format!("[con_id={}]", id).as_str(), "focus"]);
-}
-
-fn quit_window_by_id(id: i64) {
- util::swaymsg(&[format!("[con_id={}]", id).as_str(), "kill"]);
-}
-
-fn get_tree() -> r::Node {
- match s::Connection::new() {
- Ok(mut con) => con.get_tree().expect("Got no root node"),
- Err(err) => panic!(err),
- }
-}
-
-pub fn switch_to_urgent_or_lru_window() {
- let root = get_tree();
- let windows = con::get_windows(&root, true);
- if let Some(win) = windows
- .iter()
- .find(|w| w.is_urgent())
- .or_else(|| windows.get(0))
- {
- println!("Switching to {}", win);
- focus_window_by_id(win.get_id())
- } else {
- println!("No window to switch to.")
- }
-}
-
-pub fn switch_window() {
- let root = get_tree();
- let windows = con::get_windows(&root, true);
-
- if let Some(window) = con::select_window("Switch to window", &windows) {
- focus_window_by_id(window.get_id())
- }
-}
-
-pub enum Direction {
- Backward,
- Forward,
-}
-
-pub fn focus_next_window_in_direction(dir: Direction) {
- let root = get_tree();
- let windows = con::get_windows(&root, false);
-
- if windows.len() < 2 {
- return;
- }
-
- let pred: Box bool> =
- if windows.iter().find(|w| w.is_focused()).is_none() {
- let last_focused_win_id =
- con::get_windows(&root, true).get(0).unwrap().get_id();
- Box::new(move |w| w.get_id() == last_focused_win_id)
- } else {
- Box::new(|w: &con::Window| w.is_focused())
- };
-
- let mut iter: Box> = match dir {
- Direction::Forward => Box::new(windows.iter().rev().cycle()),
- Direction::Backward => Box::new(windows.iter().cycle()),
- };
-
- loop {
- let win = iter.next().unwrap();
- if pred(win) {
- let win = iter.next().unwrap();
- focus_window_by_id(win.get_id());
- return;
- }
- }
-}
-
-pub fn switch_workspace() {
- let root = get_tree();
- let workspaces = con::get_workspaces(&root, false);
-
- if let Some(workspace) =
- con::select_workspace("Switch to workspace", &workspaces)
- {
- util::swaymsg(&["workspace", "number", workspace.get_name()]);
- }
-}
-
-pub fn switch_workspace_or_window() {
- let root = get_tree();
- let workspaces = con::get_workspaces(&root, false);
- let ws_or_wins = con::WsOrWin::from_workspaces(&workspaces);
- if let Some(ws_or_win) = con::select_workspace_or_window(
- "Select workspace or window",
- &ws_or_wins,
- ) {
- match ws_or_win {
- con::WsOrWin::Ws { ws } => {
- util::swaymsg(&["workspace", "number", ws.get_name()]);
- }
- con::WsOrWin::Win { win } => focus_window_by_id(win.get_id()),
- }
- }
-}
-
-pub fn quit_window() {
- let root = get_tree();
- let windows = con::get_windows(&root, true);
-
- if let Some(window) = con::select_window("Quit window", &windows) {
- quit_window_by_id(window.get_id())
- }
-}
-
-pub fn quit_workspace_or_window() {
- let root = get_tree();
- let workspaces = con::get_workspaces(&root, false);
- let ws_or_wins = con::WsOrWin::from_workspaces(&workspaces);
- if let Some(ws_or_win) =
- con::select_workspace_or_window("Quit workspace or window", &ws_or_wins)
- {
- match ws_or_win {
- con::WsOrWin::Ws { ws } => {
- for win in &ws.windows {
- quit_window_by_id(win.get_id())
- }
- }
- con::WsOrWin::Win { win } => quit_window_by_id(win.get_id()),
- }
- }
-}
-
-fn get_swaymsg_commands<'a>() -> Vec> {
- let mut cmds = vec![];
- cmds.push(vec!["exit"]);
- cmds.push(vec!["floating", "toggle"]);
- cmds.push(vec!["focus", "child"]);
- cmds.push(vec!["focus", "parent"]);
-
- for b in &["none", "normal", "csd", "pixel"] {
- cmds.push(vec!["border", b]);
- }
-
- cmds.push(vec!["focus", "tiling"]);
- cmds.push(vec!["focus", "floating"]);
- cmds.push(vec!["focus", "mode_toggle"]);
-
- cmds.push(vec!["fullscreen", "toggle"]);
-
- for x in &["focus", "fullscreen", "open", "none", "visible"] {
- cmds.push(vec!["inhibit_idle", x])
- }
-
- for l in &["default", "splith", "splitv", "stacking", "tiling"] {
- cmds.push(vec!["layout", l])
- }
-
- cmds.push(vec!["reload"]);
-
- for e in &["enable", "disable"] {
- cmds.push(vec!["shortcuts", "inhibitor", e])
- }
-
- cmds.push(vec!["sticky", "toggle"]);
-
- for x in &["yes", "no", "always"] {
- cmds.push(vec!["focus_follows_mouse", x])
- }
-
- for x in &["smart", "urgent", "focus", "none"] {
- cmds.push(vec!["focus_on_window_activation", x])
- }
-
- for x in &["yes", "no", "force", "workspace"] {
- cmds.push(vec!["focus_wrapping", x])
- }
-
- for x in &[
- "none",
- "vertical",
- "horizontal",
- "both",
- "smart",
- "smart_no_gaps",
- ] {
- cmds.push(vec!["hide_edge_borders", x])
- }
-
- cmds.push(vec!["kill"]);
-
- for x in &["on", "no_gaps", "off"] {
- cmds.push(vec!["smart_borders", x])
- }
-
- for x in &["on", "off"] {
- cmds.push(vec!["smart_gaps", x])
- }
-
- for x in &["output", "container", "none"] {
- cmds.push(vec!["mouse_warping", x])
- }
-
- for x in &["smart", "ignore", "leave_fullscreen"] {
- cmds.push(vec!["popup_during_fullscreen", x])
- }
-
- for x in &["yes", "no"] {
- cmds.push(vec!["show_marks", x]);
- cmds.push(vec!["workspace_auto_back_and_forth", x]);
- }
-
- cmds.push(vec!["tiling_drag", "toggle"]);
-
- for x in &["left", "center", "right"] {
- cmds.push(vec!["title_align", x]);
- }
-
- for x in &["enable", "disable", "allow", "deny"] {
- cmds.push(vec!["urgent", x])
- }
-
- cmds.sort();
-
- cmds.iter()
- .map(|v| SwaymsgCmd { cmd: v.to_vec() })
- .collect()
-}
-
-struct SwaymsgCmd<'a> {
- cmd: Vec<&'a str>,
-}
-
-impl<'a> fmt::Display for SwaymsgCmd<'a> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
- write!(f, "{}", self.cmd.join(" "))
- }
-}
-
-pub fn exec_swaymsg_command() {
- let cmds = get_swaymsg_commands();
- let cmd = util::wofi_select("Execute swaymsg command", &cmds);
- if let Some(cmd) = cmd {
- util::swaymsg(&cmd.cmd);
- }
+use std::io::Write;
+use std::os::unix::net::UnixStream;
+
+pub fn send_swayr_cmd(
+ cmd: ipc::SwayrCommand,
+) -> std::result::Result<(), std::io::Error> {
+ let mut sock = UnixStream::connect(util::get_swayr_socket_path())?;
+ sock.write_all(serde_json::to_string(&cmd).unwrap().as_bytes())
}
diff --git a/src/cmds.rs b/src/cmds.rs
new file mode 100644
index 0000000..c71f6c6
--- /dev/null
+++ b/src/cmds.rs
@@ -0,0 +1,329 @@
+//! Functions and data structures of the swayr client.
+
+use crate::con;
+use crate::ipc;
+use crate::ipc::SwayrCommand;
+use crate::util;
+
+use std::collections::HashMap;
+use std::fmt;
+use std::sync::Arc;
+use std::sync::RwLock;
+
+use swayipc as s;
+use swayipc::reply as r;
+
+impl fmt::Display for SwayrCommand {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ write!(f, "{:?}", self)
+ }
+}
+
+pub fn exec_swayr_cmd(
+ cmd: &SwayrCommand,
+ extra_props: Arc>>,
+) {
+ match cmd {
+ SwayrCommand::SwitchToUrgentOrLRUWindow => {
+ switch_to_urgent_or_lru_window(Some(&*extra_props.read().unwrap()))
+ }
+ SwayrCommand::SwitchWindow => {
+ switch_window(Some(&*extra_props.read().unwrap()))
+ }
+ SwayrCommand::NextWindow => focus_next_window_in_direction(
+ Direction::Forward,
+ Some(&*extra_props.read().unwrap()),
+ ),
+ SwayrCommand::PrevWindow => focus_next_window_in_direction(
+ Direction::Backward,
+ Some(&*extra_props.read().unwrap()),
+ ),
+ SwayrCommand::QuitWindow => {
+ quit_window(Some(&*extra_props.read().unwrap()))
+ }
+ SwayrCommand::SwitchWorkspace => {
+ switch_workspace(Some(&*extra_props.read().unwrap()))
+ }
+ SwayrCommand::SwitchWorkspaceOrWindow => {
+ switch_workspace_or_window(Some(&*extra_props.read().unwrap()))
+ }
+ SwayrCommand::QuitWorkspaceOrWindow => {
+ quit_workspace_or_window(Some(&*extra_props.read().unwrap()))
+ }
+ SwayrCommand::ExecuteSwaymsgCommand => exec_swaymsg_command(),
+ SwayrCommand::ExecuteSwayrCommand => {
+ if let Some(c) = util::wofi_select(
+ "Select swayr command",
+ &[
+ SwayrCommand::ExecuteSwaymsgCommand,
+ SwayrCommand::QuitWindow,
+ SwayrCommand::QuitWorkspaceOrWindow,
+ SwayrCommand::SwitchWindow,
+ SwayrCommand::SwitchWorkspace,
+ SwayrCommand::SwitchWorkspaceOrWindow,
+ SwayrCommand::SwitchToUrgentOrLRUWindow,
+ SwayrCommand::NextWindow,
+ SwayrCommand::PrevWindow,
+ ],
+ ) {
+ exec_swayr_cmd(c, extra_props);
+ }
+ }
+ }
+}
+
+fn focus_window_by_id(id: i64) {
+ util::swaymsg(&[format!("[con_id={}]", id).as_str(), "focus"]);
+}
+
+fn quit_window_by_id(id: i64) {
+ util::swaymsg(&[format!("[con_id={}]", id).as_str(), "kill"]);
+}
+
+fn get_tree() -> r::Node {
+ match s::Connection::new() {
+ Ok(mut con) => con.get_tree().expect("Got no root node"),
+ Err(err) => panic!(err),
+ }
+}
+
+pub fn switch_to_urgent_or_lru_window(
+ extra_props: Option<&HashMap>,
+) {
+ let root = get_tree();
+ let windows = con::get_windows(&root, extra_props);
+ if let Some(win) = windows
+ .iter()
+ .find(|w| w.is_urgent())
+ .or_else(|| windows.get(0))
+ {
+ println!("Switching to {}", win);
+ focus_window_by_id(win.get_id())
+ } else {
+ println!("No window to switch to.")
+ }
+}
+
+pub fn switch_window(extra_props: Option<&HashMap>) {
+ let root = get_tree();
+ let windows = con::get_windows(&root, extra_props);
+
+ if let Some(window) = con::select_window("Switch to window", &windows) {
+ focus_window_by_id(window.get_id())
+ }
+}
+
+pub enum Direction {
+ Backward,
+ Forward,
+}
+
+pub fn focus_next_window_in_direction(
+ dir: Direction,
+ extra_props: Option<&HashMap>,
+) {
+ let root = get_tree();
+ let windows = con::get_windows(&root, None);
+
+ if windows.len() < 2 {
+ return;
+ }
+
+ let pred: Box bool> =
+ if windows.iter().find(|w| w.is_focused()).is_none() {
+ let last_focused_win_id = con::get_windows(&root, extra_props)
+ .get(0)
+ .unwrap()
+ .get_id();
+ Box::new(move |w| w.get_id() == last_focused_win_id)
+ } else {
+ Box::new(|w: &con::Window| w.is_focused())
+ };
+
+ let mut iter: Box> = match dir {
+ Direction::Forward => Box::new(windows.iter().rev().cycle()),
+ Direction::Backward => Box::new(windows.iter().cycle()),
+ };
+
+ loop {
+ let win = iter.next().unwrap();
+ if pred(win) {
+ let win = iter.next().unwrap();
+ focus_window_by_id(win.get_id());
+ return;
+ }
+ }
+}
+
+pub fn switch_workspace(extra_props: Option<&HashMap>) {
+ let root = get_tree();
+ let workspaces = con::get_workspaces(&root, false, extra_props);
+
+ if let Some(workspace) =
+ con::select_workspace("Switch to workspace", &workspaces)
+ {
+ util::swaymsg(&["workspace", "number", workspace.get_name()]);
+ }
+}
+
+pub fn switch_workspace_or_window(
+ extra_props: Option<&HashMap>,
+) {
+ let root = get_tree();
+ let workspaces = con::get_workspaces(&root, false, extra_props);
+ let ws_or_wins = con::WsOrWin::from_workspaces(&workspaces);
+ if let Some(ws_or_win) = con::select_workspace_or_window(
+ "Select workspace or window",
+ &ws_or_wins,
+ ) {
+ match ws_or_win {
+ con::WsOrWin::Ws { ws } => {
+ util::swaymsg(&["workspace", "number", ws.get_name()]);
+ }
+ con::WsOrWin::Win { win } => focus_window_by_id(win.get_id()),
+ }
+ }
+}
+
+pub fn quit_window(extra_props: Option<&HashMap>) {
+ let root = get_tree();
+ let windows = con::get_windows(&root, extra_props);
+
+ if let Some(window) = con::select_window("Quit window", &windows) {
+ quit_window_by_id(window.get_id())
+ }
+}
+
+pub fn quit_workspace_or_window(
+ extra_props: Option<&HashMap>,
+) {
+ let root = get_tree();
+ let workspaces = con::get_workspaces(&root, false, extra_props);
+ let ws_or_wins = con::WsOrWin::from_workspaces(&workspaces);
+ if let Some(ws_or_win) =
+ con::select_workspace_or_window("Quit workspace or window", &ws_or_wins)
+ {
+ match ws_or_win {
+ con::WsOrWin::Ws { ws } => {
+ for win in &ws.windows {
+ quit_window_by_id(win.get_id())
+ }
+ }
+ con::WsOrWin::Win { win } => quit_window_by_id(win.get_id()),
+ }
+ }
+}
+
+fn get_swaymsg_commands<'a>() -> Vec> {
+ let mut cmds = vec![];
+ cmds.push(vec!["exit"]);
+ cmds.push(vec!["floating", "toggle"]);
+ cmds.push(vec!["focus", "child"]);
+ cmds.push(vec!["focus", "parent"]);
+
+ for b in &["none", "normal", "csd", "pixel"] {
+ cmds.push(vec!["border", b]);
+ }
+
+ cmds.push(vec!["focus", "tiling"]);
+ cmds.push(vec!["focus", "floating"]);
+ cmds.push(vec!["focus", "mode_toggle"]);
+
+ cmds.push(vec!["fullscreen", "toggle"]);
+
+ for x in &["focus", "fullscreen", "open", "none", "visible"] {
+ cmds.push(vec!["inhibit_idle", x])
+ }
+
+ for l in &["default", "splith", "splitv", "stacking", "tiling"] {
+ cmds.push(vec!["layout", l])
+ }
+
+ cmds.push(vec!["reload"]);
+
+ for e in &["enable", "disable"] {
+ cmds.push(vec!["shortcuts", "inhibitor", e])
+ }
+
+ cmds.push(vec!["sticky", "toggle"]);
+
+ for x in &["yes", "no", "always"] {
+ cmds.push(vec!["focus_follows_mouse", x])
+ }
+
+ for x in &["smart", "urgent", "focus", "none"] {
+ cmds.push(vec!["focus_on_window_activation", x])
+ }
+
+ for x in &["yes", "no", "force", "workspace"] {
+ cmds.push(vec!["focus_wrapping", x])
+ }
+
+ for x in &[
+ "none",
+ "vertical",
+ "horizontal",
+ "both",
+ "smart",
+ "smart_no_gaps",
+ ] {
+ cmds.push(vec!["hide_edge_borders", x])
+ }
+
+ cmds.push(vec!["kill"]);
+
+ for x in &["on", "no_gaps", "off"] {
+ cmds.push(vec!["smart_borders", x])
+ }
+
+ for x in &["on", "off"] {
+ cmds.push(vec!["smart_gaps", x])
+ }
+
+ for x in &["output", "container", "none"] {
+ cmds.push(vec!["mouse_warping", x])
+ }
+
+ for x in &["smart", "ignore", "leave_fullscreen"] {
+ cmds.push(vec!["popup_during_fullscreen", x])
+ }
+
+ for x in &["yes", "no"] {
+ cmds.push(vec!["show_marks", x]);
+ cmds.push(vec!["workspace_auto_back_and_forth", x]);
+ }
+
+ cmds.push(vec!["tiling_drag", "toggle"]);
+
+ for x in &["left", "center", "right"] {
+ cmds.push(vec!["title_align", x]);
+ }
+
+ for x in &["enable", "disable", "allow", "deny"] {
+ cmds.push(vec!["urgent", x])
+ }
+
+ cmds.sort();
+
+ cmds.iter()
+ .map(|v| SwaymsgCmd { cmd: v.to_vec() })
+ .collect()
+}
+
+struct SwaymsgCmd<'a> {
+ cmd: Vec<&'a str>,
+}
+
+impl<'a> fmt::Display for SwaymsgCmd<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ write!(f, "{}", self.cmd.join(" "))
+ }
+}
+
+pub fn exec_swaymsg_command() {
+ let cmds = get_swaymsg_commands();
+ let cmd = util::wofi_select("Execute swaymsg command", &cmds);
+ if let Some(cmd) = cmd {
+ util::swaymsg(&cmd.cmd);
+ }
+}
diff --git a/src/con.rs b/src/con.rs
index 68cec4f..ac7f9ff 100644
--- a/src/con.rs
+++ b/src/con.rs
@@ -6,7 +6,6 @@ use ipc::NodeMethods;
use std::cmp;
use std::collections::HashMap;
use std::fmt;
-use std::os::unix::net::UnixStream;
use swayipc::reply as r;
#[derive(Debug)]
@@ -106,16 +105,16 @@ impl<'a> fmt::Display for Window<'a> {
}
}
-fn build_windows(
- root: &r::Node,
- mut con_props: HashMap,
-) -> Vec {
+fn build_windows<'a>(
+ root: &'a r::Node,
+ extra_props: Option<&HashMap>,
+) -> Vec> {
let mut v = vec![];
for workspace in root.workspaces() {
for n in workspace.windows() {
v.push(Window {
node: &n,
- con_props: con_props.remove(&n.id),
+ con_props: extra_props.and_then(|m| m.get(&n.id).cloned()),
workspace: &workspace,
})
}
@@ -123,10 +122,10 @@ fn build_windows(
v
}
-fn build_workspaces(
- root: &r::Node,
- mut con_props: HashMap,
-) -> Vec {
+fn build_workspaces<'a>(
+ root: &'a r::Node,
+ extra_props: Option<&HashMap>,
+) -> Vec> {
let mut v = vec![];
for workspace in root.workspaces() {
let mut wins: Vec = workspace
@@ -134,14 +133,14 @@ fn build_workspaces(
.iter()
.map(|w| Window {
node: &w,
- con_props: con_props.remove(&w.id),
+ con_props: extra_props.and_then(|m| m.get(&w.id).cloned()),
workspace: &workspace,
})
.collect();
wins.sort();
v.push(Workspace {
node: &workspace,
- con_props: con_props.remove(&workspace.id),
+ con_props: extra_props.and_then(|m| m.get(&workspace.id).cloned()),
windows: wins,
})
}
@@ -149,49 +148,26 @@ fn build_workspaces(
v
}
-fn get_con_props() -> Result, serde_json::Error> {
- if let Ok(sock) = UnixStream::connect(util::get_swayr_socket_path()) {
- serde_json::from_reader(sock)
- } else {
- panic!("Could not connect to socket!")
- }
-}
-
/// Gets all application windows of the tree.
-pub fn get_windows(root: &r::Node, sort: bool) -> Vec {
- let con_props = if sort {
- match get_con_props() {
- Ok(con_props) => Some(con_props),
- Err(e) => {
- eprintln!("Got no con_props: {:?}", e);
- None
- }
- }
- } else {
- None
- };
-
- let mut wins = build_windows(root, con_props.unwrap_or_default());
- if sort {
+pub fn get_windows<'a>(
+ root: &'a r::Node,
+ extra_props: Option<&HashMap>,
+) -> Vec> {
+ let extra_props_given = extra_props.is_some();
+ let mut wins = build_windows(root, extra_props);
+ if extra_props_given {
wins.sort();
}
wins
}
/// Gets all application windows of the tree.
-pub fn get_workspaces(
- root: &r::Node,
+pub fn get_workspaces<'a>(
+ root: &'a r::Node,
include_scratchpad: bool,
-) -> Vec {
- let con_props = match get_con_props() {
- Ok(con_props) => Some(con_props),
- Err(e) => {
- eprintln!("Got no con_props: {:?}", e);
- None
- }
- };
-
- let workspaces = build_workspaces(root, con_props.unwrap_or_default());
+ con_props: Option<&HashMap>,
+) -> Vec> {
+ let workspaces = build_workspaces(root, con_props);
let mut workspaces = if include_scratchpad {
workspaces
} else {
diff --git a/src/demon.rs b/src/demon.rs
index b2206b2..b8be845 100644
--- a/src/demon.rs
+++ b/src/demon.rs
@@ -1,10 +1,11 @@
//! Functions and data structures of the swayrd demon.
+use crate::cmds;
use crate::ipc;
use crate::util;
use std::collections::HashMap;
-use std::io::Write;
+use std::io::Read;
use std::os::unix::net::{UnixListener, UnixStream};
use std::sync::Arc;
use std::sync::RwLock;
@@ -102,7 +103,7 @@ fn update_last_focus_time(
extra_props: Arc>>,
) {
let mut write_lock = extra_props.write().unwrap();
- if let Some(mut wp) = write_lock.get_mut(&id) {
+ if let Some(wp) = write_lock.get_mut(&id) {
wp.last_focus_time = get_epoch_time_as_millis();
} else {
write_lock.insert(
@@ -160,8 +161,17 @@ fn handle_client_request(
mut stream: UnixStream,
extra_props: Arc>>,
) {
- let json = serde_json::to_string(&*extra_props.read().unwrap()).unwrap();
- if let Err(err) = stream.write_all(json.as_bytes()) {
- eprintln!("Error writing to client: {:?}", err);
+ let mut cmd_str = String::new();
+ if stream.read_to_string(&mut cmd_str).is_ok() {
+ if let Ok(cmd) = serde_json::from_str::(&cmd_str) {
+ cmds::exec_swayr_cmd(&cmd, extra_props);
+ } else {
+ eprintln!(
+ "Could not serialize following string to SwayrCommand.\n{}",
+ cmd_str
+ );
+ }
+ } else {
+ eprintln!("Could not read command from client.");
}
}
diff --git a/src/ipc.rs b/src/ipc.rs
index 926d2d7..9a61ada 100644
--- a/src/ipc.rs
+++ b/src/ipc.rs
@@ -5,6 +5,7 @@ extern crate serde_json;
extern crate swayipc;
extern crate users;
+use clap::Clap;
use serde::{Deserialize, Serialize};
use swayipc::reply as r;
@@ -73,8 +74,32 @@ impl NodeMethods for r::Node {
}
}
+#[derive(Clap, Debug, Deserialize, Serialize)]
+pub enum SwayrCommand {
+ /// Switch to next urgent window (if any) or to last recently used window.
+ SwitchToUrgentOrLRUWindow,
+ /// Focus the selected window
+ SwitchWindow,
+ /// Focus the next window.
+ NextWindow,
+ /// Focus the previous window.
+ PrevWindow,
+ /// Quit the selected window
+ QuitWindow,
+ /// Switch to the selected workspace
+ SwitchWorkspace,
+ /// Switch to the selected workspace or focus the selected window
+ SwitchWorkspaceOrWindow,
+ /// Quit all windows of selected workspace or the selected window
+ QuitWorkspaceOrWindow,
+ /// Select and execute a swaymsg command
+ ExecuteSwaymsgCommand,
+ /// Select and execute a swayr command
+ ExecuteSwayrCommand,
+}
+
/// Extra properties gathered by swayrd for windows and workspaces.
-#[derive(Debug, Deserialize, Serialize)]
+#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ExtraProps {
/// Milliseconds since UNIX epoch.
pub last_focus_time: u128,
diff --git a/src/lib.rs b/src/lib.rs
index 3dc667a..b5b9670 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -9,6 +9,7 @@
//! IPC interface. The client `swayr` offers subcommands, see `swayr --help`.
pub mod client;
+pub mod cmds;
pub mod con;
pub mod demon;
pub mod ipc;