mirror of
https://codeberg.org/hako/Rosenthal.git
synced 2025-09-19 05:04:39 +00:00
* rosenthal/packages/patches/niri.patch: New file. * rosenthal/packages/patches/rust-libspa-sys.patch: New file. * rosenthal/packages/patches/rust-libspa.patch: New file. * rosenthal/packages/patches/rust-pipewire.patch: New file. * rosenthal/packages/patches/rust-smithay.patch: New file. * rosenthal/packages/rust-crates.scm (niri-cargo-inputs): New variable. * rosenthal/packages/rust-apps.scm (niri): New variable. * README.org (Packages): Add it. * etc/manifest: Add it.
346 lines
11 KiB
Diff
346 lines
11 KiB
Diff
diff --git a/Cargo.toml b/Cargo.toml
|
|
index bef8079..f795a3e 100644
|
|
--- a/Cargo.toml
|
|
+++ b/Cargo.toml
|
|
@@ -45,7 +45,7 @@ version = "2"
|
|
version = "0.2"
|
|
|
|
[dependencies.nix]
|
|
-version = "0.27"
|
|
+version = "0.29"
|
|
features = [
|
|
"signal",
|
|
"fs",
|
|
diff --git a/src/channel.rs b/src/channel.rs
|
|
index 3c8c742..672cddc 100644
|
|
--- a/src/channel.rs
|
|
+++ b/src/channel.rs
|
|
@@ -89,7 +89,11 @@ impl<T: 'static> Receiver<T> {
|
|
F: Fn(T) + 'static,
|
|
{
|
|
let channel = self.channel.clone();
|
|
- let readfd = channel.lock().expect("Channel mutex lock poisoned").readfd;
|
|
+ let readfd = channel
|
|
+ .lock()
|
|
+ .expect("Channel mutex lock poisoned")
|
|
+ .readfd
|
|
+ .as_raw_fd();
|
|
|
|
// Attach the pipe as an IO source to the loop.
|
|
// Whenever the pipe is written to, call the users callback with each message in the queue.
|
|
@@ -97,7 +101,7 @@ impl<T: 'static> Receiver<T> {
|
|
let mut channel = channel.lock().expect("Channel mutex lock poisoned");
|
|
|
|
// Read from the pipe to make it block until written to again.
|
|
- let _ = nix::unistd::read(channel.readfd, &mut [0]);
|
|
+ let _ = nix::unistd::read(channel.readfd.as_raw_fd(), &mut [0]);
|
|
|
|
channel.queue.drain(..).for_each(&callback);
|
|
});
|
|
@@ -162,7 +166,7 @@ impl<T> Sender<T> {
|
|
// If no messages are waiting already, signal the receiver to read some.
|
|
// Because the channel mutex is locked, it is alright to do this before pushing the message.
|
|
if channel.queue.is_empty() {
|
|
- match nix::unistd::write(channel.writefd, &[1u8]) {
|
|
+ match nix::unistd::write(&channel.writefd, &[1u8]) {
|
|
Ok(_) => (),
|
|
Err(_) => return Err(t),
|
|
}
|
|
@@ -178,21 +182,12 @@ impl<T> Sender<T> {
|
|
/// Shared state between the [`Sender`]s and the [`Receiver`].
|
|
struct Channel<T> {
|
|
/// A pipe used to signal the loop the receiver is attached to that messages are waiting.
|
|
- readfd: RawFd,
|
|
- writefd: RawFd,
|
|
+ readfd: OwnedFd,
|
|
+ writefd: OwnedFd,
|
|
/// Queue of any messages waiting to be received.
|
|
queue: VecDeque<T>,
|
|
}
|
|
|
|
-impl<T> Drop for Channel<T> {
|
|
- fn drop(&mut self) {
|
|
- // We do not error check here, because the pipe does not contain any data that might be lost,
|
|
- // and because there is no way to handle an error in a `Drop` implementation anyways.
|
|
- let _ = nix::unistd::close(self.readfd);
|
|
- let _ = nix::unistd::close(self.writefd);
|
|
- }
|
|
-}
|
|
-
|
|
/// Create a Sender-Receiver pair, where the sender can be used to send messages to the receiver.
|
|
///
|
|
/// This functions similar to [`std::sync::mpsc`], but with a receiver that can be attached to any
|
|
diff --git a/src/client.rs b/src/client.rs
|
|
index cd28024..89f71e7 100644
|
|
--- a/src/client.rs
|
|
+++ b/src/client.rs
|
|
@@ -5,7 +5,10 @@ use bitflags::bitflags;
|
|
use libc::c_void;
|
|
use std::ops::Deref;
|
|
use std::pin::Pin;
|
|
-use std::{ffi::CString, ptr};
|
|
+use std::{
|
|
+ ffi::{CStr, CString},
|
|
+ ptr,
|
|
+};
|
|
use std::{fmt, mem};
|
|
|
|
use crate::{
|
|
@@ -53,7 +56,11 @@ impl Client {
|
|
|
|
pub fn error(&self, id: u32, res: i32, message: &str) {
|
|
let message = CString::new(message).expect("Null byte in message parameter");
|
|
+ let message_cstr = message.as_c_str();
|
|
+ Client::error_cstr(self, id, res, message_cstr)
|
|
+ }
|
|
|
|
+ pub fn error_cstr(&self, id: u32, res: i32, message: &CStr) {
|
|
unsafe {
|
|
spa_interface_call_method!(
|
|
self.proxy.as_ptr(),
|
|
diff --git a/src/core.rs b/src/core.rs
|
|
index 960c3c2..1feb79f 100644
|
|
--- a/src/core.rs
|
|
+++ b/src/core.rs
|
|
@@ -126,8 +126,17 @@ impl CoreRef {
|
|
factory_name: &str,
|
|
properties: &impl AsRef<spa::utils::dict::DictRef>,
|
|
) -> Result<P, Error> {
|
|
- let type_ = P::type_();
|
|
let factory_name = CString::new(factory_name).expect("Null byte in factory_name parameter");
|
|
+ let factory_name_cstr = factory_name.as_c_str();
|
|
+ CoreRef::create_object_cstr(self, factory_name_cstr, properties)
|
|
+ }
|
|
+
|
|
+ pub fn create_object_cstr<P: ProxyT>(
|
|
+ &self,
|
|
+ factory_name: &CStr,
|
|
+ properties: &impl AsRef<spa::utils::dict::DictRef>,
|
|
+ ) -> Result<P, Error> {
|
|
+ let type_ = P::type_();
|
|
let type_str = CString::new(type_.to_string())
|
|
.expect("Null byte in string representation of type_ parameter");
|
|
|
|
diff --git a/src/lib.rs b/src/lib.rs
|
|
index e63490c..7f100df 100644
|
|
--- a/src/lib.rs
|
|
+++ b/src/lib.rs
|
|
@@ -140,12 +140,6 @@ mod utils;
|
|
pub use pw_sys as sys;
|
|
pub use spa;
|
|
|
|
-// Re-export all the traits in a prelude module, so that applications
|
|
-// can always "use pipewire::prelude::*" without getting conflicts
|
|
-pub mod prelude {
|
|
- pub use spa::prelude::*;
|
|
-}
|
|
-
|
|
use std::ptr;
|
|
|
|
/// Initialize PipeWire
|
|
diff --git a/src/loop_.rs b/src/loop_.rs
|
|
index 01560c4..3dfa8bc 100644
|
|
--- a/src/loop_.rs
|
|
+++ b/src/loop_.rs
|
|
@@ -635,7 +635,14 @@ impl<'l> TimerSource<'l> {
|
|
fn duration_to_timespec(duration: Duration) -> spa_sys::timespec {
|
|
spa_sys::timespec {
|
|
tv_sec: duration.as_secs().try_into().expect("Duration too long"),
|
|
- tv_nsec: duration.subsec_nanos().try_into().unwrap(),
|
|
+ // `Into` is only implemented on some platforms for these types,
|
|
+ // so use a fallible conversion.
|
|
+ // As there are a limited amount of nanoseconds in a second, this shouldn't fail
|
|
+ #[allow(clippy::unnecessary_fallible_conversions)]
|
|
+ tv_nsec: duration
|
|
+ .subsec_nanos()
|
|
+ .try_into()
|
|
+ .expect("Nanoseconds should fit into timespec"),
|
|
}
|
|
}
|
|
|
|
diff --git a/src/metadata.rs b/src/metadata.rs
|
|
index 64a68e1..ebdc3e7 100644
|
|
--- a/src/metadata.rs
|
|
+++ b/src/metadata.rs
|
|
@@ -55,6 +55,18 @@ impl Metadata {
|
|
let key = CString::new(key).expect("Invalid byte in metadata key");
|
|
let type_ = type_.map(|t| CString::new(t).expect("Invalid byte in metadata type"));
|
|
let value = value.map(|v| CString::new(v).expect("Invalid byte in metadata value"));
|
|
+ let key_cstr = key.as_c_str();
|
|
+
|
|
+ Metadata::set_property_cstr(self, subject, key_cstr, type_.as_deref(), value.as_deref())
|
|
+ }
|
|
+
|
|
+ pub fn set_property_cstr(
|
|
+ &self,
|
|
+ subject: u32,
|
|
+ key: &CStr,
|
|
+ type_: Option<&CStr>,
|
|
+ value: Option<&CStr>,
|
|
+ ) {
|
|
unsafe {
|
|
spa::spa_interface_call_method!(
|
|
self.proxy.as_ptr(),
|
|
@@ -62,8 +74,8 @@ impl Metadata {
|
|
set_property,
|
|
subject,
|
|
key.as_ptr() as *const _,
|
|
- type_.as_deref().map_or_else(ptr::null, CStr::as_ptr) as *const _,
|
|
- value.as_deref().map_or_else(ptr::null, CStr::as_ptr) as *const _
|
|
+ type_.map_or_else(ptr::null, CStr::as_ptr) as *const _,
|
|
+ value.map_or_else(ptr::null, CStr::as_ptr) as *const _
|
|
);
|
|
}
|
|
}
|
|
diff --git a/src/permissions.rs b/src/permissions.rs
|
|
index bdb011c..7d445ad 100644
|
|
--- a/src/permissions.rs
|
|
+++ b/src/permissions.rs
|
|
@@ -16,17 +16,33 @@ bitflags! {
|
|
}
|
|
}
|
|
|
|
+#[derive(Clone, Copy)]
|
|
#[repr(transparent)]
|
|
pub struct Permission(pw_sys::pw_permission);
|
|
|
|
impl Permission {
|
|
+ pub fn new(id: u32, flags: PermissionFlags) -> Self {
|
|
+ Self(pw_sys::pw_permission {
|
|
+ id,
|
|
+ permissions: flags.bits(),
|
|
+ })
|
|
+ }
|
|
+
|
|
pub fn id(&self) -> u32 {
|
|
self.0.id
|
|
}
|
|
|
|
+ pub fn set_id(&mut self, id: u32) {
|
|
+ self.0.id = id;
|
|
+ }
|
|
+
|
|
pub fn permission_flags(&self) -> PermissionFlags {
|
|
PermissionFlags::from_bits_retain(self.0.permissions)
|
|
}
|
|
+
|
|
+ pub fn set_permission_flags(&mut self, flags: PermissionFlags) {
|
|
+ self.0.permissions = flags.bits();
|
|
+ }
|
|
}
|
|
|
|
impl fmt::Debug for Permission {
|
|
diff --git a/src/properties.rs b/src/properties.rs
|
|
index c71cf72..008bed6 100644
|
|
--- a/src/properties.rs
|
|
+++ b/src/properties.rs
|
|
@@ -1,4 +1,10 @@
|
|
-use std::{ffi::CString, fmt, mem::ManuallyDrop, ops::Deref, ptr};
|
|
+use std::{
|
|
+ ffi::{CStr, CString},
|
|
+ fmt,
|
|
+ mem::ManuallyDrop,
|
|
+ ops::Deref,
|
|
+ ptr,
|
|
+};
|
|
|
|
/// A collection of key/value pairs.
|
|
///
|
|
@@ -36,7 +42,6 @@ pub struct Properties {
|
|
///
|
|
/// Any expression that evaluates to a `impl Into<Vec<u8>>` can be used for both keys and values.
|
|
/// ```rust
|
|
-/// use pipewire::prelude::*;
|
|
/// use pipewire::properties::properties;
|
|
///
|
|
/// let key = String::from("Key");
|
|
@@ -149,6 +154,19 @@ impl Clone for Properties {
|
|
}
|
|
}
|
|
|
|
+impl<K, V> FromIterator<(K, V)> for Properties
|
|
+where
|
|
+ K: Into<Vec<u8>>,
|
|
+ V: Into<Vec<u8>>,
|
|
+{
|
|
+ fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
|
|
+ let mut props = Self::new();
|
|
+ props.extend(iter);
|
|
+
|
|
+ props
|
|
+ }
|
|
+}
|
|
+
|
|
impl Drop for Properties {
|
|
fn drop(&mut self) {
|
|
unsafe { pw_sys::pw_properties_free(self.ptr.as_ptr()) }
|
|
@@ -196,6 +214,11 @@ impl PropertiesRef {
|
|
pub fn get(&self, key: &str) -> Option<&str> {
|
|
let key = CString::new(key).expect("key contains null byte");
|
|
|
|
+ let key_cstr = key.as_c_str();
|
|
+ PropertiesRef::get_cstr(self, key_cstr)
|
|
+ }
|
|
+
|
|
+ pub fn get_cstr(&self, key: &CStr) -> Option<&str> {
|
|
let res =
|
|
unsafe { pw_sys::pw_properties_get(self.as_raw_ptr().cast_const(), key.as_ptr()) };
|
|
|
|
@@ -245,6 +268,18 @@ impl fmt::Debug for PropertiesRef {
|
|
}
|
|
}
|
|
|
|
+impl<K, V> Extend<(K, V)> for PropertiesRef
|
|
+where
|
|
+ K: Into<Vec<u8>>,
|
|
+ V: Into<Vec<u8>>,
|
|
+{
|
|
+ fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
|
|
+ for (k, v) in iter {
|
|
+ self.insert(k, v);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
diff --git a/src/stream.rs b/src/stream.rs
|
|
index ff28af8..e04ff64 100644
|
|
--- a/src/stream.rs
|
|
+++ b/src/stream.rs
|
|
@@ -64,6 +64,13 @@ impl Stream {
|
|
/// Initialises a new stream with the given `name` and `properties`.
|
|
pub fn new(core: &Core, name: &str, properties: Properties) -> Result<Self, Error> {
|
|
let name = CString::new(name).expect("Invalid byte in stream name");
|
|
+
|
|
+ let c_str = name.as_c_str();
|
|
+ Stream::new_cstr(core, c_str, properties)
|
|
+ }
|
|
+
|
|
+ /// Initialises a new stream with the given `name` as Cstr and `properties`.
|
|
+ pub fn new_cstr(core: &Core, name: &CStr, properties: Properties) -> Result<Self, Error> {
|
|
let stream = unsafe {
|
|
pw_sys::pw_stream_new(core.as_raw_ptr(), name.as_ptr(), properties.into_raw())
|
|
};
|
|
@@ -249,8 +256,18 @@ impl StreamRef {
|
|
///
|
|
pub fn set_error(&mut self, res: i32, error: &str) {
|
|
let error = CString::new(error).expect("failed to convert error to CString");
|
|
+ let error_cstr = error.as_c_str();
|
|
+ StreamRef::set_error_cstr(self, res, error_cstr)
|
|
+ }
|
|
+
|
|
+ /// Set the stream in error state with CStr
|
|
+ ///
|
|
+ /// # Panics
|
|
+ /// Will panic if `error` contains a 0 byte.
|
|
+ ///
|
|
+ pub fn set_error_cstr(&mut self, res: i32, error: &CStr) {
|
|
unsafe {
|
|
- pw_sys::pw_stream_set_error(self.as_raw_ptr(), res, error.as_c_str().as_ptr());
|
|
+ pw_sys::pw_stream_set_error(self.as_raw_ptr(), res, error.as_ptr());
|
|
}
|
|
}
|
|
|