diff --git a/Cargo.lock b/Cargo.lock index a871d41..1a8f849 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -653,7 +653,7 @@ dependencies = [ [[package]] name = "sway-flash-indicator" -version = "0.2.1" +version = "0.3.0" dependencies = [ "directories", "futures-util", diff --git a/Cargo.toml b/Cargo.toml index c5639ba..0fc0c91 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sway-flash-indicator" -version = "0.2.1" +version = "0.3.0" edition = "2021" [dependencies] diff --git a/packaging/PKGBUILD b/packaging/PKGBUILD index 4e63c36..9331c57 100644 --- a/packaging/PKGBUILD +++ b/packaging/PKGBUILD @@ -1,7 +1,7 @@ # Maintainer: Alex Janka pkgname=sway-flash-indicator -pkgver=0.2.1 +pkgver=0.3.0 pkgrel=1 pkgdesc="flashes sway indicator border rather than always showing it" arch=('x86_64' 'aarch64') diff --git a/src/config.rs b/src/config.rs index de7f282..6cf792b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,6 +12,7 @@ pub struct Config { pub flash_colour: Lab, pub autosplit_enabled: bool, pub autosplit_ratio: f64, + pub output_blocklist: Vec, } pub fn parse_config() -> Res<()> { @@ -55,6 +56,7 @@ impl Default for Config { }, autosplit_enabled: true, autosplit_ratio: 1.0, + output_blocklist: Vec::new(), } } } diff --git a/src/error.rs b/src/error.rs index 696aea0..51413a8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -14,6 +14,8 @@ pub enum Error { TomlDe(#[from] toml::de::Error), #[error(transparent)] TomlSer(#[from] toml::ser::Error), + #[error("node not found")] + NodeNotFound, } impl From> for Error { diff --git a/src/main.rs b/src/main.rs index 9e8bc0d..13e17e9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,6 +43,7 @@ async fn main() -> Res<()> { .await?; let mut fut: Option> = None; + let mut recent_code = None; while let Some(event) = events.next().await { if let Ok(event) = event { @@ -62,9 +63,37 @@ async fn main() -> Res<()> { swayipc_async::Event::Window(window) if window.change != swayipc_async::WindowChange::Mark => { + let node = window.container; + + if window.change == swayipc_async::WindowChange::New + && node.app_id == Some(String::from("code-url-handler")) + { + recent_code = Some((std::time::Instant::now(), node.id)); + } else if recent_code.is_some_and(|(t, _)| { + std::time::Instant::now().duration_since(t) + > std::time::Duration::from_millis(200) + }) { + recent_code = None; + } + + if let Some((_, id)) = recent_code { + if id == node.id && window.change == swayipc_async::WindowChange::Focus { + recent_code = None; + log::info!("focused the window we want with id {id}"); + if let Err(e) = code_trigger( + &mut autosplit_connection, + id, + &CONFIG.get().unwrap().output_blocklist, + ) + .await + { + log::error!("error {e:?} fixing vscode window"); + } + } + } + // TODO: also change on window closed - // the node we're given is the one that closes - let node = window.container; if node.node_type == swayipc_async::NodeType::Con { let (width, height) = (node.window_rect.width, node.window_rect.height); if width == 0 || height == 0 { @@ -90,6 +119,69 @@ async fn main() -> Res<()> { Ok(()) } +async fn code_trigger + std::cmp::PartialEq>( + connection: &mut swayipc_async::Connection, + id: i64, + output_blocklist: &[T], +) -> Res<()> { + let tree = connection.get_tree().await?; + + for workspace in connection.get_workspaces().await? { + let width = workspace.rect.width; + if workspace.focused { + let mut workspace = get_with_id(&tree, workspace.id)?; + if workspace + .output + .as_ref() + .is_some_and(|output| output_blocklist.iter().any(|s| s == output.as_str())) + { + return Ok(()); + } + + while workspace.focus.len() == 1 { + workspace = get_with_id(workspace, workspace.focus[0])?; + } + if workspace.layout == swayipc_async::NodeLayout::SplitH && workspace.focus.len() == 2 { + let (code, other) = { + let a = get_with_id(&tree, workspace.focus[0])?; + let b = get_with_id(&tree, workspace.focus[1])?; + if contains_child(a, id) { + (a, b) + } else { + (b, a) + } + }; + if code.focus.len() > 1 { + log::info!("more than one thing in vscode focus tree"); + return Ok(()); + } + + let (code_rect, other_rect) = (code.rect, other.rect); + + if code_rect.x > other_rect.x { + log::info!("focused window is to the right"); + connection + .run_command(format!("swap container with con_id {}", other.id)) + .await?; + } + + connection + .run_command(format!("resize set width {}px", width - 1220)) + .await?; + } + } + } + Ok(()) +} + +fn get_with_id(node: &swayipc_async::Node, id: i64) -> Res<&swayipc_async::Node> { + node.find_as_ref(|n| n.id == id).ok_or(Error::NodeNotFound) +} + +fn contains_child(node: &swayipc_async::Node, id: i64) -> bool { + node.find_as_ref(|n| n.id == id).is_some() +} + async fn get_sway_config(connection: &mut swayipc_async::Connection) -> Res<()> { let config = connection.get_config().await?; let default_colours = config