diff --git a/Cargo.lock b/Cargo.lock index 1ed68b6..3015dbb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -145,7 +145,7 @@ dependencies = [ "serde", "serde_repr", "tokio", - "zbus", + "zbus 5.15.0", ] [[package]] @@ -622,9 +622,9 @@ checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" [[package]] name = "futures-io" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" [[package]] name = "futures-lite" @@ -1637,9 +1637,9 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", "windows-sys", @@ -1705,7 +1705,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.2", "once_cell", "rustix", "windows-sys", @@ -2138,8 +2138,7 @@ dependencies = [ "wayland-protocols-misc", "wayland-protocols-wlr", "xkbcommon", - "zbus", - "zvariant", + "zbus 6.0.0", ] [[package]] @@ -2313,11 +2312,39 @@ dependencies = [ "uuid", "windows-sys", "winnow", - "zbus_macros", + "zbus_macros 5.15.0", "zbus_names", "zvariant", ] +[[package]] +name = "zbus" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266223222c9d81e5966455a9da0783e35d56a7ccab79a03c2366b2d98f8fc8a9" +dependencies = [ + "async-trait", + "bitflags", + "endi", + "futures-core", + "hex", + "libc", + "ordered-stream", + "rustix", + "serde", + "serde_repr", + "socket2", + "tokio", + "uds_windows", + "uuid", + "windows-sys", + "winnow", + "zbus_macros 6.0.0", + "zbus_utils", + "zcheapstr", + "zruntime", +] + [[package]] name = "zbus_macros" version = "5.15.0" @@ -2333,6 +2360,18 @@ dependencies = [ "zvariant_utils 3.3.1", ] +[[package]] +name = "zbus_macros" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69191782481ef4e0ac88ca487347c52e08bb85cceb2a163b79f7281fe5be0a3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", + "zbus_utils", +] + [[package]] name = "zbus_names" version = "4.3.2" @@ -2344,6 +2383,19 @@ dependencies = [ "zvariant", ] +[[package]] +name = "zbus_utils" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c27a055b114bd9fc3686e90f62bd1fe612d523fc5f620bac3b1d2f42d3f6cab8" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn 3.0.9", + "winnow", +] + [[package]] name = "zcheapstr" version = "1.1.0" @@ -2379,6 +2431,16 @@ version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +[[package]] +name = "zruntime" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "467fd80a2014d186319f14b81aef027aa466712f355c90158a0e6b39de60726d" +dependencies = [ + "futures-core", + "futures-io", +] + [[package]] name = "zune-core" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index 7b62902..23b54d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "waytool" version = "0.1.0" edition = "2024" -rust-version = "1.88" +rust-version = "1.89" description = "Command-line automation for Wayland: keyboard and pointer input, screenshots and window control on GNOME, KDE, wlroots compositors, Hyprland and niri" license = "Apache-2.0" repository = "https://github.com/mx-shift/waytool" @@ -31,8 +31,7 @@ wayland-protocols = { version = "0.32.13", features = ["client", "unstable", "st wayland-protocols-misc = { version = "0.3.12", features = ["client"] } wayland-protocols-wlr = { version = "0.3.12", features = ["client"] } xkbcommon = { version = "0.9.0", default-features = false } -zbus = { version = "5.15.0", default-features = false, features = ["tokio", "p2p"] } -zvariant = "5" +zbus = { version = "6.0.0", default-features = false, features = ["tokio", "p2p", "proxy", "service"] } [profile.release] strip = true diff --git a/README.md b/README.md index db82bfa..c96fc43 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ sha256sum -c --ignore-missing SHA256SUMS gh attestation verify --repo mx-shift/waytool ``` -Or build from source, with Rust 1.88 or later: +Or build from source, with Rust 1.89 or later: ``` sudo dnf install pipewire-devel libxkbcommon-devel clang # Fedora diff --git a/src/atspi.rs b/src/atspi.rs index c5481cd..59890aa 100644 --- a/src/atspi.rs +++ b/src/atspi.rs @@ -29,7 +29,7 @@ const UI_DEFAULT_DEPTH: u32 = 40; #[derive(Clone, Debug)] struct AccRef { dest: String, - path: zvariant::OwnedObjectPath, + path: zbus::OwnedObjectPath, } /// Connect to the dedicated accessibility bus (its address comes from @@ -46,7 +46,7 @@ pub(crate) async fn a11y_connection(session: &zbus::Connection) -> Result Result &(), ) .await?; - let kids: Vec<(String, zvariant::OwnedObjectPath)> = reply.body().deserialize()?; + let kids: Vec<(String, zbus::OwnedObjectPath)> = reply.body().deserialize()?; Ok(kids .into_iter() .filter(|(_, p)| p.as_str() != "/org/a11y/atspi/null") @@ -83,7 +83,7 @@ async fn acc_name(conn: &zbus::Connection, r: &AccRef) -> String { match reply { Ok(m) => m .body() - .deserialize::() + .deserialize::() .ok() .and_then(|v| String::try_from(v).ok()) .unwrap_or_default(), @@ -180,7 +180,7 @@ async fn a11y_app_pid(conn: &zbus::Connection, dest: &str) -> Option { async fn a11y_find_apps(conn: &zbus::Connection, win: &WindowDict) -> Result<(Vec, bool)> { let root = AccRef { dest: ATSPI_ROOT_DEST.into(), - path: zvariant::OwnedObjectPath::try_from(ATSPI_ROOT_PATH)?, + path: zbus::OwnedObjectPath::try_from(ATSPI_ROOT_PATH)?, }; let apps = acc_children(conn, &root) .await diff --git a/src/backend.rs b/src/backend.rs index fd32343..27b69e6 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -125,7 +125,7 @@ async fn remote_desktop_version(bus: &zbus::Connection) -> Result { ) .await .context("read the RemoteDesktop portal's version")?; - let value: zvariant::OwnedValue = reply.body().deserialize()?; + let value: zbus::OwnedVariant = reply.body().deserialize()?; Ok(u32::try_from(value)?) } diff --git a/src/daemon.rs b/src/daemon.rs index b1ae8c9..42482e1 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -312,7 +312,7 @@ async fn session_survives(daemon: &Daemon) -> Result { /// without reading. Best-effort: no notification server, no /// notification. async fn notify_reconsent(bus: &zbus::Connection, summary: &str, body: &str) { - let hints = std::collections::HashMap::<&str, zvariant::Value>::new(); + let hints = std::collections::HashMap::<&str, zbus::Variant>::new(); let sent = bus .call_method( Some("org.freedesktop.Notifications"), @@ -417,7 +417,7 @@ async fn screen_locked() -> bool { async fn locked() -> Result { let bus = zbus::Connection::system().await?; let dest = "org.freedesktop.login1"; - let user: zvariant::OwnedObjectPath = bus + let user: zbus::OwnedObjectPath = bus .call_method( Some(dest), "/org/freedesktop/login1", @@ -428,7 +428,7 @@ async fn screen_locked() -> bool { .await? .body() .deserialize()?; - let get = |path: zvariant::OwnedObjectPath, iface: &'static str, prop: &'static str| { + let get = |path: zbus::OwnedObjectPath, iface: &'static str, prop: &'static str| { let bus = bus.clone(); async move { let reply = bus @@ -440,11 +440,11 @@ async fn screen_locked() -> bool { &(iface, prop), ) .await?; - let value: zvariant::OwnedValue = reply.body().deserialize()?; + let value: zbus::OwnedVariant = reply.body().deserialize()?; Ok::<_, anyhow::Error>(value) } }; - let (_id, display): (String, zvariant::OwnedObjectPath) = + let (_id, display): (String, zbus::OwnedObjectPath) = get(user, "org.freedesktop.login1.User", "Display") .await? .try_into()?; @@ -1152,10 +1152,10 @@ impl Service { /// logical coordinates, and scale. async fn monitors(&self) -> Result, Error> { let _call = self.admit()?; - let dict = |entries: Vec<(&str, zvariant::Value)>| -> Result { + let dict = |entries: Vec<(&str, zbus::Variant)>| -> Result { entries .into_iter() - .map(|(k, v)| Ok((k.to_owned(), v.try_to_owned().map_err(zbus::Error::from)?))) + .map(|(k, v)| Ok((k.to_owned(), v.try_to_owned()?))) .collect() }; self.daemon @@ -1338,10 +1338,11 @@ pub(crate) async fn serve_client( make_iface: impl FnOnce(Hangup) -> I, ) -> Result<()> { let (hung_up, hangup) = watch::channel(false); + let stream = stream.into_std().context("the client's socket")?; let handshake = zbus::connection::Builder::unix_stream(stream) - .server(zbus::Guid::generate())? + .server(zbus::Guid::generate()) .p2p() - .serve_at(crate::protocol::OBJECT_PATH, make_iface(Hangup(hangup)))? + .serve_at(crate::protocol::OBJECT_PATH, make_iface(Hangup(hangup))) .build(); let conn = tokio::time::timeout(HANDSHAKE_TIMEOUT, handshake) .await @@ -1417,7 +1418,7 @@ mod tests { tx.send(hangup).ok().unwrap(); Nothing })); - let conn = zbus::connection::Builder::unix_stream(client) + let conn = zbus::connection::Builder::unix_stream(client.into_std().unwrap()) .p2p() .build() .await diff --git a/src/display.rs b/src/display.rs index b5f6aef..de47a4b 100644 --- a/src/display.rs +++ b/src/display.rs @@ -7,7 +7,7 @@ use std::collections::HashMap; use anyhow::{Context, Result}; -use zvariant::OwnedValue; +use zbus::OwnedVariant; const DEST: &str = "org.gnome.Mutter.DisplayConfig"; const PATH: &str = "/org/gnome/Mutter/DisplayConfig"; @@ -25,9 +25,9 @@ type CurrentState = ( f64, f64, Vec, - HashMap, + HashMap, )>, - HashMap, + HashMap, )>, Vec<( i32, @@ -36,9 +36,9 @@ type CurrentState = ( u32, bool, Vec<(String, String, String, String)>, - HashMap, + HashMap, )>, - HashMap, + HashMap, ); /// Whether GNOME lays monitors out in physical pixels ("layout-mode" diff --git a/src/extension.rs b/src/extension.rs index f057887..b44a1cc 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -32,8 +32,8 @@ const EXT_CALL_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(5); /// installer rather than being a bare UnknownObject. pub(crate) async fn ext_call(proxy: &zbus::Proxy<'_>, method: &str, body: &B) -> Result where - B: serde::Serialize + zvariant::DynamicType, - R: for<'d> zvariant::DynamicDeserialize<'d>, + B: serde::Serialize + zbus::DynamicType, + R: for<'d> zbus::wire::DynamicDeserialize<'d>, { // gnome-shell runs these on its main thread; one that never answers // mustn't hang the request (and the input lock it may hold). @@ -45,8 +45,8 @@ where EXT_CALL_TIMEOUT.as_secs() ) })?; - call.map_err(|e| match e { - zbus::Error::MethodError(name, _, _) + call.map_err(|e| match crate::protocol::error_reply(&e) { + Some((name, _)) if [ "org.freedesktop.DBus.Error.ServiceUnknown", "org.freedesktop.DBus.Error.UnknownObject", @@ -57,8 +57,8 @@ where { anyhow!("{EXT_INTERFACE}.{method} isn't available ({name}). {EXT_NOT_FOUND_HINT}") } - zbus::Error::MethodError(_, Some(msg), _) => anyhow!("{method}: {msg}"), - e => anyhow!("{EXT_INTERFACE}.{method} failed: {e}"), + Some((_, Some(msg))) => anyhow!("{method}: {msg}"), + _ => anyhow!("{EXT_INTERFACE}.{method} failed: {e}"), }) } diff --git a/src/kwin.rs b/src/kwin.rs index c2ebcb6..84347a1 100644 --- a/src/kwin.rs +++ b/src/kwin.rs @@ -97,7 +97,7 @@ impl Kwin { ) .await .context("serve the KWin script's object")?; - bus.request_name_with_flags(NAME, zbus::fdo::RequestNameFlags::DoNotQueue.into()) + bus.request_name_with_flags(NAME, zbus::fdo::RequestNameFlags::DO_NOT_QUEUE) .await .with_context(|| format!("own {NAME} (is another waytool daemon running?)"))?; Ok(Kwin { diff --git a/src/protocol.rs b/src/protocol.rs index 96793f4..7e258f0 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -22,7 +22,7 @@ use std::path::PathBuf; use anyhow::{Context, Result, anyhow}; use serde::{Deserialize, Serialize}; use tokio::net::UnixStream; -use zvariant::{DeserializeDict, SerializeDict, Type}; +use zbus::{DeserializeDict, SerializeDict, Type}; /// The one object the daemon serves. Its interface is /// `com.mxshift.Waytool.Daemon1`, spelled out in the proxy below @@ -61,7 +61,7 @@ impl From for Error { /// One portal stream (a monitor). `position`/`size` are its rect in /// global logical coordinates, when the portal reported one. #[derive(Debug, SerializeDict, DeserializeDict, Type)] -#[zvariant(signature = "dict")] +#[zbus(signature = "dict")] pub struct StreamDesc { /// The PipeWire node, for a portal stream. pub node_id: Option, @@ -75,7 +75,7 @@ pub struct StreamDesc { pub struct Frame { pub width: u32, pub height: u32, - pub rgba: zvariant::OwnedFd, + pub rgba: zbus::OwnedFd, } /// Elements of a window's accessibility (AT-SPI2) tree. @@ -96,7 +96,7 @@ pub struct UiTree { /// elements without extents and for hidden ones, whose reported /// positions are meaningless. #[derive(Debug, SerializeDict, DeserializeDict, Type)] -#[zvariant(signature = "dict")] +#[zbus(signature = "dict")] pub struct UiNode { pub depth: u32, pub role: String, @@ -108,28 +108,28 @@ pub struct UiNode { /// A window or monitor as the gnome-shell extension describes it, /// passed through unchanged: `a{sv}` with keys like `id`, `title`, /// `frame_x`, `scale`. -pub type WindowDict = std::collections::HashMap; +pub type WindowDict = std::collections::HashMap; -/// Render a dict value as text. zvariant doesn't implement Display on -/// OwnedValue/Value so this dispatches on the common scalar variants +/// Render a dict value as text. zbus doesn't implement Display on +/// OwnedVariant/Variant so this dispatches on the common scalar variants /// explicitly and falls back to Debug for the rest (arrays, dicts, /// structs). -pub fn render_value(v: &zvariant::OwnedValue) -> String { - use zvariant::Value; - let inner: &Value = v; +pub fn render_value(v: &zbus::OwnedVariant) -> String { + use zbus::Variant; + let inner: &Variant = v; match inner { - Value::Str(s) => s.to_string(), - Value::U64(n) => n.to_string(), - Value::U32(n) => n.to_string(), - Value::U16(n) => n.to_string(), - Value::U8(n) => n.to_string(), - Value::I64(n) => n.to_string(), - Value::I32(n) => n.to_string(), - Value::I16(n) => n.to_string(), - Value::Bool(b) => b.to_string(), - Value::F64(f) => format!("{f}"), - Value::Signature(s) => s.to_string(), - Value::ObjectPath(p) => p.to_string(), + Variant::Str(s) => s.to_string(), + Variant::U64(n) => n.to_string(), + Variant::U32(n) => n.to_string(), + Variant::U16(n) => n.to_string(), + Variant::U8(n) => n.to_string(), + Variant::I64(n) => n.to_string(), + Variant::I32(n) => n.to_string(), + Variant::I16(n) => n.to_string(), + Variant::Bool(b) => b.to_string(), + Variant::F64(f) => format!("{f}"), + Variant::Signature(s) => s.to_string(), + Variant::ObjectPath(p) => p.to_string(), _ => format!("{inner:?}"), } } @@ -140,8 +140,7 @@ pub fn render_value(v: &zvariant::OwnedValue) -> String { #[zbus::proxy( interface = "com.mxshift.Waytool.Daemon1", default_service = "com.mxshift.Waytool.Daemon", - default_path = "/com/mxshift/Waytool/Daemon", - gen_blocking = false + default_path = "/com/mxshift/Waytool/Daemon" )] pub trait Daemon { /// Cheap liveness check. @@ -239,6 +238,7 @@ pub async fn connect() -> Result> { } async fn connect_stream(stream: UnixStream) -> Result> { + let stream = stream.into_std().context("the daemon's socket")?; let handshake = zbus::connection::Builder::unix_stream(stream).p2p().build(); let conn = tokio::time::timeout(std::time::Duration::from_secs(10), handshake) .await @@ -247,26 +247,42 @@ async fn connect_stream(stream: UnixStream) -> Result> { DaemonProxy::new(&conn).await.context("daemon proxy") } +/// The name and message of the D-Bus error a method call was answered +/// with, if that's how it failed. zbus reports a name that `fdo::Error` +/// defines (`UnknownMethod`, `ServiceUnknown`, ...) as `Error::FDO`, and +/// any other as `Error::MethodError`. +pub(crate) fn error_reply(e: &zbus::Error) -> Option<(String, Option)> { + use zbus::DBusError; + match e { + zbus::Error::MethodError(name, message, _) => Some((name.to_string(), message.clone())), + zbus::Error::FDO(e) => Some((e.name().to_string(), e.description().map(str::to_owned))), + zbus::Error::DBus(e) => Some((e.name().to_string(), e.description().map(str::to_owned))), + _ => None, + } +} + /// Turn a failed method call into an error worth showing: the daemon's /// own message for `Failed`, and a hint for the mismatch you get when /// the running daemon is from a different release than the CLI. pub fn describe(e: Error) -> anyhow::Error { match e { Error::Failed(msg) => anyhow!(msg), - Error::ZBus(zbus::Error::MethodError(name, _, _)) - if [ - "org.freedesktop.DBus.Error.UnknownMethod", - "org.freedesktop.DBus.Error.UnknownInterface", - "org.freedesktop.DBus.Error.UnknownObject", - ] - .contains(&name.as_str()) => - { - anyhow!( - "the running daemon doesn't support this command ({name}); it's from \ - a different release than this CLI — restart it" - ) - } - Error::ZBus(e) => anyhow!(e), + Error::ZBus(e) => match error_reply(&e) { + Some((name, _)) + if [ + "org.freedesktop.DBus.Error.UnknownMethod", + "org.freedesktop.DBus.Error.UnknownInterface", + "org.freedesktop.DBus.Error.UnknownObject", + ] + .contains(&name.as_str()) => + { + anyhow!( + "the running daemon doesn't support this command ({name}); it's from \ + a different release than this CLI — restart it" + ) + } + _ => anyhow!(e), + }, } } diff --git a/src/tray.rs b/src/tray.rs index 335e8f9..7ee15ac 100644 --- a/src/tray.rs +++ b/src/tray.rs @@ -13,8 +13,8 @@ use std::sync::{Arc, Mutex}; use anyhow::{Context, Result}; use futures_util::StreamExt; +use zbus::OwnedObjectPath; use zbus::object_server::SignalEmitter; -use zvariant::OwnedObjectPath; const UNIT: &str = "waytool.service"; const ITEM_PATH: &str = "/StatusNotifierItem"; @@ -210,8 +210,8 @@ pub(crate) async fn run_tray() -> Result<()> { // Follow the unit. let props = zbus::fdo::PropertiesProxy::builder(&systemd) - .destination(SYSTEMD)? - .path(unit.clone())? + .destination(SYSTEMD) + .path(unit.clone()) .build() .await?; let mut changes = props.receive_properties_changed().await?; @@ -288,7 +288,7 @@ async fn read_state(systemd: &zbus::Connection, unit: &OwnedObjectPath) -> Unit ) .await .ok()?; - let value: zvariant::OwnedValue = reply.body().deserialize().ok()?; + let value: zbus::OwnedVariant = reply.body().deserialize().ok()?; String::try_from(value).ok() }; let load = get("LoadState").await.unwrap_or_default(); diff --git a/src/windows.rs b/src/windows.rs index bea121d..764abea 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -15,7 +15,7 @@ use std::sync::Arc; use anyhow::{Context, Result, anyhow}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::UnixStream; -use zvariant::{OwnedValue, Value}; +use zbus::{OwnedVariant, Variant}; use crate::extension::{ext_call, ext_proxy}; use crate::protocol::{WindowDict, render_value}; @@ -256,10 +256,10 @@ impl Windows { } /// A window dict from its fields. -fn dict(entries: Vec<(&str, Value)>) -> Result { +fn dict(entries: Vec<(&str, Variant)>) -> Result { entries .into_iter() - .map(|(k, v)| Ok((k.to_owned(), OwnedValue::try_from(v)?))) + .map(|(k, v)| Ok((k.to_owned(), OwnedVariant::try_from(v)?))) .collect() } @@ -330,20 +330,20 @@ fn kwin_window(w: &serde_json::Value) -> Result { let text = |k: &str| w[k].as_str().unwrap_or("").to_owned(); let flag = |k: &str| w[k].as_bool().unwrap_or(false); dict(vec![ - ("id", Value::U64(id)), + ("id", Variant::U64(id)), ("title", text("title").into()), ("app_id", text("app_id").into()), ("wm_class", text("wm_class").into()), - ("pid", Value::I32(int(&w["pid"]))), + ("pid", Variant::I32(int(&w["pid"]))), ("monitor", text("monitor").into()), - ("frame_x", Value::I32(int(&f[0]))), - ("frame_y", Value::I32(int(&f[1]))), - ("frame_w", Value::I32(int(&f[2]))), - ("frame_h", Value::I32(int(&f[3]))), - ("client_x", Value::I32(int(&c[0]))), - ("client_y", Value::I32(int(&c[1]))), - ("client_w", Value::I32(int(&c[2]))), - ("client_h", Value::I32(int(&c[3]))), + ("frame_x", Variant::I32(int(&f[0]))), + ("frame_y", Variant::I32(int(&f[1]))), + ("frame_w", Variant::I32(int(&f[2]))), + ("frame_h", Variant::I32(int(&f[3]))), + ("client_x", Variant::I32(int(&c[0]))), + ("client_y", Variant::I32(int(&c[1]))), + ("client_w", Variant::I32(int(&c[2]))), + ("client_h", Variant::I32(int(&c[3]))), ("focused", flag("focused").into()), ("minimized", flag("minimized").into()), ("maximized", flag("maximized").into()), @@ -358,7 +358,7 @@ fn kwin_window(w: &serde_json::Value) -> Result { fn toplevel_window(t: &crate::wayland::Toplevel) -> Result { let mut fields = vec![ - ("id", Value::U64(t.id)), + ("id", Variant::U64(t.id)), ("title", t.title.as_str().into()), ("app_id", t.app_id.as_str().into()), ("wm_class", t.app_id.as_str().into()), @@ -372,14 +372,14 @@ fn toplevel_window(t: &crate::wayland::Toplevel) -> Result { // with no frame of its own. if let Some((x, y, w, h)) = t.rect { fields.extend([ - ("frame_x", Value::I32(x)), - ("frame_y", Value::I32(y)), - ("frame_w", Value::I32(w)), - ("frame_h", Value::I32(h)), - ("client_x", Value::I32(x)), - ("client_y", Value::I32(y)), - ("client_w", Value::I32(w)), - ("client_h", Value::I32(h)), + ("frame_x", Variant::I32(x)), + ("frame_y", Variant::I32(y)), + ("frame_w", Variant::I32(w)), + ("frame_h", Variant::I32(h)), + ("client_x", Variant::I32(x)), + ("client_y", Variant::I32(y)), + ("client_w", Variant::I32(w)), + ("client_h", Variant::I32(h)), ]); } dict(fields) @@ -477,21 +477,21 @@ fn sway_window( .to_owned(); let ws_name = workspace.and_then(|w| w["name"].as_str()).unwrap_or(""); dict(vec![ - ("id", Value::U64(n["id"].as_u64().unwrap_or(0))), + ("id", Variant::U64(n["id"].as_u64().unwrap_or(0))), ("title", n["name"].as_str().unwrap_or("").into()), ("app_id", app_id.clone().into()), ("wm_class", if is_x11 { class } else { app_id }.into()), - ("pid", Value::I32(num(&n["pid"]))), + ("pid", Variant::I32(num(&n["pid"]))), ("monitor", output.into()), ("is_x11", is_x11.into()), - ("frame_x", Value::I32(num(&rect["x"]))), - ("frame_y", Value::I32(num(&rect["y"]))), - ("frame_w", Value::I32(num(&rect["width"]))), - ("frame_h", Value::I32(num(&rect["height"]))), - ("client_x", Value::I32(num(&rect["x"]) + num(&inner["x"]))), - ("client_y", Value::I32(num(&rect["y"]) + num(&inner["y"]))), - ("client_w", Value::I32(num(&inner["width"]))), - ("client_h", Value::I32(num(&inner["height"]))), + ("frame_x", Variant::I32(num(&rect["x"]))), + ("frame_y", Variant::I32(num(&rect["y"]))), + ("frame_w", Variant::I32(num(&rect["width"]))), + ("frame_h", Variant::I32(num(&rect["height"]))), + ("client_x", Variant::I32(num(&rect["x"]) + num(&inner["x"]))), + ("client_y", Variant::I32(num(&rect["y"]) + num(&inner["y"]))), + ("client_w", Variant::I32(num(&inner["width"]))), + ("client_h", Variant::I32(num(&inner["height"]))), ("focused", n["focused"].as_bool().unwrap_or(false).into()), // The scratchpad is sway's nearest thing to minimizing. ("minimized", (ws_name == "__i3_scratch").into()), @@ -560,16 +560,16 @@ async fn niri_windows(sock: &Path) -> Result> { let ws = workspace(&w["workspace_id"]); let output = ws.and_then(|ws| ws["output"].as_str()).unwrap_or(""); let mut fields = vec![ - ("id", Value::U64(w["id"].as_u64().unwrap_or(0))), + ("id", Variant::U64(w["id"].as_u64().unwrap_or(0))), ("title", w["title"].as_str().unwrap_or("").into()), ("app_id", w["app_id"].as_str().unwrap_or("").into()), ("wm_class", w["app_id"].as_str().unwrap_or("").into()), - ("pid", Value::I32(w["pid"].as_i64().unwrap_or(0) as i32)), + ("pid", Variant::I32(w["pid"].as_i64().unwrap_or(0) as i32)), ("monitor", output.into()), ("focused", w["is_focused"].as_bool().unwrap_or(false).into()), ( "workspace", - Value::I32(ws.and_then(|ws| ws["idx"].as_i64()).unwrap_or(0) as i32), + Variant::I32(ws.and_then(|ws| ws["idx"].as_i64()).unwrap_or(0) as i32), ), ( "on_active_workspace", @@ -593,14 +593,14 @@ async fn niri_windows(sock: &Path) -> Result> { let y = (f(&origin["y"]) + f(&tile[1]) + f(&offset[1])) as i32; let (w, h) = (f(&size[0]) as i32, f(&size[1]) as i32); fields.extend([ - ("frame_x", Value::I32(x)), - ("frame_y", Value::I32(y)), - ("frame_w", Value::I32(w)), - ("frame_h", Value::I32(h)), - ("client_x", Value::I32(x)), - ("client_y", Value::I32(y)), - ("client_w", Value::I32(w)), - ("client_h", Value::I32(h)), + ("frame_x", Variant::I32(x)), + ("frame_y", Variant::I32(y)), + ("frame_w", Variant::I32(w)), + ("frame_h", Variant::I32(h)), + ("client_x", Variant::I32(x)), + ("client_y", Variant::I32(y)), + ("client_w", Variant::I32(w)), + ("client_h", Variant::I32(h)), ]); } dict(fields) @@ -703,11 +703,11 @@ fn hyprland_parse(clients: &str, monitors: &str, active: &str) -> Result Result bool { } pub(crate) fn dict_i64(w: &WindowDict, key: &str) -> Result { - use zvariant::Value; + use zbus::Variant; let v = w .get(key) .ok_or_else(|| anyhow!("window dict missing {key:?}"))?; Ok(match &**v { - Value::U64(n) => *n as i64, - Value::U32(n) => *n as i64, - Value::I64(n) => *n, - Value::I32(n) => *n as i64, + Variant::U64(n) => *n as i64, + Variant::U32(n) => *n as i64, + Variant::I64(n) => *n, + Variant::I32(n) => *n as i64, other => return Err(anyhow!("window dict {key:?} is not an integer: {other:?}")), }) } pub(crate) fn dict_bool(w: &WindowDict, key: &str) -> bool { - matches!(w.get(key).map(|v| &**v), Some(zvariant::Value::Bool(true))) + matches!(w.get(key).map(|v| &**v), Some(zbus::Variant::Bool(true))) } /// One line per window — enough for a caller to pick an id. @@ -822,26 +822,29 @@ pub(crate) fn resolve_window_selector(windows: Vec, sel: &str) -> Re #[cfg(test)] mod tests { use super::*; - use zvariant::{OwnedValue, Value}; + use zbus::{OwnedVariant, Variant}; fn win(id: u64, wm_class: &str, title: &str, focused: bool) -> WindowDict { let mut w = WindowDict::new(); - w.insert("id".into(), OwnedValue::try_from(Value::U64(id)).unwrap()); + w.insert( + "id".into(), + OwnedVariant::try_from(Variant::U64(id)).unwrap(), + ); w.insert( "wm_class".into(), - OwnedValue::try_from(Value::new(wm_class)).unwrap(), + OwnedVariant::try_from(Variant::new(wm_class)).unwrap(), ); w.insert( "app_id".into(), - OwnedValue::try_from(Value::new("")).unwrap(), + OwnedVariant::try_from(Variant::new("")).unwrap(), ); w.insert( "title".into(), - OwnedValue::try_from(Value::new(title)).unwrap(), + OwnedVariant::try_from(Variant::new(title)).unwrap(), ); w.insert( "focused".into(), - OwnedValue::try_from(Value::Bool(focused)).unwrap(), + OwnedVariant::try_from(Variant::Bool(focused)).unwrap(), ); w }