From f84b4619ba9df4f96b56a8b123f26069bca76f05 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 30 Jul 2022 12:48:45 +0200 Subject: [PATCH] dbus: expose more functionality --- build/wire_dbus.rs | 7 +- src/dbus.rs | 338 +++++++++++++++++- src/dbus/holder.rs | 1 + src/dbus/incoming.rs | 73 +++- src/dbus/socket.rs | 175 ++++++++- src/dbus/types.rs | 26 ++ wire-dbus/org.freedesktop.DBus.Properties.txt | 6 + wire-dbus/org.freedesktop.DBus.txt | 4 + 8 files changed, 605 insertions(+), 25 deletions(-) diff --git a/build/wire_dbus.rs b/build/wire_dbus.rs index 1603a97b..0336ce06 100644 --- a/build/wire_dbus.rs +++ b/build/wire_dbus.rs @@ -670,8 +670,13 @@ fn write_module(f: &mut W, element: Element, indent: &str) -> Result<( } fn write_element(f: &mut W, element: Element, indent: &str) -> Result<()> { + let name = if element.name == "impl" { + "impl_".as_bytes().as_bstr() + } else { + element.name.as_bstr() + }; writeln!(f)?; - writeln!(f, "{}pub mod {} {{", indent, element.name)?; + writeln!(f, "{}pub mod {} {{", indent, name)?; writeln!(f, "{} use crate::dbus::prelude::*;", indent)?; { let indent = format!("{} ", indent); diff --git a/src/dbus.rs b/src/dbus.rs index f32c14b6..3946b835 100644 --- a/src/dbus.rs +++ b/src/dbus.rs @@ -3,7 +3,7 @@ use { crate::{ async_engine::{AsyncEngine, SpawnedFuture}, dbus::{ - property::GetReply, + property::{Get, GetReply}, types::{ObjectPath, Signature, Variant}, }, io_uring::{IoUring, IoUringError}, @@ -17,15 +17,20 @@ use { vecstorage::VecStorage, xrd::{xrd, XRD}, }, + wire_dbus::{ + org, + org::freedesktop::dbus::properties::{GetAll, GetAllReply, PropertiesChanged}, + }, }, ahash::AHashMap, std::{ - borrow::Cow, + borrow::{Borrow, Cow}, cell::{Cell, RefCell}, fmt::{Debug, Display}, future::Future, marker::PhantomData, mem, + ops::Deref, pin::Pin, rc::Rc, task::{Context, Poll, Waker}, @@ -69,6 +74,8 @@ pub enum DbusError { NoReplySerial, #[error("Signal message contains no interface or member or path")] MissingSignalHeaders, + #[error("Method call message contains no interface or member or path")] + MissingMethodCallHeaders, #[error("Error has no error name")] NoErrorName, #[error("The socket was killed")] @@ -208,6 +215,24 @@ pub struct DbusSocket { headers: RefCell)>>, run_toplevel: Rc, signal_handlers: RefCell>, + objects: CopyHashMap, Rc>, +} + +#[derive(Hash, Eq, PartialEq)] +struct MemberHandlerOwnedKey { + key: MemberHandlerKey<'static>, +} + +#[derive(Hash, Eq, PartialEq)] +struct MemberHandlerKey<'a> { + interface: &'a str, + member: &'a str, +} + +impl<'a> Borrow> for MemberHandlerOwnedKey { + fn borrow(&self) -> &MemberHandlerKey<'a> { + &self.key + } } const TY_BYTE: u8 = b'y'; @@ -247,6 +272,22 @@ const NO_AUTO_START: u8 = 0x2; #[allow(dead_code)] const ALLOW_INTERACTIVE_AUTHORIZATION: u8 = 0x4; +#[allow(dead_code)] +pub const DBUS_NAME_FLAG_ALLOW_REPLACEMENT: u32 = 0x1; +#[allow(dead_code)] +pub const DBUS_NAME_FLAG_REPLACE_EXISTING: u32 = 0x2; +#[allow(dead_code)] +pub const DBUS_NAME_FLAG_DO_NOT_QUEUE: u32 = 0x4; + +#[allow(dead_code)] +pub const DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: u32 = 1; +#[allow(dead_code)] +pub const DBUS_REQUEST_NAME_REPLY_IN_QUEUE: u32 = 2; +#[allow(dead_code)] +pub const DBUS_REQUEST_NAME_REPLY_EXISTS: u32 = 3; +#[allow(dead_code)] +pub const DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: u32 = 4; + pub const BUS_DEST: &str = "org.freedesktop.DBus"; pub const BUS_PATH: &str = "/org/freedesktop/DBus"; @@ -336,6 +377,31 @@ pub unsafe trait Message<'a>: Sized + 'a { fn num_fds(&self) -> u32; } +pub struct ErrorMessage<'a> { + pub msg: Cow<'a, str>, +} + +unsafe impl<'a> Message<'a> for ErrorMessage<'a> { + const SIGNATURE: &'static str = "s"; + const INTERFACE: &'static str = ""; + const MEMBER: &'static str = ""; + type Generic<'b> = ErrorMessage<'b>; + + fn marshal(&self, w: &mut Formatter) { + self.msg.marshal(w) + } + + fn unmarshal(p: &mut Parser<'a>) -> Result { + Ok(Self { + msg: p.unmarshal()?, + }) + } + + fn num_fds(&self) -> u32 { + 0 + } +} + pub trait Property { const INTERFACE: &'static str; const PROPERTY: &'static str; @@ -520,6 +586,274 @@ struct InterfaceSignalHandlers { conditional: AHashMap>, } +struct DbusObjectData { + path: Cow<'static, str>, + methods: CopyHashMap>, + properties: CopyHashMap>, +} + +pub struct DbusObject { + socket: Rc, + data: Rc, +} + +impl Drop for DbusObject { + fn drop(&mut self) { + self.socket.objects.remove(&self.data.path); + } +} + +impl DbusObject { + #[allow(dead_code)] + pub fn add_method(&self, handler: F) + where + T: MethodCall<'static>, + F: for<'a> Fn(T::Generic<'a>, PendingReply) + 'static, + { + let rhd = Rc::new(MethodHandlerData { + handler, + _phantom: Default::default(), + }); + let key = MemberHandlerOwnedKey { + key: MemberHandlerKey { + interface: T::INTERFACE, + member: T::MEMBER, + }, + }; + self.data.methods.set(key, rhd); + } + + #[allow(dead_code)] + pub fn set_property(&self, value: Variant<'static>) + where + T: Property + 'static, + { + self.emit_signal(&PropertiesChanged { + interface_name: T::INTERFACE.into(), + changed_properties: Cow::Borrowed(&[DictEntry { + key: T::PROPERTY.into(), + value: value.borrow(), + }]), + invalidated_properties: Default::default(), + }); + let phd = Rc::new(PropertyHandlerData:: { + data: value, + _phantom: Default::default(), + }); + let key = MemberHandlerOwnedKey { + key: MemberHandlerKey { + interface: T::INTERFACE, + member: T::PROPERTY, + }, + }; + self.data.properties.set(key, phd); + } + + #[allow(dead_code)] + pub fn emit_signal<'a, T: Signal<'a>>(&self, signal: &T) { + self.socket.emit_signal(&self.data.path, signal); + } + + #[allow(dead_code)] + pub fn path(&self) -> &str { + &self.data.path + } +} + +trait PropertyHandlerApi { + fn interface(&self) -> &'static str; + fn member(&self) -> &'static str; + fn value<'a>(&'a self) -> Variant<'a>; +} + +struct PropertyHandlerData { + data: Variant<'static>, + _phantom: PhantomData, +} + +impl PropertyHandlerApi for PropertyHandlerData +where + T: Property, +{ + fn interface(&self) -> &'static str { + T::INTERFACE + } + + fn member(&self) -> &'static str { + T::PROPERTY + } + + fn value<'a>(&'a self) -> Variant<'a> { + self.data.borrow() + } +} + +pub struct PendingReply { + reply_expected: bool, + socket: Rc, + destination: String, + serial: u32, + _phantom: PhantomData, +} + +impl PendingReply { + #[allow(dead_code)] + pub fn reply_expected(&self) -> bool { + self.reply_expected + } + + pub fn err(&self, msg: &str) { + if self.reply_expected { + self.socket.send_error(&self.destination, self.serial, msg); + } + } +} + +impl PendingReply +where + T: Message<'static>, +{ + pub fn ok<'a>(&self, msg: &T::Generic<'a>) { + if self.reply_expected { + self.socket.send_reply(&self.destination, self.serial, msg); + } + } + + #[allow(dead_code)] + pub fn complete<'a>(&self, res: Result<&T::Generic<'a>, &str>) { + match res { + Ok(m) => self.ok(m), + Err(e) => self.err(e), + } + } +} + +trait MethodHandlerApi { + fn signature(&self) -> &'static str; + fn handle( + &self, + object: &DbusObjectData, + socket: &Rc, + dest: &str, + serial: u32, + reply_expected: bool, + parser: &mut Parser, + ) -> Result<(), DbusError>; +} + +struct MethodHandlerData { + handler: F, + _phantom: PhantomData, +} + +impl MethodHandlerApi for MethodHandlerData +where + T: MethodCall<'static>, + F: for<'a> Fn(T::Generic<'a>, PendingReply) + 'static, +{ + fn signature(&self) -> &'static str { + T::SIGNATURE + } + + fn handle<'a>( + &self, + _object: &DbusObjectData, + socket: &Rc, + dest: &str, + serial: u32, + reply_expected: bool, + parser: &mut Parser<'a>, + ) -> Result<(), DbusError> { + let msg = T::Generic::<'a>::unmarshal(parser)?; + let pr = PendingReply { + reply_expected, + socket: socket.clone(), + destination: dest.to_string(), + serial, + _phantom: Default::default(), + }; + (self.handler)(msg, pr); + Ok(()) + } +} + +struct PropertyGetHandlerProxy; + +impl MethodHandlerApi for PropertyGetHandlerProxy { + fn signature(&self) -> &'static str { + Get::::SIGNATURE + } + + fn handle<'a>( + &self, + object: &DbusObjectData, + socket: &Rc, + dest: &str, + serial: u32, + reply_expected: bool, + parser: &mut Parser<'a>, + ) -> Result<(), DbusError> { + if !reply_expected { + return Ok(()); + } + let msg = org::freedesktop::dbus::properties::Get::unmarshal(parser)?; + let key = MemberHandlerKey { + interface: msg.interface_name.deref(), + member: msg.property_name.deref(), + }; + match object.properties.get(&key) { + Some(h) => socket.send_reply( + dest, + serial, + &org::freedesktop::dbus::properties::GetReply { value: h.value() }, + ), + _ => socket.send_error(dest, serial, "Property does not exist"), + }; + Ok(()) + } +} + +struct PropertyGetAllHandlerProxy; + +impl MethodHandlerApi for PropertyGetAllHandlerProxy { + fn signature(&self) -> &'static str { + GetAll::SIGNATURE + } + + fn handle<'a>( + &self, + object: &DbusObjectData, + socket: &Rc, + dest: &str, + serial: u32, + reply_expected: bool, + parser: &mut Parser<'a>, + ) -> Result<(), DbusError> { + if !reply_expected { + return Ok(()); + } + let msg = GetAll::unmarshal(parser)?; + let all_props = object.properties.lock(); + let mut props = vec![]; + for property in all_props.values() { + if property.interface() == msg.interface_name { + props.push(DictEntry { + key: property.member().into(), + value: property.value(), + }); + } + } + socket.send_reply( + dest, + serial, + &GetAllReply { + props: props.into(), + }, + ); + Ok(()) + } +} + pub mod prelude { pub use { super::{ diff --git a/src/dbus/holder.rs b/src/dbus/holder.rs index 6297edf7..36c5dc96 100644 --- a/src/dbus/holder.rs +++ b/src/dbus/holder.rs @@ -70,6 +70,7 @@ fn connect( headers: Default::default(), run_toplevel: run_toplevel.clone(), signal_handlers: Default::default(), + objects: Default::default(), }); let skt = socket.clone(); socket.call( diff --git a/src/dbus/incoming.rs b/src/dbus/incoming.rs index 178fe1ff..4e9235a5 100644 --- a/src/dbus/incoming.rs +++ b/src/dbus/incoming.rs @@ -5,14 +5,17 @@ use { }, crate::{ dbus::{ - CallError, DbusError, DbusSocket, Headers, Parser, MSG_ERROR, MSG_METHOD_RETURN, - MSG_SIGNAL, + CallError, DbusError, DbusSocket, Headers, MemberHandlerKey, Message, MethodHandlerApi, + Parser, PropertyGetAllHandlerProxy, PropertyGetHandlerProxy, MSG_ERROR, + MSG_METHOD_CALL, MSG_METHOD_RETURN, MSG_SIGNAL, NO_REPLY_EXPECTED, }, utils::{ + bitflags::BitflagsExt, bufio::BufIoIncoming, errorfmt::ErrorFmt, ptr_ext::{MutPtrExt, PtrExt}, }, + wire_dbus::org::freedesktop::dbus::properties::{Get, GetAll}, }, std::{cell::UnsafeCell, ops::Deref, rc::Rc}, }; @@ -60,14 +63,14 @@ impl Incoming { return Err(DbusError::InvalidEndianess); } let msg_ty = msg_buf[1]; - let _flags = msg_buf[2]; + let flags = msg_buf[2]; let protocol = msg_buf[3]; if protocol != 1 { return Err(DbusError::InvalidProtocol); } let mut fields2 = [0u32; 3]; uapi::pod_write(&msg_buf[4..], &mut fields2[..]).unwrap(); - let [body_len, _serial, headers_len] = fields2; + let [body_len, serial, headers_len] = fields2; let dyn_header_len = headers_len + (headers_len.wrapping_neg() & 7); let remaining = dyn_header_len + body_len; self.incoming @@ -89,6 +92,68 @@ impl Incoming { fds: &fds, }; match msg_ty { + MSG_METHOD_CALL => { + let (sender, interface, member, path) = match ( + &headers.sender, + &headers.interface, + &headers.member, + &headers.path, + ) { + (Some(s), Some(i), Some(m), Some(p)) => (s, i, m, p), + _ => return Err(DbusError::MissingMethodCallHeaders), + }; + if let Some(object) = self.socket.objects.get(path.deref()) { + let method_handler; + let handler: Option<&dyn MethodHandlerApi> = + if (interface.deref(), member.deref()) == (Get::INTERFACE, Get::MEMBER) { + Some(&PropertyGetHandlerProxy) + } else if (interface.deref(), member.deref()) + == (GetAll::INTERFACE, GetAll::MEMBER) + { + Some(&PropertyGetAllHandlerProxy) + } else { + let key = MemberHandlerKey { + interface: interface.deref(), + member: member.deref(), + }; + method_handler = object.methods.get(&key); + method_handler.as_ref().map(|mh| mh.deref()) + }; + if let Some(handler) = handler { + let sig = headers.signature.as_deref().unwrap_or(""); + if sig != handler.signature() { + let msg = format!( + "Method call has an invalid signature: expected: {}, actual: {}", + handler.signature(), + sig, + ); + self.socket.send_error(sender.deref(), serial, &msg); + } else { + let reply_expected = !flags.contains(NO_REPLY_EXPECTED); + if let Err(e) = handler.handle( + &object, + &self.socket, + &sender, + serial, + reply_expected, + &mut parser, + ) { + log::error!( + "{}: Could not handle method call: {}", + self.socket.bus_name, + ErrorFmt(e) + ); + } + } + } else { + self.socket + .send_error(sender.deref(), serial, "Method does not exist"); + } + } else { + self.socket + .send_error(sender.deref(), serial, "Object does not exist"); + } + } MSG_METHOD_RETURN | MSG_ERROR => { let serial = match headers.reply_serial { Some(s) => s, diff --git a/src/dbus/socket.rs b/src/dbus/socket.rs index 222422d0..9c4ed3d5 100644 --- a/src/dbus/socket.rs +++ b/src/dbus/socket.rs @@ -3,18 +3,20 @@ use { dbus::{ property::Get, types::{ObjectPath, Signature, Variant}, - AsyncProperty, AsyncReply, AsyncReplySlot, DbusError, DbusSocket, DbusType, Formatter, - Headers, InterfaceSignalHandlers, Message, MethodCall, Parser, Property, Reply, - ReplyHandler, Signal, SignalHandler, SignalHandlerApi, SignalHandlerData, BUS_DEST, - BUS_PATH, HDR_DESTINATION, HDR_INTERFACE, HDR_MEMBER, HDR_PATH, HDR_SIGNATURE, - HDR_UNIX_FDS, MSG_METHOD_CALL, NO_REPLY_EXPECTED, + AsyncProperty, AsyncReply, AsyncReplySlot, DbusError, DbusObject, DbusObjectData, + DbusSocket, DbusType, ErrorMessage, Formatter, Headers, InterfaceSignalHandlers, + Message, MethodCall, Parser, Property, Reply, ReplyHandler, Signal, SignalHandler, + SignalHandlerApi, SignalHandlerData, BUS_DEST, BUS_PATH, HDR_DESTINATION, + HDR_ERROR_NAME, HDR_INTERFACE, HDR_MEMBER, HDR_PATH, HDR_REPLY_SERIAL, HDR_SIGNATURE, + HDR_UNIX_FDS, MSG_ERROR, MSG_METHOD_CALL, MSG_METHOD_RETURN, MSG_SIGNAL, + NO_REPLY_EXPECTED, }, utils::{bufio::BufIoMessage, errorfmt::ErrorFmt}, wire_dbus::org, }, std::{ - cell::Cell, collections::hash_map::Entry, fmt::Write, marker::PhantomData, mem, - ops::DerefMut, rc::Rc, + borrow::Cow, cell::Cell, collections::hash_map::Entry, fmt::Write, marker::PhantomData, + mem, ops::DerefMut, rc::Rc, }, uapi::c, }; @@ -26,6 +28,7 @@ impl DbusSocket { self.outgoing_.take(); self.reply_handlers.clear(); self.signal_handlers.borrow_mut().clear(); + self.objects.clear(); } pub(super) fn kill(self: &Rc) { @@ -132,6 +135,29 @@ impl DbusSocket { } } + #[allow(dead_code)] + pub fn add_object( + self: &Rc, + object: impl Into>, + ) -> Result { + let object = object.into(); + let data = Rc::new(DbusObjectData { + path: object.clone(), + methods: Default::default(), + properties: Default::default(), + }); + match self.objects.lock().entry(object) { + Entry::Occupied(_) => Err(DbusError::AlreadyHandled), + Entry::Vacant(v) => { + v.insert(data.clone()); + Ok(DbusObject { + socket: self.clone(), + data, + }) + } + } + } + #[allow(dead_code)] pub fn handle_signal( self: &Rc, @@ -245,6 +271,30 @@ impl DbusSocket { ); } + #[allow(dead_code)] + pub fn emit_signal<'a, T: Signal<'a>>(&self, path: &str, msg: &T) -> u32 { + let (msg, serial) = self.format_signal(path, msg); + self.bufio.send(msg); + serial + } + + pub fn send_error(&self, destination: &str, reply_serial: u32, msg: &str) -> u32 { + let (msg, serial) = self.format_error(destination, reply_serial, msg); + self.bufio.send(msg); + serial + } + + pub fn send_reply<'a, T: Message<'a>>( + &self, + destination: &str, + reply_serial: u32, + msg: &T, + ) -> u32 { + let (msg, serial) = self.format_reply(destination, reply_serial, msg); + self.bufio.send(msg); + serial + } + fn send_call<'a, T: Message<'a>>( &self, path: &str, @@ -257,26 +307,99 @@ impl DbusSocket { serial } + fn format_signal<'a, T: Signal<'a>>(&self, path: &str, msg: &T) -> (BufIoMessage, u32) { + self.format_generic(MSG_SIGNAL, Some(path), None, None, 0, msg, None, true, true) + } + + fn format_error(&self, destination: &str, reply_serial: u32, msg: &str) -> (BufIoMessage, u32) { + let em = ErrorMessage { msg: msg.into() }; + self.format_generic( + MSG_ERROR, + None, + Some(reply_serial), + Some(destination), + 0, + &em, + Some("jay.Error"), + false, + false, + ) + } + + fn format_reply<'a, T: Message<'a>>( + &self, + destination: &str, + reply_serial: u32, + msg: &T, + ) -> (BufIoMessage, u32) { + self.format_generic( + MSG_METHOD_RETURN, + None, + Some(reply_serial), + Some(destination), + 0, + msg, + None, + true, + true, + ) + } + fn format_call<'a, T: Message<'a>>( &self, path: &str, destination: &str, flags: u8, msg: &T, + ) -> (BufIoMessage, u32) { + self.format_generic( + MSG_METHOD_CALL, + Some(path), + None, + Some(destination), + flags, + msg, + None, + true, + true, + ) + } + + fn format_generic<'a, T: Message<'a>>( + &self, + ty: u8, + path: Option<&str>, + reply_serial: Option, + destination: Option<&str>, + flags: u8, + msg: &T, + error_name: Option<&str>, + include_interface: bool, + include_member: bool, ) -> (BufIoMessage, u32) { let num_fds = msg.num_fds(); let mut fds = Vec::with_capacity(num_fds as _); let serial = self.serial(); let mut buf = self.bufio.buf(); let mut fmt = Formatter::new(&mut fds, &mut buf); + let interface = match include_interface { + true => Some(T::INTERFACE), + _ => None, + }; + let member = match include_member { + true => Some(T::MEMBER), + _ => None, + }; self.format_header( &mut fmt, - MSG_METHOD_CALL, + ty, flags, serial, + reply_serial, path, - T::INTERFACE, - T::MEMBER, + error_name, + interface, + member, destination, T::SIGNATURE, num_fds, @@ -294,10 +417,12 @@ impl DbusSocket { ty: u8, flags: u8, serial: u32, - path: &str, - interface: &str, - member: &str, - destination: &str, + reply_serial: Option, + path: Option<&str>, + error_name: Option<&str>, + interface: Option<&str>, + member: Option<&str>, + destination: Option<&str>, signature: &str, fds: u32, ) { @@ -312,10 +437,24 @@ impl DbusSocket { serial.marshal(fmt); let mut headers = self.headers.borrow_mut(); let mut headers = headers.take_as::<(u8, Variant)>(); - headers.push((HDR_PATH, Variant::ObjectPath(ObjectPath(path.into())))); - headers.push((HDR_INTERFACE, Variant::String(interface.into()))); - headers.push((HDR_MEMBER, Variant::String(member.into()))); - headers.push((HDR_DESTINATION, Variant::String(destination.into()))); + if let Some(path) = path { + headers.push((HDR_PATH, Variant::ObjectPath(ObjectPath(path.into())))); + } + if let Some(interface) = interface { + headers.push((HDR_INTERFACE, Variant::String(interface.into()))); + } + if let Some(member) = member { + headers.push((HDR_MEMBER, Variant::String(member.into()))); + } + if let Some(error_name) = error_name { + headers.push((HDR_ERROR_NAME, Variant::String(error_name.into()))); + } + if let Some(destination) = destination { + headers.push((HDR_DESTINATION, Variant::String(destination.into()))); + } + if let Some(rs) = reply_serial { + headers.push((HDR_REPLY_SERIAL, Variant::U32(rs))); + } if signature.len() > 0 { headers.push(( HDR_SIGNATURE, diff --git a/src/dbus/types.rs b/src/dbus/types.rs index 3cc8b4e9..73ef6bda 100644 --- a/src/dbus/types.rs +++ b/src/dbus/types.rs @@ -497,6 +497,32 @@ impl<'a> Variant<'a> { }; w.push(c); } + + pub fn borrow<'b>(&'b self) -> Variant<'b> { + match self { + Variant::U8(v) => Variant::U8(*v), + Variant::Bool(v) => Variant::Bool(*v), + Variant::I16(v) => Variant::I16(*v), + Variant::U16(v) => Variant::U16(*v), + Variant::I32(v) => Variant::I32(*v), + Variant::U32(v) => Variant::U32(*v), + Variant::I64(v) => Variant::I64(*v), + Variant::U64(v) => Variant::U64(*v), + Variant::F64(v) => Variant::F64(*v), + Variant::String(v) => Variant::String(v.deref().into()), + Variant::ObjectPath(v) => Variant::ObjectPath(ObjectPath(v.0.deref().into())), + Variant::Signature(v) => Variant::Signature(Signature(v.0.deref().into())), + Variant::Variant(v) => Variant::Variant(Box::new(v.deref().borrow())), + Variant::Fd(v) => Variant::Fd(v.clone()), + Variant::Array(t, v) => { + Variant::Array(t.clone(), v.iter().map(|v| v.borrow()).collect()) + } + Variant::DictEntry(k, v) => { + Variant::DictEntry(Box::new(k.deref().borrow()), Box::new(v.deref().borrow())) + } + Variant::Struct(v) => Variant::Struct(v.iter().map(|v| v.borrow()).collect()), + } + } } unsafe impl<'a> DbusType<'a> for Variant<'a> { diff --git a/wire-dbus/org.freedesktop.DBus.Properties.txt b/wire-dbus/org.freedesktop.DBus.Properties.txt index 24261f75..ee5031a7 100644 --- a/wire-dbus/org.freedesktop.DBus.Properties.txt +++ b/wire-dbus/org.freedesktop.DBus.Properties.txt @@ -8,3 +8,9 @@ fn Set(interface_name: string, property_name: string, value: variant) { fn GetAll(interface_name: string) { props: array(dict(string, variant)), } + +sig PropertiesChanged { + interface_name: string, + changed_properties: array(dict(string, variant)), + invalidated_properties: array(string), +} diff --git a/wire-dbus/org.freedesktop.DBus.txt b/wire-dbus/org.freedesktop.DBus.txt index a48da315..ca0583c6 100644 --- a/wire-dbus/org.freedesktop.DBus.txt +++ b/wire-dbus/org.freedesktop.DBus.txt @@ -7,3 +7,7 @@ fn AddMatch(rule: string) { } fn RemoveMatch(rule: string) { } fn UpdateActivationEnvironment(environment: array(dict(string, string))) { } + +fn RequestName(name: string, flags: u32) { + rv: u32, +}