| 1 | //! garfield-portal - XDG Desktop Portal backend for garfield file picker. |
| 2 | //! |
| 3 | //! This daemon implements the org.freedesktop.impl.portal.FileChooser interface, |
| 4 | //! spawning garfield in picker mode when applications request file dialogs. |
| 5 | |
| 6 | mod file_chooser; |
| 7 | mod request; |
| 8 | |
| 9 | use anyhow::Result; |
| 10 | use clap::Parser; |
| 11 | use tracing_subscriber::{fmt, EnvFilter}; |
| 12 | use zbus::connection::Builder; |
| 13 | |
| 14 | /// garfield-portal - XDG Desktop Portal backend |
| 15 | #[derive(Parser, Debug)] |
| 16 | #[command(name = "garfield-portal", about = "XDG Desktop Portal backend for garfield")] |
| 17 | struct Args { |
| 18 | /// Run in foreground (don't daemonize) |
| 19 | #[arg(long, short = 'f')] |
| 20 | foreground: bool, |
| 21 | } |
| 22 | |
| 23 | #[tokio::main] |
| 24 | async fn main() -> Result<()> { |
| 25 | // Initialize logging |
| 26 | let filter = EnvFilter::try_from_default_env() |
| 27 | .unwrap_or_else(|_| EnvFilter::new("info")); |
| 28 | |
| 29 | fmt() |
| 30 | .with_env_filter(filter) |
| 31 | .with_target(false) |
| 32 | .init(); |
| 33 | |
| 34 | let _args = Args::parse(); |
| 35 | |
| 36 | tracing::info!("Starting garfield-portal"); |
| 37 | |
| 38 | // Create the FileChooser interface |
| 39 | let file_chooser = file_chooser::FileChooser::new(); |
| 40 | |
| 41 | // Connect to session bus and serve the interface |
| 42 | let _connection = Builder::session()? |
| 43 | .name("org.freedesktop.impl.portal.desktop.garfield")? |
| 44 | .serve_at("/org/freedesktop/portal/desktop", file_chooser)? |
| 45 | .build() |
| 46 | .await?; |
| 47 | |
| 48 | tracing::info!("garfield-portal listening on D-Bus session bus"); |
| 49 | |
| 50 | // Keep the service running |
| 51 | loop { |
| 52 | // The connection handles incoming method calls automatically |
| 53 | // We just need to keep the main task alive |
| 54 | tokio::time::sleep(std::time::Duration::from_secs(3600)).await; |
| 55 | } |
| 56 | } |
| 57 |