| Crates.io | lamco-portal |
| lib.rs | lamco-portal |
| version | 0.3.0 |
| created_at | 2025-12-15 16:10:54.030329+00 |
| updated_at | 2025-12-31 22:42:55.905062+00 |
| description | XDG Desktop Portal integration for Wayland screen capture and input control |
| homepage | https://lamco.ai |
| repository | https://github.com/lamco-admin/lamco-wayland |
| max_upload_size | |
| id | 1986321 |
| size | 178,716 |
High-level Rust interface to XDG Desktop Portal for Wayland screen capture and input control.
xdg-desktop-portal installed and runningxdg-desktop-portal-gnomexdg-desktop-portal-kdexdg-desktop-portal-wlrAdd to your Cargo.toml:
[dependencies]
lamco-portal = "0.1"
tokio = { version = "1", features = ["full"] }
Basic usage:
use lamco_portal::{PortalManager, PortalConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create portal manager with default config
let manager = PortalManager::with_default().await?;
// Create session (triggers permission dialog)
let session = manager.create_session("my-session".to_string(), None).await?;
// Access PipeWire FD for video capture
let fd = session.pipewire_fd();
let streams = session.streams();
println!("Capturing {} streams on PipeWire FD {}", streams.len(), fd);
// Inject mouse movement
manager.remote_desktop()
.notify_pointer_motion_absolute(
session.ashpd_session(),
0, // stream index
100.0, // x position
200.0, // y position
)
.await?;
Ok(())
}
[dependencies]
# Default - basic portal functionality
lamco-portal = "0.1"
# With D-Bus clipboard bridge for GNOME (SelectionOwnerChanged workaround)
lamco-portal = { version = "0.1", features = ["dbus-clipboard"] }
# With ClipboardSink trait for lamco-clipboard-core integration
lamco-portal = { version = "0.1", features = ["clipboard-sink"] }
| Feature | Description |
|---|---|
dbus-clipboard |
D-Bus clipboard bridge for GNOME - works around missing SelectionOwnerChanged signals |
clipboard-sink |
ClipboardSink trait implementation for lamco-clipboard-core integration |
Customize Portal behavior:
use lamco_portal::{PortalManager, PortalConfig};
use ashpd::desktop::screencast::CursorMode;
use ashpd::desktop::PersistMode;
let config = PortalConfig::builder()
.cursor_mode(CursorMode::Embedded) // Embed cursor in video
.persist_mode(PersistMode::Application) // Remember permission
.build();
let manager = PortalManager::new(config).await?;
Handle specific error conditions:
use lamco_portal::PortalError;
match manager.create_session("session-1".to_string(), None).await {
Ok(session) => {
println!("Session created successfully");
}
Err(PortalError::PermissionDenied) => {
eprintln!("User denied permission");
}
Err(PortalError::PortalNotAvailable) => {
eprintln!("Portal not installed - install xdg-desktop-portal");
}
Err(e) => {
eprintln!("Other error: {}", e);
}
}
See the examples/ directory for complete examples:
basic.rs - Simple screen capture setupinput.rs - Input injection (keyboard/mouse)clipboard.rs - Clipboard integrationRun examples with:
cargo run --example basic
| Platform | Status | Backend Package |
|---|---|---|
| GNOME (Wayland) | ✅ Supported | xdg-desktop-portal-gnome |
| KDE Plasma (Wayland) | ✅ Supported | xdg-desktop-portal-kde |
| Sway / wlroots | ✅ Supported | xdg-desktop-portal-wlr |
| X11 | ❌ Not Supported | Wayland only |
This library triggers system permission dialogs. Users must explicitly grant:
Permissions can be remembered per-application using PersistMode::Application to skip the dialog on subsequent runs.
┌─────────────────┐
│ Your Application│
└────────┬────────┘
│
v
┌─────────────────┐
│ lamco-portal │
│ (this crate) │
└────────┬────────┘
│
v
┌─────────────────┐
│ ashpd │ ← Low-level Portal bindings
└────────┬────────┘
│
v
┌─────────────────┐
│ xdg-desktop- │
│ portal │ ← System Portal service
└────────┬────────┘
│
┌────┴────┬─────────────┐
v v v
┌────────┐┌────────┐ ┌──────────┐
│PipeWire││D-Bus │ │Compositor│
└────────┘└────────┘ └──────────┘
Solution: Install xdg-desktop-portal and the appropriate backend:
# Arch Linux
sudo pacman -S xdg-desktop-portal xdg-desktop-portal-gnome
# Ubuntu/Debian
sudo apt install xdg-desktop-portal xdg-desktop-portal-gnome
# Fedora
sudo dnf install xdg-desktop-portal xdg-desktop-portal-gnome
Solution: This is expected behavior when the user clicks "Cancel" in the permission dialog. Handle it gracefully in your application.
Causes:
Solution: Check that your portal backend is running and try again.
Licensed under either of:
at your option.
Contributions are welcome! Please feel free to submit a Pull Request.