wlgrid described the shape of the thing rather than what it is for, and the shape is the least interesting part now that it doesn't focus anything: it shows you what is running and reports which one you pointed at. wl-pick says that. The wl- prefix rather than wlr- is deliberate. The capture path is entirely upstream ext- protocols (ext-image-copy-capture, ext-image-capture-source, ext-foreign-toplevel-list); the only wlroots-flavoured piece is layer-shell, which KDE, niri and labwc implement too. What actually keeps this from running on other compositors is the sway IPC dependency, not wlroots, so wlr- would promise a portability that isn't there. Hyphenated because the ecosystem hyphenates when the suffix is a real word — wl-clipboard, wl-mirror, wl-screenrec — and reserves the smushed form for coinages like wlsunset. Also renames the layer-shell namespace and the memfd labels, which show up in compositor debugging.
52 lines
1.8 KiB
Rust
52 lines
1.8 KiB
Rust
//! sway is the source of truth for the window list (`swaymsg -t get_tree`); the
|
|
//! Wayland side only supplies pixels. The join between the two is
|
|
//! `foreign_toplevel_identifier`, which sway reports per view.
|
|
//!
|
|
//! Acting on the choice is deliberately not here: wl-pick reports what was picked
|
|
//! and the caller decides what that means.
|
|
|
|
use swayipc::{Connection, Node, NodeType};
|
|
|
|
use crate::target::Target;
|
|
|
|
/// 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> {
|
|
let mut out = Vec::new();
|
|
collect(&conn.get_tree()?, &mut out);
|
|
Ok(out)
|
|
}
|
|
|
|
fn collect(node: &Node, out: &mut Vec<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(
|
|
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(),
|
|
));
|
|
}
|
|
for child in node.nodes.iter().chain(node.floating_nodes.iter()) {
|
|
collect(child, out);
|
|
}
|
|
}
|
|
|
|
/// The largest integer scale in use, which is what the overlay renders at.
|
|
pub fn scale(conn: &mut Connection) -> Result<i32, swayipc::Error> {
|
|
Ok(conn
|
|
.get_outputs()?
|
|
.iter()
|
|
.filter(|o| o.active)
|
|
.map(|o| o.scale.unwrap_or(1.0).ceil() as i32)
|
|
.max()
|
|
.unwrap_or(1)
|
|
.max(1))
|
|
}
|