rosenthal: Move niri to (rosenthal packages wm).

* rosenthal/packages/rust-crates.scm: Update crates for importer change.
* rosenthal/packages/patches/atuin-disable-failing-tests.patch: Delete file.
* rosenthal/packages/patches/niri.patch: Delete file.
* rosenthal/packages/patches/rust-libspa-sys.patch: Delete file.
* rosenthal/packages/patches/rust-libspa.patch: Delete file.
* rosenthal/packages/patches/rust-pipewire.patch: Delete file.
* rosenthal/packages/patches/rust-smithay.patch: Delete file.
* rosenthal/packages/rust-apps.scm (atuin)[inputs]: Add rust-ring-0.17.
(niri): Move to ...
* rosenthal/packages/wm.scm (niri): ...here.
(rust-pipewire,rust-smithay): New variables.
This commit is contained in:
Hilton Chain 2025-03-06 15:54:55 +08:00
parent fb123e8840
commit 3ff5734c9e
No known key found for this signature in database
GPG Key ID: ACC66D09CA528292
9 changed files with 5118 additions and 10937 deletions

View File

@ -1,64 +0,0 @@
diff --git a/crates/atuin-dotfiles/src/store.rs b/crates/atuin-dotfiles/src/store.rs
index b77fa370..0449ad0b 100644
--- a/crates/atuin-dotfiles/src/store.rs
+++ b/crates/atuin-dotfiles/src/store.rs
@@ -335,6 +335,7 @@ mod tests {
assert_eq!(decoded, record);
}
+ #[ignore]
#[tokio::test]
async fn build_aliases() {
let store = SqliteStore::new(":memory:", test_local_timeout())
diff --git a/crates/atuin-dotfiles/src/store/var.rs b/crates/atuin-dotfiles/src/store/var.rs
index 0873b4d5..b2e68e34 100644
--- a/crates/atuin-dotfiles/src/store/var.rs
+++ b/crates/atuin-dotfiles/src/store/var.rs
@@ -317,6 +317,7 @@ mod tests {
assert_eq!(decoded, record);
}
+ #[ignore]
#[tokio::test]
async fn build_vars() {
let store = SqliteStore::new(":memory:", test_local_timeout())
diff --git a/crates/atuin/tests/sync.rs b/crates/atuin/tests/sync.rs
index 7e25d1c2..e16d5b96 100644
--- a/crates/atuin/tests/sync.rs
+++ b/crates/atuin/tests/sync.rs
@@ -3,6 +3,7 @@ use time::OffsetDateTime;
mod common;
+#[ignore]
#[tokio::test]
async fn sync() {
let path = format!("/{}", uuid_v7().as_simple());
diff --git a/crates/atuin/tests/users.rs b/crates/atuin/tests/users.rs
index 95fb533b..f4154803 100644
--- a/crates/atuin/tests/users.rs
+++ b/crates/atuin/tests/users.rs
@@ -2,6 +2,7 @@ use atuin_common::utils::uuid_v7;
mod common;
+#[ignore]
#[tokio::test]
async fn registration() {
let path = format!("/{}", uuid_v7().as_simple());
@@ -30,6 +31,7 @@ async fn registration() {
server.await.unwrap();
}
+#[ignore]
#[tokio::test]
async fn change_password() {
let path = format!("/{}", uuid_v7().as_simple());
@@ -68,6 +70,7 @@ async fn change_password() {
server.await.unwrap();
}
+#[ignore]
#[tokio::test]
async fn multi_user_test() {
let path = format!("/{}", uuid_v7().as_simple());

View File

@ -1,31 +0,0 @@
diff --git a/Cargo.toml b/Cargo.toml
index 6469c4e5..08d97316 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -26,15 +26,11 @@ tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
tracy-client = { version = "0.18.0", default-features = false }
[workspace.dependencies.smithay]
-# version = "0.4.1"
-git = "https://github.com/Smithay/smithay.git"
-# path = "../smithay"
+version = "0.4.1"
default-features = false
[workspace.dependencies.smithay-drm-extras]
-# version = "0.1.0"
-git = "https://github.com/Smithay/smithay.git"
-# path = "../smithay/smithay-drm-extras"
+version = "0.1.0"
[package]
name = "niri"
@@ -75,7 +71,7 @@ niri-ipc = { version = "25.2.0", path = "niri-ipc", features = ["clap"] }
ordered-float = "5.0.0"
pango = { version = "0.20.9", features = ["v1_44"] }
pangocairo = "0.20.7"
-pipewire = { git = "https://gitlab.freedesktop.org/pipewire/pipewire-rs.git", optional = true, features = ["v0_3_33"] }
+pipewire = { version = "0.8.0", optional = true, features = ["v0_3_33"] }
png = "0.17.16"
portable-atomic = { version = "1.10.0", default-features = false, features = ["float"] }
profiling = "1.0.16"

View File

@ -1,54 +0,0 @@
diff --git a/build.rs b/build.rs
index ea34c22..4bffe86 100644
--- a/build.rs
+++ b/build.rs
@@ -32,7 +32,7 @@ fn main() {
// can be called via FFI
.wrap_static_fns(true)
.wrap_static_fns_suffix("_libspa_rs")
- .wrap_static_fns_path(&out_path.join("static_fns"));
+ .wrap_static_fns_path(out_path.join("static_fns"));
let builder = libs
.iter()
diff --git a/src/type_info.rs b/src/type_info.rs
index 016c971..e1e60e9 100644
--- a/src/type_info.rs
+++ b/src/type_info.rs
@@ -101,9 +101,7 @@ mod test {
let type_info = super::spa_debug_type_find(spa_type_media_type, SPA_MEDIA_TYPE_audio);
assert_eq!(
ffi::CStr::from_ptr((*type_info).name),
- ffi::CString::new("Spa:Enum:MediaType:audio")
- .unwrap()
- .as_ref()
+ c"Spa:Enum:MediaType:audio"
);
}
}
@@ -112,12 +110,7 @@ mod test {
fn test_libspa_rs_debug_type_find_name() {
unsafe {
let name = super::spa_debug_type_find_name(spa_type_media_type, SPA_MEDIA_TYPE_audio);
- assert_eq!(
- ffi::CStr::from_ptr(name),
- ffi::CString::new("Spa:Enum:MediaType:audio")
- .unwrap()
- .as_ref()
- );
+ assert_eq!(ffi::CStr::from_ptr(name), c"Spa:Enum:MediaType:audio");
}
}
@@ -126,10 +119,7 @@ mod test {
unsafe {
let name =
super::spa_debug_type_find_short_name(spa_type_media_type, SPA_MEDIA_TYPE_audio);
- assert_eq!(
- ffi::CStr::from_ptr(name),
- ffi::CString::new("audio").unwrap().as_ref()
- );
+ assert_eq!(ffi::CStr::from_ptr(name), c"audio");
}
}
}

View File

@ -1,960 +0,0 @@
diff --git a/Cargo.toml b/Cargo.toml
index 1f2cc3e..df2d682 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -49,7 +49,7 @@ version = "0.3.2"
version = "0.2"
[dependencies.nix]
-version = "0.27"
+version = "0.29"
[dependencies.nom]
version = "7"
diff --git a/src/lib.rs b/src/lib.rs
index 398658b..6b7c995 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,7 +2,9 @@
// SPDX-License-Identifier: MIT
//! The `libspa` crate provides a high-level API to interact with
-//! [libspa](https://gitlab.freedesktop.org/pipewire/pipewire/-/tree/master/doc/spa).
+//! [libspa].
+//!
+//! [libspa]: https://docs.pipewire.org/page_spa.html
pub mod buffer;
pub mod param;
@@ -11,6 +13,3 @@ pub mod support;
pub mod utils;
pub use spa_sys as sys;
-
-/// prelude module re-exporing all the traits providing public API.
-pub mod prelude {}
diff --git a/src/param/audio/mod.rs b/src/param/audio/mod.rs
index 017fc09..f6d731d 100644
--- a/src/param/audio/mod.rs
+++ b/src/param/audio/mod.rs
@@ -51,6 +51,17 @@ impl AudioFormat {
pub const ULAW: Self = Self(spa_sys::SPA_AUDIO_FORMAT_ULAW);
pub const ALAW: Self = Self(spa_sys::SPA_AUDIO_FORMAT_ALAW);
+ pub const S16: Self = Self(spa_sys::SPA_AUDIO_FORMAT_S16);
+ pub const U16: Self = Self(spa_sys::SPA_AUDIO_FORMAT_U16);
+ pub const S18: Self = Self(spa_sys::SPA_AUDIO_FORMAT_S18);
+ pub const U18: Self = Self(spa_sys::SPA_AUDIO_FORMAT_U18);
+ pub const S20: Self = Self(spa_sys::SPA_AUDIO_FORMAT_S20);
+ pub const U20: Self = Self(spa_sys::SPA_AUDIO_FORMAT_U20);
+ pub const S24: Self = Self(spa_sys::SPA_AUDIO_FORMAT_S24);
+ pub const U24: Self = Self(spa_sys::SPA_AUDIO_FORMAT_U24);
+ pub const S32: Self = Self(spa_sys::SPA_AUDIO_FORMAT_S32);
+ pub const U32: Self = Self(spa_sys::SPA_AUDIO_FORMAT_U32);
+
pub const U8P: Self = Self(spa_sys::SPA_AUDIO_FORMAT_U8P);
pub const S16P: Self = Self(spa_sys::SPA_AUDIO_FORMAT_S16P);
pub const S24_32P: Self = Self(spa_sys::SPA_AUDIO_FORMAT_S24_32P);
diff --git a/src/pod/builder.rs b/src/pod/builder.rs
index 138caec..d0209af 100644
--- a/src/pod/builder.rs
+++ b/src/pod/builder.rs
@@ -141,7 +141,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
@@ -163,7 +163,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -177,7 +177,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -189,7 +189,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -201,7 +201,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -213,7 +213,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -225,7 +225,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -237,7 +237,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -256,7 +256,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
@@ -274,7 +274,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
@@ -290,7 +290,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -302,7 +302,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -314,7 +314,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -326,7 +326,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -344,7 +344,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
@@ -370,7 +370,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
@@ -394,7 +394,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
@@ -412,7 +412,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -438,7 +438,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -449,7 +449,7 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
@@ -468,13 +468,14 @@ impl<'d> Builder<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
pub fn add_control(&mut self, offset: u32, type_: u32) -> c_int {
// Older versions of pipewire mistakenly had the return type as uint32_t,
// so we need to use try_into().unwrap() to ensure those versions also work
+ #[allow(clippy::useless_conversion)]
unsafe {
spa_sys::spa_pod_builder_control(self.as_raw_ptr(), offset, type_)
.try_into()
@@ -511,7 +512,7 @@ impl<'d> Builder<'d> {
/// Bytes(<&[u8]>),
/// }
/// );
-/// builder_add(<&mut libspa::pod::builder::Builder>,
+/// builder_add!(<&mut libspa::pod::builder::Builder>,
/// Object(
/// <type as u32>,
/// <id as u32>
diff --git a/src/pod/mod.rs b/src/pod/mod.rs
index 98c21ee..9f51ded 100644
--- a/src/pod/mod.rs
+++ b/src/pod/mod.rs
@@ -17,6 +17,7 @@ use std::{
io::{Seek, Write},
mem::MaybeUninit,
os::fd::RawFd,
+ ptr::addr_of,
};
use bitflags::bitflags;
@@ -89,7 +90,18 @@ impl Pod {
}
pub fn as_raw_ptr(&self) -> *mut spa_sys::spa_pod {
- std::ptr::addr_of!(self.0).cast_mut()
+ addr_of!(self.0).cast_mut()
+ }
+
+ /// Returns a pointer to the pods body.
+ ///
+ /// If the pod has an empty body, this can be outside the pods allocation.
+ pub fn body(&self) -> *mut c_void {
+ unsafe {
+ self.as_raw_ptr()
+ .byte_add(std::mem::size_of::<spa_sys::spa_pod>())
+ .cast()
+ }
}
/// Construct a pod from raw bytes.
@@ -158,7 +170,7 @@ impl Pod {
if res >= 0 {
Ok(b.assume_init())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -176,7 +188,7 @@ impl Pod {
if res >= 0 {
Ok(Id(id.assume_init()))
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -194,7 +206,7 @@ impl Pod {
if res >= 0 {
Ok(int.assume_init())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -212,7 +224,7 @@ impl Pod {
if res >= 0 {
Ok(long.assume_init())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -230,7 +242,7 @@ impl Pod {
if res >= 0 {
Ok(float.assume_init())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -248,7 +260,7 @@ impl Pod {
if res >= 0 {
Ok(double.assume_init())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -278,7 +290,7 @@ impl Pod {
let bytes = std::slice::from_raw_parts(bytes.cast(), len.try_into().unwrap());
Ok(bytes)
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -303,7 +315,7 @@ impl Pod {
let pointer = pointer.assume_init();
Ok((pointer, _type))
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -323,7 +335,7 @@ impl Pod {
let fd: RawFd = fd.try_into().unwrap();
Ok(fd)
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -341,7 +353,7 @@ impl Pod {
if res >= 0 {
Ok(rectangle.assume_init())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -359,7 +371,7 @@ impl Pod {
if res >= 0 {
Ok(fraction.assume_init())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -384,17 +396,324 @@ impl Pod {
res != 0
}
+ pub fn as_struct(&self) -> Result<&PodStruct, Errno> {
+ if self.is_struct() {
+ // Safety: We already know that the pod is valid, and since it is a struct, we can
+ // safely create a PodStruct from it
+ Ok(unsafe { PodStruct::from_raw(self.as_raw_ptr() as *const spa_sys::spa_pod_struct) })
+ } else {
+ Err(Errno::EINVAL)
+ }
+ }
+
pub fn is_object(&self) -> bool {
let res = unsafe { spa_sys::spa_pod_is_object(self.as_raw_ptr()) };
res != 0
}
+ // TODO: spa_pod_is_object_type, spa_pod_is_object_id
+
+ pub fn as_object(&self) -> Result<&PodObject, Errno> {
+ if self.is_object() {
+ // Safety: We already know that the pod is valid, and since it is an object, we can
+ // safely create a PodObject from it
+ Ok(unsafe { PodObject::from_raw(self.as_raw_ptr() as *const spa_sys::spa_pod_object) })
+ } else {
+ Err(Errno::EINVAL)
+ }
+ }
+
pub fn is_sequence(&self) -> bool {
let res = unsafe { spa_sys::spa_pod_is_sequence(self.as_raw_ptr()) };
res != 0
}
}
+impl<'p> From<&'p PodStruct> for &'p Pod {
+ fn from(value: &'p PodStruct) -> Self {
+ value.as_pod()
+ }
+}
+
+impl<'p> From<&'p PodObject> for &'p Pod {
+ fn from(value: &'p PodObject) -> Self {
+ value.as_pod()
+ }
+}
+
+/// A transparent wrapper around a `spa_sys::spa_pod_struct`.
+#[repr(transparent)]
+pub struct PodStruct(spa_sys::spa_pod_struct);
+
+impl PodStruct {
+ /// # Safety
+ ///
+ /// The provided pointer must point to a valid, well-aligned pod of type struct.
+ ///
+ /// All restrictions from [`Pod::from_raw`] also apply here.
+ pub unsafe fn from_raw(pod: *const spa_sys::spa_pod_struct) -> &'static Self {
+ pod.cast::<Self>().as_ref().unwrap()
+ }
+
+ /// # Safety
+ ///
+ /// The provided pointer must point to a valid, well-aligned pod of type struct.
+ ///
+ /// All restrictions from [`Pod::from_raw_mut`] also apply here.
+ pub unsafe fn from_raw_mut(pod: *mut spa_sys::spa_pod_struct) -> &'static mut Self {
+ pod.cast::<Self>().as_mut().unwrap()
+ }
+
+ pub fn as_raw_ptr(&self) -> *mut spa_sys::spa_pod_struct {
+ std::ptr::addr_of!(self.0).cast_mut()
+ }
+
+ pub fn as_pod(&self) -> &Pod {
+ // Safety: Since this is a valid spa_pod_object, it must also be a valid spa_pod
+ unsafe { Pod::from_raw(addr_of!(self.0.pod)) }
+ }
+
+ pub fn fields(&self) -> PodStructIter<'_> {
+ PodStructIter::new(self)
+ }
+}
+
+impl<'p> TryFrom<&'p Pod> for &'p PodStruct {
+ type Error = Errno;
+
+ fn try_from(value: &'p Pod) -> Result<Self, Self::Error> {
+ value.as_struct()
+ }
+}
+
+impl AsRef<Pod> for PodStruct {
+ fn as_ref(&self) -> &Pod {
+ self.as_pod()
+ }
+}
+
+pub struct PodStructIter<'s> {
+ struct_pod: &'s PodStruct,
+ next: *mut c_void,
+}
+
+impl<'s> PodStructIter<'s> {
+ fn new(struct_pod: &'s PodStruct) -> Self {
+ let first_field = struct_pod.as_pod().body();
+
+ Self {
+ struct_pod,
+ next: first_field,
+ }
+ }
+}
+
+impl<'s> Iterator for PodStructIter<'s> {
+ type Item = &'s Pod;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ // Check if the iterator has at least one element left that we can return
+ let has_next = unsafe {
+ spa_sys::spa_pod_is_inside(
+ self.struct_pod.as_pod().body(),
+ self.struct_pod.0.pod.size,
+ self.next,
+ )
+ };
+
+ if has_next {
+ let res = unsafe { Pod::from_raw(self.next as *const spa_sys::spa_pod) };
+
+ // Advance iter to next property
+ self.next = unsafe { spa_sys::spa_pod_next(self.next) };
+
+ Some(res)
+ } else {
+ None
+ }
+ }
+}
+
+/// A transparent wrapper around a `spa_sys::spa_pod_object`.
+#[repr(transparent)]
+pub struct PodObject(spa_sys::spa_pod_object);
+
+impl PodObject {
+ /// # Safety
+ ///
+ /// The provided pointer must point to a valid, well-aligned pod of type object.
+ ///
+ /// All restrictions from [`Pod::from_raw`] also apply here.
+ pub unsafe fn from_raw(pod: *const spa_sys::spa_pod_object) -> &'static Self {
+ pod.cast::<Self>().as_ref().unwrap()
+ }
+
+ /// # Safety
+ ///
+ /// The provided pointer must point to a valid, well-aligned pod of type object.
+ ///
+ /// All restrictions from [`Pod::from_raw_mut`] also apply here.
+ pub unsafe fn from_raw_mut(pod: *mut spa_sys::spa_pod_object) -> &'static mut Self {
+ pod.cast::<Self>().as_mut().unwrap()
+ }
+
+ pub fn as_raw_ptr(&self) -> *mut spa_sys::spa_pod_object {
+ std::ptr::addr_of!(self.0).cast_mut()
+ }
+
+ pub fn as_pod(&self) -> &Pod {
+ // Safety: Since this is a valid spa_pod_object, it must also be a valid spa_pod
+ unsafe { Pod::from_raw(addr_of!(self.0.pod)) }
+ }
+
+ pub fn type_(&self) -> SpaTypes {
+ SpaTypes::from_raw(self.0.body.type_)
+ }
+
+ pub fn id(&self) -> Id {
+ Id(self.0.body.id)
+ }
+
+ pub fn props(&self) -> PodObjectIter<'_> {
+ PodObjectIter::new(self)
+ }
+
+ pub fn find_prop(&self, /* TODO: start, */ key: Id) -> Option<&PodProp> {
+ let prop = unsafe {
+ spa_sys::spa_pod_object_find_prop(self.as_raw_ptr(), std::ptr::null(), key.0)
+ };
+
+ if !prop.is_null() {
+ unsafe { Some(PodProp::from_raw(prop)) }
+ } else {
+ None
+ }
+ }
+
+ pub fn fixate(&mut self) {
+ let _res = unsafe { spa_sys::spa_pod_object_fixate(self.as_raw_ptr()) };
+ // C implementation always returns 0
+ }
+
+ #[cfg(feature = "v0_3_40")]
+ pub fn is_fixated(&self) -> bool {
+ let res = unsafe { spa_sys::spa_pod_object_is_fixated(self.as_raw_ptr()) };
+ res != 0
+ }
+}
+
+impl<'p> TryFrom<&'p Pod> for &'p PodObject {
+ type Error = Errno;
+
+ fn try_from(value: &'p Pod) -> Result<Self, Self::Error> {
+ value.as_object()
+ }
+}
+
+impl AsRef<Pod> for PodObject {
+ fn as_ref(&self) -> &Pod {
+ self.as_pod()
+ }
+}
+
+pub struct PodObjectIter<'o> {
+ object: &'o PodObject,
+ next: *mut spa_sys::spa_pod_prop,
+}
+
+impl<'o> PodObjectIter<'o> {
+ fn new(object: &'o PodObject) -> Self {
+ let first_prop = unsafe { spa_sys::spa_pod_prop_first(addr_of!(object.0.body)) };
+
+ Self {
+ object,
+ next: first_prop,
+ }
+ }
+}
+
+impl<'o> Iterator for PodObjectIter<'o> {
+ type Item = &'o PodProp;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ // Check if the iterator has at least one element left that we can return
+ let has_next = unsafe {
+ spa_sys::spa_pod_prop_is_inside(
+ addr_of!(self.object.0.body),
+ self.object.0.pod.size,
+ self.next,
+ )
+ };
+
+ if has_next {
+ let res = unsafe { PodProp::from_raw(self.next.cast_const()) };
+
+ // Advance iter to next property
+ self.next = unsafe { spa_sys::spa_pod_prop_next(self.next) };
+
+ Some(res)
+ } else {
+ None
+ }
+ }
+}
+
+bitflags! {
+ #[derive(Debug, PartialEq, Eq, Clone, Copy)]
+ pub struct PodPropFlags: u32 {
+ const READONLY = spa_sys::SPA_POD_PROP_FLAG_READONLY;
+ const HARDWARE = spa_sys::SPA_POD_PROP_FLAG_HARDWARE;
+ const HINT_DICT = spa_sys::SPA_POD_PROP_FLAG_HINT_DICT;
+ const MANDATORY = spa_sys::SPA_POD_PROP_FLAG_MANDATORY;
+ const DONT_FIXATE = spa_sys::SPA_POD_PROP_FLAG_DONT_FIXATE;
+ }
+}
+
+/// A transparent wrapper around a `spa_sys::spa_pod_prop`.
+#[repr(transparent)]
+pub struct PodProp(spa_sys::spa_pod_prop);
+
+impl PodProp {
+ /// # Safety
+ ///
+ /// The provided pointer must point to a valid, well-aligned [`spa_sys::spa_pod_prop`].
+ ///
+ /// While this struct doesn't represent a full pod, all restrictions from [`Pod::from_raw`] also apply
+ /// to this struct and the contained `value` pod.
+ pub unsafe fn from_raw(prop: *const spa_sys::spa_pod_prop) -> &'static Self {
+ prop.cast::<Self>().as_ref().unwrap()
+ }
+
+ /// # Safety
+ ///
+ /// The provided pointer must point to a valid, well-aligned pod of type object.
+ ///
+ /// While this struct doesn't represent a full pod, all restrictions from [`Pod::from_raw`] also apply
+ /// to this struct and the contained `value` pod.
+ pub unsafe fn from_raw_mut(prop: *mut spa_sys::spa_pod_prop) -> &'static mut Self {
+ prop.cast::<Self>().as_mut().unwrap()
+ }
+
+ pub fn as_raw_ptr(&self) -> *mut spa_sys::spa_pod_prop {
+ std::ptr::addr_of!(self.0).cast_mut()
+ }
+
+ pub fn key(&self) -> Id {
+ Id(self.0.key)
+ }
+
+ pub fn flags(&self) -> PodPropFlags {
+ PodPropFlags::from_bits_retain(self.0.flags)
+ }
+
+ pub fn value(&self) -> &Pod {
+ // Safety: Since PodProp may only be constructed around valid Pods, the contained value must also be valid.
+ // We don't mutate the pod and neither can the returned reference.
+ // The returned lifetime is properly shortened by this methods signature.
+ unsafe { Pod::from_raw(addr_of!(self.0.value)) }
+ }
+}
+
/// Implementors of this trait are the canonical representation of a specific type of fixed sized SPA pod.
///
/// They can be used as an output type for [`FixedSizedPod`] implementors
diff --git a/src/pod/parser.rs b/src/pod/parser.rs
index a909d57..7203ce5 100644
--- a/src/pod/parser.rs
+++ b/src/pod/parser.rs
@@ -134,7 +134,7 @@ impl<'d> Parser<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
@@ -145,7 +145,7 @@ impl<'d> Parser<'d> {
if res >= 0 {
Ok(b.assume_init())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -157,7 +157,7 @@ impl<'d> Parser<'d> {
if res >= 0 {
Ok(Id(id.assume_init()))
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -169,7 +169,7 @@ impl<'d> Parser<'d> {
if res >= 0 {
Ok(int.assume_init())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -181,7 +181,7 @@ impl<'d> Parser<'d> {
if res >= 0 {
Ok(long.assume_init())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -193,7 +193,7 @@ impl<'d> Parser<'d> {
if res >= 0 {
Ok(float.assume_init())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -205,7 +205,7 @@ impl<'d> Parser<'d> {
if res >= 0 {
Ok(double.assume_init())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -220,7 +220,7 @@ impl<'d> Parser<'d> {
let string = CStr::from_ptr(string);
Ok(string)
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -241,7 +241,7 @@ impl<'d> Parser<'d> {
let bytes = std::slice::from_raw_parts(bytes, len.try_into().unwrap());
Ok(bytes)
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -258,7 +258,7 @@ impl<'d> Parser<'d> {
if res >= 0 {
Ok((ptr.assume_init(), Id(type_.assume_init())))
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -270,7 +270,7 @@ impl<'d> Parser<'d> {
if res >= 0 {
Ok(fd.assume_init())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -282,7 +282,7 @@ impl<'d> Parser<'d> {
if res >= 0 {
Ok(rect.assume_init())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -294,7 +294,7 @@ impl<'d> Parser<'d> {
if res >= 0 {
Ok(frac.assume_init())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -311,7 +311,7 @@ impl<'d> Parser<'d> {
Ok(pod)
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
@@ -329,7 +329,7 @@ impl<'d> Parser<'d> {
if res >= 0 {
Ok(())
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
@@ -353,7 +353,7 @@ impl<'d> Parser<'d> {
if res >= 0 {
Ok(Id(id.assume_init()))
} else {
- Err(Errno::from_i32(-res))
+ Err(Errno::from_raw(-res))
}
}
}
diff --git a/src/utils/dict.rs b/src/utils/dict.rs
index 7c02cff..4e99133 100644
--- a/src/utils/dict.rs
+++ b/src/utils/dict.rs
@@ -102,7 +102,6 @@ impl DictRef {
///
/// # Examples
/// ```
- /// use libspa::prelude::*;
/// use libspa::{utils::dict::StaticDict, static_dict};
///
/// static DICT: StaticDict = static_dict! {
@@ -145,9 +144,7 @@ impl std::fmt::Debug for DictRef {
impl<'a> fmt::Debug for Entries<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_map()
- .entries(self.0.clone().map(|(k, v)| (k, v)))
- .finish()
+ f.debug_map().entries(self.0.clone()).finish()
}
}
@@ -392,7 +389,7 @@ macro_rules! static_dict {
};
unsafe {
- let ptr = &RAW as *const _ as *mut _;
+ let ptr = std::ptr::addr_of!(RAW).cast_mut();
StaticDict::from_ptr(ptr::NonNull::new_unchecked(ptr))
}
}};
@@ -421,7 +418,7 @@ unsafe impl Sync for StaticDict {}
mod tests {
use super::{DictRef, Flags, StaticDict};
use spa_sys::spa_dict;
- use std::{ffi::CString, ptr};
+ use std::ptr;
#[test]
fn test_empty_dict() {
@@ -447,20 +444,8 @@ mod tests {
};
let mut iter = dict.iter_cstr();
- assert_eq!(
- (
- CString::new("K0").unwrap().as_c_str(),
- CString::new("V0").unwrap().as_c_str()
- ),
- iter.next().unwrap()
- );
- assert_eq!(
- (
- CString::new("K1").unwrap().as_c_str(),
- CString::new("V1").unwrap().as_c_str()
- ),
- iter.next().unwrap()
- );
+ assert_eq!((c"K0", c"V0"), iter.next().unwrap());
+ assert_eq!((c"K1", c"V1"), iter.next().unwrap());
assert_eq!(None, iter.next());
}
diff --git a/src/utils/mod.rs b/src/utils/mod.rs
index c0c4051..6aa83f2 100644
--- a/src/utils/mod.rs
+++ b/src/utils/mod.rs
@@ -144,7 +144,7 @@ impl SpaTypes {
Self(raw)
}
- /// Get the raw [`c_uint`](std::os::raw::c_uint) representing this `SpaTypes`.
+ /// Get the raw [`c_uint`] representing this `SpaTypes`.
pub fn as_raw(&self) -> c_uint {
self.0
}
diff --git a/src/utils/result.rs b/src/utils/result.rs
index 83d1e87..8d06636 100644
--- a/src/utils/result.rs
+++ b/src/utils/result.rs
@@ -133,7 +133,7 @@ impl Error {
fn new(e: i32) -> Self {
assert!(e > 0);
- Self(Errno::from_i32(e))
+ Self(Errno::from_raw(e))
}
}

View File

@ -1,345 +0,0 @@
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());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -6,20 +6,9 @@
#:use-module ((guix licenses) #:prefix license:) #:use-module ((guix licenses) #:prefix license:)
#:use-module (guix gexp) #:use-module (guix gexp)
#:use-module (guix packages) #:use-module (guix packages)
#:use-module (guix download)
#:use-module (guix git-download) #:use-module (guix git-download)
#:use-module (guix build-system cargo) #:use-module (guix build-system cargo)
#:use-module (gnu packages admin) #:use-module (gnu packages crates-crypto)
#:use-module (gnu packages freedesktop)
#:use-module (gnu packages gl)
#:use-module (gnu packages glib)
#:use-module (gnu packages gtk)
#:use-module (gnu packages linux)
#:use-module (gnu packages llvm)
#:use-module (gnu packages pkg-config)
#:use-module (gnu packages wm)
#:use-module (gnu packages xdisorg)
#:use-module (rosenthal packages)
#:use-module (rosenthal packages rust-crates)) #:use-module (rosenthal packages rust-crates))
(define-public atuin (define-public atuin
@ -34,9 +23,7 @@
(file-name (git-file-name name version)) (file-name (git-file-name name version))
(sha256 (sha256
(base32 (base32
"1zi7ar999ycvig9c9crylab540xdgr0h6v99q9j8ypk9i1fviyiz")) "1zi7ar999ycvig9c9crylab540xdgr0h6v99q9j8ypk9i1fviyiz"))))
(patches
(rosenthal-patches "atuin-disable-failing-tests.patch"))))
(build-system cargo-build-system) (build-system cargo-build-system)
(arguments (arguments
(list (list
@ -45,6 +32,24 @@
''("client" "sync" "server" "clipboard" "daemon") ''("client" "sync" "server" "clipboard" "daemon")
#:phases #:phases
#~(modify-phases %standard-phases #~(modify-phases %standard-phases
(add-after 'unpack 'disable-failing-tests
(lambda _
(substitute* '("crates/atuin/tests/sync.rs"
"crates/atuin/tests/users.rs"
"crates/atuin-dotfiles/src/store.rs"
"crates/atuin-dotfiles/src/store/var.rs")
(((string-append
".*async fn (" (string-join
'(;; Require running database.
"build_aliases"
"build_vars"
"sync"
"registration"
"change_password"
"multi_user_test")
"|") ")")
all)
(string-append "#[ignore]\n" all)))))
(add-after 'unpack 'patch-references (add-after 'unpack 'patch-references
(lambda _ (lambda _
(substitute* (find-files "crates/atuin/src/shell") (substitute* (find-files "crates/atuin/src/shell")
@ -63,7 +68,7 @@
;; otherwise cargo will raise an error. ;; otherwise cargo will raise an error.
(invoke "cargo" "install" "--no-track" "--path" "crates/atuin" (invoke "cargo" "install" "--no-track" "--path" "crates/atuin"
"--root" out "--features" (string-join features)))))))) "--root" out "--features" (string-join features))))))))
(inputs (force atuin-cargo-inputs)) (inputs (cons* rust-ring-0.17 atuin-cargo-inputs))
(home-page "https://atuin.sh/") (home-page "https://atuin.sh/")
(synopsis "Sync, search and backup shell history") (synopsis "Sync, search and backup shell history")
(description (description
@ -71,60 +76,3 @@
additional context for commands. Additionally, it provides optional and fully additional context for commands. Additionally, it provides optional and fully
encrypted synchronisation of history between machines, via an Atuin server.") encrypted synchronisation of history between machines, via an Atuin server.")
(license license:gpl3))) (license license:gpl3)))
(define-public niri
(package
(name "niri")
(version "25.02")
(source (origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/YaLTeR/niri")
(commit (string-append "v" version))))
(file-name (git-file-name name version))
(sha256
(base32
"0vzskaalcz6pcml687n54adjddzgf5r07gggc4fhfsa08h1wfd4r"))
(patches (list (local-file "./patches/niri.patch")))))
(build-system cargo-build-system)
(arguments
(list #:install-source? #f
#:phases
#~(modify-phases %standard-phases
(add-after 'configure 'set-rust-flags
(lambda _
(setenv "RUSTFLAGS" (string-join
'("-C" "link-arg=-lEGL"
"-C" "link-arg=-lwayland-client")
" "))))
(add-before 'check 'prepare-test-environment
(lambda _
(setenv "XDG_RUNTIME_DIR" "/tmp")))
(add-after 'install 'install-extras
(lambda _
(install-file
"resources/niri.desktop"
(in-vicinity #$output "share/wayland-sessions"))
(install-file
"resources/niri-portals.conf"
(in-vicinity #$output "share/xdg-desktop-portal")))))))
(native-inputs
(list pkg-config))
(inputs
(cons* clang
libdisplay-info
libinput-minimal
libseat
libxkbcommon
mesa
pango
pipewire
wayland
(force niri-cargo-inputs)))
(home-page "https://github.com/YaLTeR/niri")
(synopsis "Scrollable-tiling Wayland compositor")
(description
"Niri is a scrollable-tiling Wayland compositor which arranges windows in a
scrollable format. It is considered stable for daily use and performs most
functions expected of a Wayland compositor.")
(license license:gpl3)))

File diff suppressed because it is too large Load Diff

200
rosenthal/packages/wm.scm Normal file
View File

@ -0,0 +1,200 @@
;; SPDX-FileCopyrightText: 2025 Hilton Chain <hako@ultrarare.space>
;;
;; SPDX-License-Identifier: GPL-3.0-or-later
(define-module (rosenthal packages wm)
#:use-module ((guix licenses) #:prefix license:)
#:use-module (guix gexp)
#:use-module (guix packages)
#:use-module (guix git-download)
#:use-module (guix build-system cargo)
#:use-module (gnu packages admin)
#:use-module (gnu packages freedesktop)
#:use-module (gnu packages gl)
#:use-module (gnu packages glib)
#:use-module (gnu packages gtk)
#:use-module (gnu packages linux)
#:use-module (gnu packages llvm)
#:use-module (gnu packages pkg-config)
#:use-module (gnu packages wm)
#:use-module (gnu packages xdisorg)
#:use-module (rosenthal packages rust-crates))
(define rust-pipewire
(let ((commit "fd3d8f7861a29c2eeaa4c393402e013578bb36d9")
(revision "0"))
(package
(name "rust-pipewire")
(version (git-version "0.8.0" revision commit))
(source
(origin
(method git-fetch)
(uri (git-reference
(url "https://gitlab.freedesktop.org/pipewire/pipewire-rs.git")
(commit commit)))
(file-name (git-file-name name version))
(sha256
(base32 "1hzyhz7xg0mz8a5y9j6yil513p1m610q3j9pzf6q55vdh5mcn79v"))))
(build-system cargo-build-system)
(arguments
(list #:skip-build? #t
#:phases
#~(modify-phases %standard-phases
;; Avoid circular dependency.
(add-after 'unpack 'remove-dev-dependencies
(lambda _
(substitute* "libspa/Cargo.toml"
(("^pipewire.*") ""))))
(replace 'package
(lambda _
(begin
;;error: invalid inclusion of reserved file name Cargo.toml.orig in package source
(when (file-exists? "Cargo.toml.orig")
(delete-file "Cargo.toml.orig"))
;; Use unstable feature --registry.
(setenv "RUSTC_BOOTSTRAP" "1")
(for-each
(lambda (pkg)
(invoke "cargo" "package" "--offline" "--package" pkg
"--registry" "crates-io" "-Z" "package-workspace"
"--no-metadata" "--no-verify")
(for-each
(lambda (crate)
(invoke "tar" "xzf" crate "-C" "guix-vendor"))
(begin
(delete-file-recursively "target/package/tmp-registry")
(find-files "target/package" "\\.crate$")))
((assoc-ref %standard-phases 'patch-cargo-checksums)))
'("libspa-sys" "libspa" "pipewire-sys" "pipewire"))
(unsetenv "RUSTC_BOOTSTRAP")))))))
(inputs rust-pipewire-cargo-inputs)
(home-page "https://pipewire.org/")
(synopsis "Rust bindings for PipeWire")
(description "This package provides Rust bindings for PipeWire.")
(license license:expat))))
(define rust-smithay
(let ((commit "0cd3345c59f7cb139521f267956a1a4e33248393")
(revision "0"))
(package
(name "rust-smithay")
(version (git-version "0.4.0" revision commit))
(source (origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/Smithay/smithay")
(commit commit)))
(file-name (git-file-name name version))
(sha256
(base32
"191h87bpzg0l1ihfb4hmx00b86pfb5mwwc6s8i49al0vigc14l37"))))
(build-system cargo-build-system)
(arguments
(list #:skip-build? #t
#:phases
#~(modify-phases %standard-phases
(replace 'package
(lambda _
(begin
;;error: invalid inclusion of reserved file name Cargo.toml.orig in package source
(when (file-exists? "Cargo.toml.orig")
(delete-file "Cargo.toml.orig"))
;; Use unstable feature --registry.
(setenv "RUSTC_BOOTSTRAP" "1")
(for-each
(lambda (pkg)
(invoke "cargo" "package" "--offline" "--package" pkg
"--registry" "crates-io" "-Z" "package-workspace"
"--no-metadata" "--no-verify")
(for-each
(lambda (crate)
(invoke "tar" "xzf" crate "-C" "guix-vendor"))
(begin
(delete-file-recursively "target/package/tmp-registry")
(find-files "target/package" "\\.crate$")))
((assoc-ref %standard-phases 'patch-cargo-checksums)))
'("smithay" "smithay-drm-extras"))
(unsetenv "RUSTC_BOOTSTRAP")))))))
(inputs rust-smithay-cargo-inputs)
(home-page "https://github.com/Smithay/smithay")
(synopsis "Smithy for Rust Wayland compositors")
(description
"Smithay aims to provide building blocks to create wayland compositors in
Rust. While not being a full-blown compositor, it'll provide objects and
interfaces implementing common functionalities that pretty much any compositor
will need, in a generic fashion.
It supports the @code{wayland}, @code{wayland-protocols}, and some external
extensions, such as @code{wlr-protocols} and @code{plasma-wayland-protocols}.")
(license license:expat))))
(define-public niri
(package
(name "niri")
(version "25.02")
(source (origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/YaLTeR/niri")
(commit (string-append "v" version))))
(file-name (git-file-name name version))
(sha256
(base32
"0vzskaalcz6pcml687n54adjddzgf5r07gggc4fhfsa08h1wfd4r"))))
(build-system cargo-build-system)
(arguments
(list #:install-source? #f
#:phases
#~(modify-phases %standard-phases
(add-after 'unpack 'use-guix-vendored-dependencies
(lambda _
(substitute* "Cargo.toml"
(("# version = \"0.4.1\"")
"version = \"0.4.0\"")
(("# version = \"0.1.0\"")
"version = \"0.1.0\"")
(("git.*optional")
"version = \"0.8.0\", optional")
(("^git = .*")
""))))
(add-after 'configure 'set-rust-flags
(lambda _
(setenv "RUSTFLAGS" (string-join
'("-C" "link-arg=-lEGL"
"-C" "link-arg=-lwayland-client")
" "))))
(add-before 'check 'prepare-test-environment
(lambda _
(setenv "XDG_RUNTIME_DIR" "/tmp")))
(add-after 'install 'install-extras
(lambda _
(install-file
"resources/niri.desktop"
(in-vicinity #$output "share/wayland-sessions"))
(install-file
"resources/niri-portals.conf"
(in-vicinity #$output "share/xdg-desktop-portal")))))))
(native-inputs
(list pkg-config))
(inputs
(cons* clang
libdisplay-info
libinput-minimal
libseat
libxkbcommon
mesa
pango
pipewire
rust-pipewire
rust-smithay
wayland
niri-cargo-inputs))
(home-page "https://github.com/YaLTeR/niri")
(synopsis "Scrollable-tiling Wayland compositor")
(description
"Niri is a scrollable-tiling Wayland compositor which arranges windows in a
scrollable format. It is considered stable for daily use and performs most
functions expected of a Wayland compositor.")
(license license:gpl3)))