alt-tab
This commit is contained in:
+72
-10
@@ -99,32 +99,87 @@ fn live_sockets() -> Vec<PathBuf> {
|
||||
found
|
||||
}
|
||||
|
||||
/// Every view in the tree, in tree order (the same traversal the jq filter did,
|
||||
/// so the grid keeps the ordering the muscle memory expects).
|
||||
pub fn windows(conn: &mut Connection) -> Result<Vec<Target>, swayipc::Error> {
|
||||
/// How to order windows in the grid.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||||
pub enum Order {
|
||||
/// Most-Recently-Used (MRU) focus order: current window first, then previous, etc.
|
||||
#[default]
|
||||
Mru,
|
||||
/// Traversal of sway's layout tree (workspace by workspace).
|
||||
Tree,
|
||||
}
|
||||
|
||||
impl Order {
|
||||
pub fn parse(s: &str) -> Result<Self, String> {
|
||||
match s.trim() {
|
||||
"mru" => Ok(Order::Mru),
|
||||
"tree" => Ok(Order::Tree),
|
||||
other => Err(format!("{other:?} is not mru or tree")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Views in the tree, either in MRU focus order or tree layout order.
|
||||
pub fn windows(conn: &mut Connection, order: Order) -> Result<Vec<Target>, swayipc::Error> {
|
||||
let mut out = Vec::new();
|
||||
collect(&conn.get_tree()?, &mut out);
|
||||
let tree = conn.get_tree()?;
|
||||
match order {
|
||||
Order::Mru => {
|
||||
collect_mru(&tree, &mut out);
|
||||
// Ensure the currently focused window is at index 0
|
||||
if let Some(pos) = out.iter().position(|t| t.focused) {
|
||||
if pos > 0 {
|
||||
let focused = out.remove(pos);
|
||||
out.insert(0, focused);
|
||||
}
|
||||
}
|
||||
}
|
||||
Order::Tree => collect_tree(&tree, &mut out),
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
fn collect(node: &Node, out: &mut Vec<Target>) {
|
||||
fn collect_target(node: &Node) -> Option<Target> {
|
||||
let is_con = matches!(node.node_type, NodeType::Con | NodeType::FloatingCon);
|
||||
let class = node
|
||||
.window_properties
|
||||
.as_ref()
|
||||
.and_then(|p| p.class.clone());
|
||||
if is_con && (node.app_id.is_some() || class.is_some()) {
|
||||
// A view with no identifier can't be captured, but it still belongs in
|
||||
// the list: it gets a tile with no thumbnail.
|
||||
out.push(Target::window(
|
||||
Some(Target::window(
|
||||
node.id,
|
||||
node.foreign_toplevel_identifier.clone().unwrap_or_default(),
|
||||
node.app_id.clone().or(class).unwrap_or_default(),
|
||||
node.name.clone().unwrap_or_default(),
|
||||
));
|
||||
node.focused,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_tree(node: &Node, out: &mut Vec<Target>) {
|
||||
if let Some(target) = collect_target(node) {
|
||||
out.push(target);
|
||||
}
|
||||
for child in node.nodes.iter().chain(node.floating_nodes.iter()) {
|
||||
collect(child, out);
|
||||
collect_tree(child, out);
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_mru(node: &Node, out: &mut Vec<Target>) {
|
||||
if let Some(target) = collect_target(node) {
|
||||
out.push(target);
|
||||
}
|
||||
let mut children: Vec<&Node> = node.nodes.iter().chain(node.floating_nodes.iter()).collect();
|
||||
children.sort_by_key(|child| {
|
||||
node.focus
|
||||
.iter()
|
||||
.position(|&id| id == child.id)
|
||||
.unwrap_or(usize::MAX)
|
||||
});
|
||||
for child in children {
|
||||
collect_mru(child, out);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,4 +239,11 @@ mod tests {
|
||||
assert_eq!(socket_pid("sway-ipc.1000..sock"), None);
|
||||
assert_eq!(socket_pid("sway-ipc.1000.notapid.sock"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn order_parses() {
|
||||
assert_eq!(super::Order::parse("mru"), Ok(super::Order::Mru));
|
||||
assert_eq!(super::Order::parse("tree"), Ok(super::Order::Tree));
|
||||
assert!(super::Order::parse("invalid").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user