|
|
@ -2,118 +2,125 @@ |
|
|
|
|
|
|
|
|
|
|
|
use crate::ipc; |
|
|
|
use crate::ipc; |
|
|
|
use crate::util; |
|
|
|
use crate::util; |
|
|
|
use serde_json::Deserializer; |
|
|
|
|
|
|
|
use std::collections::HashMap; |
|
|
|
use std::collections::HashMap; |
|
|
|
use std::io::Write; |
|
|
|
use std::io::Write; |
|
|
|
use std::os::unix::net::{UnixListener, UnixStream}; |
|
|
|
use std::os::unix::net::{UnixListener, UnixStream}; |
|
|
|
use std::process as proc; |
|
|
|
|
|
|
|
use std::sync::Arc; |
|
|
|
use std::sync::Arc; |
|
|
|
use std::sync::RwLock; |
|
|
|
use std::sync::RwLock; |
|
|
|
use std::time::{SystemTime, UNIX_EPOCH}; |
|
|
|
use std::time::{SystemTime, UNIX_EPOCH}; |
|
|
|
|
|
|
|
|
|
|
|
pub fn monitor_con_events( |
|
|
|
use swayipc as s; |
|
|
|
con_props: Arc<RwLock<HashMap<ipc::Id, ipc::ConProps>>>, |
|
|
|
use swayipc::reply as r; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn monitor_sway_events( |
|
|
|
|
|
|
|
extra_props: Arc<RwLock<HashMap<i64, ipc::ExtraProps>>>, |
|
|
|
) { |
|
|
|
) { |
|
|
|
let mut child = proc::Command::new("swaymsg") |
|
|
|
let iter = s::Connection::new() |
|
|
|
.arg("--monitor") |
|
|
|
.expect("Could not connect!") |
|
|
|
.arg("--raw") |
|
|
|
.subscribe(&[s::EventType::Window, s::EventType::Workspace]) |
|
|
|
.arg("-t") |
|
|
|
.expect("Could not subscribe to window and workspace events."); |
|
|
|
.arg("subscribe") |
|
|
|
|
|
|
|
.arg("[\"window\", \"workspace\"]") |
|
|
|
|
|
|
|
.stdout(proc::Stdio::piped()) |
|
|
|
|
|
|
|
.spawn() |
|
|
|
|
|
|
|
.expect("Failed to subscribe to window events"); |
|
|
|
|
|
|
|
let stdout = child.stdout.take().unwrap(); |
|
|
|
|
|
|
|
let reader = std::io::BufReader::new(stdout); |
|
|
|
|
|
|
|
let deserializer = Deserializer::from_reader(reader); |
|
|
|
|
|
|
|
for res in deserializer.into_iter::<ipc::ConEvent>() { |
|
|
|
|
|
|
|
match res { |
|
|
|
|
|
|
|
Ok(win_ev) => handle_con_event(win_ev, con_props.clone()), |
|
|
|
|
|
|
|
Err(err) => eprintln!("Error handling window event:\n{:?}", err), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
match child.try_wait() { |
|
|
|
for ev_result in iter { |
|
|
|
Ok(exit_code) => match exit_code { |
|
|
|
let handled; |
|
|
|
None => { |
|
|
|
match ev_result { |
|
|
|
eprintln!("Stopped monitoring con events. Restarting..."); |
|
|
|
Ok(ev) => match ev { |
|
|
|
monitor_con_events(con_props) |
|
|
|
r::Event::Window(win_ev) => { |
|
|
|
} |
|
|
|
let extra_props_clone = extra_props.clone(); |
|
|
|
Some(exit_code) => { |
|
|
|
handled = handle_window_event(win_ev, extra_props_clone); |
|
|
|
println!("Swaymsg exited with code {}. Exiting.", exit_code) |
|
|
|
} |
|
|
|
|
|
|
|
r::Event::Workspace(ws_ev) => { |
|
|
|
|
|
|
|
let extra_props_clone = extra_props.clone(); |
|
|
|
|
|
|
|
handled = handle_workspace_event(ws_ev, extra_props_clone); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
_ => handled = false, |
|
|
|
}, |
|
|
|
}, |
|
|
|
Err(err) => println!("Swaymsg errored with {}. Exiting.", err), |
|
|
|
Err(e) => { |
|
|
|
|
|
|
|
eprintln!("Error while receiving events: {}", e); |
|
|
|
|
|
|
|
handled = false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if handled { |
|
|
|
fn update_last_focus_time( |
|
|
|
println!( |
|
|
|
id: ipc::Id, |
|
|
|
"New extra_props state:\n{:#?}", |
|
|
|
con_props: Arc<RwLock<HashMap<ipc::Id, ipc::ConProps>>>, |
|
|
|
*extra_props.read().unwrap() |
|
|
|
) { |
|
|
|
|
|
|
|
let mut write_lock = con_props.write().unwrap(); |
|
|
|
|
|
|
|
if let Some(mut wp) = write_lock.get_mut(&id) { |
|
|
|
|
|
|
|
wp.last_focus_time = get_epoch_time_as_millis(); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
write_lock.insert( |
|
|
|
|
|
|
|
id, |
|
|
|
|
|
|
|
ipc::ConProps { |
|
|
|
|
|
|
|
last_focus_time: get_epoch_time_as_millis(), |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn remove_con_props( |
|
|
|
fn handle_window_event( |
|
|
|
id: ipc::Id, |
|
|
|
ev: Box<r::WindowEvent>, |
|
|
|
con_props: Arc<RwLock<HashMap<ipc::Id, ipc::ConProps>>>, |
|
|
|
extra_props: Arc<RwLock<HashMap<i64, ipc::ExtraProps>>>, |
|
|
|
) { |
|
|
|
) -> bool { |
|
|
|
con_props.write().unwrap().remove(&id); |
|
|
|
let r::WindowEvent { change, container } = *ev; |
|
|
|
|
|
|
|
match change { |
|
|
|
|
|
|
|
r::WindowChange::New | r::WindowChange::Focus => { |
|
|
|
|
|
|
|
update_last_focus_time(container.id, extra_props); |
|
|
|
|
|
|
|
true |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
r::WindowChange::Close => { |
|
|
|
|
|
|
|
remove_extra_props(container.id, extra_props); |
|
|
|
|
|
|
|
true |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
_ => false, |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn handle_con_event( |
|
|
|
fn handle_workspace_event( |
|
|
|
ev: ipc::ConEvent, |
|
|
|
ev: Box<r::WorkspaceEvent>, |
|
|
|
con_props: Arc<RwLock<HashMap<ipc::Id, ipc::ConProps>>>, |
|
|
|
extra_props: Arc<RwLock<HashMap<i64, ipc::ExtraProps>>>, |
|
|
|
) { |
|
|
|
) -> bool { |
|
|
|
let mut handled = true; |
|
|
|
let r::WorkspaceEvent { |
|
|
|
let con_props2 = con_props.clone(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
match ev { |
|
|
|
|
|
|
|
ipc::ConEvent::WindowEvent { change, container } => match change { |
|
|
|
|
|
|
|
ipc::WindowEventType::New | ipc::WindowEventType::Focus => { |
|
|
|
|
|
|
|
update_last_focus_time(container.id, con_props) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ipc::WindowEventType::Close => { |
|
|
|
|
|
|
|
remove_con_props(container.id, con_props) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
_ => handled = false, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
ipc::ConEvent::WorkspaceEvent { |
|
|
|
|
|
|
|
change, |
|
|
|
change, |
|
|
|
current, |
|
|
|
current, |
|
|
|
old: _, |
|
|
|
old: _, |
|
|
|
} => match change { |
|
|
|
} = *ev; |
|
|
|
ipc::WorkspaceEventType::Init | ipc::WorkspaceEventType::Focus => { |
|
|
|
match change { |
|
|
|
|
|
|
|
r::WorkspaceChange::Init | r::WorkspaceChange::Focus => { |
|
|
|
update_last_focus_time( |
|
|
|
update_last_focus_time( |
|
|
|
current |
|
|
|
current |
|
|
|
.expect("No current in Init or Focus workspace event") |
|
|
|
.expect("No current in Init or Focus workspace event") |
|
|
|
.id, |
|
|
|
.id, |
|
|
|
con_props, |
|
|
|
extra_props, |
|
|
|
) |
|
|
|
); |
|
|
|
|
|
|
|
true |
|
|
|
} |
|
|
|
} |
|
|
|
ipc::WorkspaceEventType::Empty => remove_con_props( |
|
|
|
r::WorkspaceChange::Empty => { |
|
|
|
|
|
|
|
remove_extra_props( |
|
|
|
current.expect("No current in Empty workspace event").id, |
|
|
|
current.expect("No current in Empty workspace event").id, |
|
|
|
con_props, |
|
|
|
extra_props, |
|
|
|
), |
|
|
|
); |
|
|
|
_ => handled = false, |
|
|
|
false |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
_ => false, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if handled { |
|
|
|
fn update_last_focus_time( |
|
|
|
println!("New con_props state:\n{:#?}", *con_props2.read().unwrap()); |
|
|
|
id: i64, |
|
|
|
|
|
|
|
extra_props: Arc<RwLock<HashMap<i64, ipc::ExtraProps>>>, |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
let mut write_lock = extra_props.write().unwrap(); |
|
|
|
|
|
|
|
if let Some(mut wp) = write_lock.get_mut(&id) { |
|
|
|
|
|
|
|
wp.last_focus_time = get_epoch_time_as_millis(); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
write_lock.insert( |
|
|
|
|
|
|
|
id, |
|
|
|
|
|
|
|
ipc::ExtraProps { |
|
|
|
|
|
|
|
last_focus_time: get_epoch_time_as_millis(), |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn remove_extra_props( |
|
|
|
|
|
|
|
id: i64, |
|
|
|
|
|
|
|
extra_props: Arc<RwLock<HashMap<i64, ipc::ExtraProps>>>, |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
extra_props.write().unwrap().remove(&id); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn get_epoch_time_as_millis() -> u128 { |
|
|
|
fn get_epoch_time_as_millis() -> u128 { |
|
|
|
SystemTime::now() |
|
|
|
SystemTime::now() |
|
|
|
.duration_since(UNIX_EPOCH) |
|
|
|
.duration_since(UNIX_EPOCH) |
|
|
@ -122,7 +129,7 @@ fn get_epoch_time_as_millis() -> u128 { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn serve_client_requests( |
|
|
|
pub fn serve_client_requests( |
|
|
|
con_props: Arc<RwLock<HashMap<ipc::Id, ipc::ConProps>>>, |
|
|
|
extra_props: Arc<RwLock<HashMap<i64, ipc::ExtraProps>>>, |
|
|
|
) { |
|
|
|
) { |
|
|
|
match std::fs::remove_file(util::get_swayr_socket_path()) { |
|
|
|
match std::fs::remove_file(util::get_swayr_socket_path()) { |
|
|
|
Ok(()) => println!("Deleted stale socket from previous run."), |
|
|
|
Ok(()) => println!("Deleted stale socket from previous run."), |
|
|
@ -134,7 +141,7 @@ pub fn serve_client_requests( |
|
|
|
for stream in listener.incoming() { |
|
|
|
for stream in listener.incoming() { |
|
|
|
match stream { |
|
|
|
match stream { |
|
|
|
Ok(stream) => { |
|
|
|
Ok(stream) => { |
|
|
|
handle_client_request(stream, con_props.clone()); |
|
|
|
handle_client_request(stream, extra_props.clone()); |
|
|
|
} |
|
|
|
} |
|
|
|
Err(err) => { |
|
|
|
Err(err) => { |
|
|
|
eprintln!("Error handling client request: {}", err); |
|
|
|
eprintln!("Error handling client request: {}", err); |
|
|
@ -151,9 +158,9 @@ pub fn serve_client_requests( |
|
|
|
|
|
|
|
|
|
|
|
fn handle_client_request( |
|
|
|
fn handle_client_request( |
|
|
|
mut stream: UnixStream, |
|
|
|
mut stream: UnixStream, |
|
|
|
con_props: Arc<RwLock<HashMap<ipc::Id, ipc::ConProps>>>, |
|
|
|
extra_props: Arc<RwLock<HashMap<i64, ipc::ExtraProps>>>, |
|
|
|
) { |
|
|
|
) { |
|
|
|
let json = serde_json::to_string(&*con_props.read().unwrap()).unwrap(); |
|
|
|
let json = serde_json::to_string(&*extra_props.read().unwrap()).unwrap(); |
|
|
|
if let Err(err) = stream.write_all(json.as_bytes()) { |
|
|
|
if let Err(err) = stream.write_all(json.as_bytes()) { |
|
|
|
eprintln!("Error writing to client: {:?}", err); |
|
|
|
eprintln!("Error writing to client: {:?}", err); |
|
|
|
} |
|
|
|
} |
|
|
|