Execute commands in the demon instead of the client

timeout_old
Tassilo Horn 4 years ago
parent 1d3b83f288
commit 5c348fb7c4
  1. 7
      src/bin/swayr.rs
  2. 330
      src/client.rs
  3. 329
      src/cmds.rs
  4. 70
      src/con.rs
  5. 20
      src/demon.rs
  6. 27
      src/ipc.rs
  7. 1
      src/lib.rs

@ -4,6 +4,7 @@
extern crate clap; extern crate clap;
use clap::Clap; use clap::Clap;
use swayr::client; use swayr::client;
use swayr::ipc;
/// Windows are sorted urgent first, then windows in LRU order, focused window /// Windows are sorted urgent first, then windows in LRU order, focused window
/// last. Licensed under the GPLv3 (or later). /// last. Licensed under the GPLv3 (or later).
@ -15,10 +16,12 @@ use swayr::client;
)] )]
struct Opts { struct Opts {
#[clap(subcommand)] #[clap(subcommand)]
command: client::SwayrCommand, command: ipc::SwayrCommand,
} }
fn main() { fn main() {
let opts: Opts = Opts::parse(); 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);
}
} }

@ -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 crate::util;
use std::io::Write;
use clap::Clap; use std::os::unix::net::UnixStream;
use std::fmt;
pub fn send_swayr_cmd(
use swayipc as s; cmd: ipc::SwayrCommand,
use swayipc::reply as r; ) -> std::result::Result<(), std::io::Error> {
let mut sock = UnixStream::connect(util::get_swayr_socket_path())?;
#[derive(Clap, Debug)] sock.write_all(serde_json::to_string(&cmd).unwrap().as_bytes())
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, "<b>{:?}</b>", 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<dyn Fn(&con::Window) -> 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<dyn Iterator<Item = &con::Window>> = 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<SwaymsgCmd<'a>> {
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, "<b>{}</b>", 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);
}
} }

@ -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, "<b>{:?}</b>", self)
}
}
pub fn exec_swayr_cmd(
cmd: &SwayrCommand,
extra_props: Arc<RwLock<HashMap<i64, ipc::ExtraProps>>>,
) {
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<i64, ipc::ExtraProps>>,
) {
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<i64, ipc::ExtraProps>>) {
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<i64, ipc::ExtraProps>>,
) {
let root = get_tree();
let windows = con::get_windows(&root, None);
if windows.len() < 2 {
return;
}
let pred: Box<dyn Fn(&con::Window) -> 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<dyn Iterator<Item = &con::Window>> = 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<i64, ipc::ExtraProps>>) {
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<i64, ipc::ExtraProps>>,
) {
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<i64, ipc::ExtraProps>>) {
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<i64, ipc::ExtraProps>>,
) {
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<SwaymsgCmd<'a>> {
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, "<b>{}</b>", 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);
}
}

@ -6,7 +6,6 @@ use ipc::NodeMethods;
use std::cmp; use std::cmp;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::os::unix::net::UnixStream;
use swayipc::reply as r; use swayipc::reply as r;
#[derive(Debug)] #[derive(Debug)]
@ -106,16 +105,16 @@ impl<'a> fmt::Display for Window<'a> {
} }
} }
fn build_windows( fn build_windows<'a>(
root: &r::Node, root: &'a r::Node,
mut con_props: HashMap<i64, ipc::ExtraProps>, extra_props: Option<&HashMap<i64, ipc::ExtraProps>>,
) -> Vec<Window> { ) -> Vec<Window<'a>> {
let mut v = vec![]; let mut v = vec![];
for workspace in root.workspaces() { for workspace in root.workspaces() {
for n in workspace.windows() { for n in workspace.windows() {
v.push(Window { v.push(Window {
node: &n, node: &n,
con_props: con_props.remove(&n.id), con_props: extra_props.and_then(|m| m.get(&n.id).cloned()),
workspace: &workspace, workspace: &workspace,
}) })
} }
@ -123,10 +122,10 @@ fn build_windows(
v v
} }
fn build_workspaces( fn build_workspaces<'a>(
root: &r::Node, root: &'a r::Node,
mut con_props: HashMap<i64, ipc::ExtraProps>, extra_props: Option<&HashMap<i64, ipc::ExtraProps>>,
) -> Vec<Workspace> { ) -> Vec<Workspace<'a>> {
let mut v = vec![]; let mut v = vec![];
for workspace in root.workspaces() { for workspace in root.workspaces() {
let mut wins: Vec<Window> = workspace let mut wins: Vec<Window> = workspace
@ -134,14 +133,14 @@ fn build_workspaces(
.iter() .iter()
.map(|w| Window { .map(|w| Window {
node: &w, node: &w,
con_props: con_props.remove(&w.id), con_props: extra_props.and_then(|m| m.get(&w.id).cloned()),
workspace: &workspace, workspace: &workspace,
}) })
.collect(); .collect();
wins.sort(); wins.sort();
v.push(Workspace { v.push(Workspace {
node: &workspace, node: &workspace,
con_props: con_props.remove(&workspace.id), con_props: extra_props.and_then(|m| m.get(&workspace.id).cloned()),
windows: wins, windows: wins,
}) })
} }
@ -149,49 +148,26 @@ fn build_workspaces(
v v
} }
fn get_con_props() -> Result<HashMap<i64, ipc::ExtraProps>, 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. /// Gets all application windows of the tree.
pub fn get_windows(root: &r::Node, sort: bool) -> Vec<Window> { pub fn get_windows<'a>(
let con_props = if sort { root: &'a r::Node,
match get_con_props() { extra_props: Option<&HashMap<i64, ipc::ExtraProps>>,
Ok(con_props) => Some(con_props), ) -> Vec<Window<'a>> {
Err(e) => { let extra_props_given = extra_props.is_some();
eprintln!("Got no con_props: {:?}", e); let mut wins = build_windows(root, extra_props);
None if extra_props_given {
}
}
} else {
None
};
let mut wins = build_windows(root, con_props.unwrap_or_default());
if sort {
wins.sort(); wins.sort();
} }
wins wins
} }
/// Gets all application windows of the tree. /// Gets all application windows of the tree.
pub fn get_workspaces( pub fn get_workspaces<'a>(
root: &r::Node, root: &'a r::Node,
include_scratchpad: bool, include_scratchpad: bool,
) -> Vec<Workspace> { con_props: Option<&HashMap<i64, ipc::ExtraProps>>,
let con_props = match get_con_props() { ) -> Vec<Workspace<'a>> {
Ok(con_props) => Some(con_props), let workspaces = build_workspaces(root, con_props);
Err(e) => {
eprintln!("Got no con_props: {:?}", e);
None
}
};
let workspaces = build_workspaces(root, con_props.unwrap_or_default());
let mut workspaces = if include_scratchpad { let mut workspaces = if include_scratchpad {
workspaces workspaces
} else { } else {

@ -1,10 +1,11 @@
//! Functions and data structures of the swayrd demon. //! Functions and data structures of the swayrd demon.
use crate::cmds;
use crate::ipc; use crate::ipc;
use crate::util; use crate::util;
use std::collections::HashMap; use std::collections::HashMap;
use std::io::Write; use std::io::Read;
use std::os::unix::net::{UnixListener, UnixStream}; use std::os::unix::net::{UnixListener, UnixStream};
use std::sync::Arc; use std::sync::Arc;
use std::sync::RwLock; use std::sync::RwLock;
@ -102,7 +103,7 @@ fn update_last_focus_time(
extra_props: Arc<RwLock<HashMap<i64, ipc::ExtraProps>>>, extra_props: Arc<RwLock<HashMap<i64, ipc::ExtraProps>>>,
) { ) {
let mut write_lock = extra_props.write().unwrap(); 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(); wp.last_focus_time = get_epoch_time_as_millis();
} else { } else {
write_lock.insert( write_lock.insert(
@ -160,8 +161,17 @@ fn handle_client_request(
mut stream: UnixStream, mut stream: UnixStream,
extra_props: Arc<RwLock<HashMap<i64, ipc::ExtraProps>>>, extra_props: Arc<RwLock<HashMap<i64, ipc::ExtraProps>>>,
) { ) {
let json = serde_json::to_string(&*extra_props.read().unwrap()).unwrap(); let mut cmd_str = String::new();
if let Err(err) = stream.write_all(json.as_bytes()) { if stream.read_to_string(&mut cmd_str).is_ok() {
eprintln!("Error writing to client: {:?}", err); if let Ok(cmd) = serde_json::from_str::<ipc::SwayrCommand>(&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.");
} }
} }

@ -5,6 +5,7 @@ extern crate serde_json;
extern crate swayipc; extern crate swayipc;
extern crate users; extern crate users;
use clap::Clap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use swayipc::reply as r; 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. /// Extra properties gathered by swayrd for windows and workspaces.
#[derive(Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ExtraProps { pub struct ExtraProps {
/// Milliseconds since UNIX epoch. /// Milliseconds since UNIX epoch.
pub last_focus_time: u128, pub last_focus_time: u128,

@ -9,6 +9,7 @@
//! IPC interface. The client `swayr` offers subcommands, see `swayr --help`. //! IPC interface. The client `swayr` offers subcommands, see `swayr --help`.
pub mod client; pub mod client;
pub mod cmds;
pub mod con; pub mod con;
pub mod demon; pub mod demon;
pub mod ipc; pub mod ipc;

Loading…
Cancel
Save