| Crates.io | xdg-portal |
| lib.rs | xdg-portal |
| version | 0.2.0 |
| created_at | 2025-03-21 08:32:30.864862+00 |
| updated_at | 2025-04-05 12:53:40.100828+00 |
| description | implement for xdg-desktop-portal |
| homepage | |
| repository | https://github.com/dlzht/xdg-desktop-portal |
| max_upload_size | |
| id | 1600290 |
| size | 144,178 |
[dependencies]
xdg-portal = "0.1"
XDG Desktop Portal allow Flatpak apps, and other desktop containment frameworks, to interact with the system in a secure and well defined way.
| impl | example | version | doc | description | |
|---|---|---|---|---|---|
| Account | ✅ | ✅ | 1 | Account.xml | query basic information about the user, like their name and avatar photo |
| Background | ❌ | ❌ | 2 | Background.xml | let application run in the background or started automatically when the user logs in |
| Camera | ✅ | ✅ | - | Camera.xml | access camera devices, such as web cams |
| Clipboard | ❌ | ❌ | - | Clipboard.xml | access system clipboard |
| Document | ❌ | ❌ | 5 | Documents.xml | make files from the outside world available to sandboxed applications in a controlled way |
| Launcher | ❌ | ❌ | 1 | DynamicLauncher.xml | instal application launchers(.desktop files) which have an icon associated with them and which execute a command in the application |
| ✅ | ✅ | 4 | Email.xml | request to send an email, optionally providing an address, subject, body and attachments | |
| File Chooser | ✅ | ✅ | 4 | FileChooser.xml | ask the user for access to files |
| File Transfer | ❌ | ❌ | 1 | FileTransfer.xml | transfer files between apps |
| Game Mode | ✅ | ✅ | 4 | GameMode.xml | access GameMode |
| Global Shortcuts | ❌ | ❌ | 1 | GlobalShortcuts.xml | create global shortcuts sessions, and register shortcuts |
| Inhibit | ❌ | ❌ | 3 | Inhibit.xml | inhibit the user session from ending, suspending, idling or getting switched away |
| Input Capture | ❌ | ❌ | 1 | InputCapture.xml | capture input events from connected physical or logical devices |
| Location | ✅ | ✅ | 1 | Location.xml | query basic information about the location |
| Momory Monitor | ✅ | ✅ | 1 | MemoryMonitor.xml | provides information about low system memory |
| Network Monitor | ✅ | ✅ | 3 | NetworkMonitor.xml | provides network status information |
| Notification | ✅ | ✅ | 2 | Notification.xml | send and withdraw notifications |
| OpenURI | ❌ | ❌ | 5 | OpenURI.xml | open URIs (e.g. a http: link to the applications homepage) under the control of the user |
| Power Profile Monitor | ✅ | ✅ | 1 | PowerProfileMonitor.xml | provides information about the user-selected system-wide power profile |
| ❌ | ❌ | 3 | Print.xml | allows applications to print | |
| Proxy Resolver | ✅ | ✅ | 1 | ProxyResolver.xml | provides network proxy information |
| Realtime | ❌ | ❌ | 1 | Realtime.xml | set threads to realtime |
| Remote Desktop | ❌ | ❌ | 2 | RemoteDesktop.xml | create remote desktop sessions |
| Request | ✅ | ❌ | - | Request.xml | shared request interface |
| Screencast | ✅ | ✅ | 5 | ScreenCast.xml | create screen cast sessions |
| Screenshot | ✅ | ✅ | 2 | Screenshot.xml | request a screenshot |
| Secret | ❌ | ❌ | 1 | Secret.xml | retrieve a per-application secret |
| Session | ❌ | ❌ | - | Session.xml | shared session interface |
| Settings | ❌ | ❌ | 2 | Settings.xml | provides read-only access to a small number of standardized host settings required for toolkits similar to XSettings |
| Trash | ✅ | ✅ | 1 | Trash.xml | send files to the trashcan |
| Usb | ❌ | ❌ | 1 | Usb.xml | monitor and request access to connected USB devices |
| Wallpaper | ✅ | ✅ | 1 | Wallpaper.xml | set the user’s desktop background picture |
#[tokio::main(flavor = "current_thread")]
async fn main() {
let portal = Portal::new().await.unwrap();
let mut account_portal = portal.account().await.unwrap();
let req = GetUserInfoReq::default()
.reason("I want to get user info");
println!("{:?}", account_portal.get_user_information(req).await);
}
// Ok(AccountUserInformation { id: "dlzht", name: "", image: "file:///home/dlzht/.face" })
#[tokio::main(flavor = "current_thread")]
async fn main() {
let portal = Portal::new().await.unwrap();
let camera_portal = portal.camera().await.unwrap();
if let Ok(res) = camera_portal.is_camera_present().await && res{
let fd = camera_portal.open_camera().await.unwrap();
println!("Opened camera: {:?}", fd);
}
}
// Opened camera: OwnedFd { fd: 11 }
#[tokio::main(flavor = "current_thread")]
async fn main() {
let portal = Portal::new().await.unwrap();
let email_portal = portal.email().await.unwrap();
let req = ComposeEmailReq::default()
.subject("Email Subject")
.body("Hello")
.addresses(vec!["example@github.com".to_string()]);
email_portal.compose_email(req).await.unwrap();
}
// mailto:example@github.com?subject=Email Subject&body=Hello
open_file
async fn open_file() {
let portal = Portal::new().await.unwrap();
let mut file_chooser_portal = portal.file_chooser().await.unwrap();
let filter1 = FileFilterReq::new("image-jpg".to_string(), vec!["*.jpg".to_string()]);
let filter2 = FileFilterReq::new("image-png".to_string(), vec!["*.png".to_string()]);
let filters = vec![filter1.clone(), filter2.clone()];
let req = OpenFileReq::new()
.title("This is open file title".to_string())
.modal(true)
.multiple(true)
.filters(filters)
.current_filter(filter2)
.accept_label("This is accept label".to_string());
let res = file_chooser_portal.open_file(req).await;
println!("{:?}", res);
}
// Ok(OpenFileRes { uris: ["file:///home/dlzht/example.png"], current_filter: Some(FileFilterRes { name: "image-png", matches: ["*.png"] }) })
save_file
async fn save_file() {
let portal = Portal::new().await.unwrap();
let mut file_chooser_portal = portal.file_chooser().await.unwrap();
let filter1 = FileFilterReq::new("image-jpg".to_string(), vec!["*.jpg".to_string()]);
let filter2 = FileFilterReq::new("image-png".to_string(), vec!["*.png".to_string()]);
let filters = vec![filter1.clone(), filter2.clone()];
let req = SaveFileReq::new()
.title("This is save file title".to_string())
.modal(true)
.filters(filters)
.current_filter(filter2)
.current_name("FILE_NAME".to_string())
.accept_label("This is accept label".to_string());
let res = file_chooser_portal.save_file(req).await;
println!("{:?}", res);
}
// Ok(SaveFileRes { uris: ["file:///home/dlzht/FILE_NAME.png"], current_filter: Some(FileFilterRes { name: "image-png", matches: ["*.png"] }) })
save_files(nothing happened on my machine KDE/WAYLAND)
async fn save_files() {
let portal = Portal::new().await.unwrap();
let mut file_chooser_portal = portal.file_chooser().await.unwrap();
let path_buf1 = PathBuf::from("image-jpg1");
let path_buf2 = PathBuf::from("image-jpg2");
let req = SaveFilesReq::new()
.title("This is save files title".to_string())
.modal(true)
.files(vec![path_buf1.clone(), path_buf2.clone()])
.accept_label("This is accept label".to_string());
let res = file_chooser_portal.save_files(req).await;
println!("{:?}", res);
}
#[tokio::main(flavor = "current_thread")]
async fn main() {
let portal = Portal::new().await.unwrap();
let game_mode_portal = portal.game_mode().await.unwrap();
let res1 = game_mode_portal.active().await;
println!("{:?}", res1);
}
// Ok(false)
#[tokio::main(flavor = "current_thread")]
async fn main() {
let portal = Portal::new().await.unwrap();
let location_portal = portal.location().await.unwrap();
let req = GetLocationsReq::new();
let mut locations = location_portal.locations(req)
.await.unwrap();
while let Some(location) = locations.next().await {
println!("{:?}", location);
}
}
#[tokio::main(flavor = "current_thread")]
async fn main() {
let portal = Portal::new().await.unwrap();
let mut memory_monitor_portal = portal.memory_monitor().await.unwrap();
tokio::spawn(async move {
if let Ok(level) = memory_monitor_portal.low_memory_warning().await {
}
});
}
#[tokio::main(flavor = "current_thread")]
async fn main() {
let portal = Portal::new().await.unwrap();
let network_monitor_portal = portal.network_monitor().await.unwrap();
let res = network_monitor_portal.get_available().await;
println!("available: {:?}", res);
let res = network_monitor_portal.get_metered().await;
println!("metered: {:?}", res);
let res = network_monitor_portal.get_connectivity().await;
println!("connectivity: {:?}", res);
let res = network_monitor_portal.get_connectivity().await;
println!("connectivity: {:?}", res);
let res = network_monitor_portal.can_reach("github.com", 443).await;
println!("can_reach: {:?}", res);
let mut changed = network_monitor_portal.change().await.unwrap();
while let Some(_signal) = changed.next().await {
println!("receive changed signal");
}
}
// available: Ok(true)
// metered: Ok(false)
// connectivity: Ok(FullNetwork)
// connectivity: Ok(FullNetwork)
// can_reach: Ok(true)
#[tokio::main(flavor = "current_thread")]
async fn main() {
let portal = Portal::new().await.unwrap();
let notification_portal = portal.notification().await.unwrap();
let send_req = SendNotificationReq::new()
.id("1".to_string())
.title("This is title".to_string())
.body("this is a high priority notification".to_string())
.priority(NotificationPriority::High);
let _ = notification_portal.send_notification(send_req).await;
tokio::time::sleep(Duration::from_millis(1000)).await;
// remove notification which has id "1")
let remove_req = RemoveNotificationReq::new("1".to_string());
let _ = notification_portal.remove_notification(remove_req).await;
}
#[tokio::main(flavor = "current_thread")]
async fn main() {
let portal = Portal::new().await.unwrap();
let power_monitor_portal = portal.power_profile_monitor().await.unwrap();
let res = power_monitor_portal.power_saver_enabled().await;
println!("{:?}", res);
}
// Ok(false)
#[tokio::main(flavor = "current_thread")]
async fn main() {
let portal = Portal::new().await.unwrap();
let proxy_resolver_portal = portal.proxy_resolver().await.unwrap();
let res = proxy_resolver_portal.lookup("https://github.com")
.await;
println!("{:?}", res);
}
// Ok(["direct://"])
#[tokio::main(flavor = "current_thread")]
async fn main() {
let portal = Portal::new().await.unwrap();
let mut screencast_portal = portal.screencast().await.unwrap();
let screencast_req = ScreencastReq::new()
.source_type(SourceType::Window | SourceType::Monitor);
let res = screencast_portal.screencast(screencast_req).await;
println!("screencast_portal returned: {:?}", res);
}
// screencast_portal returned: Ok(ScreencastRes { streams: [SelectedSource { node_id: 73, identifier: None, source_type: SourceType(Virtual), size: Some((1920, 1080)), position: None, mapping_id: None }], fd: OwnedFd { fd: 11 } })
screenshot
async fn screenshot() {
let portal = Portal::new().await.unwrap();
let mut screenshot_portal = portal.screenshot().await.unwrap();
let req = ScreenshotReq::new()
.interactive(true)
.modal(false);
let res = screenshot_portal.screenshot(req).await;
println!("{:?}", res);
}
// Ok(ScreenshotRes { uri: "file:///home/dlzht/Screenshot_20250321_121919.png" })
pick_color
async fn pick_color() {
let portal = Portal::new().await.unwrap();
let mut screenshot_portal = portal.screenshot().await.unwrap();
let req = PickColorReq::new();
let res = screenshot_portal.pick_color(req).await;
println!("{:?}", res);
}
// Ok(PickColorRes { r: 0.11764705926179886, g: 0.12156862765550613, b: 0.13333334028720856 })
#[tokio::main(flavor = "current_thread")]
async fn main() {
let portal = Portal::new().await.unwrap();
let trash_portal = portal.trash().await.unwrap();
let file = tokio::fs::File::open("some_file").await.unwrap();
trash_portal.trash_file(file.as_fd()).await.unwrap();
}
set_wallpaper_url
async fn set_wallpaper_url() {
let portal = Portal::new().await.unwrap();
let wallpaper_portal = portal.wallpaper().await.unwrap();
let req = SetWallpaperUriReq::new("example.png".to_string())
.show_preview(true)
.set_on(WallpaperLocation::Background);
wallpaper_portal.set_wallpaper_uri(req).await.unwrap();
}
set_wallpaper_file
async fn set_wallpaper_file() {
let portal = Portal::new().await.unwrap();
let wallpaper_portal = portal.wallpaper().await.unwrap();
let file = std::fs::File::open("example.png").unwrap();
let req = SetWallpaperFileReq::new(file.as_fd())
.show_preview(true)
.set_on(WallpaperLocation::Background);
wallpaper_portal.set_wallpaper_file(req).await.unwrap();
}