From f008e9169d62211b29f4ae0283678e0b9ced2388 Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 17 Jan 2022 21:20:58 -0600 Subject: [PATCH] use XDG Desktop Portal on Linux & BSDs This new backend does not support MessageDialog nor AsyncMessageDialog because there is no corresponding API in the XDG Desktop Portal. The GTK backend is still available with the new `gtk3` Cargo feature. Fixes #36 --- Cargo.lock | 661 ++++++++++++++++++++++++++++++ Cargo.toml | 13 +- src/backend.rs | 22 +- src/backend/xdg_desktop_portal.rs | 274 +++++++++++++ src/lib.rs | 30 ++ 5 files changed, 994 insertions(+), 6 deletions(-) create mode 100644 src/backend/xdg_desktop_portal.rs diff --git a/Cargo.lock b/Cargo.lock index 19ee393..e5fc928 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,163 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "ashpd" +version = "0.2.0-beta-1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0e317c257d4733c44475b3cefd53adb2540771ba8bd4adf37eabef3bbf8298e" +dependencies = [ + "enumflags2", + "futures", + "rand", + "serde", + "serde_repr", + "zbus", + "zbus_macros", + "zvariant", + "zvariant_derive", +] + +[[package]] +name = "async-broadcast" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90622698a1218e0b2fb846c97b5f19a0831f6baddee73d9454156365ccfa473b" +dependencies = [ + "easy-parallel", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "once_cell", + "slab", +] + +[[package]] +name = "async-fs" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b3ca4f8ff117c37c278a2f7415ce9be55560b846b5bc4412aaa5d29c1c3dae2" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-io" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" +dependencies = [ + "concurrent-queue", + "futures-lite", + "libc", + "log", + "once_cell", + "parking", + "polling", + "slab", + "socket2", + "waker-fn", + "winapi", +] + +[[package]] +name = "async-lock" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-net" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5373304df79b9b4395068fb080369ec7178608827306ce4d081cba51cac551df" +dependencies = [ + "async-io", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-process" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83137067e3a2a6a06d67168e49e68a0957d215410473a740cea95a2425c0b7c6" +dependencies = [ + "async-io", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "libc", + "once_cell", + "signal-hook", + "winapi", +] + +[[package]] +name = "async-recursion" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-task" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" + +[[package]] +name = "async-trait" +version = "0.1.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "atk-sys" version = "0.15.1" @@ -14,18 +171,62 @@ dependencies = [ "system-deps", ] +[[package]] +name = "atomic-waker" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "block" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" +[[package]] +name = "blocking" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046e47d4b2d391b1f6f8b407b1deb8dee56c1852ccd868becf2710f601b5f427" +dependencies = [ + "async-channel", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", + "once_cell", +] + [[package]] name = "bumpalo" version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cache-padded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" + [[package]] name = "cairo-sys-rs" version = "0.15.1" @@ -36,6 +237,12 @@ dependencies = [ "system-deps", ] +[[package]] +name = "cc" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" + [[package]] name = "cfg-expr" version = "0.9.0" @@ -51,18 +258,80 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "concurrent-queue" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +dependencies = [ + "cache-padded", +] + [[package]] name = "cty" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "dispatch" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "easy-parallel" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6907e25393cdcc1f4f3f513d9aac1e840eb1cc341a0fccb01171f7d14d10b946" + +[[package]] +name = "enumflags2" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a25c90b056b3f84111cf183cbeddef0d3a0bbe9a674f057e1a1533c315f24def" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "144ec79496cbab6f84fa125dc67be9264aef22eb8a28da8454d9c33f15108da4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "event-listener" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" + +[[package]] +name = "fastrand" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "779d043b6a0b90cc4c0ed7ee380a6504394cee7efd7db050e3774eee387324b2" +dependencies = [ + "instant", +] + [[package]] name = "futures" version = "0.3.19" @@ -111,6 +380,21 @@ version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" +[[package]] +name = "futures-lite" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + [[package]] name = "futures-macro" version = "0.3.19" @@ -182,6 +466,17 @@ dependencies = [ "system-deps", ] +[[package]] +name = "getrandom" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "gio-sys" version = "0.15.1" @@ -243,6 +538,21 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "js-sys" version = "0.3.55" @@ -288,6 +598,28 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "nix" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "memoffset", +] + [[package]] name = "objc" version = "0.2.7" @@ -317,6 +649,22 @@ dependencies = [ "objc", ] +[[package]] +name = "once_cell" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" + +[[package]] +name = "ordered-stream" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44630c059eacfd6e08bdaa51b1db2ce33119caa4ddc1235e923109aa5f25ccb1" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "pango-sys" version = "0.15.1" @@ -329,6 +677,12 @@ dependencies = [ "system-deps", ] +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + [[package]] name = "pin-project-lite" version = "0.2.8" @@ -347,6 +701,35 @@ version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" +[[package]] +name = "polling" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" +dependencies = [ + "cfg-if", + "libc", + "log", + "wepoll-ffi", + "winapi", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro-crate" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83" +dependencies = [ + "thiserror", + "toml", +] + [[package]] name = "proc-macro2" version = "1.0.36" @@ -365,6 +748,46 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + [[package]] name = "raw-window-handle" version = "0.4.2" @@ -374,10 +797,28 @@ dependencies = [ "cty", ] +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + [[package]] name = "rfd" version = "0.6.4" dependencies = [ + "ashpd", "block", "dispatch", "futures", @@ -390,6 +831,7 @@ dependencies = [ "objc-foundation", "objc_id", "raw-window-handle", + "smol", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -401,6 +843,65 @@ name = "serde" version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.133" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_repr" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + +[[package]] +name = "signal-hook" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] [[package]] name = "slab" @@ -414,6 +915,40 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +[[package]] +name = "smol" +version = "1.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cf3b5351f3e783c1d79ab5fc604eeed8b8ae9abd36b166e8b87a089efd85e4" +dependencies = [ + "async-channel", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-net", + "async-process", + "blocking", + "futures-lite", + "once_cell", +] + +[[package]] +name = "socket2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "syn" version = "1.0.85" @@ -438,6 +973,26 @@ dependencies = [ "version-compare", ] +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "toml" version = "0.5.8" @@ -465,6 +1020,18 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe88247b92c1df6b6de80ddc290f3976dbdf2f5f5d3fd049a9fb598c6dd5ca73" +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + [[package]] name = "wasm-bindgen" version = "0.2.78" @@ -541,6 +1108,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "wepoll-ffi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" +dependencies = [ + "cc", +] + [[package]] name = "winapi" version = "0.3.9" @@ -605,3 +1181,88 @@ name = "windows_x86_64_msvc" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08cabc9f0066848fef4bc6a1c1668e6efce38b661d2aeec75d18d8617eebb5f1" + +[[package]] +name = "zbus" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ac8424f5aa1f239d2d7ecb32f9d5ffc6fcf5fb9298d2d524a7e7c8b258c3f80" +dependencies = [ + "async-broadcast", + "async-channel", + "async-executor", + "async-io", + "async-lock", + "async-recursion", + "async-task", + "async-trait", + "byteorder", + "derivative", + "enumflags2", + "event-listener", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix", + "once_cell", + "ordered-stream", + "rand", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e03af45fc15e2c977161c5ffea56c43c41f425a963affd7074bf91b5bf5a8cf" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "syn", +] + +[[package]] +name = "zbus_names" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45dfcdcf87b71dad505d30cc27b1b7b88a64b6d1c435648f48f9dbc1fdc4b7e1" +dependencies = [ + "serde", + "static_assertions", + "zvariant", +] + +[[package]] +name = "zvariant" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb31b009e0b0c4f2c1283c9c23129e4f76020da4b3c4dfa032abfbfe30a2c02" +dependencies = [ + "byteorder", + "enumflags2", + "libc", + "serde", + "static_assertions", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5295bdc2688c7239423889191d730ad071f814dc36c48edf7cda23f38dd28b2a" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index ab019ab..1b98c8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ documentation = "https://docs.rs/rfd" default = ["parent"] parent = ["raw-window-handle"] file-handle-inner = [] +gtk3 = ["gtk-sys", "glib-sys", "gobject-sys", "lazy_static"] [dev-dependencies] futures = "0.3.12" @@ -35,11 +36,13 @@ windows = { version = "0.30.0", features = [ "Win32_UI_WindowsAndMessaging", ] } -[target.'cfg(any(target_os = "freebsd", target_os = "linux"))'.dependencies] -gtk-sys = { version = "0.15.1", features = ["v3_20"] } -glib-sys = "0.15.1" -gobject-sys = "0.15.1" -lazy_static = "1.4.0" +[target.'cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd", target_os = "openbsd"))'.dependencies] +ashpd = "0.2.0-beta-1" +smol = "1.2" +gtk-sys = { version = "0.15.1", features = ["v3_20"], optional = true } +glib-sys = { version = "0.15.1", optional = true } +gobject-sys = { version = "0.15.1", optional = true } +lazy_static = { version = "1.4.0", optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2.69" diff --git a/src/backend.rs b/src/backend.rs index 79ff28d..9ae3c1e 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -3,7 +3,16 @@ use std::future::Future; use std::path::PathBuf; use std::pin::Pin; -#[cfg(any(target_os = "freebsd", target_os = "linux"))] +#[cfg(all( + any( + target_os = "linux", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk3" +))] mod gtk3; #[cfg(target_os = "macos")] mod macos; @@ -11,6 +20,17 @@ mod macos; mod wasm; #[cfg(target_os = "windows")] mod win_cid; +#[cfg(all( + any( + target_os = "linux", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd", + target_os = "openbsd" + ), + not(feature = "gtk3") +))] +mod xdg_desktop_portal; // // Sync diff --git a/src/backend/xdg_desktop_portal.rs b/src/backend/xdg_desktop_portal.rs new file mode 100644 index 0000000..0425185 --- /dev/null +++ b/src/backend/xdg_desktop_portal.rs @@ -0,0 +1,274 @@ +use std::path::PathBuf; + +use crate::backend::DialogFutureType; +use crate::file_dialog::Filter; +use crate::{FileDialog, FileHandle}; + +use ashpd::desktop::file_chooser::{ + FileChooserProxy, FileFilter, OpenFileOptions, SaveFileOptions, +}; +// TODO: convert raw_window_handle::RawWindowHandle to ashpd::WindowIdentifier +use ashpd::{zbus, WindowIdentifier}; + +use smol::block_on; + +// +// Utility functions +// + +fn add_filters_to_open_file_options( + filters: Vec, + mut options: OpenFileOptions, +) -> OpenFileOptions { + for filter in &filters { + let mut ashpd_filter = FileFilter::new(&filter.name); + for file_extension in &filter.extensions { + ashpd_filter = ashpd_filter.glob(&format!("*.{}", file_extension)); + } + options = options.add_filter(ashpd_filter); + } + options +} + +fn add_filters_to_save_file_options( + filters: Vec, + mut options: SaveFileOptions, +) -> SaveFileOptions { + for filter in &filters { + let mut ashpd_filter = FileFilter::new(&filter.name); + for file_extension in &filter.extensions { + ashpd_filter = ashpd_filter.glob(&format!("*.{}", file_extension)); + } + options = options.add_filter(ashpd_filter); + } + options +} + +// refer to https://github.com/flatpak/xdg-desktop-portal/issues/213 +fn uri_to_path(uri: &str) -> Option { + uri.strip_prefix("file://").map(PathBuf::from) +} + +// +// File Picker +// + +use crate::backend::FilePickerDialogImpl; +impl FilePickerDialogImpl for FileDialog { + fn pick_file(self) -> Option { + let connection = block_on(zbus::Connection::session()).unwrap(); + let proxy = block_on(FileChooserProxy::new(&connection)).unwrap(); + let mut options = OpenFileOptions::default() + .accept_label("Pick file") + .multiple(false); + options = add_filters_to_open_file_options(self.filters, options); + let selected_files = block_on(proxy.open_file( + &WindowIdentifier::default(), + &self.title.unwrap_or_else(|| "Pick a file".to_string()), + options, + )); + if selected_files.is_err() { + return None; + } + uri_to_path(&selected_files.unwrap().uris()[0]) + } + + fn pick_files(self) -> Option> { + let connection = block_on(zbus::Connection::session()).unwrap(); + let proxy = block_on(FileChooserProxy::new(&connection)).unwrap(); + let mut options = OpenFileOptions::default() + .accept_label("Pick file") + .multiple(true); + options = add_filters_to_open_file_options(self.filters, options); + let selected_files = block_on(proxy.open_file( + &WindowIdentifier::default(), + &self.title.unwrap_or_else(|| "Pick a file".to_string()), + options, + )); + if selected_files.is_err() { + return None; + } + let selected_files = selected_files + .unwrap() + .uris() + .iter() + .filter_map(|string| uri_to_path(string)) + .collect::>(); + if selected_files.is_empty() { + return None; + } + Some(selected_files) + } +} + +use crate::backend::AsyncFilePickerDialogImpl; +impl AsyncFilePickerDialogImpl for FileDialog { + fn pick_file_async(self) -> DialogFutureType> { + Box::pin(async { + let connection = zbus::Connection::session().await.unwrap(); + let proxy = FileChooserProxy::new(&connection).await.unwrap(); + let mut options = OpenFileOptions::default() + .accept_label("Pick file") + .multiple(false); + options = add_filters_to_open_file_options(self.filters, options); + let selected_files = proxy + .open_file( + &WindowIdentifier::default(), + &self.title.unwrap_or_else(|| "Pick a file".to_string()), + options, + ) + .await; + if selected_files.is_err() { + return None; + } + uri_to_path(&selected_files.unwrap().uris()[0]).map(FileHandle::from) + }) + } + + fn pick_files_async(self) -> DialogFutureType>> { + Box::pin(async { + let connection = zbus::Connection::session().await.unwrap(); + let proxy = FileChooserProxy::new(&connection).await.unwrap(); + let mut options = OpenFileOptions::default() + .accept_label("Pick file(s)") + .multiple(true); + options = add_filters_to_open_file_options(self.filters, options); + let selected_files = proxy + .open_file( + &WindowIdentifier::default(), + &self + .title + .unwrap_or_else(|| "Pick one or more files".to_string()), + options, + ) + .await; + if selected_files.is_err() { + return None; + } + let selected_files = selected_files + .unwrap() + .uris() + .iter() + .filter_map(|string| uri_to_path(string)) + .map(FileHandle::from) + .collect::>(); + if selected_files.is_empty() { + return None; + } + Some(selected_files) + }) + } +} + +// +// Folder Picker +// + +use crate::backend::FolderPickerDialogImpl; +impl FolderPickerDialogImpl for FileDialog { + fn pick_folder(self) -> Option { + let connection = block_on(zbus::Connection::session()).unwrap(); + let proxy = block_on(FileChooserProxy::new(&connection)).unwrap(); + let mut options = OpenFileOptions::default() + .accept_label("Pick folder") + .multiple(false) + .directory(true); + options = add_filters_to_open_file_options(self.filters, options); + let selected_files = block_on(proxy + .open_file( + &WindowIdentifier::default(), + &self.title.unwrap_or_else(|| "Pick a folder".to_string()), + options, + )); + if selected_files.is_err() { + return None; + } + uri_to_path(&selected_files.unwrap().uris()[0]) + } +} + +use crate::backend::AsyncFolderPickerDialogImpl; +impl AsyncFolderPickerDialogImpl for FileDialog { + fn pick_folder_async(self) -> DialogFutureType> { + Box::pin(async { + let connection = zbus::Connection::session().await.unwrap(); + let proxy = FileChooserProxy::new(&connection).await.unwrap(); + let mut options = OpenFileOptions::default() + .accept_label("Pick folder") + .multiple(false) + .directory(true); + options = add_filters_to_open_file_options(self.filters, options); + let selected_files = proxy + .open_file( + &WindowIdentifier::default(), + &self.title.unwrap_or_else(|| "Pick a folder".to_string()), + options, + ) + .await; + if selected_files.is_err() { + return None; + } + uri_to_path(&selected_files.unwrap().uris()[0]).map(FileHandle::from) + }) + } +} + +// +// File Save +// + +use crate::backend::FileSaveDialogImpl; +impl FileSaveDialogImpl for FileDialog { + fn save_file(self) -> Option { + let connection = block_on(zbus::Connection::session()).unwrap(); + let proxy = block_on(FileChooserProxy::new(&connection)).unwrap(); + let mut options = SaveFileOptions::default().accept_label("Save"); + options = add_filters_to_save_file_options(self.filters, options); + if let Some(file_name) = self.file_name { + options = options.current_name(&file_name); + } + // TODO: impl zvariant::Type for PathBuf? + // if let Some(dir) = self.starting_directory { + // options.current_folder(dir); + // } + let selected_files = block_on(proxy.save_file( + &WindowIdentifier::default(), + &self.title.unwrap_or_else(|| "Save file".to_string()), + options, + )); + if selected_files.is_err() { + return None; + } + uri_to_path(&selected_files.unwrap().uris()[0]) + } +} + +use crate::backend::AsyncFileSaveDialogImpl; +impl AsyncFileSaveDialogImpl for FileDialog { + fn save_file_async(self) -> DialogFutureType> { + Box::pin(async { + let connection = zbus::Connection::session().await.unwrap(); + let proxy = FileChooserProxy::new(&connection).await.unwrap(); + let mut options = SaveFileOptions::default().accept_label("Save"); + options = add_filters_to_save_file_options(self.filters, options); + if let Some(file_name) = self.file_name { + options = options.current_name(&file_name); + } + // TODO: impl zvariant::Type for PathBuf? + // if let Some(dir) = self.starting_directory { + // options.current_folder(dir); + // } + let selected_files = proxy + .save_file( + &WindowIdentifier::default(), + &self.title.unwrap_or_else(|| "Save file".to_string()), + options, + ) + .await; + if selected_files.is_err() { + return None; + } + uri_to_path(&selected_files.unwrap().uris()[0]).map(FileHandle::from) + }) + } +} diff --git a/src/lib.rs b/src/lib.rs index ed21e20..359e9f8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,36 @@ pub use file_dialog::FileDialog; pub use file_dialog::AsyncFileDialog; +#[cfg(any( + target_os = "windows", + target_os = "macos", + target_family = "wasm", + all( + any( + target_os = "linux", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk3" + ) +))] mod message_dialog; +#[cfg(any( + target_os = "windows", + target_os = "macos", + target_family = "wasm", + all( + any( + target_os = "linux", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk3" + ) +))] pub use message_dialog::{AsyncMessageDialog, MessageButtons, MessageDialog, MessageLevel};