diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 23e530cef..482a4dca7 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -74,6 +74,8 @@ jobs: sed -e s/UID/$UID/ -e s/PATH/path/ CI/dbus-session.conf > /tmp/dbus-session.conf sed -e s/UID/$UID/ -e s/PATH/abstract/ CI/dbus-session.conf > /tmp/dbus-session-abstract.conf sudo apt-get install -y dbus + sudo apt-get install -y ibus + ibus start & - uses: dtolnay/rust-toolchain@master with: toolchain: stable @@ -83,7 +85,7 @@ jobs: dbus-run-session --config-file /tmp/dbus-session-abstract.conf -- cargo --locked test --profile "$PROFILE" --verbose -- basic_connection # All features except tokio. dbus-run-session --config-file /tmp/dbus-session.conf -- \ - cargo --locked test --profile "$PROFILE" --verbose --features uuid,url,time,chrono,option-as-array,vsock,bus-impl \ + cargo --locked test --profile "$PROFILE" --verbose --features uuid,url,time,chrono,option-as-array,vsock,bus-impl,ibus \ -- --skip fdpass_systemd # Test tokio support. dbus-run-session --config-file /tmp/dbus-session.conf -- \ diff --git a/zbus/Cargo.toml b/zbus/Cargo.toml index a70a1a183..b591c85b9 100644 --- a/zbus/Cargo.toml +++ b/zbus/Cargo.toml @@ -26,6 +26,8 @@ camino = ["zvariant/camino"] bus-impl = ["p2p"] # Enables API that is only needed for peer-to-peer (p2p) connections. p2p = ["dep:rand"] +# Enables API that is only needed for IBus Daemon. +ibus = [] async-io = [ "dep:async-io", "async-executor", diff --git a/zbus/src/blocking/connection/builder.rs b/zbus/src/blocking/connection/builder.rs index 3af0f96aa..accf94df4 100644 --- a/zbus/src/blocking/connection/builder.rs +++ b/zbus/src/blocking/connection/builder.rs @@ -37,6 +37,14 @@ impl<'a> Builder<'a> { crate::connection::Builder::system().map(Self) } + /// Create a builder for the [IBus] daemon. + /// + /// [IBus]: https://en.wikipedia.org/wiki/Intelligent_Input_Bus + #[cfg(feature = "ibus")] + pub fn ibus() -> Result { + block_on(crate::connection::Builder::ibus()).map(Self) + } + /// Create a builder for a connection that will use the given [D-Bus bus address]. /// /// [D-Bus bus address]: https://dbus.freedesktop.org/doc/dbus-specification.html#addresses diff --git a/zbus/src/connection/builder.rs b/zbus/src/connection/builder.rs index 64e1b42c6..68bffa5e6 100644 --- a/zbus/src/connection/builder.rs +++ b/zbus/src/connection/builder.rs @@ -6,6 +6,8 @@ use static_assertions::assert_impl_all; use std::net::TcpStream; #[cfg(all(unix, not(feature = "tokio")))] use std::os::unix::net::UnixStream; +#[cfg(feature = "ibus")] +use std::process::Stdio; use std::{ collections::{HashMap, HashSet}, vec, @@ -23,6 +25,9 @@ use vsock::VsockStream; use zvariant::ObjectPath; +#[cfg(feature = "ibus")] +use crate::process::Command; + use crate::{ address::{self, Address}, names::{InterfaceName, WellKnownName}, @@ -85,6 +90,36 @@ impl<'a> Builder<'a> { Ok(Self::new(Target::Address(Address::system()?))) } + /// Create a builder for the [IBus] daemon. + /// + /// [IBus]: https://en.wikipedia.org/wiki/Intelligent_Input_Bus + #[cfg(feature = "ibus")] + pub async fn ibus() -> Result { + let child_process = Command::new("ibus") + .args(["address"]) + .stdout(Stdio::piped()) + .spawn() + .expect("Fail to call `ibus address`"); + + #[cfg(not(feature = "tokio"))] + let output = child_process + .output() + .await + .expect("Fail to run `ibus address`"); + + #[cfg(feature = "tokio")] + let output = child_process + .wait_with_output() + .await + .expect("Fail to run `ibus address`"); + + let ibus_address = std::str::from_utf8(&output.stdout) + .expect("Invalid utf8 when getting stdout") + .trim(); + + Builder::address(ibus_address) + } + /// Create a builder for a connection that will use the given [D-Bus bus address]. /// /// # Example diff --git a/zbus/tests/basic.rs b/zbus/tests/basic.rs index 335f03443..e9140c901 100644 --- a/zbus/tests/basic.rs +++ b/zbus/tests/basic.rs @@ -117,6 +117,19 @@ async fn fdpass_systemd_async() { f.metadata().unwrap(); } +#[cfg(all(target_os = "linux", feature = "ibus"))] +#[test] +fn ibus() { + use zbus::blocking; + + let ibus_blocking = blocking::connection::Builder::ibus() + .unwrap() + .build() + .unwrap(); + + assert!(!ibus_blocking.server_guid().is_empty()); +} + #[test] #[instrument] #[timeout(15000)]