diff --git a/.zed/settings.json b/.zed/settings.json deleted file mode 100644 index 2cc7b98..0000000 --- a/.zed/settings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "format_on_save": "on", - "lsp": { - "rust-analyzer": { - "initialization_options": { - "check": { - "command": "clippy", - }, - "rustfmt": { - "extraArgs": ["+nightly"], - }, - }, - }, - }, -} diff --git a/Cargo.lock b/Cargo.lock index f39c221..0084c8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,7 +35,7 @@ dependencies = [ "accesskit_consumer", "atspi-common", "serde", - "zvariant 5.12.0", + "zvariant 5.10.0", ] [[package]] @@ -72,7 +72,7 @@ dependencies = [ "serde", "tokio", "tokio-stream", - "zbus 5.16.0", + "zbus 5.14.0", ] [[package]] @@ -109,13 +109,13 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aes" -version = "0.9.1" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fc76eaeac4c9164506c466d4ffdd8ec9d0c5bf57ee97177c4d8eceb3a0e138" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ + "cfg-if", "cipher", - "cpubits", - "cpufeatures 0.3.0", + "cpufeatures", ] [[package]] @@ -172,19 +172,13 @@ checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" [[package]] name = "alloc-stdlib" -version = "0.2.4" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" dependencies = [ "alloc-no-stdlib", ] -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - [[package]] name = "almost" version = "0.2.0" @@ -198,7 +192,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f2a1bb052857d5dd49572219344a7332b31b76405648eabac5bc68978251bcd" dependencies = [ "android-properties", - "bitflags 2.13.0", + "bitflags 2.11.1", "cc", "jni", "libc", @@ -277,9 +271,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.103" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "apply" @@ -304,9 +298,9 @@ checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" [[package]] name = "arc-swap" -version = "1.9.2" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" +checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" dependencies = [ "rustversion", ] @@ -330,9 +324,15 @@ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.7" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" [[package]] name = "as-slice" @@ -367,7 +367,7 @@ dependencies = [ "serde_repr", "tokio", "url", - "zbus 5.16.0", + "zbus 5.14.0", ] [[package]] @@ -387,7 +387,7 @@ dependencies = [ "wayland-backend", "wayland-client", "wayland-protocols", - "zbus 5.16.0", + "zbus 5.14.0", ] [[package]] @@ -573,11 +573,11 @@ dependencies = [ "enumflags2", "serde", "static_assertions", - "zbus 5.16.0", + "zbus 5.14.0", "zbus-lockstep", "zbus-lockstep-macros", - "zbus_names 4.3.2", - "zvariant 5.12.0", + "zbus_names 4.3.1", + "zvariant 5.10.0", ] [[package]] @@ -588,14 +588,14 @@ checksum = "2230e48787ed3eb4088996eab66a32ca20c0b67bbd4fd6cdfe79f04f1f04c9fc" dependencies = [ "atspi-common", "serde", - "zbus 5.16.0", + "zbus 5.14.0", ] [[package]] name = "auto_enums" -version = "0.8.9" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e4487600931c9a89f8db7ffbdf3fbdd45bb7bd85e26861f659a463cd0dff966" +checksum = "65398a2893f41bce5c9259f6e1a4f03fbae40637c1bdc755b4f387f48c613b03" dependencies = [ "derive_utils", "proc-macro2", @@ -605,9 +605,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.5.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "av-scenechange" @@ -645,9 +645,9 @@ dependencies = [ [[package]] name = "avif-serialize" -version = "0.8.9" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7178fe5f7d460b13895ebb9dcb28a3a6216d2df2574a0806cb51b555d297f38" +checksum = "375082f007bd67184fb9c0374614b29f9aaa604ec301635f72338bb65386a53d" dependencies = [ "arrayvec", ] @@ -696,9 +696,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.13.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" dependencies = [ "serde_core", ] @@ -727,16 +727,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-buffer" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" -dependencies = [ - "hybrid-array", - "zeroize", -] - [[package]] name = "block2" version = "0.5.1" @@ -770,9 +760,9 @@ dependencies = [ [[package]] name = "borsh" -version = "1.7.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f3f6da4992df95bbcd9af42a6c7dcb994498fc9048230405f3b36ff7cd3f145" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" dependencies = [ "bytes", "cfg_aliases", @@ -780,32 +770,23 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "5.0.3" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", ] -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "tinyvec", -] - [[package]] name = "bstr" -version = "1.12.3" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cee35f73844aa3014bb606320a6c1f010249dbdf43342fe54b5a4f6a8ed4b79" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" dependencies = [ "memchr", "regex-automata", - "serde_core", + "serde", ] [[package]] @@ -819,15 +800,15 @@ dependencies = [ [[package]] name = "built" -version = "0.8.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c0e531d93d39c34eef561e929e8a7f86d77a5af08aac4f6d6e39976c51858e9" +checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64" [[package]] name = "bumpalo" -version = "3.20.3" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "by_address" @@ -869,9 +850,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.12.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "bzip2" @@ -898,7 +879,7 @@ version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "polling", "rustix 1.1.4", "slab", @@ -919,14 +900,14 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.65" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" dependencies = [ "find-msvc-tools", "jobserver", "libc", - "shlex 2.0.1", + "shlex", ] [[package]] @@ -942,9 +923,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.20.8" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb693542bcafa528e198be0ebd9d3632ca5b7c93dbe7237460e199910835997c" +checksum = "3c6b04e07d8080154ed4ac03546d9a2b303cc2fe1901ba0b35b301516e289368" dependencies = [ "smallvec", "target-lexicon", @@ -964,9 +945,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.45" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ "iana-time-zone", "js-sys", @@ -978,11 +959,11 @@ dependencies = [ [[package]] name = "cipher" -version = "0.5.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common 0.2.2", + "crypto-common", "inout", ] @@ -998,6 +979,7 @@ dependencies = [ [[package]] name = "clipboard_macos" version = "0.1.0" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#f68595ee0e62fbd6589f4709b5aaa5c3c7ea5f6c" dependencies = [ "objc", "objc-foundation", @@ -1007,6 +989,7 @@ dependencies = [ [[package]] name = "clipboard_wayland" version = "0.2.2" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#f68595ee0e62fbd6589f4709b5aaa5c3c7ea5f6c" dependencies = [ "dnd", "mime 0.1.0", @@ -1014,10 +997,13 @@ dependencies = [ ] [[package]] -name = "cmov" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" +name = "clipboard_x11" +version = "0.4.2" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#f68595ee0e62fbd6589f4709b5aaa5c3c7ea5f6c" +dependencies = [ + "thiserror 1.0.69", + "x11rb", +] [[package]] name = "cocoa" @@ -1099,9 +1085,9 @@ dependencies = [ [[package]] name = "compio-buf" -version = "0.8.3" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b51a2c35873865376ed4cdb6cfeb602b6cf569815f017ddd7bd8f86ad49b34c7" +checksum = "a00d719dbd8c602ab0d25d219cbc6b517008858de7a8d6c51b4dc95aefff4dce" dependencies = [ "arrayvec", "bytes", @@ -1221,15 +1207,9 @@ dependencies = [ [[package]] name = "configparser" -version = "3.2.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b46dec724fd22199ebde05033a0cbae453bc3b1ecff11eb6a6bb3eec4b90c6a4" - -[[package]] -name = "const-oid" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" +checksum = "e57e3272f0190c3f1584272d613719ba5fc7df7f4942fe542e63d949cf3a649b" [[package]] name = "constant_time_eq" @@ -1293,7 +1273,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "core-foundation 0.10.1", "libc", ] @@ -1321,22 +1301,10 @@ dependencies = [ [[package]] name = "cosmic-client-toolkit" version = "0.2.0" +source = "git+https://github.com/pop-os/cosmic-protocols?rev=160b086#160b086abe03cd34a8a375d7fbe47b24308d1f38" dependencies = [ - "bitflags 2.13.0", - "cosmic-protocols 0.2.0", - "libc", - "smithay-client-toolkit", - "wayland-client", - "wayland-protocols", -] - -[[package]] -name = "cosmic-client-toolkit" -version = "0.2.0" -source = "git+https://github.com/pop-os/cosmic-protocols?rev=c253ec1#c253ec1d6804afbcdf250f5cc37ae1194bba7bd2" -dependencies = [ - "bitflags 2.13.0", - "cosmic-protocols 0.2.0 (git+https://github.com/pop-os/cosmic-protocols?rev=c253ec1)", + "bitflags 2.11.1", + "cosmic-protocols", "libc", "smithay-client-toolkit", "wayland-client", @@ -1346,6 +1314,7 @@ dependencies = [ [[package]] name = "cosmic-config" version = "1.0.0" +source = "git+https://github.com/pop-os/libcosmic.git#c423ad1bfc25057922406c687f2ddc75ead5ab67" dependencies = [ "atomicwrites", "cosmic-config-derive", @@ -1355,17 +1324,18 @@ dependencies = [ "iced_futures", "known-folders", "notify", - "ron 0.12.2", + "ron 0.12.1", "serde", "tokio", "tracing", "xdg", - "zbus 5.16.0", + "zbus 5.14.0", ] [[package]] name = "cosmic-config-derive" version = "1.0.0" +source = "git+https://github.com/pop-os/libcosmic.git#c423ad1bfc25057922406c687f2ddc75ead5ab67" dependencies = [ "quote", "syn", @@ -1373,14 +1343,13 @@ dependencies = [ [[package]] name = "cosmic-files" -version = "1.3.0" +version = "1.0.11" dependencies = [ "anyhow", "atomic_float", - "bstr", "bzip2", "compio", - "cosmic-client-toolkit 0.2.0 (git+https://github.com/pop-os/cosmic-protocols?rev=c253ec1)", + "cosmic-client-toolkit", "cosmic-mime-apps", "dirs 6.0.0", "fastrand", @@ -1399,7 +1368,7 @@ dependencies = [ "jiff-icu", "jxl-oxide", "libc", - "libcosmic-yoda", + "libcosmic", "log", "lzma-rust2", "md-5", @@ -1418,8 +1387,7 @@ dependencies = [ "rust-embed", "rustc-hash 2.1.2", "serde", - "sha2 0.10.9", - "shlex 1.3.0", + "shlex", "slotmap", "tar", "tempfile", @@ -1442,7 +1410,7 @@ dependencies = [ [[package]] name = "cosmic-files-applet" -version = "1.2.0" +version = "1.0.11" dependencies = [ "cosmic-files", "log", @@ -1452,11 +1420,12 @@ dependencies = [ [[package]] name = "cosmic-freedesktop-icons" version = "0.4.0" +source = "git+https://github.com/pop-os/freedesktop-icons#9c562fe3ecf03241a46a60c0078cd6ea10bd75ce" dependencies = [ "bstr", "btoi", "memchr", - "memmap2 0.9.11", + "memmap2 0.9.10", "thiserror 2.0.18", "tracing", "xdg", @@ -1464,8 +1433,8 @@ dependencies = [ [[package]] name = "cosmic-mime-apps" -version = "0.2.0" -source = "git+https://github.com/pop-os/cosmic-mime-apps.git#8fc81e8857e46c018ea21ab985aaf30ac853c007" +version = "0.1.0" +source = "git+https://github.com/pop-os/cosmic-mime-apps.git#673f3758920a7b20d307d356d586deef714df6b0" dependencies = [ "freedesktop-desktop-entry", "mime 0.3.17", @@ -1476,22 +1445,9 @@ dependencies = [ [[package]] name = "cosmic-protocols" version = "0.2.0" +source = "git+https://github.com/pop-os/cosmic-protocols?rev=160b086#160b086abe03cd34a8a375d7fbe47b24308d1f38" dependencies = [ - "bitflags 2.13.0", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-protocols-wlr", - "wayland-scanner", - "wayland-server", -] - -[[package]] -name = "cosmic-protocols" -version = "0.2.0" -source = "git+https://github.com/pop-os/cosmic-protocols?rev=c253ec1#c253ec1d6804afbcdf250f5cc37ae1194bba7bd2" -dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -1503,6 +1459,7 @@ dependencies = [ [[package]] name = "cosmic-settings-config" version = "0.1.0" +source = "git+https://github.com/pop-os/cosmic-settings-daemon#716da6d6af0b252e2f78aba2ad72ee19ae0241e0" dependencies = [ "cosmic-config", "ron 0.11.0", @@ -1514,16 +1471,18 @@ dependencies = [ [[package]] name = "cosmic-settings-daemon" -version = "0.1.1-yoda.1" +version = "0.1.0" +source = "git+https://github.com/pop-os/dbus-settings-bindings#507e342c21d3ce6ae41b1d4f3fa2f0ad5ee23e75" dependencies = [ - "zbus 5.16.0", + "zbus 5.14.0", ] [[package]] name = "cosmic-text" -version = "0.19.0" +version = "0.18.2" +source = "git+https://github.com/pop-os/cosmic-text.git#4d74f795cc771fdcc7ea0f9cacba63fcf036fad6" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "fontdb", "harfrust", "linebender_resource_handle", @@ -1531,7 +1490,7 @@ dependencies = [ "rangemap", "rustc-hash 2.1.2", "self_cell", - "skrifa 0.40.0", + "skrifa", "smol_str", "swash", "sys-locale", @@ -1539,32 +1498,25 @@ dependencies = [ "unicode-linebreak", "unicode-script", "unicode-segmentation", - "unicode-width", ] [[package]] name = "cosmic-theme" version = "1.0.0" +source = "git+https://github.com/pop-os/libcosmic.git#c423ad1bfc25057922406c687f2ddc75ead5ab67" dependencies = [ "almost", "configparser", "cosmic-config", "csscolorparser", "dirs 6.0.0", - "hex_color", "palette", - "ron 0.12.2", + "ron 0.12.1", "serde", "serde_json", "thiserror 2.0.18", ] -[[package]] -name = "cpubits" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" - [[package]] name = "cpufeatures" version = "0.2.17" @@ -1574,15 +1526,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cpufeatures" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" -dependencies = [ - "libc", -] - [[package]] name = "crc32fast" version = "1.5.0" @@ -1635,6 +1578,7 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "cryoglyph" version = "0.1.0" +source = "git+https://github.com/pop-os/glyphon.git?tag=cosmic-0.14#c49de15bce4d8254ac136d1be9911960cc85ce12" dependencies = [ "cosmic-text", "etagere", @@ -1653,15 +1597,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-common" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" -dependencies = [ - "hybrid-array", -] - [[package]] name = "css-color" version = "0.2.8" @@ -1681,13 +1616,10 @@ dependencies = [ ] [[package]] -name = "ctutils" -version = "0.4.2" +name = "ctor-lite" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" -dependencies = [ - "cmov", -] +checksum = "e162d0c2e2068eb736b71e5597eff0b9944e6b973cd9f37b6a288ab9bf20e300" [[package]] name = "cursor-icon" @@ -1776,44 +1708,13 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac6b926516df9c60bfa16e107b21086399f8285a44ca9711344b9e553c5146e2" -[[package]] -name = "defmt" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6e524506490a1953d237cb87b1cfc1e46f88c18f10a22dfe0f507dc6bfc7f7f" -dependencies = [ - "bitflags 1.3.2", - "defmt-macros", -] - -[[package]] -name = "defmt-macros" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0a27770e9c8f719a79d8b638281f4d828f77d8fd61e0bd94451b9b85e576a0b" -dependencies = [ - "defmt-parser", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "defmt-parser" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" -dependencies = [ - "thiserror 2.0.18", -] - [[package]] name = "deranged" version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ + "powerfmt", "serde_core", ] @@ -1846,21 +1747,9 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", - "crypto-common 0.1.7", -] - -[[package]] -name = "digest" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" -dependencies = [ - "block-buffer 0.12.1", - "const-oid", - "crypto-common 0.2.2", - "ctutils", - "zeroize", + "block-buffer", + "crypto-common", + "subtle", ] [[package]] @@ -1932,7 +1821,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "block2 0.6.2", "libc", "objc2 0.6.4", @@ -1940,9 +1829,9 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.6" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", @@ -1961,8 +1850,9 @@ dependencies = [ [[package]] name = "dnd" version = "0.1.0" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#f68595ee0e62fbd6589f4709b5aaa5c3c7ea5f6c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "mime 0.1.0", "raw-window-handle", "smithay-client-toolkit", @@ -1987,6 +1877,46 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dpi" version = "0.1.2" +source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" + +[[package]] +name = "drm" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0f8a69e60d75ae7dab4ef26a59ca99f2a89d4c142089b537775ae0c198bdcde" +dependencies = [ + "bitflags 2.11.1", + "bytemuck", + "drm-ffi", + "drm-fourcc", + "rustix 0.38.44", +] + +[[package]] +name = "drm-ffi" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41334f8405792483e32ad05fbb9c5680ff4e84491883d2947a4757dc54cb2ac6" +dependencies = [ + "drm-sys", + "rustix 0.38.44", +] + +[[package]] +name = "drm-fourcc" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" + +[[package]] +name = "drm-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d09ff881f92f118b11105ba5e34ff8f4adf27b30dae8f12e28c193af1c83176" +dependencies = [ + "libc", + "linux-raw-sys 0.6.5", +] [[package]] name = "dyn-clone" @@ -1996,9 +1926,9 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "either" -version = "1.16.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "endi" @@ -2029,19 +1959,18 @@ dependencies = [ [[package]] name = "env_filter" -version = "2.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217" +checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" dependencies = [ "log", - "regex", ] [[package]] name = "env_logger" -version = "0.11.11" +version = "0.11.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6" +checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" dependencies = [ "anstream", "anstyle", @@ -2160,9 +2089,23 @@ checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "fax" -version = "0.2.7" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a" +checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" +dependencies = [ + "fax_derive", +] + +[[package]] +name = "fax_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "fdeflate" @@ -2184,12 +2127,13 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.29" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" dependencies = [ "cfg-if", "libc", + "libredox", ] [[package]] @@ -2348,7 +2292,7 @@ checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905" dependencies = [ "fontconfig-parser", "log", - "memmap2 0.9.11", + "memmap2 0.9.10", "slotmap", "tinyvec", "ttf-parser", @@ -2536,9 +2480,9 @@ dependencies = [ [[package]] name = "generator" -version = "0.8.9" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3b854b0e584ead1a33f18b2fcad7cf7be18b3875c78816b753639aa501513ae" +checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" dependencies = [ "cc", "cfg-if", @@ -2559,6 +2503,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "gethostname" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" +dependencies = [ + "rustix 1.1.4", + "windows-link 0.2.1", +] + [[package]] name = "getrandom" version = "0.2.17" @@ -2584,14 +2538,16 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.4.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", "js-sys", "libc", "r-efi 6.0.0", + "wasip2", + "wasip3", "wasm-bindgen", ] @@ -2688,7 +2644,7 @@ version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16de123c2e6c90ce3b573b7330de19be649080ec612033d397d72da265f1bd8b" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "futures-channel", "futures-core", "futures-executor", @@ -2778,17 +2734,34 @@ dependencies = [ ] [[package]] -name = "gpu-allocator" -version = "0.28.0" +name = "gpu-alloc" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51255ea7cfaadb6c5f1528d43e92a82acb2b96c43365989a28b2d44ee38f8795" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" +dependencies = [ + "bitflags 2.11.1", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" +dependencies = [ + "bitflags 2.11.1", +] + +[[package]] +name = "gpu-allocator" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" dependencies = [ - "ash", - "hashbrown 0.16.1", "log", "presser", - "thiserror 2.0.18", - "windows 0.62.2", + "thiserror 1.0.69", + "windows 0.58.0", ] [[package]] @@ -2797,7 +2770,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "gpu-descriptor-types", "hashbrown 0.15.5", ] @@ -2808,14 +2781,14 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", ] [[package]] name = "grid" -version = "1.0.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b40ca9252762c466af32d0b1002e91e4e1bc5398f77455e55474deb466355ff5" +checksum = "f9e2d4c0a8296178d8802098410ca05d86b17a10bb5ab559b3fb404c1f948220" [[package]] name = "guillotiere" @@ -2845,10 +2818,10 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9da2e5ae821f6e96664977bf974d6d6a2d6682f9ccee23e62ec1d134246845f9" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "bytemuck", "core_maths", - "read-fonts 0.37.0", + "read-fonts", "smallvec", ] @@ -2873,16 +2846,14 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ - "allocator-api2", - "equivalent", "foldhash 0.2.0", ] [[package]] name = "hashbrown" -version = "0.17.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" [[package]] name = "heck" @@ -2908,17 +2879,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hex_color" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d37f101bf4c633f7ca2e4b5e136050314503dd198e78e325ea602c327c484ef0" -dependencies = [ - "arrayvec", - "rand 0.8.6", - "serde", -] - [[package]] name = "hexf-parse" version = "0.2.1" @@ -2927,20 +2887,11 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" [[package]] name = "hmac" -version = "0.13.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.11.3", -] - -[[package]] -name = "hybrid-array" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" -dependencies = [ - "typenum", + "digest", ] [[package]] @@ -3037,6 +2988,7 @@ dependencies = [ [[package]] name = "iced" version = "0.14.0" +source = "git+https://github.com/pop-os/libcosmic.git#c423ad1bfc25057922406c687f2ddc75ead5ab67" dependencies = [ "dnd", "iced_accessibility", @@ -3057,6 +3009,7 @@ dependencies = [ [[package]] name = "iced_accessibility" version = "0.1.0" +source = "git+https://github.com/pop-os/libcosmic.git#c423ad1bfc25057922406c687f2ddc75ead5ab67" dependencies = [ "accesskit", "accesskit_winit", @@ -3065,10 +3018,11 @@ dependencies = [ [[package]] name = "iced_core" version = "0.14.0" +source = "git+https://github.com/pop-os/libcosmic.git#c423ad1bfc25057922406c687f2ddc75ead5ab67" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "bytes", - "cosmic-client-toolkit 0.2.0", + "cosmic-client-toolkit", "dnd", "glam", "lilt", @@ -3081,7 +3035,6 @@ dependencies = [ "serde", "smol_str", "thiserror 2.0.18", - "unicode-segmentation", "web-time", "window_clipboard", ] @@ -3089,6 +3042,7 @@ dependencies = [ [[package]] name = "iced_debug" version = "0.14.0" +source = "git+https://github.com/pop-os/libcosmic.git#c423ad1bfc25057922406c687f2ddc75ead5ab67" dependencies = [ "iced_core", "iced_futures", @@ -3098,6 +3052,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.14.0" +source = "git+https://github.com/pop-os/libcosmic.git#c423ad1bfc25057922406c687f2ddc75ead5ab67" dependencies = [ "futures", "iced_core", @@ -3111,8 +3066,9 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.14.0" +source = "git+https://github.com/pop-os/libcosmic.git#c423ad1bfc25057922406c687f2ddc75ead5ab67" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "bytemuck", "cosmic-text", "half", @@ -3131,6 +3087,7 @@ dependencies = [ [[package]] name = "iced_program" version = "0.14.0" +source = "git+https://github.com/pop-os/libcosmic.git#c423ad1bfc25057922406c687f2ddc75ead5ab67" dependencies = [ "iced_graphics", "iced_runtime", @@ -3139,6 +3096,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.14.0" +source = "git+https://github.com/pop-os/libcosmic.git#c423ad1bfc25057922406c687f2ddc75ead5ab67" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -3150,9 +3108,10 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.14.0" +source = "git+https://github.com/pop-os/libcosmic.git#c423ad1bfc25057922406c687f2ddc75ead5ab67" dependencies = [ "bytes", - "cosmic-client-toolkit 0.2.0", + "cosmic-client-toolkit", "dnd", "iced_core", "iced_futures", @@ -3164,6 +3123,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.14.0" +source = "git+https://github.com/pop-os/libcosmic.git#c423ad1bfc25057922406c687f2ddc75ead5ab67" dependencies = [ "bytemuck", "cosmic-text", @@ -3180,10 +3140,12 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.14.0" +source = "git+https://github.com/pop-os/libcosmic.git#c423ad1bfc25057922406c687f2ddc75ead5ab67" dependencies = [ - "bitflags 2.13.0", + "as-raw-xcb-connection", + "bitflags 2.11.1", "bytemuck", - "cosmic-client-toolkit 0.2.0", + "cosmic-client-toolkit", "cryoglyph", "futures", "glam", @@ -3197,18 +3159,21 @@ dependencies = [ "rustc-hash 2.1.2", "rustix 0.38.44", "thiserror 2.0.18", + "tiny-xlib", "wayland-backend", "wayland-client", "wayland-protocols", "wayland-sys", "wgpu", + "x11rb", ] [[package]] name = "iced_widget" version = "0.14.2" +source = "git+https://github.com/pop-os/libcosmic.git#c423ad1bfc25057922406c687f2ddc75ead5ab67" dependencies = [ - "cosmic-client-toolkit 0.2.0", + "cosmic-client-toolkit", "dnd", "iced_renderer", "iced_runtime", @@ -3224,8 +3189,9 @@ dependencies = [ [[package]] name = "iced_winit" version = "0.14.0" +source = "git+https://github.com/pop-os/libcosmic.git#c423ad1bfc25057922406c687f2ddc75ead5ab67" dependencies = [ - "cosmic-client-toolkit 0.2.0", + "cosmic-client-toolkit", "cursor-icon", "dnd", "iced_debug", @@ -3324,9 +3290,9 @@ checksum = "846b0857ca091204be3c874bc93daaf89d4777e8d2d20b0d3ffe8f671d98014b" [[package]] name = "icu_collator" -version = "2.2.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bbdf98e5e0aa827770acee171ebb568aaab975a36b56afdb5fd0e2f525750bb" +checksum = "b521b92a2666061ddda902769d8a4cf730b5c9529a845cc1b69770b12a6c9a71" dependencies = [ "icu_collator_data", "icu_collections", @@ -3651,6 +3617,12 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f2f8aeca682d874a5247084aa4fb7d1cef9ba45d889c21209a8818dcaaa0ec9" +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "ident_case" version = "1.0.1" @@ -3670,9 +3642,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.2" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -3680,9 +3652,9 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.26" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b915661dd01db3f05050265b2477bcc6527b3792388e2749b41623cc592be67d" +checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" dependencies = [ "crossbeam-deque", "globset", @@ -3720,9 +3692,9 @@ dependencies = [ [[package]] name = "image-extras" -version = "0.1.1" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60d02eb2c9ccbbab470538fce34c7bc3be7b4e59268e65a3171367b296cdb842" +checksum = "86d29ba92ef6970a2685cc758b455d190842b8b9e96c865ffd31cdb9954b7548" dependencies = [ "image", ] @@ -3745,9 +3717,9 @@ checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" [[package]] name = "imgref" -version = "1.12.2" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89194689a993ab15268672e99e7b0e19da2da3268ac682e8f02d29d4d1434cd7" +checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8" [[package]] name = "indexmap" @@ -3767,7 +3739,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.17.1", + "hashbrown 0.17.0", "serde", "serde_core", ] @@ -3783,11 +3755,11 @@ dependencies = [ [[package]] name = "inotify" -version = "0.11.2" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533e68a5842e734946fe159fb03fc9bbbb254f590dd0d8ad321ae5ff7beca2c1" +checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "inotify-sys", "libc", ] @@ -3803,11 +3775,11 @@ dependencies = [ [[package]] name = "inout" -version = "0.2.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ - "hybrid-array", + "generic-array", ] [[package]] @@ -3842,11 +3814,11 @@ dependencies = [ [[package]] name = "io-uring" -version = "0.7.13" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9080b15e63775b9a2ac7dca720f7050a8b955e092ea0f6020a4a80f69998cdc0" +checksum = "fdd7bddefd0a8833b88a4b68f90dae22c7450d11b354198baee3874fd811b344" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "cfg-if", "libc", ] @@ -3910,18 +3882,17 @@ checksum = "2ceaf4c6c48465bead8cb6a0b7c4ee0c86ecbb31239032b9c66ab9a08d2f3ee1" [[package]] name = "jiff" -version = "0.2.31" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccfe6121cbe750cf81efa362d85c0bde7ea298ec43092d3a193baca59cdbd634" +checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" dependencies = [ - "defmt", "jiff-static", "jiff-tzdb-platform", "log", "portable-atomic", "portable-atomic-util", "serde_core", - "windows-link 0.2.1", + "windows-sys 0.61.2", ] [[package]] @@ -3937,9 +3908,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.31" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e165e897f662d428f3cd3828a919dbe067c2d42bb1031eede74ef9d27ecdedd2" +checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" dependencies = [ "proc-macro2", "quote", @@ -4031,12 +4002,13 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.103" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" dependencies = [ "cfg-if", "futures-util", + "once_cell", "wasm-bindgen", ] @@ -4093,9 +4065,9 @@ dependencies = [ [[package]] name = "jxl-grid" -version = "0.6.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01671307879a033bfa52e6e8784b941aca770b3f3a7d33830b455b6844f793fb" +checksum = "a0e0ef92d5d60e76bf41098e57e985f523185e08fad54268da448637feca6989" dependencies = [ "tracing", ] @@ -4132,9 +4104,9 @@ dependencies = [ [[package]] name = "jxl-modular" -version = "0.11.3" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2f045b24c738dd91d482be385512b512721ae08a671bd4b27bf1c47f215235" +checksum = "da758b2f989aafd9eeb39489fe43d7be5a3a0d2ad61cf1bad705eb6990a6053c" dependencies = [ "jxl-bitstream", "jxl-coding", @@ -4146,9 +4118,9 @@ dependencies = [ [[package]] name = "jxl-oxide" -version = "0.12.6" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d36c662923f47586880211f3bc7c0d83fb3a9b410d278c7bde93450748abeef3" +checksum = "ee8ecd2678ed70c1eda42b811ccb2e25ab836edeb18e7f1178c1f917ed36b772" dependencies = [ "brotli-decompressor", "bytemuck", @@ -4176,9 +4148,9 @@ dependencies = [ [[package]] name = "jxl-render" -version = "0.12.4" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34386bfdb6a19b5a30cc9beb4d475d537422c31ae8c39bb69640fcce3fcaf19" +checksum = "aa0c3100918bd3c41bb0f8ce1f4f1664e48f3032ff8eeab0d6a2cfc3276f462d" dependencies = [ "bytemuck", "jxl-bitstream", @@ -4235,7 +4207,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fbe853b403ae61a04233030ae8a79d94975281ed9770a1f9e246732b534b28d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "serde", ] @@ -4267,9 +4239,9 @@ dependencies = [ [[package]] name = "kqueue" -version = "1.2.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "273c0752728918e0ac4976f2b275b6fefb9ecd400585dec929419f3844cd87b5" +checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" dependencies = [ "kqueue-sys", "libc", @@ -4277,11 +4249,11 @@ dependencies = [ [[package]] name = "kqueue-sys" -version = "1.1.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07293a4e297ac234359b510362495713f75ea345d5307140414f20c69ffeb087" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" dependencies = [ - "bitflags 2.13.0", + "bitflags 1.3.2", "libc", ] @@ -4312,6 +4284,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "lebe" version = "0.5.3" @@ -4320,24 +4298,25 @@ checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] name = "libbz2-rs-sys" -version = "0.2.5" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34b357333733e8260735ba5894eb928c02ecc69c78715f01a8019e7fa7f2db4c" +checksum = "b3a6a8c165077efc8f3a971534c50ea6a1a18b329ef4a66e897a7e3a1494565f" [[package]] name = "libc" -version = "0.2.186" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] -name = "libcosmic-yoda" -version = "0.1.0-yoda.2" +name = "libcosmic" +version = "1.0.0" +source = "git+https://github.com/pop-os/libcosmic.git#c423ad1bfc25057922406c687f2ddc75ead5ab67" dependencies = [ "apply", "ashpd 0.12.3", "auto_enums", - "cosmic-client-toolkit 0.2.0", + "cosmic-client-toolkit", "cosmic-config", "cosmic-freedesktop-icons", "cosmic-settings-config", @@ -4345,7 +4324,6 @@ dependencies = [ "cosmic-theme", "css-color", "derive_setters", - "enumflags2", "float-cmp 0.10.0", "freedesktop-desktop-entry", "futures", @@ -4372,7 +4350,7 @@ dependencies = [ "rust-embed", "rustix 1.1.4", "serde", - "shlex 1.3.0", + "shlex", "slotmap", "taffy", "thiserror 2.0.18", @@ -4380,14 +4358,14 @@ dependencies = [ "tracing", "unicode-segmentation", "url", - "zbus 5.16.0", + "zbus 5.14.0", ] [[package]] name = "libfuzzer-sys" -version = "0.4.13" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9fd2f41a1cba099f79a0b6b6c35656cf7c03351a7bae8ff0f28f25270f929d2" +checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d" dependencies = [ "arbitrary", "cc", @@ -4411,14 +4389,14 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.17" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "libc", "plain", - "redox_syscall 0.8.1", + "redox_syscall 0.7.4", ] [[package]] @@ -4442,6 +4420,12 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "linux-raw-sys" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7" + [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -4484,9 +4468,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.33" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "loom" @@ -4529,9 +4513,9 @@ dependencies = [ [[package]] name = "lyon_algorithms" -version = "1.0.20" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8575c0d003ae459399623c4def180c63b77f343b1a7fee64f249b349e7699a31" +checksum = "9815fac08e6fd96733a11dce4f9d15a3f338e96a2e2311ee21e1b738efc2bc0f" dependencies = [ "lyon_path", "num-traits", @@ -4571,25 +4555,23 @@ dependencies = [ [[package]] name = "lzma-rust2" -version = "0.16.4" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce716bf1a316f47a280fc76295f6495b5bea4752bca01c3b3885e101b1c23c02" +checksum = "47bb1e988e6fb779cf720ad431242d3f03167c1b3f2b1aae7f1a94b2495b36ae" dependencies = [ - "sha2 0.11.0", + "sha2", ] [[package]] name = "mac-notification-sys" -version = "0.6.15" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd604973958ddcc11b561193c0fb96ba146506ef2f231ef2e7c35fd2cbc9beca" +checksum = "29a16783dd1a47849b8c8133c9cd3eb2112cfbc6901670af3dba47c8bbfb07d3" dependencies = [ "cc", - "log", "objc2 0.6.4", "objc2-foundation 0.3.2", "time", - "uuid", ] [[package]] @@ -4627,14 +4609,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest 0.10.7", + "digest", ] [[package]] name = "memchr" -version = "2.8.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memmap2" @@ -4647,9 +4629,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.9.11" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" dependencies = [ "libc", ] @@ -4665,11 +4647,11 @@ dependencies = [ [[package]] name = "metal" -version = "0.33.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7047791b5bc903b8cd963014b355f71dc9864a9a0b727057676c1dcae5cbc15" +checksum = "00c15a6f673ff72ddcc22394663290f870fb224c1bfce55734a75c414150e605" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "block", "core-graphics-types 0.2.0", "foreign-types", @@ -4681,6 +4663,7 @@ dependencies = [ [[package]] name = "mime" version = "0.1.0" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#f68595ee0e62fbd6589f4709b5aaa5c3c7ea5f6c" dependencies = [ "smithay-clipboard", ] @@ -4719,9 +4702,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", "log", @@ -4747,13 +4730,13 @@ checksum = "13d2233c9842d08cfe13f9eac96e207ca6a2ea10b80259ebe8ad0268be27d2af" [[package]] name = "naga" -version = "28.0.0" +version = "27.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "618f667225063219ddfc61251087db8a9aec3c3f0950c916b614e403486f1135" +checksum = "066cf25f0e8b11ee0df221219010f213ad429855f57c494f995590c861a9a7d8" dependencies = [ "arrayvec", "bit-set", - "bitflags 2.13.0", + "bitflags 2.11.1", "cfg-if", "cfg_aliases", "codespan-reporting", @@ -4777,7 +4760,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "jni-sys 0.3.1", "log", "ndk-sys", @@ -4813,7 +4796,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "cfg-if", "cfg_aliases", "libc", @@ -4822,9 +4805,9 @@ dependencies = [ [[package]] name = "no_std_io2" -version = "0.9.4" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418abd1b6d34fbf6cae440dc874771b0525a604428704c76e48b29a5e67b8003" +checksum = "b51ed7824b6e07d354605f4abb3d9d300350701299da96642ee084f5ce631550" dependencies = [ "memchr", ] @@ -4860,7 +4843,7 @@ version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "fsevent-sys", "inotify", "kqueue", @@ -4887,16 +4870,16 @@ dependencies = [ [[package]] name = "notify-rust" -version = "4.18.0" +version = "4.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b4c1b4f2aa9f25f63a7a49d3dd0ed567b3670da15330a66b29434be899b891" +checksum = "3c8146c105ae33d744e2d645f684d063b01176a99daf5986556266777b428816" dependencies = [ "futures-lite", "log", "mac-notification-sys", "serde", "tauri-winrt-notification", - "zbus 5.16.0", + "zbus 5.14.0", ] [[package]] @@ -4905,7 +4888,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", ] [[package]] @@ -4929,9 +4912,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.2.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" [[package]] name = "num-derive" @@ -5057,7 +5040,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -5073,7 +5056,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "block2 0.6.2", "objc2 0.6.4", "objc2-core-foundation", @@ -5086,7 +5069,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -5098,7 +5081,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "block2 0.6.2", "dispatch2", "objc2 0.6.4", @@ -5110,7 +5093,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "libc", "objc2-core-foundation", ] @@ -5133,7 +5116,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "objc2-core-foundation", "objc2-core-graphics", ] @@ -5150,7 +5133,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -5162,7 +5145,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "block2 0.6.2", "libc", "objc2 0.6.4", @@ -5175,7 +5158,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -5187,7 +5170,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -5200,7 +5183,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "objc2 0.6.4", "objc2-core-foundation", "objc2-foundation 0.3.2", @@ -5229,12 +5212,13 @@ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "open" -version = "5.3.6" +version = "5.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d3b65c44123a56e0133d2cd06ce4361bd3ca99d41198b2f25e3c3db9b8b4a" +checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc" dependencies = [ "is-wsl", "libc", + "pathdiff", ] [[package]] @@ -5245,9 +5229,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "orbclient" -version = "0.3.55" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5df339f526ea9a60e371768d50efc2f2508c7203290731565d1f7a6f71d21747" +checksum = "59aed3b33578edcfa1bc96a321d590d31832b6ad55a26f0313362ce687e9abd6" dependencies = [ "libc", "libredox", @@ -5393,12 +5377,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" [[package]] -name = "pbkdf2" -version = "0.13.0" +name = "pathdiff" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112d82ceb8c5bf524d9af484d4e4970c9fd5a0cc15ba14ad93dccd28873b0629" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ - "digest 0.11.3", + "digest", "hmac", ] @@ -5503,18 +5493,18 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pin-project" -version = "1.1.13" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.13" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" dependencies = [ "proc-macro2", "quote", @@ -5575,7 +5565,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "crc32fast", "fdeflate", "flate2", @@ -5655,6 +5645,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro-crate" version = "3.5.0" @@ -5714,7 +5714,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25485360a54d6861439d60facef26de713b1e126bf015ec8f98239467a2b82f7" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "chrono", "flate2", "procfs-core", @@ -5727,25 +5727,25 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6401bf7b6af22f78b563665d15a22e9aef27775b79b149a66ca022468a4e405" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "chrono", "hex", ] [[package]] name = "profiling" -version = "1.0.18" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" dependencies = [ "profiling-procmacros", ] [[package]] name = "profiling-procmacros" -version = "1.0.18" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4488a4a36b9a4ba6b9334a32a39971f77c1436ec82c38707bce707699cc3bbcb" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" dependencies = [ "quote", "syn", @@ -5796,25 +5796,25 @@ name = "quick-xml" version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" -dependencies = [ - "memchr", -] - -[[package]] -name = "quick-xml" -version = "0.39.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" dependencies = [ "memchr", "serde", ] [[package]] -name = "quote" -version = "1.0.46" +name = "quick-xml" +version = "0.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -5989,16 +5989,6 @@ dependencies = [ "font-types", ] -[[package]] -name = "read-fonts" -version = "0.39.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4ed38b89c2c77ff968c524145ad65fb010f38af5c7a224b53b81d47ac2daa81" -dependencies = [ - "bytemuck", - "font-types", -] - [[package]] name = "recently-used-xbel" version = "1.2.0" @@ -6015,32 +6005,22 @@ dependencies = [ "url", ] -[[package]] -name = "redox_event" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c07d0d6d291e3a951bd847b1cd4af32fc6243d64116cf7702838c02797688b7" -dependencies = [ - "bitflags 2.13.0", - "libredox", -] - [[package]] name = "redox_syscall" version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", ] [[package]] name = "redox_syscall" -version = "0.8.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b44b894f2a6e36457d665d1e08c3866add6ed5e70050c1b4ba8a8ddedb02ce7" +checksum = "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", ] [[package]] @@ -6087,9 +6067,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.4" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -6110,9 +6090,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.11" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "renderdoc-sys" @@ -6177,7 +6157,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db09040cc89e461f1a265139777a2bde7f8d8c67c4936f700c63ce3e2904d468" dependencies = [ "base64", - "bitflags 2.13.0", + "bitflags 2.11.1", "serde", "serde_derive", "unicode-ident", @@ -6185,11 +6165,11 @@ dependencies = [ [[package]] name = "ron" -version = "0.12.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81116b9531d61eabc41aeb228e4b6b2435bcca3233b98cf3b3077d4e6e9debb3" +checksum = "4147b952f3f819eca0e99527022f7d6a8d05f111aeb0a62960c74eb283bec8fc" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "once_cell", "serde", "serde_derive", @@ -6233,7 +6213,7 @@ version = "8.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1" dependencies = [ - "sha2 0.10.9", + "sha2", "walkdir", ] @@ -6264,7 +6244,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "errno", "libc", "linux-raw-sys 0.4.15", @@ -6277,7 +6257,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "errno", "libc", "linux-raw-sys 0.12.1", @@ -6296,7 +6276,7 @@ version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "bytemuck", "core_maths", "log", @@ -6361,7 +6341,7 @@ checksum = "1dd3accc0f3f4bbaf2c9e1957a030dc582028130c67660d44c0a0345a22ca69b" dependencies = [ "ab_glyph", "log", - "memmap2 0.9.11", + "memmap2 0.9.10", "smithay-client-toolkit", "tiny-skia", ] @@ -6410,9 +6390,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.150" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "indexmap 2.14.0", "itoa", @@ -6444,12 +6424,11 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.21.0" +version = "3.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" +checksum = "dd5414fad8e6907dbdd5bc441a50ae8d6e26151a03b1de04d89a5576de61d01f" dependencies = [ "base64", - "bs58", "chrono", "hex", "indexmap 1.9.3", @@ -6464,9 +6443,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.21.0" +version = "3.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" +checksum = "d3db8978e608f1fe7357e211969fd9abdcae80bac1ba7a3369bb7eb6b404eb65" dependencies = [ "darling 0.23.0", "proc-macro2", @@ -6481,19 +6460,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures 0.2.17", - "digest 0.10.7", -] - -[[package]] -name = "sha1" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "digest 0.11.3", + "cpufeatures", + "digest", ] [[package]] @@ -6503,19 +6471,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures 0.2.17", - "digest 0.10.7", -] - -[[package]] -name = "sha2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "digest 0.11.3", + "cpufeatures", + "digest", ] [[package]] @@ -6533,12 +6490,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "shlex" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" - [[package]] name = "signal-hook-registry" version = "1.4.8" @@ -6591,9 +6542,9 @@ dependencies = [ [[package]] name = "siphasher" -version = "1.0.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "skrifa" @@ -6602,17 +6553,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fbdfe3d2475fbd7ddd1f3e5cf8288a30eb3e5f95832829570cd88115a7434ac" dependencies = [ "bytemuck", - "read-fonts 0.37.0", -] - -[[package]] -name = "skrifa" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c34617370ae968efb7161bb2beb517d9084659aae19e24b89e3db25b46e4564" -dependencies = [ - "bytemuck", - "read-fonts 0.39.2", + "read-fonts", ] [[package]] @@ -6632,9 +6573,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.15.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smithay-client-toolkit" @@ -6642,14 +6583,14 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "bytemuck", "calloop", "calloop-wayland-source", "cursor-icon", "libc", "log", - "memmap2 0.9.11", + "memmap2 0.9.10", "pkg-config", "rustix 1.1.4", "thiserror 2.0.18", @@ -6669,6 +6610,7 @@ dependencies = [ [[package]] name = "smithay-clipboard" version = "0.8.0" +source = "git+https://github.com/pop-os/smithay-clipboard?tag=sctk-0.20#859b02c88f45c554049a67c6ddeec1692ce0e20b" dependencies = [ "libc", "raw-window-handle", @@ -6688,9 +6630,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.4" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", "windows-sys 0.61.2", @@ -6699,26 +6641,31 @@ dependencies = [ [[package]] name = "softbuffer" version = "0.4.1" +source = "git+https://github.com/pop-os/softbuffer?tag=cosmic-4.0#a3f77e251e7422803f693df6e3fc313c010c4dcb" dependencies = [ + "as-raw-xcb-connection", "bytemuck", "cfg_aliases", "cocoa", "core-graphics", + "drm", "fastrand", "foreign-types", "js-sys", "log", - "memmap2 0.9.11", + "memmap2 0.9.10", "objc", "raw-window-handle", "redox_syscall 0.5.18", "rustix 0.38.44", + "tiny-xlib", "wasm-bindgen", "wayland-backend", "wayland-client", "wayland-sys", "web-sys", "windows-sys 0.52.0", + "x11rb", ] [[package]] @@ -6736,7 +6683,7 @@ version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", ] [[package]] @@ -6766,6 +6713,12 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "svg_fmt" version = "0.4.5" @@ -6784,20 +6737,20 @@ dependencies = [ [[package]] name = "swash" -version = "0.2.9" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0811b01ca2c4e8718760713911feaf4675c24f94e50530a015ec646cfb622f7c" +checksum = "842f3cd369c2ba38966204f983eaa5e54a8e84a7d7159ed36ade2b6c335aae64" dependencies = [ - "skrifa 0.42.1", + "skrifa", "yazi", "zeno", ] [[package]] name = "syn" -version = "2.0.118" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -6806,9 +6759,9 @@ dependencies = [ [[package]] name = "synchrony" -version = "0.1.8" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416090a4d8f6358526df5f9f65dfe28750b8b7bfd1fd8a5620f483fc4a75722c" +checksum = "c174d82fd56da8214ec095cfe4568e59e5ccb49d060e70c2f98e3ba352b23e45" dependencies = [ "futures-util", "loom", @@ -6861,9 +6814,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.46" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" +checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973" dependencies = [ "filetime", "libc", @@ -6872,9 +6825,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.13.5" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" +checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" [[package]] name = "tauri-winrt-notification" @@ -6901,7 +6854,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.4.3", + "getrandom 0.4.2", "once_cell", "rustix 1.1.4", "windows-sys 0.61.2", @@ -6918,9 +6871,9 @@ dependencies = [ [[package]] name = "test-log" -version = "0.2.21" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b9c218384242b5c89b68303ab6f6fc53a312d923f0c14dc6bb860c6aeee40f1" +checksum = "37d53ac171c92a39e4769491c4b4dde7022c60042254b5fc044ae409d34a24d4" dependencies = [ "env_logger", "test-log-macros", @@ -6928,26 +6881,16 @@ dependencies = [ ] [[package]] -name = "test-log-core" -version = "0.2.21" +name = "test-log-macros" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c26ef8b00e4d382e59f6a8ddb3cd790b3a5bb29f21a358a9a69ea2f29f13f27b" +checksum = "be35209fd0781c5401458ab66e4f98accf63553e8fae7425503e92fdd319783b" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "test-log-macros" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "944ad38adcbb71eaa682c56bceeb079e4ca82b4b3edc2a0fde5cb297b77dac8d" -dependencies = [ - "syn", - "test-log-core", -] - [[package]] name = "thin-cell" version = "0.1.2" @@ -7039,11 +6982,12 @@ dependencies = [ [[package]] name = "time" -version = "0.3.52" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e48db7b415311b615f910b3dcaa4557bcd4bf1982379c95c223fd8c2a20e210" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", + "itoa", "js-sys", "num-conv", "powerfmt", @@ -7054,15 +6998,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.9" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.31" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", @@ -7094,6 +7038,19 @@ dependencies = [ "strict-num", ] +[[package]] +name = "tiny-xlib" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0324504befd01cab6e0c994f34b2ffa257849ee019d3fb3b64fb2c858887d89e" +dependencies = [ + "as-raw-xcb-connection", + "ctor-lite", + "libloading", + "pkg-config", + "tracing", +] + [[package]] name = "tinystr" version = "0.8.3" @@ -7122,9 +7079,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.52.3" +version = "1.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" +checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" dependencies = [ "bytes", "libc", @@ -7180,7 +7137,7 @@ dependencies = [ "toml_datetime", "toml_parser", "toml_writer", - "winnow", + "winnow 1.0.1", ] [[package]] @@ -7194,14 +7151,14 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.12+spec-1.1.0" +version = "0.25.11+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" dependencies = [ "indexmap 2.14.0", "toml_datetime", "toml_parser", - "winnow", + "winnow 1.0.1", ] [[package]] @@ -7210,7 +7167,7 @@ version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "winnow", + "winnow 1.0.1", ] [[package]] @@ -7283,15 +7240,14 @@ dependencies = [ [[package]] name = "trash" -version = "5.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7602e0c7d66ec2d92a8c917219fbc7894039efa2063b9064260110828a356f46" +version = "5.2.2" +source = "git+https://github.com/jackpot51/trash-rs.git?branch=cosmic#a225f753a88e722aeeb27bb2fb00144739911035" dependencies = [ "chrono", "libc", "log", - "objc2 0.6.4", - "objc2-foundation 0.3.2", + "objc2 0.5.2", + "objc2-foundation 0.2.2", "once_cell", "percent-encoding", "scopeguard", @@ -7331,9 +7287,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.20.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "uds_windows" @@ -7424,9 +7380,9 @@ checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee" [[package]] name = "unicode-segmentation" -version = "1.13.3" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" [[package]] name = "unicode-vo" @@ -7440,6 +7396,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "url" version = "2.5.8" @@ -7506,11 +7468,10 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.23.4" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" +checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" dependencies = [ - "getrandom 0.4.3", "js-sys", "serde_core", "wasm-bindgen", @@ -7573,18 +7534,27 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.4+wasi-0.2.12" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.126" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" dependencies = [ "cfg-if", "once_cell", @@ -7595,9 +7565,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.76" +version = "0.4.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" +checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8" dependencies = [ "js-sys", "wasm-bindgen", @@ -7605,9 +7575,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.126" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7615,9 +7585,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.126" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" dependencies = [ "bumpalo", "proc-macro2", @@ -7628,13 +7598,47 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.126" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.14.0", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.1", + "hashbrown 0.15.5", + "indexmap 2.14.0", + "semver", +] + [[package]] name = "wasmtimer" version = "0.4.3" @@ -7669,7 +7673,7 @@ version = "0.31.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "rustix 1.1.4", "wayland-backend", "wayland-scanner", @@ -7681,7 +7685,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "cursor-icon", "wayland-backend", ] @@ -7699,11 +7703,11 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.32.13" +version = "0.32.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6" +checksum = "563a85523cade2429938e790815fd7319062103b9f4a2dc806e9b53b95982d8f" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "wayland-backend", "wayland-client", "wayland-scanner", @@ -7716,7 +7720,7 @@ version = "20250721.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40a1f863128dcaaec790d7b4b396cc9b9a7a079e878e18c47e6c2d2c5a8dcbb1" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -7729,7 +7733,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e9567599ef23e09b8dad6e429e5738d4509dfc46b3b21f32841a304d16b29c8" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -7742,7 +7746,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b6d8cf1eb2c1c31ed1f5643c88a6e53538129d4af80030c8cabd1f9fa884d91" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -7755,7 +7759,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -7770,7 +7774,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a" dependencies = [ "proc-macro2", - "quick-xml 0.39.4", + "quick-xml 0.39.2", "quote", ] @@ -7780,7 +7784,7 @@ version = "0.31.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc1846eb04c49182e04f4a099e2a830a2b745610bbc1d61246e206f29c7000a0" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "downcast-rs", "rustix 1.1.4", "wayland-backend", @@ -7801,9 +7805,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.103" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" +checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d" dependencies = [ "js-sys", "wasm-bindgen", @@ -7827,13 +7831,12 @@ checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" [[package]] name = "wgpu" -version = "28.0.0" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cb534d5ffd109c7d1135f34cdae29e60eab94855a625dcfe1705f8bc7ad79f" +checksum = "bfe68bac7cde125de7a731c3400723cadaaf1703795ad3f4805f187459cd7a77" dependencies = [ "arrayvec", - "bitflags 2.13.0", - "bytemuck", + "bitflags 2.11.1", "cfg-if", "cfg_aliases", "document-features", @@ -7857,14 +7860,14 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "28.0.1" +version = "27.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23f4642f53f666adcfd2d3218ab174d1e6681101aef18696b90cbe64d1c10f9" +checksum = "27a75de515543b1897b26119f93731b385a19aea165a1ec5f0e3acecc229cae7" dependencies = [ "arrayvec", "bit-set", "bit-vec", - "bitflags 2.13.0", + "bitflags 2.11.1", "bytemuck", "cfg_aliases", "document-features", @@ -7889,42 +7892,42 @@ dependencies = [ [[package]] name = "wgpu-core-deps-apple" -version = "28.0.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87b7b696b918f337c486bf93142454080a32a37832ba8a31e4f48221890047da" +checksum = "0772ae958e9be0c729561d5e3fd9a19679bcdfb945b8b1a1969d9bfe8056d233" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-emscripten" -version = "28.0.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34b251c331f84feac147de3c4aa3aa45112622a95dd7ee1b74384fa0458dbd79" +checksum = "b06ac3444a95b0813ecfd81ddb2774b66220b264b3e2031152a4a29fda4da6b5" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-windows-linux-android" -version = "28.0.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ca976e72b2c9964eb243e281f6ce7f14a514e409920920dcda12ae40febaae" +checksum = "71197027d61a71748e4120f05a9242b2ad142e3c01f8c1b47707945a879a03c3" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-hal" -version = "28.0.1" +version = "27.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d6cb474beb218824dcc9e1ce679d973f719262789bfb27407da560cac20eeb" +checksum = "5b21cb61c57ee198bc4aff71aeadff4cbb80b927beb912506af9c780d64313ce" dependencies = [ "android_system_properties", "arrayvec", "ash", "bit-set", - "bitflags 2.13.0", + "bitflags 2.11.1", "block", "bytemuck", "cfg-if", @@ -7932,6 +7935,7 @@ dependencies = [ "core-graphics-types 0.2.0", "glow", "glutin_wgl_sys", + "gpu-alloc", "gpu-allocator", "gpu-descriptor", "hashbrown 0.16.1", @@ -7958,20 +7962,21 @@ dependencies = [ "wasm-bindgen", "web-sys", "wgpu-types", - "windows 0.62.2", - "windows-core 0.62.2", + "windows 0.58.0", + "windows-core 0.58.0", ] [[package]] name = "wgpu-types" -version = "28.0.0" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e18308757e594ed2cd27dddbb16a139c42a683819d32a2e0b1b0167552f5840c" +checksum = "afdcf84c395990db737f2dd91628706cb31e86d72e53482320d368e52b5da5eb" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "bytemuck", "js-sys", "log", + "thiserror 2.0.18", "web-sys", ] @@ -8015,10 +8020,12 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "window_clipboard" version = "0.4.1" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#f68595ee0e62fbd6589f4709b5aaa5c3c7ea5f6c" dependencies = [ "clipboard-win", "clipboard_macos", "clipboard_wayland", + "clipboard_x11", "dnd", "mime 0.1.0", "raw-window-handle", @@ -8037,27 +8044,25 @@ dependencies = [ [[package]] name = "windows" -version = "0.61.3" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ - "windows-collections 0.2.0", - "windows-core 0.61.2", - "windows-future 0.2.1", - "windows-link 0.1.3", - "windows-numerics 0.2.0", + "windows-core 0.58.0", + "windows-targets 0.52.6", ] [[package]] name = "windows" -version = "0.62.2" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ - "windows-collections 0.3.2", - "windows-core 0.62.2", - "windows-future 0.3.2", - "windows-numerics 0.3.1", + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", ] [[package]] @@ -8069,15 +8074,6 @@ dependencies = [ "windows-core 0.61.2", ] -[[package]] -name = "windows-collections" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" -dependencies = [ - "windows-core 0.62.2", -] - [[package]] name = "windows-core" version = "0.56.0" @@ -8090,6 +8086,19 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows-core" version = "0.61.2" @@ -8124,18 +8133,7 @@ checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ "windows-core 0.61.2", "windows-link 0.1.3", - "windows-threading 0.1.0", -] - -[[package]] -name = "windows-future" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" -dependencies = [ - "windows-core 0.62.2", - "windows-link 0.2.1", - "windows-threading 0.2.1", + "windows-threading", ] [[package]] @@ -8149,6 +8147,17 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-implement" version = "0.60.2" @@ -8171,6 +8180,17 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-interface" version = "0.59.3" @@ -8204,16 +8224,6 @@ dependencies = [ "windows-link 0.1.3", ] -[[package]] -name = "windows-numerics" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" -dependencies = [ - "windows-core 0.62.2", - "windows-link 0.2.1", -] - [[package]] name = "windows-result" version = "0.1.2" @@ -8223,6 +8233,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-result" version = "0.3.4" @@ -8241,6 +8260,16 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result 0.2.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows-strings" version = "0.4.2" @@ -8361,15 +8390,6 @@ dependencies = [ "windows-link 0.1.3", ] -[[package]] -name = "windows-threading" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" -dependencies = [ - "windows-link 0.2.1", -] - [[package]] name = "windows-version" version = "0.1.7" @@ -8520,8 +8540,9 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winit" version = "0.31.0-beta.2" +source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "cfg_aliases", "cursor-icon", "dpi", @@ -8539,14 +8560,16 @@ dependencies = [ "winit-wayland", "winit-web", "winit-win32", + "winit-x11", ] [[package]] name = "winit-android" version = "0.31.0-beta.2" +source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ "android-activity", - "bitflags 2.13.0", + "bitflags 2.11.1", "dpi", "ndk", "raw-window-handle", @@ -8558,8 +8581,9 @@ dependencies = [ [[package]] name = "winit-appkit" version = "0.31.0-beta.2" +source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "block2 0.6.2", "dispatch2", "dpi", @@ -8579,21 +8603,24 @@ dependencies = [ [[package]] name = "winit-common" version = "0.31.0-beta.2" +source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ - "memmap2 0.9.11", + "memmap2 0.9.10", "objc2 0.6.4", "objc2-core-foundation", "smol_str", "tracing", "winit-core", + "x11-dl", "xkbcommon-dl", ] [[package]] name = "winit-core" version = "0.31.0-beta.2" +source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "cursor-icon", "dpi", "keyboard-types", @@ -8605,13 +8632,14 @@ dependencies = [ [[package]] name = "winit-orbital" version = "0.31.0-beta.2" +source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "dpi", "libredox", "orbclient", "raw-window-handle", - "redox_event", + "redox_syscall 0.7.4", "smol_str", "tracing", "winit-core", @@ -8620,8 +8648,9 @@ dependencies = [ [[package]] name = "winit-uikit" version = "0.31.0-beta.2" +source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "block2 0.6.2", "dispatch2", "dpi", @@ -8639,14 +8668,15 @@ dependencies = [ [[package]] name = "winit-wayland" version = "0.31.0-beta.2" +source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ "ahash", - "bitflags 2.13.0", + "bitflags 2.11.1", "calloop", "cursor-icon", "dpi", "libc", - "memmap2 0.9.11", + "memmap2 0.9.10", "raw-window-handle", "rustix 1.1.4", "sctk-adwaita", @@ -8664,9 +8694,10 @@ dependencies = [ [[package]] name = "winit-web" version = "0.31.0-beta.2" +source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ "atomic-waker", - "bitflags 2.13.0", + "bitflags 2.11.1", "concurrent-queue", "cursor-icon", "dpi", @@ -8685,8 +8716,9 @@ dependencies = [ [[package]] name = "winit-win32" version = "0.31.0-beta.2" +source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "cursor-icon", "dpi", "raw-window-handle", @@ -8697,20 +8729,134 @@ dependencies = [ "winit-core", ] +[[package]] +name = "winit-x11" +version = "0.31.0-beta.2" +source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" +dependencies = [ + "bitflags 2.11.1", + "bytemuck", + "calloop", + "cursor-icon", + "dpi", + "libc", + "percent-encoding", + "raw-window-handle", + "rustix 1.1.4", + "smol_str", + "tracing", + "winit-common", + "winit-core", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + [[package]] name = "winnow" -version = "1.0.3" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen" -version = "0.57.1" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck 0.5.0", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap 2.14.0", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.1", + "indexmap 2.14.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.14.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "write16" @@ -8727,6 +8873,39 @@ dependencies = [ "either", ] +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" +dependencies = [ + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading", + "once_cell", + "rustix 1.1.4", + "x11rb-protocol", + "xcursor", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" + [[package]] name = "xattr" version = "1.6.1" @@ -8801,7 +8980,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d66ca9352cbd4eecbbc40871d8a11b4ac8107cfc528a6e14d7c19c69d0e1ac9" dependencies = [ "libc", - "memmap2 0.9.11", + "memmap2 0.9.10", "xkeysym", ] @@ -8812,7 +8991,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a974f48060a14e95705c01f24ad9c3345022f4d97441b8a36beb7ed5c4a02d" dependencies = [ "libc", - "memmap2 0.9.11", + "memmap2 0.9.10", "xkeysym", ] @@ -8822,7 +9001,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.11.1", "dlib", "log", "once_cell", @@ -8840,9 +9019,9 @@ dependencies = [ [[package]] name = "xml" -version = "1.3.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "636f85e5ca6488e96401b61eb7de54f4e44755c988af0f52cf90230c312a1a89" +checksum = "b8aa498d22c9bbaf482329839bc5620c46be275a19a812e9a22a2b07529a642a" [[package]] name = "xml-rs" @@ -8885,9 +9064,9 @@ checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5" [[package]] name = "yoke" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -8933,7 +9112,7 @@ dependencies = [ "rand 0.8.6", "serde", "serde_repr", - "sha1 0.10.6", + "sha1", "static_assertions", "tracing", "uds_windows", @@ -8946,9 +9125,9 @@ dependencies = [ [[package]] name = "zbus" -version = "5.16.0" +version = "5.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee682d202a77e4a9f3b2c2bdf48a7b28af5c08c34ddf66f98c93e5e39464285" +checksum = "ca82f95dbd3943a40a53cfded6c2d0a2ca26192011846a1810c4256ef92c60bc" dependencies = [ "async-broadcast", "async-executor", @@ -8974,10 +9153,10 @@ dependencies = [ "uds_windows", "uuid", "windows-sys 0.61.2", - "winnow", - "zbus_macros 5.16.0", - "zbus_names 4.3.2", - "zvariant 5.12.0", + "winnow 0.7.15", + "zbus_macros 5.14.0", + "zbus_names 4.3.1", + "zvariant 5.10.0", ] [[package]] @@ -8987,7 +9166,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6998de05217a084b7578728a9443d04ea4cd80f2a0839b8d78770b76ccd45863" dependencies = [ "zbus_xml", - "zvariant 5.12.0", + "zvariant 5.10.0", ] [[package]] @@ -9001,7 +9180,7 @@ dependencies = [ "syn", "zbus-lockstep", "zbus_xml", - "zvariant 5.12.0", + "zvariant 5.10.0", ] [[package]] @@ -9019,17 +9198,17 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "5.16.0" +version = "5.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adf1bd45a81a103745b1757754762a26e8cd01e4532e4d6c8ec431624b80d1d6" +checksum = "897e79616e84aac4b2c46e9132a4f63b93105d54fe8c0e8f6bffc21fa8d49222" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", "syn", - "zbus_names 4.3.2", - "zvariant 5.12.0", - "zvariant_utils 3.4.0", + "zbus_names 4.3.1", + "zvariant 5.10.0", + "zvariant_utils 3.3.0", ] [[package]] @@ -9045,25 +9224,25 @@ dependencies = [ [[package]] name = "zbus_names" -version = "4.3.2" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7074f3e50b894eac91750142016d30d0a89be8e67dbfd9704fb875825760e52d" +checksum = "ffd8af6d5b78619bab301ff3c560a5bd22426150253db278f164d6cf3b72c50f" dependencies = [ "serde", - "winnow", - "zvariant 5.12.0", + "winnow 0.7.15", + "zvariant 5.10.0", ] [[package]] name = "zbus_xml" -version = "5.1.1" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8067892e940ed1727dea64690378601603b31d62dfde019a5335fbb7c0e0ed9" +checksum = "441a0064125265655bccc3a6af6bef56814d9277ac83fce48b1cd7e160b80eac" dependencies = [ - "quick-xml 0.39.4", + "quick-xml 0.38.4", "serde", - "zbus_names 4.3.2", - "zvariant 5.12.0", + "zbus_names 4.3.1", + "zvariant 5.10.0", ] [[package]] @@ -9074,18 +9253,18 @@ checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" [[package]] name = "zerocopy" -version = "0.8.52" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.52" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", @@ -9094,9 +9273,9 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.8" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" dependencies = [ "zerofrom-derive", ] @@ -9115,9 +9294,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.9.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" @@ -9156,9 +9335,9 @@ dependencies = [ [[package]] name = "zip" -version = "8.6.0" +version = "8.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" +checksum = "dcab981e19633ebcf0b001ddd37dd802996098bc1864f90b7c5d970ce76c1d59" dependencies = [ "aes", "bzip2", @@ -9166,14 +9345,14 @@ dependencies = [ "crc32fast", "deflate64", "flate2", - "getrandom 0.4.3", + "getrandom 0.4.2", "hmac", "indexmap 2.14.0", "lzma-rust2", "memchr", "pbkdf2", "ppmd-rust", - "sha1 0.11.0", + "sha1", "time", "typed-path", "zeroize", @@ -9183,9 +9362,9 @@ dependencies = [ [[package]] name = "zlib-rs" -version = "0.6.4" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "977347db8caa080403f6b6b7c1cda9479a8e869316f7e13a59b19076a40f94e3" +checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" [[package]] name = "zmij" @@ -9287,17 +9466,17 @@ dependencies = [ [[package]] name = "zvariant" -version = "5.12.0" +version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a192a0bde63360d77a7523c833d4b4ce6070a927e2c53246e4c540b1a3e27be0" +checksum = "5708299b21903bbe348e94729f22c49c55d04720a004aa350f1f9c122fd2540b" dependencies = [ "endi", "enumflags2", "serde", "url", - "winnow", - "zvariant_derive 5.12.0", - "zvariant_utils 3.4.0", + "winnow 0.7.15", + "zvariant_derive 5.10.0", + "zvariant_utils 3.3.0", ] [[package]] @@ -9315,15 +9494,15 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "5.12.0" +version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc6cde9c01c511074be97f7ccb6c19d0da89e3f8662e812e999dcfd4638737" +checksum = "5b59b012ebe9c46656f9cc08d8da8b4c726510aef12559da3e5f1bf72780752c" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", "syn", - "zvariant_utils 3.4.0", + "zvariant_utils 3.3.0", ] [[package]] @@ -9339,32 +9518,13 @@ dependencies = [ [[package]] name = "zvariant_utils" -version = "3.4.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e8535915cfa75547e559d8c68e8139909a4aeee076831e4ef7fc59d8172c4d6" +checksum = "f75c23a64ef8f40f13a6989991e643554d9bef1d682a281160cf0c1bc389c5e9" dependencies = [ "proc-macro2", "quote", "serde", "syn", - "winnow", + "winnow 0.7.15", ] - -[[patch.unused]] -name = "winit-x11" -version = "0.31.0-beta.2" - -[[patch.unused]] -name = "dnd" -version = "0.1.0" -source = "git+https://forge.aditua.com/leyoda/window_clipboard.git?branch=yoda-x11-optional#af8e6a872d8ac4956e044b9cb05a615a48261a57" - -[[patch.unused]] -name = "mime" -version = "0.1.0" -source = "git+https://forge.aditua.com/leyoda/window_clipboard.git?branch=yoda-x11-optional#af8e6a872d8ac4956e044b9cb05a615a48261a57" - -[[patch.unused]] -name = "window_clipboard" -version = "0.4.1" -source = "git+https://forge.aditua.com/leyoda/window_clipboard.git?branch=yoda-x11-optional#af8e6a872d8ac4956e044b9cb05a615a48261a57" diff --git a/Cargo.toml b/Cargo.toml index eae37a1..8f81194 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,17 @@ [package] name = "cosmic-files" -version = "1.3.0" +version = "1.0.11" authors = ["Jeremy Soller "] edition = "2024" license = "GPL-3.0-only" -rust-version = "1.93" +rust-version = "1.90" [dependencies] anyhow = "1" jiff = "0.2" jiff-icu = "0.2" -icu = { version = "2.2.0", features = ["compiled_data"] } -cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "c253ec1", optional = true } +icu = { version = "2.1.1", features = ["compiled_data"] } +cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "160b086", optional = true } cosmic-mime-apps = { git = "https://github.com/pop-os/cosmic-mime-apps.git", optional = true } dirs = "6.0.0" gio = { version = "0.21", optional = true } @@ -24,7 +24,7 @@ log = "0.4" mime_guess = "2" notify-debouncer-full = "0.7" notify-rust = { version = "4", optional = true } -open = "5.3.4" +open = "5.3.3" paste = "1.0" regex = "1" rustc-hash = "2.1" @@ -33,18 +33,18 @@ shlex = { version = "1.3" } tempfile = "3" tikv-jemallocator = { version = "0.6", optional = true } tokio = { version = "1", features = ["process", "sync"] } -trash = "5.2.6" +trash = { git = "https://github.com/jackpot51/trash-rs.git", branch = "cosmic" } url = "2.5" walkdir = "2.5.0" -wayland-client = { version = "0.31.14", optional = true } +wayland-client = { version = "0.31.13", optional = true } xdg = { version = "3.0", optional = true } xdg-mime = { git = "https://github.com/ebassi/xdg-mime-rs" } # Compression bzip2 = { version = "0.6", optional = true } #TODO: replace with pure Rust crate flate2 = "1.1" -tar = "0.4.45" +tar = "0.4.44" lzma-rust2 = { version = "0.16", optional = true } -ordermap = { version = "1.2.0", features = ["serde"] } +ordermap = { version = "1.1.0", features = ["serde"] } # Internationalization i18n-embed = { version = "0.16", features = [ "fluent-system", @@ -56,17 +56,15 @@ slotmap = "1.1.1" recently-used-xbel = "1.2.0" zip = "8" md-5 = "0.10.6" -sha2 = "0.10" png = "0.18" jxl-oxide = { version = "0.12.5", features = ["image"] } num_cpus = "1.17.0" filetime = "0.2" tracing = "0.1.44" -tracing-subscriber = { version = "0.3.23", features = ["env-filter"] } +tracing-subscriber = { version = "0.3.22", features = ["env-filter"] } thiserror = "2.0.18" atomic_float = "1.1.0" num_enum = "0.7.6" -bstr = "1.12.1" # Completion-based IO runtime to enable io_uring / IOCP file IO support. [dependencies.compio] @@ -74,9 +72,8 @@ version = "0.18" default-features = false features = ["fs", "io", "macros", "polling", "runtime"] -# Yoda fork — depend on libcosmic-yoda directly by path (no git/no patch). -[dependencies.libcosmic-yoda] -path = "../libcosmic" +[dependencies.libcosmic] +git = "https://github.com/pop-os/libcosmic.git" default-features = false #TODO: a11y feature crashes features = [ @@ -85,7 +82,7 @@ features = [ "autosize", "multi-window", "tokio", - "wayland", + "winit", "surface-message", ] @@ -113,15 +110,15 @@ default = [ "wayland", "wgpu", ] -dbus-config = ["libcosmic-yoda/dbus-config"] -desktop = ["libcosmic-yoda/desktop", "dep:cosmic-mime-apps", "dep:xdg"] +dbus-config = ["libcosmic/dbus-config"] +desktop = ["libcosmic/desktop", "dep:cosmic-mime-apps", "dep:xdg"] desktop-applet = [] gvfs = ["dep:gio", "dep:glib"] io-uring = ["compio/io-uring"] jemalloc = ["dep:tikv-jemallocator"] notify = ["dep:notify-rust"] -wayland = ["libcosmic-yoda/wayland", "dep:cctk", "dep:wayland-client"] -wgpu = ["libcosmic-yoda/wgpu"] +wayland = ["libcosmic/wayland", "dep:cctk", "dep:wayland-client"] +wgpu = ["libcosmic/wgpu"] [profile.dev] opt-level = 1 @@ -147,23 +144,19 @@ fastrand = "2" test-log = "0.2" tokio = { version = "1", features = ["rt", "macros"] } -# Yoda fork — libcosmic dep is now a direct path dep (libcosmic-yoda above), -# no [patch] block needed anymore. Keeping the block below would be a no-op -# since nothing in the dep graph still asks for pop-os/libcosmic.git. +# [patch.'https://github.com/pop-os/cosmic-text'] +# cosmic-text = { path = "../cosmic-text" } -# Yoda wayland cut: redirect window_clipboard (x11 gated behind opt-in -# feature) to our public Forgejo fork and cosmic-text to the local checkout -# carrying PR#503 plus the EAW monospace width fix. The window_clipboard patch -# is needed to consolidate the -# upstream pop-os/libcosmic chain (pulled by cosmic-settings-daemon) onto -# the same fork iced uses, otherwise cargo compiles two versions. -[patch.'https://github.com/pop-os/window_clipboard.git'] -window_clipboard = { git = "https://forge.aditua.com/leyoda/window_clipboard.git", branch = "yoda-x11-optional" } -dnd = { git = "https://forge.aditua.com/leyoda/window_clipboard.git", branch = "yoda-x11-optional" } -mime = { git = "https://forge.aditua.com/leyoda/window_clipboard.git", branch = "yoda-x11-optional" } +[patch.'https://github.com/pop-os/libcosmic'] +libcosmic = { path = "../libcosmic" } +cosmic-config = { path = "../libcosmic/cosmic-config" } +cosmic-theme = { path = "../libcosmic/cosmic-theme" } +iced_futures = { path = "../libcosmic/iced/futures" } +iced_winit = { path = "../libcosmic/iced/winit" } -[patch.'https://github.com/pop-os/cosmic-text.git'] -cosmic-text = { path = "../cosmic-text" } + +# [patch.'https://github.com/pop-os/smithay-clipboard'] +# smithay-clipboard = { path = "../smithay-clipboard" } [workspace] members = ["cosmic-files-applet"] diff --git a/build.rs b/build.rs index 206e897..5edc53b 100644 --- a/build.rs +++ b/build.rs @@ -1,5 +1,4 @@ -use std::path::PathBuf; -use std::{env, fs}; +use std::{env, fs, path::PathBuf}; use xdgen::{App, Context, FluentString}; fn main() { diff --git a/cosmic-files-applet/Cargo.toml b/cosmic-files-applet/Cargo.toml index b4f5bcc..b20226b 100644 --- a/cosmic-files-applet/Cargo.toml +++ b/cosmic-files-applet/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmic-files-applet" -version = "1.2.0" +version = "1.0.11" edition = "2024" [dependencies] diff --git a/debian/changelog b/debian/changelog index 0dbce82..bea1aee 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,45 +1,3 @@ -cosmic-files (1.2.0) noble; urgency=medium - - * Epoch 1.2.0 version update - - -- Jeremy Soller Tue, 30 Jun 2026 12:21:07 -0600 - -cosmic-files (1.1.0) noble; urgency=medium - - * Epoch 1.1.0 version update - - -- Jeremy Soller Tue, 23 Jun 2026 08:47:18 -0600 - -cosmic-files (1.0.16) noble; urgency=medium - - * Epoch 1.0.16 version update - - -- Jeremy Soller Tue, 09 Jun 2026 10:26:05 -0600 - -cosmic-files (1.0.15) noble; urgency=medium - - * Epoch 1.0.15 version update - - -- Jeremy Soller Tue, 02 Jun 2026 11:02:29 -0600 - -cosmic-files (1.0.14) noble; urgency=medium - - * Epoch 1.0.14 version update - - -- Jeremy Soller Tue, 26 May 2026 08:30:59 -0600 - -cosmic-files (1.0.13) noble; urgency=medium - - * Epoch 1.0.13 version update - - -- Jeremy Soller Tue, 12 May 2026 09:39:14 -0600 - -cosmic-files (1.0.12) noble; urgency=medium - - * Epoch 1.0.12 version update - - -- Jeremy Soller Tue, 05 May 2026 10:23:57 -0600 - cosmic-files (1.0.11) noble; urgency=medium * Epoch 1.0.11 version update diff --git a/docs/local-performance-and-portal-notes.md b/docs/local-performance-and-portal-notes.md deleted file mode 100644 index a3dabbe..0000000 --- a/docs/local-performance-and-portal-notes.md +++ /dev/null @@ -1,78 +0,0 @@ -# Local performance and portal notes - -Date: 2026-05-05 - -This repository carries a local patch aimed at improving initial directory -display latency in large folders, plus a system-level workaround for a COSMIC -portal FileChooser crash observed with Firefox and Chromium. - -## Directory listing latency - -The slow path was the initial construction of `Item` values in `src/tab.rs`. -On a test folder with about 2000 entries, raw filesystem enumeration and stat -calls completed in a few milliseconds, while COSMIC Files took multiple seconds -before showing the directory. - -The local patch keeps initial item construction cheap: - -- directory child counts are no longer computed synchronously in - `item_from_entry` and `item_from_gvfs_info`; -- initial MIME detection uses extension-based `mime_guess`; -- regular files use a generic file icon during the initial scan instead of - resolving the full MIME icon immediately. - -This keeps folders and `.desktop` files special-cased, while avoiding expensive -per-file work for ordinary files during first paint. - -Measured locally during investigation: - -- before the MIME/icon changes: about 3.1 seconds for `~/Téléchargements`; -- after avoiding full MIME icon resolution during scan: below the temporary - 100 ms perf-log threshold for the same folder. - -## File chooser portal workaround - -Firefox and Chromium were failing to open `Save As` on the first attempt because -`xdg-desktop-portal-cosmic` crashed while handling `FileChooser`. - -Logs showed: - -```text -Backend call failed: Remote peer disconnected -xdg-desktop-portal-cosmic ... status=11/SEGV -``` - -The working local system workaround is to remove -`org.freedesktop.impl.portal.FileChooser` from: - -```text -/usr/share/xdg-desktop-portal/portals/cosmic.portal -``` - -so the file chooser falls back to GTK. The resulting local `cosmic.portal` -keeps COSMIC for the other interfaces: - -```ini -[portal] -DBusName=org.freedesktop.impl.portal.desktop.cosmic -Interfaces=org.freedesktop.impl.portal.Access;org.freedesktop.impl.portal.Screenshot;org.freedesktop.impl.portal.Settings;org.freedesktop.impl.portal.ScreenCast -UseIn=COSMIC -``` - -Backups created locally: - -```text -/usr/share/xdg-desktop-portal/portals/cosmic.portal.bak-codex-20260505-filechooser -/usr/share/xdg-desktop-portal/cosmic-portals.conf.bak-codex-20260505 -/usr/share/xdg-desktop-portal/cosmic-portals.conf.bak-codex-20260505-2 -``` - -After editing portal files, restart: - -```sh -systemctl --user restart xdg-desktop-portal.service xdg-desktop-portal-gtk.service -``` - -Package updates may overwrite `/usr/share/xdg-desktop-portal/portals/cosmic.portal`. -If `Save As` starts needing two attempts again, re-check that `FileChooser` has -not been reintroduced in `cosmic.portal`. diff --git a/examples/copy.rs b/examples/copy.rs index 7f37abd..6396209 100644 --- a/examples/copy.rs +++ b/examples/copy.rs @@ -1,8 +1,6 @@ -use cosmic_files::operation::recursive::{Context, Method}; -use cosmic_files::operation::{Controller, ReplaceResult}; -use std::error::Error; -use std::io; -use std::path::PathBuf; +use cosmic_files::operation::recursive::Method; +use cosmic_files::operation::{Controller, ReplaceResult, recursive::Context}; +use std::{error::Error, io, path::PathBuf}; #[compio::main] async fn main() -> Result<(), Box> { diff --git a/examples/dialog.rs b/examples/dialog.rs index df77069..be93576 100644 --- a/examples/dialog.rs +++ b/examples/dialog.rs @@ -1,12 +1,15 @@ -use cosmic::app::{self, Core, Settings, Task}; -use cosmic::iced::{Subscription, window}; -use cosmic::{Application, Element, executor, widget}; +use cosmic::{ + Application, Element, + app::{self, Core, Settings, Task}, + executor, + iced::{Subscription, window}, + widget, +}; use cosmic_files::dialog::{ Dialog, DialogChoice, DialogChoiceOption, DialogFilter, DialogFilterPattern, DialogKind, DialogMessage, DialogResult, DialogSettings, }; -use tracing_subscriber::layer::SubscriberExt; -use tracing_subscriber::util::SubscriberInitExt; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; fn main() -> Result<(), Box> { let log_format = tracing_subscriber::fmt::format() diff --git a/i18n/ar/cosmic_files.ftl b/i18n/ar/cosmic_files.ftl index c4e3292..867e83c 100644 --- a/i18n/ar/cosmic_files.ftl +++ b/i18n/ar/cosmic_files.ftl @@ -372,14 +372,3 @@ show-recents = مجلد الحديثة في الشريط الجانبي clear-recents-history = امحُ التأريخ الحديث copy-path = انسخ المسار mixed = مختلط -context-action = إجراء السياق -context-action-confirm-title = شغِّل "{ $name }"؟ -context-action-confirm-warning = - سيُشغِّل هذا على { $items } { $items -> - [one] عنصر - [two] عنصرين - [few] عناصر - [many] عنصرًا - *[other] عنصر - }. -run = شغِّل diff --git a/i18n/ca/cosmic_files.ftl b/i18n/ca/cosmic_files.ftl index f37cc18..010ddb0 100644 --- a/i18n/ca/cosmic_files.ftl +++ b/i18n/ca/cosmic_files.ftl @@ -1,11 +1,11 @@ cosmic-files = Fitxers del COSMIC empty-folder = Carpeta buida -empty-folder-hidden = Carpeta buida (conté elements ocults) +empty-folder-hidden = Carpeta buida (té elements ocults) no-results = No s'ha trobat cap resultat filesystem = Sistema de fitxers home = Inici networks = Xarxes -notification-in-progress = Operacions de fitxers en curs +notification-in-progress = Hi ha operacions amb fitxers en curs. trash = Paperera recents = Recents undo = Desfés @@ -29,14 +29,14 @@ details = Detalls dismiss = Descarta el missatge operations-running = { $running } { $running -> - [one] operació + [one] operacion *[other] operacions } en curs ({ $percent }%)... operations-running-finished = { $running }{ $running -> - [one] operació + [one] operacion *[other] operacions - } en curs ({ $percent }%), { $finished } acabada/es... + } en curs ({ $percent }%), { $finished } acabat... pause = Pausa resume = Reprèn @@ -54,7 +54,7 @@ extract-password-required = Cal una contrasenya ## Empty Trash Dialog empty-trash = Buida la paperera -empty-trash-warning = Els elements dins la Paperera s'eliminaran permanentment +empty-trash-warning = Voleu suprimir permanentment tots els fitxers de la paperera? ## Mount Error Dialog @@ -64,17 +64,17 @@ mount-error = No es pot accedir a la unitat create-new-file = Crea un nou fitxer create-new-folder = Crea una nova carpeta -file-name = Nom del fitxer +file-name = Nom del fixer folder-name = Nom de la carpeta -file-already-exists = Ja existeix un fitxer amb aquest nom -folder-already-exists = Ja existeix una carpeta amb aquest nom -name-hidden = Els noms que comencin amb "." s'ocultaran. -name-invalid = El nom no pot ser "{ $filename }" +file-already-exists = Ja existeix un fitxer amb aquest nom. +folder-already-exists = Ja existeix una carpeta amb aquest nom. +name-hidden = Els noms que comencin amb "." seran ocults. +name-invalid = El nom no pot ser "{ $filename }". name-no-slashes = El nom no pot contenir barres. ## Open/Save Dialog -cancel = Cancel·lar +cancel = Cancel·la create = Crea open = Obre open-file = Obre el fixer @@ -352,14 +352,3 @@ sort-newest-first = Primer més recents sort-oldest-first = Primer més antics sort-smallest-to-largest = De petit a gran sort-largest-to-smallest = De gran a petit -run = Executa -extract-to-title = Extreu a una carpeta -empty-trash-title = Voleu buidar la paperera? -extract-to = Extreu a... -delete = Suprimeix -comment = Gestor de fitxers de l'escriptori COSMIC -copy-to-title = Escolliu el destí de la còpia -copy-to-button-label = Copia -move-to-title = Escolliu el destí del trasllat -move-to-button-label = Mou -keywords = Carpeta;Fitxers;Arxius;Gestor;Explorador; diff --git a/i18n/cs/cosmic_files.ftl b/i18n/cs/cosmic_files.ftl index fac1794..54b9e10 100644 --- a/i18n/cs/cosmic_files.ftl +++ b/i18n/cs/cosmic_files.ftl @@ -17,7 +17,7 @@ size = Velikost ## Empty Trash Dialog -empty-trash = Vyprázdnit koš +empty-trash = Vysypat koš empty-trash-warning = Položky v koši budou trvale smazány ## New File/Folder Dialog @@ -195,8 +195,8 @@ deleted = [few] položky *[other] položek } z koše -emptying-trash = Vyprazdňování koše ({ $progress })... -emptied-trash = Koš vyprázdněn +emptying-trash = Vysypávání koše ({ $progress })... +emptied-trash = Koš vysypán restoring = Obnovování { $items } { $items -> [one] položky @@ -403,7 +403,7 @@ sort-largest-to-smallest = Od největšího po nejmenší gallery-preview = Náhled galerie sort = Řazení sort-a-z = A-Z -empty-trash-title = Vyprázdnit koš? +empty-trash-title = Vysypat koš? type-to-search-select = Vybere první shodující se soubor nebo složku pasted-image = Vložený obrázek pasted-text = Vložený text @@ -418,13 +418,3 @@ show-recents = Složka „Nedávné“ v postranním panelu copy-path = Kopírovat cestu clear-recents-history = Vymazat historii „Nedávné“ mixed = Různé -context-action = Kontextová akce -context-action-confirm-title = Spustit „{ $name }“? -context-action-confirm-warning = - Tato akce se spustí pro { $items } { $items -> - [one] položku - [few] položky - *[other] položek - }. -run = Spustit -rename-confirm = Přejmenovat diff --git a/i18n/de/cosmic_files.ftl b/i18n/de/cosmic_files.ftl index 65a5ebf..98d2f1b 100644 --- a/i18n/de/cosmic_files.ftl +++ b/i18n/de/cosmic_files.ftl @@ -429,12 +429,3 @@ remove-from-recents = Aus den zuletzt verwendeten Elementen entfernen move-to = Verschieben nach... copy-path = Pfad kopieren mixed = Gemischt -context-action = Kontextaktion -context-action-confirm-title = „{ $name }“ ausführen? -context-action-confirm-warning = - Dies wird ausgeführt auf { $items } { $items -> - [one] Element - *[other] Elementen - }. -run = Ausführen -rename-confirm = Umbenennen diff --git a/i18n/el/cosmic_files.ftl b/i18n/el/cosmic_files.ftl index c75e419..b28272c 100644 --- a/i18n/el/cosmic_files.ftl +++ b/i18n/el/cosmic_files.ftl @@ -1,330 +1,15 @@ empty-folder = Άδειος φάκελος no-results = Δεν βρέθηκαν αποτελέσματα -trash = Απορρίμματα +trash = Κάδος Ανακύκλωσης recents = Πρόσφατα -cosmic-files = Αρχεία COSMIC -empty-folder-hidden = Άδειος φάκελος (περιέχει κρυφά στοιχεία) +cosmic-files = COSMIC Αρχεία +empty-folder-hidden = Άδειος φάκελος (περιέχει κρυφά αντικείμενα) filesystem = Σύστημα αρχείων home = Προσωπικός φάκελος -networks = Δίκτυα -comment = Διαχείριση αρχείων για το περιβάλλον επιφάνειας εργασίας COSMIC -keywords = Αρχείο;Φάκελος;Διαχείριση;Folder;Manager; +networks = Δίκτυο +comment = Αρχεία για το COSMIC περιβάλλον +keywords = Φάκελος;Διαχειριστής; rename = Μετονομασία... close-tab = Κλείσιμο καρτέλας -light = Ανοιχτόχρωμο -dark = Σκουρόχρωμο -connect = Σύνδεση -dismiss = Απόρριψη μηνύματος -copy_noun = Αντιγραφή -open-file = Άνοιγμα αρχείου -save = Αποθήκευση -password = Κωδικός πρόσβασης -remove = Αφαίρεση -create = Δημιουργία -pause = Παύση -quit = Έξοδος -calculating = Υπολογισμός... -keep = Διατήρηση -edit = Επεξεργασία -connecting = Σύνδεση... -copy = Αντιγραφή -theme = Θέμα -appearance = Εμφάνιση -name = Όνομα -resume = Συνέχιση -username = Όνομα χρήστη -delete = Διαγραφή -repository = Αποθετήριο -support = Υποστήριξη -eject = Εξαγωγή -group = Ομάδα -skip = Παράλειψη -paste = Επικόλληση -menu-settings = Ρυθμίσεις... -view = Προβολή -undo = Αναίρεση -details = Λεπτομέρειες -sort-a-z = Α-Ω -extract-here = Αποσυμπίεση -cancel = Ακύρωση -sort-z-a = Ω-Α -open = Άνοιγμα -history = Ιστορικό -domain = Τομέας -sort = Ταξινόμηση -settings = Ρυθμίσεις -pending = Σε εκκρεμότητα -open-folder = Άνοιγμα φακέλου -replace = Αντικατάσταση -cut = Αποκοπή -file = Αρχείο -today = Σήμερα -compress = Συμπίεση... -size = Μέγεθος -related-apps = Σχετικές εφαρμογές -zoom-in = Μεγέθυνση -select-all = Επιλογή όλων -icon-size-and-spacing = Μέγεθος και απόσταση εικονιδίων -new-window = Νέο παράθυρο -zoom-out = Σμίκρυνση -default-size = Προεπιλεγμένο μέγεθος -create-archive = Δημιουργία συμπιεσμένου αρχείου -other-apps = Άλλες εφαρμογές -rename-folder = Μετονομασία φακέλου -folder-name = Όνομα φακέλου -connect-anonymously = Ανώνυμη σύνδεση -replace-with = Αντικατάσταση με -mounted-drives = Προσαρτημένες μονάδες -desktop-view-options = Επιλογές προβολής επιφάνειας εργασίας... -show-on-desktop = Εμφάνιση στην επιφάνεια εργασίας -trash-folder-icon = Εικονίδιο φακέλου απορριμμάτων -open-with = Άνοιγμα με -keep-both = Διατήρηση αμφότερων -icon-size = Μέγεθος εικονιδίων -open-with-title = Πώς θέλετε να ανοίξετε το «{ $name }»; -extract-password-required = Απαιτείται κωδικός πρόσβασης -rename-file = Μετονομασία αρχείου -file-name = Όνομα αρχείου -save-file = Αποθήκευση αρχείου -name-hidden = Τα ονόματα που ξεκινούν με «.» θα αποκρύπτονται -folder-already-exists = Υπάρχει ήδη ένας φάκελος με αυτό το όνομα -empty-trash = Άδειασμα απορριμμάτων -permanently-delete-question = Οριστική διαγραφή; -copy-to-button-label = Αντιγραφή -move-to-button-label = Μετακίνηση -run = Εκτέλεση -copy-to-title = Επιλογή προορισμού αντιγραφής -sort-newest-first = Πρώτα τα νεότερα -default-app = { $name } (προεπιλογή) -renamed = Έγινε μετονομασία από «{ $from }» σε «{ $to }» -read-execute = Ανάγνωση και εκτέλεση -deleted = - Έγινε διαγραφή { $items } { $items -> - [one] στοιχείου - *[other] στοιχείων - } από τα { trash } -item-modified = Ημερομηνία τροποποίησης: { $modified } -list-view = Προβολή λίστας -reload-folder = Επαναφόρτωση φακέλου -favorite-path-error = Σφάλμα ανοίγματος καταλόγου -progress = { $percent }% -remove-from-sidebar = Αφαίρεση από την πλαϊνή στήλη -restoring = - Ανάκτηση { $items } { $items -> - [one] στοιχείου - *[other] στοιχείων - } από τα { trash } ({ $progress })... -network-drive-error = Αδυναμία πρόσβασης σε μονάδα δικτύου -gallery-preview = Προεπισκόπηση συλλογής -sort-smallest-to-largest = Από τα μικρότερα στα μεγαλύτερα -removing-from-recents = - Αφαίρεση { $items } { $items -> - [one] στοιχείου - *[other] στοιχείων - } από τα { recents } -type-to-search-enter-path = Εισέρχεται στη διαδρομή προς τον κατάλογο ή το αρχείο -emptying-trash = Άδειασμα φακέλου «{ trash }» ({ $progress })... -trashed-on = Ημερομηνία διαγραφής -compressing = - Συμπίεση { $items } { $items -> - [one] στοιχείου - *[other] στοιχείων - } από τον φάκελο «{ $from }» στο αρχείο «{ $to }» ({ $progress })... -move-to-trash = Μετακίνηση στα απορρίμματα -menu-about = Σχετικά με τα Αρχεία COSMIC... -setting-executable-and-launching = Ορισμός του «{ $name }» ως εκτελέσιμου και εκκίνηση -open-multiple-files = Άνοιγμα πολλαπλών αρχείων -menu-open-with = Άνοιγμα με... -extracted = - Έγινε αποσυμπίεση { $items } { $items -> - [one] στοιχείου - *[other] στοιχείων - } από το αρχείο «{ $from }» στον φάκελο «{ $to }» -create-new-folder = Δημιουργία νέου φακέλου -original-file = Πρωτότυπο αρχείο -read-write-execute = Ανάγνωση, εγγραφή και εκτέλεση -set-permissions = Έγινε ορισμός των δικαιωμάτων για το «{ $name }» σε: { $mode } -sort-by-size = Ταξινόμηση κατά μέγεθος -item-size = Μέγεθος: { $size } -permanently-deleting = - Οριστική διαγραφή { $items } { $items -> - [one] στοιχείου - *[other] στοιχείων - } -read-write = Ανάγνωση και εγγραφή -none = Κανένα -items = Στοιχεία: { $items } -type = Τύπος: { $mime } -compressed = - Έγινε συμπίεση { $items } { $items -> - [one] στοιχείου - *[other] στοιχείων - } από τον φάκελο «{ $from }» στο αρχείο «{ $to }» -replace-warning = Θέλετε να το αντικαταστήσετε με αυτό που αποθηκεύετε; Αυτό θα οδηγήσει στην αντικατάσταση του περιεχομένου του. -new-file = Νέο αρχείο... -open-in-terminal = Άνοιγμα σε τερματικό -open-multiple-folders = Άνοιγμα πολλαπλών φακέλων -remember-password = Απομνημόνευση κωδικού πρόσβασης -show-details = Εμφάνιση λεπτομερειών -grid-spacing = Απόσταση πλέγματος -extract-to = Αποσυμπίεση σε... -add-network-drive = Προσθήκη μονάδας δικτύου -copying = - Αντιγραφή { $items } { $items -> - [one] στοιχείου - *[other] στοιχείων - } από τον φάκελο «{ $from }» στον φάκελο «{ $to }» ({ $progress })... -sort-oldest-first = Πρώτα τα παλαιότερα -create-new-file = Δημιουργία νέου αρχείου -sort-by-trashed = Ταξινόμηση κατά ημερομηνία διαγραφής -replace-warning-operation = Θέλετε να το αντικαταστήσετε; Αυτό θα οδηγήσει στην αντικατάσταση του περιεχομένου του. -try-again = Δοκιμή ξανά -copied = - Έγινε αντιγραφή { $items } { $items -> - [one] στοιχείου - *[other] στοιχείων - } από τον φάκελο «{ $from }» στον φάκελο «{ $to }» -other = Άλλο -open-in-new-window = Άνοιγμα σε νέο παράθυρο -sort-by-modified = Ταξινόμηση κατά ημερομηνία τροποποίησης -list-directories-first = Παράθεση των καταλόγων πρώτα -read-only = Μόνο ανάγνωση -browse-store = Περιήγηση στο { $store } -enter-server-address = Εισαγάγετε τη διεύθυνση διακομιστή -remove-from-recents = Αφαίρεση από τα πρόσφατα -apply-to-all = Εφαρμογή σε όλα -moving = - Μετακίνηση { $items } { $items -> - [one] στοιχείου - *[other] στοιχείων - } από τον φάκελο «{ $from }» στον φάκελο «{ $to }» ({ $progress })... -change-wallpaper = Αλλαγή ταπετσαρίας... -network-drive-description = - Οι διευθύνσεις διακομιστών αποτελούνται από ένα πρόθεμα πρωτοκόλλου και μια διεύθυνση. - Παραδείγματα: ssh://192.168.0.1, ftp://[2001:db8::1] -deleting = - Διαγραφή { $items } { $items -> - [one] στοιχείου - *[other] στοιχείων - } από τα { trash } ({ $progress })... -single-click = Μονό κλικ για άνοιγμα -setting-permissions = Ορισμός των δικαιωμάτων για το «{ $name }» σε: { $mode } -owner = Κάτοχος -creating = Δημιουργία του «{ $name }» στον φάκελο «{ $parent }» -execute-only = Μόνο εκτέλεση -open-item-location = Άνοιγμα τοποθεσίας στοιχείου -set-executable-and-launched = Έγινε ορισμός του «{ $name }» ως εκτελέσιμου και εκκινήθηκε -mount-error = Αδυναμία πρόσβασης στη μονάδα -grid-view = Προβολή πλέγματος -set-and-launch = Ορισμός και εκκίνηση -removed-from-recents = - Έγινε αφαίρεση { $items } { $items -> - [one] στοιχείου - *[other] στοιχείων - } από τα { recents } -add-to-sidebar = Προσθήκη στην πλαϊνή στήλη -item-created = Ημερομηνία δημιουργίας: { $created } -network-drive-schemes = - Διαθέσιμα πρωτόκολλα,Πρόθεμα - AppleTalk,afp:// - File Transfer Protocol,ftp:// ή ftps:// - Network File System,nfs:// - Server Message Block,smb:// - SSH File Transfer Protocol,sftp:// ή ssh:// - WebDAV,dav:// ή davs:// -set-executable-and-launch = Ορισμός ως εκτελέσιμο και εκκίνηση -restored = - Έγινε ανάκτηση { $items } { $items -> - [one] στοιχείου - *[other] στοιχείων - } από τα { trash } -type-to-search-recursive = Κάνει αναζήτηση στον τρέχοντα φάκελο και όλους τους υποφακέλους -progress-paused = { $percent }%, σε παύση -cancelled = Ακυρωμένες -new-folder = Νέος φάκελος... -match-desktop = Συμφωνία με την επιφάνεια εργασίας -operations-running-finished = - Εκτέλεση { $running } { $running -> - [one] διεργασίας - *[other] διεργασιών - } ({ $percent }%), { $finished } ολοκληρωμένες... -sort-by-name = Ταξινόμηση κατά όνομα -edit-history = Ιστορικό επεξεργασιών -show-hidden-files = Εμφάνιση κρυφών αρχείων -progress-failed = { $percent }%, απέτυχε -item-accessed = Ημερομηνία πρόσβασης: { $accessed } -extract-to-title = Αποσυμπίεση σε φάκελο -extracting = - Αποσυμπίεση { $items } { $items -> - [one] στοιχείου - *[other] στοιχείων - } από το αρχείο «{ $from }» στον φάκελο «{ $to }» ({ $progress })... -permanently-deleted = - Έγινε οριστική διαγραφή { $items } { $items -> - [one] στοιχείου - *[other] στοιχείων - } -complete = Ολοκληρωμένες -write-execute = Εγγραφή και εκτέλεση -desktop-folder-content = Περιεχόμενο φακέλου επιφάνειας εργασίας -renaming = Μετονομασία από «{ $from }» σε «{ $to }» -set-executable-and-launch-description = Θέλετε να ορίσετε το «{ $name }» ως εκτελέσιμο και να το εκκινήσετε; -no-history = Δεν υπάρχουν στοιχεία στο ιστορικό. -emptied-trash = Έγινε άδειασμα του φακέλου «{ trash }» -sort-largest-to-smallest = Από τα μεγαλύτερα στα μικρότερα -restore-from-trash = Ανάκτηση από τα απορρίμματα -moved = - Έγινε μετακίνηση { $items } { $items -> - [one] στοιχείου - *[other] στοιχείων - } από τον φάκελο «{ $from }» στον φάκελο «{ $to }» -progress-cancelled = { $percent }%, ακυρώθηκε -open-in-new-tab = Άνοιγμα σε νέα καρτέλα -unknown-folder = άγνωστος φάκελος -created = Έγινε δημιουργία του «{ $name }» στον φάκελο «{ $parent }» -delete-permanently = Οριστική διαγραφή -write-only = Μόνο εγγραφή -display-settings = Ρυθμίσεις οθόνης... -new-tab = Νέα καρτέλα -failed = Αποτυχημένες -modified = Ημερομηνία τροποποίησης -desktop-appearance = Εμφάνιση επιφάνειας εργασίας... -file-already-exists = Υπάρχει ήδη ένα αρχείο με αυτό το όνομα -permanently-delete-warning = Θα διαγραφούν οριστικά τα εξής: { $target }. Δεν είναι δυνατή η αναίρεση αυτής της ενέργειας. -favorite-path-error-description = - Αδυναμία ανοίγματος του «{ $path }» - Το «{ $path }» ενδέχεται να μην υπάρχει ή να μην έχετε το δικαίωμα να το ανοίξετε - - Θέλετε να το αφαιρέσετε από την πλαϊνή στήλη; -empty-trash-warning = Τα στοιχεία του φακέλου «Απορρίμματα» θα διαγραφούν οριστικά -empty-trash-title = Άδειασμα απορριμμάτων; -type-to-search = Πληκτρολόγηση για αναζήτηση -notification-in-progress = Βρίσκονται σε εξέλιξη διεργασίες αρχείων -name-no-slashes = Το όνομα δεν μπορεί να περιέχει καθέτους -replace-title = Το «{ $filename }» υπάρχει ήδη σε αυτήν την τοποθεσία -name-invalid = Το όνομα δεν μπορεί να είναι «{ $filename }» -operations-running = - Εκτέλεση { $running } { $running -> - [one] διεργασίας - *[other] διεργασιών - } ({ $percent }%)... -context-action-confirm-title = Εκτέλεση του «{ $name }»; -pasted-image = Επικολλημένη εικόνα -pasted-text = Επικολλημένο κείμενο -pasted-video = Επικολλημένο βίντεο -show-recents = Φάκελος «Πρόσφατα» στην πλαϊνή στήλη -move-to = Μετακίνηση σε... -copy-path = Αντιγραφή διαδρομής -move-to-title = Επιλογή προορισμού μετακίνησης -selected-items = { $items } επιλεγμένα στοιχεία -context-action = Ενέργεια περιβάλλοντος -copy-to = Αντιγραφή σε... -mixed = Μικτό -type-to-search-select = Επιλέγει την πρώτη αντιστοιχία αρχείου ή φακέλου -clear-recents-history = Απαλοιφή ιστορικού πρόσφατων -context-action-confirm-warning = - Θα εκτελεστεί σε { $items } { $items -> - [one] στοιχείο - *[other] στοιχεία - }. -rename-confirm = Μετονομασία +light = Φωτεινό +dark = Σκοτεινό diff --git a/i18n/en/cosmic_files.ftl b/i18n/en/cosmic_files.ftl index 129e6f9..69a76c6 100644 --- a/i18n/en/cosmic_files.ftl +++ b/i18n/en/cosmic_files.ftl @@ -96,7 +96,6 @@ save-file = Save file ## Open With Dialog open-with-title = How do you want to open "{$name}"? -open-with-set-default = Always use this app for this file type browse-store = Browse {$store} other-apps = Other applications related-apps = Related applications @@ -117,7 +116,6 @@ permanently-delete-warning = {$target} will be permanently deleted. This action ## Rename Dialog rename-file = Rename file rename-folder = Rename folder -rename-confirm = Rename ## Replace Dialog replace = Replace @@ -140,11 +138,6 @@ open-with = Open with owner = Owner group = Group other = Other -toolbar = Toolbar -toolbar-available = Available -toolbar-empty-hint = No buttons. Drag or add from below. -toolbar-reset = Reset to defaults -parent-directory = Parent directory mixed = Mixed ### Mode 0 none = None @@ -309,9 +302,6 @@ item-created = Created: {$created} item-modified = Modified: {$modified} item-accessed = Accessed: {$accessed} calculating = Calculating... -checksum = {$kind} checksum -calculate = Calculate -error = Error ## Settings settings = Settings diff --git a/i18n/fi/cosmic_files.ftl b/i18n/fi/cosmic_files.ftl index 6000bc7..f22b7b4 100644 --- a/i18n/fi/cosmic_files.ftl +++ b/i18n/fi/cosmic_files.ftl @@ -405,13 +405,3 @@ removed-from-recents = [one] kohde *[other] kohdetta } viimeaikaisista -mixed = Sekoitettu -context-action = Kontekstitoiminto -context-action-confirm-title = Suoritetaanko "{ $name }"? -context-action-confirm-warning = - Tämä suorittaa { $items } { $items -> - [one] kohteen - *[other] kohdetta - }. -run = Suorita -rename-confirm = Nimeä uudelleen diff --git a/i18n/fr/cosmic_files.ftl b/i18n/fr/cosmic_files.ftl index e85a1f6..a461a9f 100644 --- a/i18n/fr/cosmic_files.ftl +++ b/i18n/fr/cosmic_files.ftl @@ -92,7 +92,6 @@ save-file = Enregistrer fichier ## Open With Dialog open-with-title = Comment souhaitez-vous ouvrir "{ $name }" ? -open-with-set-default = Toujours utiliser cette application pour ce type de fichier browse-store = Parcourir { $store } ## Permanently delete Dialog @@ -131,11 +130,6 @@ open-with = Ouvrir avec owner = Propriétaire group = Groupe other = Autre -toolbar = Barre d'outils -toolbar-available = Disponibles -toolbar-empty-hint = Aucun bouton. Glisser-déposer ou ajouter depuis la liste ci-dessous. -toolbar-reset = Rétablir par défaut -parent-directory = Dossier parent ### Mode 0 @@ -443,12 +437,3 @@ show-recents = Dossier Récents dans la barre latérale copy-path = Copier le chemin clear-recents-history = Effacer l'historique des Récents mixed = Mixte -context-action-confirm-title = Exécuter "{ $name }" ? -context-action-confirm-warning = - Cela exécutera sur { $items } { $items -> - [one] élément - *[other] éléments - }. -run = Exécuter -context-action = Action contextuelle -rename-confirm = Renommer diff --git a/i18n/ga/cosmic_files.ftl b/i18n/ga/cosmic_files.ftl index 773c2fa..5a9aa9a 100644 --- a/i18n/ga/cosmic_files.ftl +++ b/i18n/ga/cosmic_files.ftl @@ -434,12 +434,3 @@ show-recents = Fillteán le déanaí sa bharra taoibh clear-recents-history = Glan stair na n-earraí le déanaí copy-path = Cóipeáil an chosán mixed = Measctha -context-action = Gníomh comhthéacsúil -context-action-confirm-title = Rith "{ $name }"? -context-action-confirm-warning = - Rithfidh sé seo ar { $items } { $items -> - [one] mhír - *[other] míreanna - }. -run = Rith -rename-confirm = Athainmnigh diff --git a/i18n/hu/cosmic_files.ftl b/i18n/hu/cosmic_files.ftl index dfdbf44..6a87c44 100644 --- a/i18n/hu/cosmic_files.ftl +++ b/i18n/hu/cosmic_files.ftl @@ -2,7 +2,7 @@ cosmic-files = COSMIC Fájlok comment = Fájlkezelő a COSMIC asztali környezethez keywords = mappa;fájl;kezelő; empty-folder = Üres mappa -empty-folder-hidden = Üres mappa (rejtett elemeket tartalmaz) +empty-folder-hidden = Üres mappa (Rejtett elemeket tartalmaz) no-results = Nincs találat filesystem = Fájlrendszer home = Saját mappa @@ -17,7 +17,7 @@ desktop-view-options = Asztali nézet beállításai… show-on-desktop = Megjelenítés az asztalon desktop-folder-content = Asztal mappa tartalma mounted-drives = Csatolt meghajtók -trash-folder-icon = Kuka ikon +trash-folder-icon = Kuka ikonja icon-size-and-spacing = Ikonméret és távolság icon-size = Ikonméret grid-spacing = Rácsköz @@ -47,18 +47,18 @@ resume = Folytatás ## Compress Dialog -create-archive = Archívum létrehozása +create-archive = Tömörített fájl létrehozása ## Extract Dialog extract-password-required = Jelszó szükséges extract-to = Kibontás ide… -extract-to-title = Kibontási cél kiválasztása +extract-to-title = Kibontás mappába ## Empty Trash Dialog -empty-trash = A Kuka ürítése -empty-trash-warning = A Kukában lévő összes elem véglegesen törölve lesz +empty-trash = Kuka ürítése +empty-trash-warning = A kukában lévő összes elem véglegesen törölve lesz ## Mount Error Dialog @@ -93,7 +93,7 @@ save-file = Fájl mentése ## Open With Dialog -open-with-title = Hogyan szeretnéd megnyitni a(z) „{ $name }” fájlt? +open-with-title = Hogyan szeretnéd megnyitni a következőt: „{ $name }”? browse-store = { $store } böngészése other-apps = Egyéb alkalmazások related-apps = Hasonló alkalmazások @@ -103,7 +103,7 @@ related-apps = Hasonló alkalmazások selected-items = A(z) { $items } kijelölt elem permanently-delete-question = Végleges törlés? delete = Törlés -permanently-delete-warning = { $target } véglegesen törölve lesz. A művelet nem vonható vissza. +permanently-delete-warning = { $target } véglegesen törölve lesz. A művelet nem visszavonható. ## Rename Dialog @@ -113,7 +113,7 @@ rename-folder = Mappa átnevezése ## Replace Dialog replace = Csere -replace-title = „{ $filename }” már létezik ezen a helyen +replace-title = „{ $filename }” már létezik replace-warning = Szeretnéd lecserélni a meglévő fájlt a mentendő fájllal? A cserével felülírod annak tartalmát. replace-warning-operation = Szeretnéd lecserélni? A csere felülírja annak tartalmát. original-file = Eredeti fájl @@ -133,7 +133,7 @@ set-and-launch = Beállítás és indítás open-with = Megnyitás ezzel owner = Tulajdonos group = Csoport -other = Mások +other = Többi ### Mode 0 @@ -172,7 +172,7 @@ read-write-execute = Olvasás, írás és végrehajtás favorite-path-error = Hiba a könyvtár megnyitásakor favorite-path-error-description = Nem sikerült megnyitni ezt: „{ $path }” - A(z) „{ $path }” útvonal lehet, hogy nem létezik, vagy nincs jogosultságod a megnyitásához + „{ $path }” lehet nem létezik, vagy nincs jogosultságod a megnyitásához Szeretnéd eltávolítani az oldalsávról? remove = Eltávolítás @@ -187,9 +187,9 @@ keep = Megtartás ## Add Network Drive add-network-drive = Hálózati meghajtó hozzáadása -connect = Kapcsolódás -connect-anonymously = Kapcsolódás névtelenül -connecting = Kapcsolódás… +connect = Csatlakozás +connect-anonymously = Csatlakozás névtelenül +connecting = Csatlakozás… domain = Tartomány enter-server-address = Add meg a kiszolgáló címét network-drive-description = @@ -209,7 +209,7 @@ network-drive-schemes = network-drive-error = Nem érhető el a hálózati meghajtó password = Jelszó remember-password = Jelszó megjegyzése -try-again = Próbáld újra +try-again = Újra username = Felhasználónév ## Operations @@ -217,7 +217,7 @@ username = Felhasználónév cancelled = Megszakítva edit-history = Fájlműveleti előzmények history = Előzmények -no-history = Nem találhatók elemek az előzményekben. +no-history = Nem találhatók elemek az előzményekben pending = Függőben progress = { $percent }% progress-cancelled = { $percent }%, megszakítva @@ -251,13 +251,13 @@ deleting = { $items } { $items -> [one] elem *[other] elem - } törlése a Kukából ({ $progress })… + } törlése a kukából ({ $progress })… deleted = { $items } { $items -> [one] elem *[other] elem - } törölve a Kukából -emptying-trash = { trash } ürítése ({ $progress })… + } törölve a kukából +emptying-trash = { trash } kiürítése ({ $progress })… emptied-trash = { trash } kiürítve extracting = { $items } { $items -> @@ -309,12 +309,12 @@ restoring = { $items } { $items -> [one] elem *[other] elem - } visszaállítása a Kukából ({ $progress })… + } visszaállítása a kukából ({ $progress })… restored = { $items } { $items -> [one] elem *[other] elem - } visszaállítva a Kukából + } visszaállítva a kukából unknown-folder = ismeretlen mappa ## Open with @@ -330,7 +330,7 @@ items = Elemek: { $items } item-size = Méret: { $size } item-created = Létrehozva: { $created } item-modified = Módosítva: { $modified } -item-accessed = Utolsó hozzáférés: { $accessed } +item-accessed = Hozzáférve: { $accessed } calculating = Számítás… ## Settings @@ -349,8 +349,8 @@ light = Világos ### Type to Search type-to-search = Gépeléssel keresés -type-to-search-recursive = Keresés a jelenlegi mappában és az almappákban -type-to-search-enter-path = Elérési út megnyitása +type-to-search-recursive = Keresés a jelenlegi mappában és almappákban +type-to-search-enter-path = Elérési út megadása # Context menu add-to-sidebar = Hozzáadás az oldalsávhoz compress = Tömörítés… @@ -360,8 +360,8 @@ extract-here = Kibontás new-file = Új fájl… new-folder = Új mappa… open-in-terminal = Megnyitás a terminálban -move-to-trash = Áthelyezés a Kukába -restore-from-trash = Visszaállítás a Kukából +move-to-trash = Kukába helyezés +restore-from-trash = Visszaállítás a kukából remove-from-sidebar = Eltávolítás az oldalsávról sort-by-name = Név szerinti rendezés sort-by-modified = Módosítás szerinti rendezés @@ -372,8 +372,8 @@ remove-from-recents = Eltávolítás a legutóbbiak közül ## Desktop change-wallpaper = Háttérkép cseréje… -desktop-appearance = Asztal megjelenése… -display-settings = Kijelzőbeállítások… +desktop-appearance = Asztali megjelenés… +display-settings = Képernyő-beállítások… # Menu @@ -406,7 +406,7 @@ grid-view = Rácsnézet list-view = Listanézet show-hidden-files = Rejtett fájlok megjelenítése list-directories-first = Könyvtárak listázása először -gallery-preview = Galéria-előnézet +gallery-preview = Galéria előnézet menu-settings = Beállítások… menu-about = A COSMIC Fájlok névjegye… @@ -415,14 +415,14 @@ menu-about = A COSMIC Fájlok névjegye… sort = Rendezés sort-a-z = A-Z sort-z-a = Z-A -sort-newest-first = Legújabb elöl -sort-oldest-first = Legrégibb elöl +sort-newest-first = Legújabb előre +sort-oldest-first = Legrégibb előre sort-smallest-to-largest = Legkisebbtől a legnagyobbig sort-largest-to-smallest = Legnagyobbtól a legkisebbig repository = Tároló support = Támogatás progress-failed = { $percent }%, sikertelen -empty-trash-title = Kiüríted a Kukát? +empty-trash-title = Kuka ürítése? type-to-search-select = Kijelöli az első egyező fájlt vagy mappát pasted-image = Beillesztett kép pasted-text = Beillesztett szöveg @@ -437,12 +437,3 @@ show-recents = Legutóbbiak mappa megjelenítése az oldalsávban copy-path = Útvonal másolása clear-recents-history = Legutóbbiak előzményének törlése mixed = Vegyes -context-action = Helyi művelet -context-action-confirm-title = Futtatod ezt: „{ $name }”? -context-action-confirm-warning = - Ez a művelet { $items } { $items -> - [one] elemen - *[other] elemen - } fog lefutni. -run = Futtatás -rename-confirm = Átnevezés diff --git a/i18n/id/cosmic_files.ftl b/i18n/id/cosmic_files.ftl index 3300d25..2f1f21b 100644 --- a/i18n/id/cosmic_files.ftl +++ b/i18n/id/cosmic_files.ftl @@ -319,12 +319,3 @@ show-recents = Map terbaru di bilah sisi clear-recents-history = Bersihkan riwayat Terbaru copy-path = Salin jalur mixed = Bercampur -context-action = Tindakan konteks -context-action-confirm-title = Jalankan "{ $name }"? -run = Jalankan -context-action-confirm-warning = - Ini akan dijalankan pada { $items } { $items -> - [one] item - *[other] item - }. -rename-confirm = Ganti nama diff --git a/i18n/kk/cosmic_files.ftl b/i18n/kk/cosmic_files.ftl index 0ee3ffe..3b97025 100644 --- a/i18n/kk/cosmic_files.ftl +++ b/i18n/kk/cosmic_files.ftl @@ -319,12 +319,3 @@ show-recents = Бүйір панеліндегі «Жуырдағы құжатт clear-recents-history = Жуырдағылар тарихын өшіру copy-path = Орналасқан жолын көшіру mixed = Аралас -context-action = Контекст әрекеті -context-action-confirm-title = "{ $name }" орындау керек пе? -context-action-confirm-warning = - Бұл { $items } орындалады { $items -> - [one] нәрсеге - *[other] нәрсеге - }. -run = Орындау -rename-confirm = Атын өзгерту diff --git a/i18n/kmr/cosmic_files.ftl b/i18n/kmr/cosmic_files.ftl index 6c08bd0..e69de29 100644 --- a/i18n/kmr/cosmic_files.ftl +++ b/i18n/kmr/cosmic_files.ftl @@ -1,330 +0,0 @@ -sort-newest-first = Pêşî ya herî nû -connect = Girê bide -deleted = - { $items } hat jêbirin{ $items -> - [one] hêman - *[other] hêman - } ji { trash } -dismiss = Peyamê paşguh bike -list-view = Dîtina lîsteyê -copy_noun = Jê bigire -favorite-path-error = Şaşetiya vekirina rêgehê -progress = { $percent }% -open-file = Pelê veke -remove-from-sidebar = Ji benda kêlekê rake -related-apps = Bernameyên têkildar -network-drive-error = Nikaribû bigihêje ajokarê torê -gallery-preview = Pêşdîtina galeriyê -sort-smallest-to-largest = Biçûktir bo mezintir -zoom-in = Nêzîk bike -select-all = Hemûyan hilbijêre -removing-from-recents = - { $items } tê rakirin { $items -> - [one] hêman - *[other] hêman - } ji { recents } -password = Borînpeyv -cosmic-files = Pelên COSMIC -emptying-trash = { trash } tê valakirin({ $progress })... -new-window = Çarçoveya nû -remove = Rake -zoom-out = Dûr bike -compressing = - { $items } tê guvaştin { $items -> - [one] hêman - *[other] hêman - } ji "{ $from }" bo "{ $to }" ({ $progress })... -move-to-trash = Bilivîne bo jêbirdankê -menu-about = Derbarê Pelên COSMIC... -file-already-exists = Pelek bi heman navî jixwe heye -setting-executable-and-launching = "{ $name }" wekî pelê xebitandinê tê sazkirin û xebitandin -open-multiple-files = Gelek pelan veke -default-size = Mezinahiya berdest -name-hidden = Navên ku bi "." tê destpêkirin wê werin veşartin -extracted = - { $items } hate derxistin { $items -> - [one] hêman - *[other] hêman - } ji "{ $from }" bo "{ $to }" -create-new-folder = Peldanka nû biafrîne -folder-already-exists = Peldankek bi heman navî jixwe heye -create-archive = Erşîvê biafrîne -permanently-delete-warning = { $target } wê bi mayînde were jêbirin û nayê vegerandin. -favorite-path-error-description = - Nikaribû "{ $path }" veke. - "{ $path }" dibe ku tune be yan jî mafê te yê - vekirina wê tune be. - Tu dixwazî wê ji benda kêlekê rakî? -empty-trash-warning = Hêmanên di jêbirdankê de wê bi mayînde werin jêbirin -other-apps = Bernameyên din -set-permissions = Maf hatine sazkirin ji bo "{ $name }" bo { $mode } -quit = Biqedîne -sort-by-size = Li gorî mezinahiyê rêz bike -rename = Navê biguhêrîne... -empty-folder-hidden = Peldanka vala (tiştên veşartî tê de hene) -keep = Bihêle -operations-running = - { $running } { $running -> - [one] pêvajo - *[other] pêvajo - } dixebite ({ $percent }%)... -permanently-deleting = - { $items } bi mayînde tê jêbirin { $items -> - [one] hêman - *[other] hêman - } -edit = Biguhêrîne -copy = Jê bigire -none = Ne yek -no-results = Tu encam nehatin dîtin -theme = Rûkar -compressed = - { $items } hate guvaştin{ $items -> - [one] hêman - *[other] hêman - } ji "{ $from }" bo "{ $to }" -appearance = Xuyang -rename-folder = Navê peldankê biguherîne -new-file = Pela nû... -close-tab = Rûgerê bigire -open-in-terminal = Di termînalê de veke -open-multiple-folders = Gelek peldankan veke -remember-password = Borînpeyvê bi bîr bîne -username = Navê bikarhêner -light = Ronî -extract-to = Derxîne bo... -add-network-drive = Ajokarê torê tevlî bike -copying = - { $items } tê jêgirtin{ $items -> - [one] hêman - *[other] hêman - } ji "{ $from }" bo "{ $to }" ({ $progress })... -create-new-file = Pelê nû biafrîne -sort-by-trashed = Li gorî demê rêz bike -support = Piştgirî -try-again = Dîsa hewl bide -eject = Biavêje -copied = - { $items } hate jêgirtin { $items -> - [one] hêman - *[other] hêman - } ji "{ $from }" bo "{ $to }" -open-in-new-window = Di çarçoveyeke nû de veke -empty-folder = Peldanka vala -empty-trash = Jêbirdankê vala bike -sort-by-modified = Li gorî guhertinê rêz bike -list-directories-first = Pêşî rêgehan lîste bike -folder-name = Navê peldankê -browse-store = { $store } bigere -remove-from-recents = Ji dawiyê rake -paste = Pêve bike -empty-trash-title = Jêbirdankê vala bike? -menu-settings = Sazkarî... -moving = - { $items } tê livandin{ $items -> - [one] hêman - *[other] hêman - } ji "{ $from }" bo "{ $to }" ({ $progress })... -change-wallpaper = Wêneyê dîwêr biguhêrîne... -network-drive-description = - Di nav navnîşanên rajekarê de pêşgira protokolekê û navnîşanek heye. - Mînak: ssh://192.168.0.1, ftp://[2001:db8::1] -deleting = - { $items } tê jêbirin { $items -> - [one] hêman - *[other] hêman - } ji { trash } ({ $progress })... -single-click = Tikandina yekane bo vekriinê -view = Dîtin -setting-permissions = Maf tên sazkirin ji bo "{ $name }" bo { $mode } -creating = "{ $name }" tê afirandin di "{ $parent }" de -execute-only = Tenê xebitandin -open-item-location = Cihê hêmanê veke -type-to-search = Bo lêgerînê binivîse -set-executable-and-launched = "{ $name }" wekî pelê xebitandinê hat sazkirin û xebitandin -mounted-drives = Ajokarên siwarkirî -sort-a-z = A-Z -mount-error = Nikare bigihêje ajokerê -extract-here = Derxîne -grid-view = Dîtina torê -add-to-sidebar = Tevlî benda kêlekê bike -dark = Tarî -notification-in-progress = Pêvajoyên pelê didome -home = Rûpela sereke -sort-z-a = Z-A -type-to-search-recursive = Di peldank û binpeldankên heyî de digere -history = Dîrok -progress-paused = { $percent }%, hate rawestandin -desktop-view-options = Vebijêrkên dîtina sermaseyê... -show-on-desktop = Li ser sermaseyê nîşan bide -cancelled = Têkbirî -new-folder = Peldankan nû... -match-desktop = Li gorî sermaseyê -name-no-slashes = Nav nabe ku "/" tê de hebe -operations-running-finished = - { $running } { $running -> - [one] pêvajo - *[other] pêvajo - } dixebite ({ $percent }%), { $finished } qediya... -sort-by-name = Li gorî navê rêz bike -edit-history = Dîrokê biguhêrînê -show-hidden-files = Pelên veşartî nîşan bide -progress-failed = { $percent }%, têk çû -trash-folder-icon = Îkona peldanka jêbirdankê -extract-to-title = Derxîne bo peldankê -icon-size = Mezinahiya îkonê -open-with-title = Tu çawa dixwazî "{ $name }" vekî? -extracting = - { $items } tê derxistin { $items -> - [one] hêman - *[other] hêman - } ji "{ $from }" bo"{ $to }" ({ $progress })... -settings = Sazkarî -complete = Qediya -permanently-delete-question = Bi mayînde jê bibe? -extract-password-required = Borînpeyv pêdivî ye -pending = Li bendê ye -desktop-folder-content = Naveroka peldanka sermaseyê -no-history = Tu hêman di dîrok de tune ne. -open-folder = Peldankê veke -emptied-trash = { trash } hate valakirin -rename-file = Navê pelê biguherîne -sort-largest-to-smallest = Mezintir bo biçûktir -restore-from-trash = Ji jêbirdankê vegerîne -cut = Jê bike -moved = - { $items } hate livandin { $items -> - [one] hêman - *[other] hêman - } ji "{ $from }" bo "{ $to }" -progress-cancelled = { $percent }%, hat têkbirin -open-in-new-tab = Di rûgerê nû de veke -file = Pel -file-name = Navê pelê -save-file = Pelê tomar bike -created = "{ $name }" hate afirandin di "{ $parent }" de -delete-permanently = Bi mayînde jê bibe -display-settings = Sazkariyên dîmenderê... -new-tab = Rûgera nû -failed = Têk çû -name-invalid = Nav nabe ku \"{ $filename }\" be -desktop-appearance = Xuyanga sermaseyê... -comment = Rêveberê pelê ji bo sermaseya COSMIC -keywords = Rêveber;Peldank; -filesystem = Pergala pelê -networks = Tor -recents = Dawî -open = Veke -cancel = Têk bibe -trash = Jêbirdank -undo = Vegerîne -today = Îro -name = Nav -modified = Guhertî -size = Mezinahî -details = Hûrgilî -pause = Rawestîne -resume = Bidomîne -copy-to-title = Rêgeha jêgirtinê hilbijêre -copy-to-button-label = Jê bigire -move-to-title = Rêgeha livandinê hilbijêre -move-to-button-label = Bilivîne -create = Biafrîne -save = Tomar bike -context-action = Çalakiya naverokê -context-action-confirm-title = "{ $name }" bixebtîne? -context-action-confirm-warning = - Ev ê li ser { $items } { $items -> - [one] hêman - *[other] hêman - } bixebite. -run = Bixebitîne -selected-items = { $items } hêmanên hilbijartî -delete = Jê bibe -rename-confirm = Navê biguherîne -pasted-image = Wêneya pêvekirî -pasted-text = Nivîsa pêvekirî -pasted-video = Vîdiyoya pêvekirî -copy-path = Rêgehê jê bigire -show-recents = Peldanka dawî di benda kêlekê de -clear-recents-history = Dîroka dawî pak bike -compress = Biguvşîne... -copy-to = Jê bigire bo... -move-to = Bilivîne bo... -default-app = { $name } (berdest) -renamed = Nav hate guhertin ji "{ $from }" bo "{ $to }" -read-execute = Xwendin û xebitandin -item-modified = Guhertin: { $modified } -reload-folder = Peldankê ji nû ve bar bike -restoring = - { $items } tê vegerandin { $items -> - [one] hêman - *[other] hêman - } ji { trash } ({ $progress })... -icon-size-and-spacing = Mezinahiya îkonan û valahiya di navbera wan de -type-to-search-enter-path = Riya rêgehê yan jî pelê têdixîne -menu-open-with = Veke bi... -original-file = Pelê resen -read-write-execute = Xwendin, nivîsandin û xebitandin -calculating = Tê jimartin... -item-size = Mezinahî: { $size } -connecting = Tê girêdan... -read-write = Xwendin û nivîsandin -items = Hêman: { $items } -type = Cûre: { $mime } -replace-warning = Tu dixwazî bi ya ku tu niha tomar dikî biguhêrînî? Naveroka berê wê were jêbirin. -show-details = Hûrgiliyan nîşan bide -grid-spacing = Valahiya torê -sort-oldest-first = Pêşî ya herî kevn -repository = Embar -replace-warning-operation = Tu dixwazî biguherînî? Naveroka berê wê were jêbirin. -other = Ên din -read-only = Tenê xwendin -enter-server-address = Navnîşana rajekarê têxîne -connect-anonymously = Bi awayekî anonîm girê bide -group = Kom -apply-to-all = Bo hemûyan bisepîne -skip = Derbas bike -replace-with = Biguhêrîne bi -owner = Xwedî -set-and-launch = Saz bike û dest pê bike -removed-from-recents = - { $items } hate rakirin { $items -> - [one] hêman - *[other] hêman - } ji { recents } -item-created = Afirandin:{ $created } -network-drive-schemes = - Protokolên berdest,pêşgirê - AppleTalk,afp:// - Protokola şandina pelê,ftp:// an ftps:// - Pergala pelê torê,nfs:// - Astengiya peyama rajekarê,smb:// - SSH protokola şandina pelê,sftp:// an ssh:// - WebDAV, dav:// an davs:// -set-executable-and-launch = Wekî pelê xebitandinê saz bike û bixebitîne -restored = - { $items } hate vegerandin { $items -> - [one] hêman - *[other] hêman - } ji { trash } -domain = Navper -sort = Rêz bike -item-accessed = Gihîştin: { $accessed } -open-with = Veke bi -keep-both = Herduyan bihêle -permanently-deleted = - { $items } bi mayînde hate jêbirin{ $items -> - [one] hêman - *[other] hêman - } -write-execute = Nivîsandin û xebitandin -renaming = Navê ji "{ $from }" biguhêrîne bo "{ $to }" -set-executable-and-launch-description = Tu dixwazî "{ $name }" wekî pelê xebitandinê saz bikî û bixebtînî? -replace = Biguhêrîne -replace-title = "{ $filename }" jixwe di vê cihê de heye -unknown-folder = Peldanka nenas -write-only = Tenê nivîsandin -trashed-on = Li Jêbirdankê hatiye avêtin -mixed = Tevlihev -type-to-search-select = Pel an peldanka yekem a lihevhatî hildibijêre diff --git a/i18n/ko/cosmic_files.ftl b/i18n/ko/cosmic_files.ftl index 5683c39..3a9f2f6 100644 --- a/i18n/ko/cosmic_files.ftl +++ b/i18n/ko/cosmic_files.ftl @@ -277,4 +277,3 @@ copy-to-button-label = 복사 move-to-button-label = 이동 clear-recents-history = 최근 기록 비우기 copy-path = 복사 경로 -move-to-title = 이동 위치 선택 diff --git a/i18n/lo/cosmic_files.ftl b/i18n/lo/cosmic_files.ftl deleted file mode 100644 index e69de29..0000000 diff --git a/i18n/lt/cosmic_files.ftl b/i18n/lt/cosmic_files.ftl index 2a8e36f..acceb7c 100644 --- a/i18n/lt/cosmic_files.ftl +++ b/i18n/lt/cosmic_files.ftl @@ -1,5 +1,5 @@ progress = { $percent }% -cosmic-files = COSMIC Failai +cosmic-files = Cosmic Files empty-folder = Tuščias aplankas empty-folder-hidden = Tuščias aplankas (turi paslėptų failų) no-results = Rezultatų nėra @@ -76,7 +76,7 @@ delete = Ištrinti permanently-delete-warning = { $target } bus ištrintas visam laikui. Šis veiksmas yra negrįžtamas. rename-file = Pervadinti failą rename-folder = Pervadinti aplanką -replace = Keisti +replace = Pakeisti replace-title = „{ $filename }“ jau egzistuoja šioje vietoje replace-warning = Ar norite pakeisti tai su tuo, kas yra įrašoma? Keičiant bus pakeistas turinys. replace-warning-operation = Ar norite pakeisti tai? Pakeičiant bus keičiamas turinys. @@ -244,7 +244,7 @@ item-created = Sukurtas: { $created } item-modified = Modifikuota: { $modified } item-accessed = Paskutinė prieiga: { $accessed } calculating = Skaičiuojama... -settings = Nuostatos +settings = Nustatymai single-click = Vieno paspaudimo atidarymas appearance = Išvaizda match-desktop = Pagal darbalaukio temą @@ -280,18 +280,18 @@ quit = Išeiti edit = Redaguoti cut = Iškirpti copy = Kopijuoti -paste = Įdėti -select-all = Žymėti viską -zoom-in = Artinti +paste = Įklijuoti +select-all = Pažymėti viską +zoom-in = Priartinti default-size = Numatytas dydis -zoom-out = Tolinti +zoom-out = Nutolinti view = Rodymas grid-view = Tinklelio išdėstymas list-view = Sąrašo išdėstymas show-hidden-files = Rodyti paslėptus failus list-directories-first = Pirmiau pateikti aplankus gallery-preview = Galerijos peržiūra -menu-settings = Nuostatos... +menu-settings = Nustatymai... menu-about = Apie COSMIC Files... sort = Rikiuoti sort-a-z = A-Ž @@ -302,7 +302,7 @@ sort-smallest-to-largest = Nuo mažiausio iki didžiausio sort-largest-to-smallest = Nuo didžiausio iki mažiausio dark = Tamsus light = Šviesus -comment = COSMIC aplinkos failų tvarkyklė +comment = COSMIC desktop failų tvarkyklė keywords = Aplankas;Tvarkyklė; copy-to-title = Pasirinkti kopijavimo vietą copy-to-button-label = Kopijuoti @@ -317,4 +317,3 @@ clear-recents-history = Išvalyti Neseniai naudotų istoriją copy-to = Kopijuoti į... move-to = Perkeltiį į... copy-path = Kopijuoti kelią -theme = Stilius diff --git a/i18n/nb-NO/cosmic_files.ftl b/i18n/nb-NO/cosmic_files.ftl index cae2b5b..e0fb82c 100644 --- a/i18n/nb-NO/cosmic_files.ftl +++ b/i18n/nb-NO/cosmic_files.ftl @@ -98,7 +98,7 @@ permanently-delete-question = Slett permanent permanently-delete-warning = Er du sukker på om du vil permanent slette { $target }? Dette kan ikke angres. rename-file = Endre filnavn rename-folder = Endre mappenavn -replace-title = «{ $filename }» finnes allerede på denne plasseringen +replace-title = "{ $filename }" finnes allerede på denne plasseringen. replace-warning = Vil du bytte den ut med filen du lagrer? Dette vil overskrive innholdet. replace-warning-operation = Vil du erstatte den? Dette vil overskrive innholdet. original-file = Orginalfil @@ -122,8 +122,8 @@ read-write = Kun skrive- og lesbar read-write-execute = Lesbar, skrivbar og kjørbar favorite-path-error = Feil ved åpning av mappen favorite-path-error-description = - Klarte ikke åpne «{ $path }». - «{ $path }» finnes ikke eller så har du ikke tilgang til å åpne den. + Kunne ikke åpne "{ $path }". + Den kan ikke eksistere eller så har du ikke tilgang til å åpne den. Vil du fjerne den fra sidepanelet? keep = Behold @@ -140,7 +140,7 @@ zoom-out = Zoom ut cut = Klipp ut set-and-launch = Still inn og start domain = Domene -enter-server-address = Angi tjeneradresse +enter-server-address = Angi serveradresse network-drive-description = Serveradresser inkluderer ett protokollprefiks og en addresse. Examples: ssh://192.168.0.1, ftp://[2001:db8::1] diff --git a/i18n/pl/cosmic_files.ftl b/i18n/pl/cosmic_files.ftl index 2f58d64..b0bc7a8 100644 --- a/i18n/pl/cosmic_files.ftl +++ b/i18n/pl/cosmic_files.ftl @@ -438,12 +438,3 @@ show-recents = Ostatnie katalogi w panelu bocznym clear-recents-history = Wyczyść bierzącą historię copy-path = Skopiuj ścieżkę mixed = Mieszane -context-action = Akcja sytuacyjna -context-action-confirm-title = Uruchomić "{ $name }"? -context-action-confirm-warning = - Zostanie uruchomionych { $items } { $items -> - [one] element - *[other] elementów - }. -run = Uruchom -rename-confirm = Zmień nazwę diff --git a/i18n/pt-BR/cosmic_files.ftl b/i18n/pt-BR/cosmic_files.ftl index 6309e46..86ebd88 100644 --- a/i18n/pt-BR/cosmic_files.ftl +++ b/i18n/pt-BR/cosmic_files.ftl @@ -437,12 +437,3 @@ show-recents = Pasta de recentes na barra lateral clear-recents-history = Limpar histórico de recentes copy-path = Copiar caminho mixed = Misto -context-action = Ação de contexto -context-action-confirm-title = Executar "{ $name }"? -context-action-confirm-warning = - Isso será executado em { $items } { $items -> - [one] item - *[other] itens - }. -run = Executar -rename-confirm = Renomear diff --git a/i18n/pt/cosmic_files.ftl b/i18n/pt/cosmic_files.ftl index b0c7e30..33921f1 100644 --- a/i18n/pt/cosmic_files.ftl +++ b/i18n/pt/cosmic_files.ftl @@ -1,12 +1,12 @@ cosmic-files = Ficheiros COSMIC comment = Gerenciador de arquivos do COSMIC -keywords = Pasta;Gestor; +keywords = Pastas;Gerenciador;Arquivos;Gestor;Explorer; empty-folder = Pasta vazia empty-folder-hidden = Pasta vazia (tem ficheiros ocultos) no-results = Nenhum resultado encontrado filesystem = Sistema de ficheiros home = Pasta Pessoal -notification-in-progress = Operações em curso +notification-in-progress = Operações em curso. trash = Lixo undo = Anular # List view @@ -204,7 +204,7 @@ desktop-view-options = Opções de visualização da área de trabalho... show-on-desktop = Mostrar na área de trabalho desktop-folder-content = Conteúdo da pasta da área de trabalho mounted-drives = Dispositivos montados -trash-folder-icon = Ícone da pasta lixo +trash-folder-icon = Ícone do lixo icon-size-and-spacing = Tamanho e espaçamento do ícone icon-size = Tamanho do ícone grid-spacing = Espaçamento entre ícones @@ -352,6 +352,3 @@ sort-newest-first = Mais recentes primeiro sort-oldest-first = Mais antigos primeiro sort-smallest-to-largest = Do menor para o maior sort-largest-to-smallest = Do maior para o menor -context-action-confirm-title = Executar "{ $name }"? -run = Executar -rename-confirm = Renomear diff --git a/i18n/ru/cosmic_files.ftl b/i18n/ru/cosmic_files.ftl index f34a377..e9673f1 100644 --- a/i18n/ru/cosmic_files.ftl +++ b/i18n/ru/cosmic_files.ftl @@ -381,12 +381,3 @@ show-recents = «Недавние документы» в бок. панели clear-recents-history = Очистить историю недавних copy-path = Копировать путь mixed = Смешанные -context-action = Контекстная команда -context-action-confirm-title = Выполнить «{ $name }»? -context-action-confirm-warning = - Команда затронет { $items } { $items -> - [one] элемент - *[other] элем. - }. -run = Выполнить -rename-confirm = Переименовать diff --git a/i18n/sr/cosmic_files.ftl b/i18n/sr/cosmic_files.ftl index 98a9e35..e69de29 100644 --- a/i18n/sr/cosmic_files.ftl +++ b/i18n/sr/cosmic_files.ftl @@ -1,330 +0,0 @@ -open-file = Отвори датотеку -quit = Изађи -cancel = Откажи -open = Отвори -run = Покрени -connect = Повежи -save = Сачувај -password = Лозинка -remove = Уклони -appearance = Изглед -username = Корисничко име -light = Светла -dark = Тамна -settings = Подешавања -replace = Замени -size = Величина -sort-newest-first = Најновије прво -default-app = { $name } (подразумевано) -renamed = Преименована „{ $from }“ у „{ $to }“ -read-execute = Читање и извршавање -deleted = - Обрисано је { $items } { $items -> - [one] ставка - *[other] ставки - } из { trash } -item-modified = Измењено: { $modified } -dismiss = Одбаци поруку -list-view = Преглед у виду списака -reload-folder = Поново учитај фасциклу -copy_noun = Копија -favorite-path-error = Грешка при отварању директоријума -progress = { $percent }% -remove-from-sidebar = Уклони из бочне траке -related-apps = Повезани програми -restoring = - Враћање { $items } { $items -> - [one] ставке - *[other] ставки - } из { trash } ({ $progress })... -network-drive-error = Немогуће приступити мрежном уређају -gallery-preview = Преглед галерије -sort-smallest-to-largest = Од најмање до највеће -zoom-in = Увећајте приказ -select-all = Означи све -icon-size-and-spacing = Величина и размак иконица -removing-from-recents = - Уклањање { $items } { $items -> - [one] ставке - *[other] ставки - } из { recents } -cosmic-files = Космик датотеке -type-to-search-enter-path = Уноси путању до директоријума или датотеке -trash = Смеће -emptying-trash = Пражњење { trash } ({ $progress })... -trashed-on = Премештено у смеће -new-window = Нови прозор -zoom-out = Умањите приказ -compressing = - Сажимање { $items } { $items -> - [one] ставке - *[other] ставки - } из „{ $from }“ у „{ $to }“ ({ $progress })... -move-to-trash = Премести у смеће -menu-about = О програму Космик Датотеке... -setting-executable-and-launching = Подешавање „{ $name }“ као извршне датотеке и покретање -open-multiple-files = Отвори више датотека -default-size = Подразумевана величина -menu-open-with = Отвори програмом... -extracted = - Извлачено { $items } { $items -> - [one] ставка - *[other] ставки - } из „{ $from }“ у „{ $to }“ -create-new-folder = Направи нову фасциклу -original-file = Изворна датотека -create = Направи -create-archive = Направи архиву -read-write-execute = Читање, уписивање и извршавање -other-apps = Остали програми -set-permissions = Овлашћења за „{ $name }“ су постављена на { $mode } -pause = Паузирај -calculating = Израчунавам… -sort-by-size = Поређај по величини -rename = Преименуј... -empty-folder-hidden = Празна фасцикла (има сакривених ставки) -keep = Задржи -item-size = Величина: { $size } -permanently-deleting = - Трајно брисање { $items } { $items -> - [one] ставке - *[other] ставки - } -edit = Уреди -connecting = Повезујем се... -read-write = Читање и уписивање -copy = Умножи -none = Ништа -items = Ставки: { $items } -no-results = Нису пронађени резултати -theme = Тема -type = Врста: { $mime } -compressed = - Сажето { $items } { $items -> - [one] ставка - *[other] ставки - } из „{ $from }“ у „{ $to }“ -replace-warning = Да ли желите да га замените оним који снимате? Замена ће преписати његов садржај. -rename-folder = Преименуј фасциклу -new-file = Нова датотека... -close-tab = Затвори језичак -name = Назив -open-in-terminal = Отвори у терминалу -resume = Настави -open-multiple-folders = Отвори више фасцикла -remember-password = Запамти лозинку -show-details = Прикажи детаље -grid-spacing = Размак мреже -extract-to = Распакуј у... -add-network-drive = Додај мрежни уређај -copying = - Умножавање { $items } { $items -> - [one] ставке - *[other] ставки - } из „{ $from }“ у „{ $to }“ ({ $progress })... -delete = Обриши -sort-oldest-first = Најстарије прво -repository = Ризница -create-new-file = Направи нову датотеку -sort-by-trashed = Поређај по времену брисања -replace-warning-operation = Да ли желите да га замените? Замена ће преписати његов садржај. -support = Подршка -try-again = Покушај поново -eject = Избаци -copied = - Умножено { $items } { $items -> - [one] ставке - *[other] ставки - } из „{ $from }“ у „{ $to }“ -other = Друго -open-in-new-window = Отвори у новом прозору -empty-folder = Празна фасцикла -sort-by-modified = Поређај по датуму измене -list-directories-first = Прикажи директоријуме прво -read-only = Само за читање -folder-name = Назив фасцикле -browse-store = Разгледај { $store } -enter-server-address = Унесите адресу сервера -remove-from-recents = Уклони из недавних -connect-anonymously = Повежи се анонимно -group = Група -apply-to-all = Примени на све -skip = Прескочи -paste = Залепи -menu-settings = Подешавања... -moving = - Премештање { $items } { $items -> - [one] датотеке - *[other] датотека - } из „{ $from }“ у „{ $to }“ ({ $progress })... -replace-with = Замени са -recents = Недавно -change-wallpaper = Промени позадину... -network-drive-description = - Адресе сервера укључују префикс протокола и адресу. - Примери: ssh://192.168.0.1, ftp://[2001:db8::1] -deleting = - Брише се { $items } { $items -> - [one] ставка - *[other] ставки - } из { trash } ({ $progress })... -single-click = Један клик за отварање -view = Преглед -undo = Опозови -setting-permissions = Подешавање овлашћења за „{ $name }“ на { $mode } -owner = Власник -creating = Правим „{ $name }“ у „{ $parent }“ -execute-only = Само извршавање -open-item-location = Отвори локацију ставке -details = Детаљи -set-executable-and-launched = Постављено „{ $name }“ као извршну датотеку и покренуто -mounted-drives = Прикључени дискови -sort-a-z = А-Ш -mount-error = Немогуће приступити уређају -extract-here = Извуци -grid-view = Преглед у виду мреже -filesystem = Систем датотека -set-and-launch = Подеси и покрени -removed-from-recents = - Уклоњено { $items } { $items -> - [one] ставке - *[other] ставки - } из { recents } -add-to-sidebar = Додај у страничник -item-created = Направљено: { $created } -network-drive-schemes = - Доступни протоколи,Префикс - ЕплТок,afp:// - Протокол за пренос датотека,ftp:// или ftps:// - Мрежни систем датотека,nfs:// - Серверски блок порука,smb:// - SSH протокол за пренос датотека,sftp:// или ssh:// - ВебДАВ,dav:// или davs:// -home = Лична -set-executable-and-launch = Постави као извршну и покрени -restored = - Враћено { $items } { $items -> - [one] ставка - *[other] ставки - } из { trash } -sort-z-a = Ш-А -type-to-search-recursive = Претражује тренутну фасциклу и све подфасцикле -history = Историјат -progress-paused = { $percent }%, паузирано -desktop-view-options = Могућности приказа радне површине... -show-on-desktop = Прикажи на радној површини -cancelled = Отказано -new-folder = Нова фасцикла... -match-desktop = Прати радну површину -domain = Домен -operations-running-finished = - { $running } { $running -> - [one] радња покренута - *[other] радње покренуте - } ({ $percent }%), { $finished } завршено... -sort-by-name = Поређај по називу -edit-history = Историјат уређивања -sort = Поређај -show-hidden-files = Прикажи скривене датотеке -progress-failed = { $percent }%, није успело -trash-folder-icon = Иконица фасцикле Смеће -item-accessed = Приступљено: { $accessed } -extract-to-title = Распакуј у фасциклу -open-with = Отвори помоћу -keep-both = Задржи оба -icon-size = Величина иконице -open-with-title = Како желите да отворите „{ $name }“? -extracting = - Извлачење { $items } { $items -> - [one] ставке - *[other] ставки - } из „{ $from }“ у „{ $to }“ ({ $progress })... -permanently-deleted = - Трајно обрисано { $items } { $items -> - [one] ставке - *[other] ставки - } -complete = Завршено -write-execute = Писање и извршавање -extract-password-required = Потребна је лозинка -pending = У току -desktop-folder-content = Садржај фасцикле радне површине -renaming = Преименовање „{ $from }“ у „{ $to }“ -set-executable-and-launch-description = Да ли желите да поставите „{ $name }“ као извршну и покренете је? -no-history = Нема ставки у историјату. -open-folder = Отвори фасциклу -emptied-trash = Опражњено { trash } -rename-file = Преименуј датотеку -sort-largest-to-smallest = Од највеће до најмање -restore-from-trash = Врати из смећа -cut = Исеци -moved = - Премештено { $items } { $items -> - [one] датотеке - *[other] датотека - } из „{ $from }“ у „{ $to }“ -progress-cancelled = { $percent }%, отказано -open-in-new-tab = Отвори у новом језичку -unknown-folder = непозната фасцикла -file = Датотека -file-name = Назив датотеке -save-file = Сачувај датотеку -created = Направљено „{ $name }“ у „{ $parent }“ -delete-permanently = Трајно обриши -networks = Мреже -write-only = Само писање -today = Данас -display-settings = Подешавања екрана... -new-tab = Нови језичак -failed = Неуспешно -modified = Измењено -desktop-appearance = Изглед радне површине... -file-already-exists = Датотека са овим називом већ постоји -name-hidden = Називи који почињу тачком „.“ ће бити сакривени -folder-already-exists = Фасцикла са овим називом већ постоји -permanently-delete-warning = { $target } ће бити трајно обрисано. Ова радња се не може поништити. -favorite-path-error-description = - Не можемо да отворимо „{ $path }“ - „{ $path }“ можда не постоји или немате дозволу за његово отварање - - Желите ли да га уклоните из бочне површи? -empty-trash-warning = Ставке у смећу биће трајно обрисане -empty-trash = Испразни смеће -empty-trash-title = Испразнити смеће? -type-to-search = Куцајте за претрагу -notification-in-progress = Радње са датотекама су у току -name-no-slashes = Назив не може садржати косе црте -permanently-delete-question = Трајно обриши? -replace-title = „{ $filename }“ већ постоји на овој локацији -name-invalid = Назив не може бити „{ $filename }“ -operations-running = - { $running } { $running -> - [one] радња покренута - *[other] радње покренуте - } ({ $percent }%)... -comment = Управник датотека за Космик радну површину -keywords = Folder;Manager;Фасцикла;Управник;fascikla;upravnik; -copy-to-title = Изабери одредиште умножавања -copy-to-button-label = Умножи -move-to-title = Изабери одредиште премештања -move-to-button-label = Помери -context-action = Контекстна радња -context-action-confirm-title = Покрени „{ $name }“? -context-action-confirm-warning = - Ово ће се извршити на { $items } { $items -> - [one] ставку - *[other] ставки - }. -selected-items = Изабраних { $items } ставки -mixed = Помешано -pasted-image = Убачена слика -pasted-text = Убачен текст -pasted-video = Убачен видео -show-recents = Недавна фасцикла у бочној површи -type-to-search-select = Обира прву подударајућу датотеку или фасциклу -clear-recents-history = Очисти историју недавних -compress = Сажми... -copy-to = Умножи у... -move-to = Помери у... -copy-path = Умножи путању -rename-confirm = Преименуј diff --git a/i18n/sv/cosmic_files.ftl b/i18n/sv/cosmic_files.ftl index 506be0b..cbd28dd 100644 --- a/i18n/sv/cosmic_files.ftl +++ b/i18n/sv/cosmic_files.ftl @@ -410,12 +410,3 @@ move-to = Flytta till... show-recents = Mapp för senast använda filer i sidofältet clear-recents-history = Töm historik för Senaste copy-path = Kopiera sökväg -context-action = Kontextåtgärd -context-action-confirm-title = Kör "{ $name }"? -context-action-confirm-warning = - Detta kommer att köras på { $items } { $items -> - [one] objekt - *[other] objekt - }. -run = Kör -rename-confirm = Byt namn diff --git a/i18n/uk/cosmic_files.ftl b/i18n/uk/cosmic_files.ftl index 31b4103..611c2b1 100644 --- a/i18n/uk/cosmic_files.ftl +++ b/i18n/uk/cosmic_files.ftl @@ -5,7 +5,7 @@ filesystem = Файлова система home = Домівка trash = Смітник recents = Нещодавні -undo = Скасувати +undo = Відмінити # List view name = Назва modified = Змінено @@ -82,11 +82,10 @@ copying = Копіювання { $items } { $items -> [one] елемента *[other] елементів - } з «{ $from }» до «{ $to }» ({ $progress })... + } з «{ $from }» в «{ $to }» ({ $progress })... copied = Скопійовано { $items } { $items -> [one] елемент - [few] елементи *[other] елеменів } з «{ $from }» в «{ $to }» emptying-trash = Спорожнення { trash } ({ $progress })... @@ -95,12 +94,11 @@ moving = Переміщення { $items } { $items -> [one] елемента *[other] елементів - } з «{ $from }» до «{ $to }» ({ $progress })... + } з «{ $from }» в «{ $to }» ({ $progress })... moved = Переміщено { $items } { $items -> [one] елемент - [few] елементи - *[other] елементів + *[other] елементи } з «{ $from }» в «{ $to }» renaming = Перейменування «{ $from }» на «{ $to }» renamed = Перейменовано «{ $from }» на «{ $to }» @@ -112,8 +110,7 @@ restoring = restored = Відновлено { $items } { $items -> [one] елемент - [few] елементи - *[other] елементів + *[other] елементи } з { trash } unknown-folder = невідома тека @@ -226,7 +223,7 @@ permanently-delete-question = Остаточно видалити? delete = Видалити permanently-delete-warning = { $target } буде остаточно видалено. Цю дію не можна скасувати. set-executable-and-launch = Зробити виконуваним і запустити -set-executable-and-launch-description = Бажаєте зробити «{ $name }» виконуваним і запустити його? +set-executable-and-launch-description = Бажаєте зробити "{ $name }" виконуваним і запустити його? set-and-launch = Зробити і запустити open-with = Відкрити за допомогою owner = Власник @@ -248,7 +245,7 @@ favorite-path-error-description = Вилучити з бічної панелі? keep = Залишити add-network-drive = Додати мережевий диск -connect = З’єднати +connect = З'єднати connect-anonymously = З'єднатись анонімно connecting = З'єднання… domain = Домен @@ -277,13 +274,12 @@ compressing = Стиснення { $items } { $items -> [one] елемента *[other] елементів - } з «{ $from }» до «{ $to }» ({ $progress })... + } з "{ $from }" до "{ $to }" ({ $progress })... compressed = Стиснуто { $items } { $items -> [one] елемент - [few] елементи - *[other] елементів - } з «{ $from }» до «{ $to }» + *[other] елементи + } з "{ $from }" до "{ $to }" deleting = Видалення { $items } { $items -> [one] елемента @@ -292,19 +288,17 @@ deleting = deleted = Видалено { $items } { $items -> [one] елемент - [few] елементи *[other] елементи } з { trash } extracting = Видобування { $items } { $items -> [one] елемента *[other] елементів - } з «{ $from }» до «{ $to }» ({ $progress })... + } з «{ $from }» в «{ $to }» ({ $progress })... extracted = Видобуто { $items } { $items -> [one] елемент - [few] елементи - *[other] елементів + *[other] елементи } з «{ $from }» в «{ $to }» setting-executable-and-launching = Надання «{ $name }» прав на виконання та запуск set-executable-and-launched = «{ $name }» надано права на виконання і відкрито @@ -349,8 +343,7 @@ permanently-deleting = permanently-deleted = Остаточно вилучено { $items } { $items -> [one] елемент - [few] елементи - *[other] елементів + *[other] елементи } removing-from-recents = Вилучення { $items } { $items -> @@ -360,14 +353,13 @@ removing-from-recents = removed-from-recents = Вилучено { $items } { $items -> [one] елемент - [few] елементи - *[other] елементів + *[other] елементи } з { recents } empty-trash-title = Спорожити смітник? -type-to-search-select = Вибирає перший відповідний файл або теку -pasted-image = Вставлене зображення -pasted-text = Вставлений текст -pasted-video = Вставлене видиво +type-to-search-select = Вибирає перший відповідний файл або папку +pasted-image = Вставлене Зображення +pasted-text = Вставлений Текст +pasted-video = Вставлене Видиво copy-to-button-label = Копіювати move-to-button-label = Перемістити copy-to = Копіювати до… @@ -379,13 +371,3 @@ keywords = Тека;Папка;Провідник;Менеджер;Катало show-recents = Тека «Нещодавні» на бічній панелі copy-path = Копіювати шлях clear-recents-history = Очистити нещодавні -context-action-confirm-title = Запустити «{ $name }»? -run = Виконати -context-action-confirm-warning = - Запуститься для { $items } { $items -> - [one] елемента - *[other] елементів - }. -context-action = Контекстна дія -rename-confirm = Перейменувати -mixed = Змішано diff --git a/i18n/zh-CN/cosmic_files.ftl b/i18n/zh-CN/cosmic_files.ftl index 4807c4a..11441d1 100644 --- a/i18n/zh-CN/cosmic_files.ftl +++ b/i18n/zh-CN/cosmic_files.ftl @@ -167,7 +167,7 @@ read-write-execute = 读取、写入和执行 ## Favorite Path Error Dialog -favorite-path-error = 打开目录时出错 +favorite-path-error = 打开路径时出错 favorite-path-error-description = 无法打开 "{ $path }" 。 "{ $path }" 可能不存在或您没有权限打开它。 @@ -348,7 +348,7 @@ light = 亮色模式 type-to-search = 输入即可搜索 type-to-search-recursive = 搜索当前文件夹及其所有子文件夹 -type-to-search-enter-path = 输入文件夹或文件目录 +type-to-search-enter-path = 输入文件夹或文件路径 # Context menu add-to-sidebar = 加入侧边栏 compress = 压缩… @@ -437,12 +437,3 @@ clear-recents-history = 清除最近访问历史 copy-path = 复制文件路径 show-recents = 侧边栏中的最近访问 mixed = 混合 -context-action-confirm-title = 运行 “{ $name }” ? -run = 运行 -context-action-confirm-warning = - 该行动将会在 { $items } { $items -> - [one] 项目 - *[other] 项目 - } 上运行。 -context-action = 环境行动 -rename-confirm = 重命名 diff --git a/i18n/zh-TW/cosmic_files.ftl b/i18n/zh-TW/cosmic_files.ftl index 294ed2a..2bf8e5b 100644 --- a/i18n/zh-TW/cosmic_files.ftl +++ b/i18n/zh-TW/cosmic_files.ftl @@ -42,7 +42,7 @@ name-no-slashes = 名稱不能包含斜線 ## Open/Save Dialog cancel = 取消 -create = 建立 +create = 創作 open = 開啟 open-file = 開啟檔案 open-folder = 開啟資料夾 @@ -358,7 +358,7 @@ calculating = 計算中... single-click = 點按以開啟 type-to-search = 輸入進行搜尋 type-to-search-recursive = 搜尋目前資料夾及全部子資料夾 -type-to-search-enter-path = 輸入目錄或檔案的目錄 +type-to-search-enter-path = 輸入目錄或檔案的路徑 delete-permanently = 永久刪除 eject = 彈出 remove-from-recents = 從最近項目中移除 @@ -384,12 +384,3 @@ set-executable-and-launched = 設定「{ $name }」為可以執行並已經啟 setting-permissions = 設定「{ $name }」的權限至 { $mode } set-permissions = 設定「{ $name }」的權限至 { $mode } mixed = 混合 -context-action = 環境行動 -context-action-confirm-title = 執行「{ $name }」嗎? -context-action-confirm-warning = - 該行動將會在 { $items } { $items -> - [one] 項目 - *[other] 項目 - } 上執行。 -run = 執行 -rename-confirm = 重新命名 diff --git a/justfile b/justfile index 5e8d024..9522e98 100644 --- a/justfile +++ b/justfile @@ -48,7 +48,7 @@ build-debug *args: # Compiles with release profile build-release *args: (build-debug '--release' args) - + # Compiles applet with release profile build-release-applet *args: cargo build --package {{applet-name}} --release {{args}} @@ -111,7 +111,7 @@ uninstall: vendor: #!/usr/bin/env bash mkdir -p .cargo - cargo vendor --locked --sync Cargo.toml | head -n -1 > .cargo/config.toml + cargo vendor --sync Cargo.toml | head -n -1 > .cargo/config.toml echo 'directory = "vendor"' >> .cargo/config.toml echo >> .cargo/config.toml echo '[env]' >> .cargo/config.toml diff --git a/rust-toolchain.toml b/rust-toolchain.toml deleted file mode 100644 index fb5449a..0000000 --- a/rust-toolchain.toml +++ /dev/null @@ -1,3 +0,0 @@ -[toolchain] -channel = "1.93.0" -components = ["clippy", "rustfmt"] diff --git a/rustfmt.toml b/rustfmt.toml deleted file mode 100644 index c1578aa..0000000 --- a/rustfmt.toml +++ /dev/null @@ -1 +0,0 @@ -imports_granularity = "Module" diff --git a/src/app.rs b/src/app.rs index ebd32d9..feca9c5 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,24 +1,8 @@ // Copyright 2023 System76 // SPDX-License-Identifier: GPL-3.0-only -use cosmic::app::{self, Core, Task, context_drawer}; -use cosmic::cosmic_config::{self, ConfigSet}; -use cosmic::iced::clipboard::dnd::DndAction; -use cosmic::iced::core::SmolStr; -use cosmic::iced::core::widget::operation::focusable::unfocus; -use cosmic::iced::futures::{self, SinkExt}; -use cosmic::iced::keyboard::key::Physical; -use cosmic::iced::keyboard::{Event as KeyEvent, Key, Modifiers}; #[cfg(all(feature = "wayland", feature = "desktop-applet"))] use cosmic::iced::platform_specific::shell::wayland::commands::overlap_notify::overlap_notify; -use cosmic::iced::runtime::{clipboard, task}; -use cosmic::iced::widget::button::focus; -use cosmic::iced::widget::scrollable; -use cosmic::iced::widget::scrollable::AbsoluteOffset; -use cosmic::iced::window::{self, Event as WindowEvent, Id as WindowId}; -use cosmic::iced::{ - self, Alignment, Event, Length, Rectangle, Size, Subscription, event, mouse, stream, -}; #[cfg(all(feature = "wayland", feature = "desktop-applet"))] use cosmic::iced::{ Limits, Point, @@ -30,20 +14,43 @@ use cosmic::iced::{ Anchor, KeyboardInteractivity, Layer, destroy_layer_surface, get_layer_surface, }, }; -use cosmic::widget::about::About; -use cosmic::widget::dnd_destination::DragId; -use cosmic::widget::menu::action::MenuAction; -use cosmic::widget::menu::key_bind::KeyBind; -use cosmic::widget::segmented_button::{self, Entity, ReorderEvent}; -use cosmic::widget::{self, icon, settings, space}; -use cosmic::{Application, ApplicationExt, Element, cosmic_theme, executor, style, surface, theme}; +use cosmic::{ + Application, ApplicationExt, Element, + app::{self, Core, Task, context_drawer}, + cosmic_config::{self, ConfigSet}, + cosmic_theme, executor, + iced::core::widget::operation::focusable::unfocus, + iced::runtime::{clipboard, task}, + iced::widget::{button::focus, scrollable::AbsoluteOffset}, + iced::{ + self, Alignment, Event, Length, Rectangle, Size, Subscription, + clipboard::dnd::DndAction, + core::SmolStr, + event, + futures::{self, SinkExt}, + keyboard::{Event as KeyEvent, Key, Modifiers}, + mouse, stream, + widget::scrollable, + window::{self, Event as WindowEvent, Id as WindowId}, + }, + style, surface, theme, + widget::{ + self, + about::About, + dnd_destination::DragId, + icon, + menu::{action::MenuAction, key_bind::KeyBind}, + segmented_button::{self, Entity, ReorderEvent}, + space, + }, +}; use mime_guess::Mime; -use notify_debouncer_full::notify::{self, RecommendedWatcher}; -use notify_debouncer_full::{DebouncedEvent, Debouncer, RecommendedCache, new_debouncer}; +use notify_debouncer_full::{ + DebouncedEvent, Debouncer, RecommendedCache, new_debouncer, + notify::{self, RecommendedWatcher}, +}; use rustc_hash::{FxHashMap, FxHashSet}; use slotmap::Key as SlotMapKey; -#[cfg(feature = "notify")] -use std::sync::Mutex; use std::{ any::TypeId, collections::{BTreeMap, BTreeSet, HashMap, VecDeque}, @@ -54,7 +61,7 @@ use std::{ path::{Path, PathBuf}, pin::Pin, process, - sync::{Arc, LazyLock}, + sync::{Arc, LazyLock, Mutex}, time::{self, Duration, Instant}, }; use tokio::sync::mpsc; @@ -62,33 +69,37 @@ use trash::TrashItem; #[cfg(all(feature = "wayland", feature = "desktop-applet"))] use wayland_client::{Proxy, protocol::wl_output::WlOutput}; -use crate::clipboard::{ - ClipboardCache, ClipboardCopy, ClipboardKind, ClipboardPaste, ClipboardPasteImage, - ClipboardPasteText, ClipboardPasteVideo, +use crate::{ + FxOrderMap, + clipboard::{ + ClipboardCache, ClipboardCopy, ClipboardKind, ClipboardPaste, ClipboardPasteImage, + ClipboardPasteText, ClipboardPasteVideo, + }, + config::{ + AppTheme, Config, DesktopConfig, Favorite, IconSizes, State, TIME_CONFIG_ID, TabConfig, + TimeConfig, TypeToSearch, + }, + context_action, + dialog::{Dialog, DialogKind, DialogMessage, DialogResult, DialogSettings}, + fl, home_dir, + key_bind::key_binds, + localize::LANGUAGE_SORTER, + menu, + mime_app::{self, MimeApp, MimeAppCache}, + mime_icon, + mounter::{MOUNTERS, MounterAuth, MounterItem, MounterItems, MounterKey, MounterMessage}, + operation::{ + Controller, Operation, OperationError, OperationErrorType, OperationSelection, + ReplaceResult, copy_unique_path, + }, + spawn_detached::spawn_detached, + tab::{ + self, HOVER_DURATION, HeadingOptions, ItemMetadata, Location, SORT_OPTION_FALLBACK, + SearchLocation, Tab, + }, + trash::{Trash, TrashExt}, + zoom::{zoom_in_view, zoom_out_view, zoom_to_default}, }; -use crate::config::{ - AppTheme, Config, DesktopConfig, Favorite, IconSizes, State, TIME_CONFIG_ID, TabConfig, - TimeConfig, ToolbarAction, TypeToSearch, default_toolbar, -}; -use crate::dialog::{Dialog, DialogKind, DialogMessage, DialogResult, DialogSettings}; -use crate::key_bind::key_binds; -use crate::localize::LANGUAGE_SORTER; -use crate::mime_app::{self, MimeApp, MimeAppCache, MimeAppMatch}; -use crate::mounter::{ - MOUNTERS, MounterAuth, MounterItem, MounterItems, MounterKey, MounterMessage, -}; -use crate::operation::{ - Controller, Operation, OperationError, OperationErrorType, OperationSelection, ReplaceResult, - copy_unique_path, -}; -use crate::spawn_detached::spawn_detached; -use crate::tab::{ - self, HOVER_DURATION, HeadingOptions, ItemMetadata, Location, SORT_OPTION_FALLBACK, - SearchLocation, Tab, -}; -use crate::trash::{Trash, TrashExt}; -use crate::zoom::{zoom_in_view, zoom_out_view, zoom_to_default}; -use crate::{FxOrderMap, context_action, fl, home_dir, menu, mime_icon}; static PERMANENT_DELETE_BUTTON_ID: LazyLock = LazyLock::new(|| widget::Id::new("permanent-delete-button")); @@ -134,105 +145,6 @@ pub struct Flags { pub uris: Vec, } -/// Yoda phase 3: MIME for the DnD payload carried when a user drags a -/// toolbar row in the Settings editor. A single byte = ToolbarAction -/// discriminant (see `ToolbarAction::to_u8`). -const TOOLBAR_MIME: &str = "application/x-cosmic-files-toolbar-action"; - -/// Yoda phase 3: DnD payload wrapping a ToolbarAction discriminant. -#[derive(Clone, Debug)] -pub struct ToolbarActionPayload(pub u8); - -impl cosmic::iced::clipboard::mime::AsMimeTypes for ToolbarActionPayload { - fn available(&self) -> std::borrow::Cow<'static, [String]> { - std::borrow::Cow::Owned(vec![TOOLBAR_MIME.to_owned()]) - } - fn as_bytes(&self, mime_type: &str) -> Option> { - if mime_type == TOOLBAR_MIME { - Some(std::borrow::Cow::Owned(vec![self.0])) - } else { - None - } - } -} - -impl cosmic::iced::clipboard::mime::AllowedMimeTypes for ToolbarActionPayload { - fn allowed() -> std::borrow::Cow<'static, [String]> { - std::borrow::Cow::Owned(vec![TOOLBAR_MIME.to_owned()]) - } -} - -impl TryFrom<(Vec, String)> for ToolbarActionPayload { - type Error = (); - fn try_from((data, _mime): (Vec, String)) -> Result { - if data.len() == 1 { - Ok(Self(data[0])) - } else { - Err(()) - } - } -} - -/// Yoda phase 3 helper: map a ToolbarAction to its button UI (icon name, -/// localized label, app Message). Shared by the toolbar renderer in -/// `view()` and by the Settings page row renderer so the two stay in -/// sync. -fn toolbar_action_ui(a: ToolbarAction) -> (&'static str, String, Message) { - match a { - ToolbarAction::LocationUp => ( - "go-up-symbolic", - fl!("parent-directory"), - Action::LocationUp.message(None), - ), - ToolbarAction::Reload => ( - "view-refresh-symbolic", - fl!("reload-folder"), - Action::Reload.message(None), - ), - ToolbarAction::NewFolder => ( - "folder-new-symbolic", - fl!("new-folder"), - Action::NewFolder.message(None), - ), - ToolbarAction::NewFile => ( - "document-new-symbolic", - fl!("new-file"), - Action::NewFile.message(None), - ), - ToolbarAction::Rename => ( - "pencil-symbolic", - fl!("rename"), - Action::Rename.message(None), - ), - ToolbarAction::Delete => ( - "edit-delete-symbolic", - fl!("delete"), - Action::Delete.message(None), - ), - ToolbarAction::Cut => ("edit-cut-symbolic", fl!("cut"), Action::Cut.message(None)), - ToolbarAction::Copy => ( - "edit-copy-symbolic", - fl!("copy"), - Action::Copy.message(None), - ), - ToolbarAction::Paste => ( - "edit-paste-symbolic", - fl!("paste"), - Action::Paste.message(None), - ), - ToolbarAction::ToggleShowHidden => ( - "view-reveal-symbolic", - fl!("show-hidden-files"), - Action::ToggleShowHidden.message(None), - ), - ToolbarAction::OpenTerminal => ( - "utilities-terminal-symbolic", - fl!("open-in-terminal"), - Action::OpenTerminal.message(None), - ), - } -} - #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Action { About, @@ -260,8 +172,6 @@ pub enum Action { HistoryPrevious, ItemDown, ItemLeft, - ItemPageDown, - ItemPageUp, ItemRight, ItemUp, LocationUp, @@ -335,8 +245,6 @@ impl Action { Self::HistoryPrevious => Message::TabMessage(entity_opt, tab::Message::GoPrevious), Self::ItemDown => Message::TabMessage(entity_opt, tab::Message::ItemDown), Self::ItemLeft => Message::TabMessage(entity_opt, tab::Message::ItemLeft), - Self::ItemPageDown => Message::TabMessage(entity_opt, tab::Message::ItemPageDown), - Self::ItemPageUp => Message::TabMessage(entity_opt, tab::Message::ItemPageUp), Self::ItemRight => Message::TabMessage(entity_opt, tab::Message::ItemRight), Self::ItemUp => Message::TabMessage(entity_opt, tab::Message::ItemUp), Self::LocationUp => Message::TabMessage(entity_opt, tab::Message::LocationUp), @@ -397,7 +305,7 @@ impl MenuAction for Action { } #[derive(Clone, Debug)] -pub struct PreviewItem(pub Box); +pub struct PreviewItem(pub tab::Item); impl PartialEq for PreviewItem { fn eq(&self, other: &Self) -> bool { @@ -465,7 +373,7 @@ pub enum Message { ExtractToResult(DialogResult), #[cfg(all(feature = "wayland", feature = "desktop-applet"))] Focused(window::Id), - Key(window::Id, Modifiers, Key, Physical, Option), + Key(window::Id, Modifiers, Key, Option), LaunchUrl(String), MaybeExit, ModifiersChanged(window::Id, Modifiers), @@ -499,7 +407,6 @@ pub enum Message { OpenWithBrowse, OpenWithDialog(Option), OpenWithSelection(usize), - OpenWithToggleDefault(bool), #[cfg(all(feature = "wayland", feature = "desktop-applet"))] Overlap(window::Id, OverlapNotifyEvent), Paste(Option), @@ -526,7 +433,6 @@ pub enum Message { PendingPauseAll(bool), PermanentlyDelete(Option), Preview(Option), - ReloadMimeAppCache, ReorderTab(ReorderEvent), RescanRecents, RescanTrash, @@ -541,22 +447,6 @@ pub enum Message { SearchInput(String), SetShowDetails(bool), SetShowRecents(bool), - /// Yoda phase 3 — toolbar editing messages. - ToolbarAdd(ToolbarAction), - ToolbarRemove(ToolbarAction), - ToolbarReorder { - src: ToolbarAction, - target: ToolbarAction, - }, - /// Move one step up (toward index 0) inside the enabled toolbar list. - ToolbarMoveUp(ToolbarAction), - /// Move one step down (toward the end) inside the enabled toolbar list. - ToolbarMoveDown(ToolbarAction), - ToolbarReset, - /// Click on a toolbar button (via segmented_button activation). - ToolbarTabActivate(segmented_button::Entity), - /// Drag-reorder inside the toolbar (via segmented_button drag). - ToolbarTabReorder(segmented_button::ReorderEvent), SetTypeToSearch(TypeToSearch), SystemThemeModeChange, Size(window::Id, Size), @@ -570,7 +460,7 @@ pub enum Message { TabRescan( Entity, Location, - Option>, + Option, Vec, Option>, ), @@ -686,10 +576,7 @@ pub enum DialogPage { path: PathBuf, mime: mime_guess::Mime, selected: usize, - store_opt: Option>, - /// When true, the chosen app is written to mimeapps.list as the - /// default handler for `mime` after it spawns. - set_default: bool, + store_opt: Option, }, PermanentlyDelete { paths: Box<[PathBuf]>, @@ -704,8 +591,8 @@ pub enum DialogPage { dir: bool, }, Replace { - from: Box, - to: Box, + from: tab::Item, + to: tab::Item, multiple: bool, apply_to_all: bool, conflict_count: usize, @@ -785,6 +672,13 @@ impl DialogPages { pub struct FavoriteIndex(usize); +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum MimeAppMatch { + Exact, + Related, + Other, +} + pub struct MounterData(MounterKey, MounterItem); #[derive(Clone, Debug)] @@ -840,11 +734,6 @@ pub struct App { nav_bar_context_id: segmented_button::Entity, nav_model: segmented_button::SingleSelectModel, tab_model: segmented_button::Model, - /// Yoda phase 3: segmented_button model mirroring config.toolbar so the - /// toolbar row gets free drag-reorder + click activation (same widget - /// that powers the tab bar, its reorder is proven to work in this - /// setup unlike the generic dnd_source/dnd_destination wrappers). - toolbar_model: segmented_button::Model, config_handler: Option, state_handler: Option, config: Config, @@ -1013,39 +902,31 @@ impl App { #[cfg(feature = "desktop")] fn launch_desktop_entries(paths: &[impl AsRef]) { use cosmic::desktop::fde::DesktopEntry; - let locales = cosmic::desktop::fde::get_languages_from_env(); for path in paths.iter().map(AsRef::as_ref) { match DesktopEntry::from_path::<&str>(path, None) { Ok(entry) => match entry.exec() { - Some(exec) => { - match mime_app::exec_to_command( - exec, - entry.name(&locales).as_deref().unwrap_or_default(), - Some(path), - &[] as &[&str; 0], - ) { - Some(commands) => { - let cwd_opt = entry.desktop_entry("Path"); + Some(exec) => match mime_app::exec_to_command(exec, &[] as &[&str; 0]) { + Some(commands) => { + let cwd_opt = entry.desktop_entry("Path"); - for mut command in commands { - if let Some(cwd) = cwd_opt { - command.current_dir(cwd); - } + for mut command in commands { + if let Some(cwd) = cwd_opt { + command.current_dir(cwd); + } - if let Err(err) = spawn_detached(&mut command) { - log::warn!("failed to execute {}: {}", path.display(), err); - } + if let Err(err) = spawn_detached(&mut command) { + log::warn!("failed to execute {}: {}", path.display(), err); } } - None => { - log::warn!( - "failed to parse {}: invalid Desktop Entry/Exec", - path.display() - ); - } } - } + None => { + log::warn!( + "failed to parse {}: invalid Desktop Entry/Exec", + path.display() + ); + } + }, None => { log::warn!( "failed to parse {}: missing Desktop Entry/Exec", @@ -1139,12 +1020,6 @@ impl App { .and_then(|first| first.as_ref().parent()) .map(Path::to_path_buf) { - let mut tasks = Vec::new(); - if let Some(old_dialog) = self.file_dialog_opt.take() { - let old_id = old_dialog.window_id(); - self.windows.remove(&old_id); - tasks.push(window::close(old_id)); - } let (mut dialog, dialog_task) = Dialog::new( DialogSettings::new() .kind(DialogKind::OpenFolder) @@ -1161,9 +1036,7 @@ impl App { ))), ); self.file_dialog_opt = Some(dialog); - tasks.push(set_title_task); - tasks.push(dialog_task); - Task::batch(tasks) + Task::batch([set_title_task, dialog_task]) } else { Task::none() } @@ -1208,7 +1081,7 @@ impl App { .sort_by(|a, b| (b.1.width * b.1.height).total_cmp(&(a.1.width * b.1.height))); for (w_id, overlap) in sorted_overlaps { - let Some((bl, br, tl, tr, size)) = self.layer_sizes.get(w_id).map(|s| { + let Some((bl, br, tl, tr, mut size)) = self.layer_sizes.get(w_id).map(|s| { ( Rectangle::new( Point::new(0., s.height / 2.), @@ -1258,18 +1131,30 @@ impl App { if tl && !(tr || bl) { *top += min_dim.1; *left += min_dim.0; + + size.height -= min_dim.1; + size.width -= min_dim.0; } if tr && !(tl || br) { *top += min_dim.1; *right += min_dim.0; + + size.height -= min_dim.1; + size.width -= min_dim.0; } if bl && !(br || tl) { *bottom += min_dim.1; *left += min_dim.0; + + size.height -= min_dim.1; + size.width -= min_dim.0; } if br && !(bl || tr) { *bottom += min_dim.1; *right += min_dim.0; + + size.height -= min_dim.1; + size.width -= min_dim.0; } } self.margin = overlaps; @@ -1516,7 +1401,7 @@ impl App { // Manually rescan any trash tabs after any operation is completed commands.push(self.rescan_trash()); - Task::batch(commands) + return Task::batch(commands); } fn handle_operation_errors(&mut self, errors: Vec<(u64, OperationError)>) -> Task { @@ -1561,7 +1446,7 @@ impl App { } // Manually rescan any trash tabs after any operation is completed tasks.push(self.rescan_trash()); - Task::batch(tasks) + return Task::batch(tasks); } fn remove_window(&mut self, id: &window::Id) { @@ -1628,18 +1513,12 @@ impl App { ) -> Task { log::info!("rescan_tab {entity:?} {location:?} {selection_paths:?}"); let icon_sizes = self.config.tab.icon_sizes; - #[cfg(feature = "gvfs")] let mounter_items = self.mounter_items.clone(); Task::future(async move { let location2 = location.clone(); match tokio::task::spawn_blocking(move || location2.scan(icon_sizes)).await { - Ok((parent_item_opt, items)) => { - #[cfg(feature = "gvfs")] - let mut items = items; - #[cfg(not(feature = "gvfs"))] - let items = items; - + Ok((parent_item_opt, mut items)) => { #[cfg(feature = "gvfs")] { let mounter_paths: Box<[_]> = mounter_items @@ -1809,7 +1688,6 @@ impl App { fn update_config(&mut self) -> Task { self.update_nav_model(); - self.rebuild_toolbar_model(); // Tabs are collected first to placate the borrowck let tabs: Box<[_]> = self.tab_model.iter().collect(); // Update main conf and each tab with the new config @@ -1823,52 +1701,6 @@ impl App { Task::batch(commands) } - /// Yoda phase 3: rebuild `toolbar_model` so it matches `config.toolbar`. - /// Called on init and on every config update. Each entity carries the - /// associated `ToolbarAction` as data so click/reorder handlers can - /// round-trip Entity → ToolbarAction without maintaining a side map. - /// - /// We insert ONLY the icon (no `.text()`) so the toolbar renders as a - /// clean icon row — user-visible labels stay in Settings/tooltips on - /// other surfaces. - fn rebuild_toolbar_model(&mut self) { - self.toolbar_model.clear(); - for action in self.config.toolbar.iter().copied() { - let (icon_name, _label, _msg) = toolbar_action_ui(action); - self.toolbar_model - .insert() - .icon(widget::icon::from_name(icon_name).size(16).icon()) - .data::(action); - } - } - - /// Yoda phase 3: after a drag-reorder, sync `config.toolbar` with the - /// new entity order in `toolbar_model`. Inlines what `config_set!` - /// would do (the macro lives inside update()). - fn sync_toolbar_config_from_model(&mut self) -> Task { - let new_toolbar: Vec = self - .toolbar_model - .iter() - .filter_map(|e| self.toolbar_model.data::(e).copied()) - .collect(); - if new_toolbar == self.config.toolbar { - return Task::none(); - } - match self.config_handler.as_ref() { - Some(h) => { - if let Err(err) = self.config.set_toolbar(h, new_toolbar) { - log::warn!("failed to save toolbar order: {err}"); - } - } - None => self.config.toolbar = new_toolbar, - } - // Don't call update_config() — that would rebuild the - // toolbar_model from config and undo the reorder the user just - // made. The model already has the new order; config is just - // catching up for persistence. - Task::none() - } - fn update_desktop(&mut self) -> Task { let needs_reload: Box<[_]> = (self.tab_model.iter()) .filter_map(|entity| { @@ -1939,8 +1771,6 @@ impl App { if let Some(path) = favorite.path_opt() { let name = if matches!(favorite, Favorite::Home) { fl!("home") - } else if let Favorite::Network { name, .. } = favorite { - name.clone() } else if let Some(file_name) = path.file_name().and_then(|x| x.to_str()) { file_name.to_string() } else { @@ -2116,7 +1946,7 @@ impl App { fn network_drive(&self) -> Element<'_, Message> { let cosmic_theme::Spacing { space_xxs, space_m, .. - } = theme::spacing(); + } = theme::active().cosmic().spacing; let mut table = widget::column::with_capacity(8); for (i, line) in fl!("network-drive-schemes").lines().enumerate() { let mut row = widget::row::with_capacity(2); @@ -2147,23 +1977,25 @@ impl App { fn desktop_view_options(&self) -> Element<'_, Message> { let cosmic_theme::Spacing { space_m, space_l, .. - } = theme::spacing(); + } = theme::active().cosmic().spacing; let config = self.config.desktop; - let show_on_desktop = settings::section() - .title(fl!("show-on-desktop")) - .add( - settings::item::builder(fl!("desktop-folder-content")).toggler( - config.show_content, - move |show_content| { - Message::DesktopConfig(DesktopConfig { - show_content, - ..config - }) - }, - ), - ) - .add(settings::item::builder(fl!("mounted-drives")).toggler( + let mut column = widget::column::with_capacity(2); + + let mut section = widget::settings::section().title(fl!("show-on-desktop")); + section = section.add( + widget::settings::item::builder(fl!("desktop-folder-content")).toggler( + config.show_content, + move |show_content| { + Message::DesktopConfig(DesktopConfig { + show_content, + ..config + }) + }, + ), + ); + section = section.add( + widget::settings::item::builder(fl!("mounted-drives")).toggler( config.show_mounted_drives, move |show_mounted_drives| { Message::DesktopConfig(DesktopConfig { @@ -2171,8 +2003,10 @@ impl App { ..config }) }, - )) - .add(settings::item::builder(fl!("trash-folder-icon")).toggler( + ), + ); + section = section.add( + widget::settings::item::builder(fl!("trash-folder-icon")).toggler( config.show_trash, move |show_trash| { Message::DesktopConfig(DesktopConfig { @@ -2180,49 +2014,50 @@ impl App { ..config }) }, - )); + ), + ); + column = column.push(section); + let mut section = widget::settings::section().title(fl!("icon-size-and-spacing")); let icon_size = config.icon_size; - let grid_spacing = config.grid_spacing; - let icon_size_and_spacing = settings::section() - .title(fl!("icon-size-and-spacing")) - .add( - settings::item::builder(fl!("icon-size")) - .description(format!("{icon_size}%")) - .control( - widget::slider(50..=500, icon_size.get(), move |new_value| { - Message::DesktopConfig(DesktopConfig { - icon_size: NonZeroU16::new(new_value).unwrap_or(icon_size), - ..config - }) + section = section.add( + widget::settings::item::builder(fl!("icon-size")) + .description(format!("{icon_size}%")) + .control( + widget::slider(50..=500, icon_size.get(), move |new_value| { + Message::DesktopConfig(DesktopConfig { + icon_size: NonZeroU16::new(new_value).unwrap_or(icon_size), + ..config }) - .step(25u16), - ), - ) - .add( - settings::item::builder(fl!("grid-spacing")) - .description(format!("{grid_spacing}%")) - .control( - widget::slider(50..=500, grid_spacing.get(), move |new_value| { - Message::DesktopConfig(DesktopConfig { - grid_spacing: NonZeroU16::new(new_value).unwrap_or(grid_spacing), - ..config - }) - }) - .step(25u16), - ), - ); + }) + .step(25u16), + ), + ); - widget::column::with_capacity(2) + let grid_spacing = config.grid_spacing; + section = section.add( + widget::settings::item::builder(fl!("grid-spacing")) + .description(format!("{grid_spacing}%")) + .control( + widget::slider(50..=500, grid_spacing.get(), move |new_value| { + Message::DesktopConfig(DesktopConfig { + grid_spacing: NonZeroU16::new(new_value).unwrap_or(grid_spacing), + ..config + }) + }) + .step(25u16), + ), + ); + column = column.push(section); + + column .padding([0, space_l, space_l, space_l]) .spacing(space_m) - .push(show_on_desktop) - .push(icon_size_and_spacing) .into() } fn edit_history(&self) -> Element<'_, Message> { - let cosmic_theme::Spacing { space_m, .. } = theme::spacing(); + let cosmic_theme::Spacing { space_m, .. } = theme::active().cosmic().spacing; let mut children = Vec::new(); @@ -2314,7 +2149,7 @@ impl App { kind: &'a PreviewKind, context_drawer: bool, ) -> Element<'a, tab::Message> { - let cosmic_theme::Spacing { space_l, .. } = theme::spacing(); + let cosmic_theme::Spacing { space_l, .. } = theme::active().cosmic().spacing; let mut children = Vec::with_capacity(1); let entity = entity_opt.unwrap_or_else(|| self.tab_model.active()); @@ -2384,8 +2219,8 @@ impl App { let tab_config = self.config.tab; // TODO: Should dialog be updated here too? - settings::view_column(vec![ - settings::section() + widget::settings::view_column(vec![ + widget::settings::section() .title(fl!("appearance")) .add({ let app_theme_selected = match self.config.app_theme { @@ -2393,7 +2228,7 @@ impl App { AppTheme::Light => 2, AppTheme::System => 0, }; - settings::item::builder(fl!("theme")).control(widget::dropdown( + widget::settings::item::builder(fl!("theme")).control(widget::dropdown( &self.app_themes, Some(app_theme_selected), move |index| { @@ -2406,32 +2241,31 @@ impl App { )) }) .into(), - settings::section() + widget::settings::section() .title(fl!("type-to-search")) - .add( - settings::item::builder(fl!("type-to-search-recursive")).radio( - TypeToSearch::Recursive, - Some(self.config.type_to_search), - Message::SetTypeToSearch, - ), - ) - .add( - settings::item::builder(fl!("type-to-search-enter-path")).radio( - TypeToSearch::EnterPath, - Some(self.config.type_to_search), - Message::SetTypeToSearch, - ), - ) - .add(settings::item::builder(fl!("type-to-search-select")).radio( + .add(widget::radio( + widget::text::body(fl!("type-to-search-recursive")), + TypeToSearch::Recursive, + Some(self.config.type_to_search), + Message::SetTypeToSearch, + )) + .add(widget::radio( + widget::text::body(fl!("type-to-search-enter-path")), + TypeToSearch::EnterPath, + Some(self.config.type_to_search), + Message::SetTypeToSearch, + )) + .add(widget::radio( + widget::text::body(fl!("type-to-search-select")), TypeToSearch::SelectByPrefix, Some(self.config.type_to_search), Message::SetTypeToSearch, )) .into(), - settings::section() + widget::settings::section() .title(fl!("other")) .add({ - settings::item::builder(fl!("single-click")).toggler( + widget::settings::item::builder(fl!("single-click")).toggler( tab_config.single_click, move |single_click| { Message::TabConfig(TabConfig { @@ -2442,136 +2276,51 @@ impl App { ) }) .add({ - settings::item::builder(fl!("show-recents")) + widget::settings::item::builder(fl!("show-recents")) .toggler(self.config.show_recents, Message::SetShowRecents) }) .into(), - // Yoda phase 3: toolbar editor. Two stacked lists: - // - top: enabled buttons in their current order (drag to reorder) - // - bottom: available (not-yet-enabled) buttons - // Each row's toggle adds/removes; enabled rows are also - // drag sources + drop targets. - self.toolbar_settings_section(), ]) .into() } - /// Yoda phase 3: build the Toolbar settings section. - fn toolbar_settings_section(&self) -> Element<'_, Message> { - use iced::clipboard::dnd::DndAction; - let enabled = &self.config.toolbar; - let disabled: Vec = ToolbarAction::ALL - .iter() - .copied() - .filter(|a| !enabled.contains(a)) - .collect(); + fn get_apps_for_mime(&self, mime_type: &Mime) -> Vec<(&MimeApp, MimeAppMatch)> { + let mut results = Vec::new(); - let space_xxs = theme::active().cosmic().spacing.space_xxs; + let mut dedupe = FxHashSet::default(); - let drag_icon = |size: u16| -> Element<'static, Message> { - widget::icon::from_name("list-drag-handle-symbolic") - .size(size) - .into() - }; + // start with exact matches + results.extend( + self.mime_app_cache + .get(mime_type) + .iter() + .filter(|&mime_app| dedupe.insert(&mime_app.id)) + .map(|mime_app| (mime_app, MimeAppMatch::Exact)), + ); - let row_enabled = - |action: ToolbarAction, pos: usize, last: usize| -> Element<'_, Message> { - let (icon, label, _msg) = toolbar_action_ui(action); - let up_btn = - widget::button::icon(widget::icon::from_name("go-up-symbolic").size(14)); - let up_btn = if pos > 0 { - up_btn.on_press(Message::ToolbarMoveUp(action)) - } else { - up_btn - }; - let down_btn = - widget::button::icon(widget::icon::from_name("go-down-symbolic").size(14)); - let down_btn = if pos < last { - down_btn.on_press(Message::ToolbarMoveDown(action)) - } else { - down_btn - }; - - let row_content: Element<_> = widget::row::with_children(vec![ - drag_icon(14), - widget::icon::from_name(icon).size(16).into(), - widget::text::body(label).width(Length::Fill).into(), - up_btn.into(), - down_btn.into(), - widget::button::icon(widget::icon::from_name("list-remove-symbolic").size(14)) - .on_press(Message::ToolbarRemove(action)) - .into(), - ]) - .spacing(space_xxs) - .align_y(Alignment::Center) - .into(); - - let row_container = widget::container(row_content) - .width(Length::Fill) - .padding(space_xxs); - - // Wrap as DnD source (drags itself) + DnD destination (accepts - // drops from other enabled rows; on drop, move the src before - // this row). - let source = widget::dnd_source::(row_container) - .drag_content(move || ToolbarActionPayload(action.to_u8())); - widget::dnd_destination(source, vec![std::borrow::Cow::Borrowed(TOOLBAR_MIME)]) - .data_received_for::( - move |payload: Option| { - match payload.and_then(|p| ToolbarAction::from_u8(p.0)) { - Some(src) if src != action => Message::ToolbarReorder { - src, - target: action, - }, - // No-op if payload missing / malformed / same row. - _ => Message::ToolbarReorder { - src: action, - target: action, - }, - } - }, - ) - .action(DndAction::Move) - .into() - }; - - let row_disabled = |action: ToolbarAction| -> Element<'_, Message> { - let (icon, label, _msg) = toolbar_action_ui(action); - widget::row::with_children(vec![ - widget::icon::from_name(icon).size(16).into(), - widget::text::body(label).width(Length::Fill).into(), - widget::button::icon(widget::icon::from_name("list-add-symbolic").size(14)) - .on_press(Message::ToolbarAdd(action)) - .into(), - ]) - .spacing(space_xxs) - .align_y(Alignment::Center) - .padding(space_xxs) - .into() - }; - - let mut section = widget::settings::section().title(fl!("toolbar")); - if enabled.is_empty() { - section = section.add(widget::text::body(fl!("toolbar-empty-hint"))); - } else { - let last = enabled.len() - 1; - for (pos, a) in enabled.iter().copied().enumerate() { - section = section.add(row_enabled(a, pos, last)); + // grab matches based off of subclass / parent mime type + if let Some(parent_types) = mime_icon::parent_mime_types(mime_type) { + for parent_type in parent_types { + results.extend( + self.mime_app_cache + .get(&parent_type) + .iter() + .filter(|&mime_app| dedupe.insert(&mime_app.id)) + .map(|mime_app| (mime_app, MimeAppMatch::Related)), + ); } } - let mut col = widget::column::with_capacity(3).spacing(space_xxs); - col = col.push(section); - if !disabled.is_empty() { - let mut avail = widget::settings::section().title(fl!("toolbar-available")); - for a in disabled { - avail = avail.add(row_disabled(a)); - } - col = col.push(avail); - } - col = col - .push(widget::button::standard(fl!("toolbar-reset")).on_press(Message::ToolbarReset)); - col.into() + // Add other apps + results.extend( + self.mime_app_cache + .apps() + .iter() + .filter(|&mime_app| dedupe.insert(&mime_app.id)) + .map(|mime_app| (mime_app, MimeAppMatch::Other)), + ); + + results } // Update favorites based on renaming or moving dirs. @@ -2706,7 +2455,6 @@ impl Application for App { nav_bar_context_id: segmented_button::Entity::null(), nav_model: segmented_button::ModelBuilder::default().build(), tab_model: segmented_button::ModelBuilder::default().build(), - toolbar_model: segmented_button::ModelBuilder::default().build(), config_handler: flags.config_handler, state_handler: flags.state_handler, config: flags.config, @@ -2817,7 +2565,7 @@ impl Application for App { .on_middle_press(|entity| { cosmic::Action::App(Message::NavMenuAction(NavMenuAction::OpenInNewTab(entity))) }) - .context_menu(self.nav_context_menu()) + .context_menu(self.nav_context_menu(self.nav_bar_context_id)) .close_icon(icon::from_name("media-eject-symbolic").size(16).icon()) .into_container(); @@ -2832,100 +2580,95 @@ impl Application for App { fn nav_context_menu( &self, + entity: widget::nav_bar::Id, ) -> Option>>> { - let items = self.nav_model.iter().map(|entity| { - let favorite_index_opt = self.nav_model.data::(entity); - let location_opt = self.nav_model.data::(entity); + let favorite_index_opt = self.nav_model.data::(entity); + let location_opt = self.nav_model.data::(entity); - let mut items = Vec::with_capacity(7); + let mut items = Vec::with_capacity(7); - if location_opt - .and_then(Location::path_opt) - .is_some_and(|x| x.is_file()) - { - items.push(cosmic::widget::menu::Item::Button( - fl!("open"), - None, - NavMenuAction::Open(entity), - )); - items.push(cosmic::widget::menu::Item::Button( - fl!("menu-open-with"), - None, - NavMenuAction::OpenWith(entity), - )); - } else { - items.push(cosmic::widget::menu::Item::Button( - fl!("open-in-new-tab"), - None, - NavMenuAction::OpenInNewTab(entity), - )); - items.push(cosmic::widget::menu::Item::Button( - fl!("open-in-new-window"), - None, - NavMenuAction::OpenInNewWindow(entity), - )); - } - if let Some(path) = location_opt.and_then(Location::path_opt) { - let selected_dir = usize::from(path.is_dir()); - let action_items: Vec<_> = self - .config - .context_actions - .iter() - .enumerate() - .filter(|(_, action)| action.matches_selection(1, selected_dir)) - .map(|(i, action)| { - cosmic::widget::menu::Item::Button( - action.name.clone(), - None, - NavMenuAction::RunContextAction(entity, i), - ) - }) - .collect(); + if location_opt + .and_then(Location::path_opt) + .is_some_and(|x| x.is_file()) + { + items.push(cosmic::widget::menu::Item::Button( + fl!("open"), + None, + NavMenuAction::Open(entity), + )); + items.push(cosmic::widget::menu::Item::Button( + fl!("menu-open-with"), + None, + NavMenuAction::OpenWith(entity), + )); + } else { + items.push(cosmic::widget::menu::Item::Button( + fl!("open-in-new-tab"), + None, + NavMenuAction::OpenInNewTab(entity), + )); + items.push(cosmic::widget::menu::Item::Button( + fl!("open-in-new-window"), + None, + NavMenuAction::OpenInNewWindow(entity), + )); + } + if let Some(path) = location_opt.and_then(Location::path_opt) { + let selected_dir = usize::from(path.is_dir()); + let action_items: Vec<_> = self + .config + .context_actions + .iter() + .enumerate() + .filter(|(_, action)| action.matches_selection(1, selected_dir)) + .map(|(i, action)| { + cosmic::widget::menu::Item::Button( + action.name.clone(), + None, + NavMenuAction::RunContextAction(entity, i), + ) + }) + .collect(); - if !action_items.is_empty() { - items.push(cosmic::widget::menu::Item::Divider); - items.extend(action_items); - } - } - items.push(cosmic::widget::menu::Item::Divider); - if matches!(location_opt, Some(Location::Path(..))) { - items.push(cosmic::widget::menu::Item::Button( - fl!("show-details"), - None, - NavMenuAction::Preview(entity), - )); - } - items.push(cosmic::widget::menu::Item::Divider); - if favorite_index_opt.is_some() { - items.push(cosmic::widget::menu::Item::Button( - fl!("remove-from-sidebar"), - None, - NavMenuAction::RemoveFromSidebar(entity), - )); + if !action_items.is_empty() { + items.push(cosmic::widget::menu::Item::Divider); + items.extend(action_items); } + } + items.push(cosmic::widget::menu::Item::Divider); + if matches!(location_opt, Some(Location::Path(..))) { + items.push(cosmic::widget::menu::Item::Button( + fl!("show-details"), + None, + NavMenuAction::Preview(entity), + )); + } + items.push(cosmic::widget::menu::Item::Divider); + if favorite_index_opt.is_some() { + items.push(cosmic::widget::menu::Item::Button( + fl!("remove-from-sidebar"), + None, + NavMenuAction::RemoveFromSidebar(entity), + )); + } - if matches!(location_opt, Some(Location::Recents)) && tab::has_recents() { - items.push(cosmic::widget::menu::Item::Button( - fl!("clear-recents-history"), - None, - NavMenuAction::ClearRecents, - )); - } + if matches!(location_opt, Some(Location::Recents)) && tab::has_recents() { + items.push(cosmic::widget::menu::Item::Button( + fl!("clear-recents-history"), + None, + NavMenuAction::ClearRecents, + )); + } - if matches!(location_opt, Some(Location::Trash)) && !Trash::is_empty() { - items.push(cosmic::widget::menu::Item::Button( - fl!("empty-trash"), - None, - NavMenuAction::EmptyTrash, - )); - } - items - }); + if matches!(location_opt, Some(Location::Trash)) && !Trash::is_empty() { + items.push(cosmic::widget::menu::Item::Button( + fl!("empty-trash"), + None, + NavMenuAction::EmptyTrash, + )); + } - Some(cosmic::widget::menu::nav_context( - &HashMap::new(), - items.collect(), - )) + Some(cosmic::widget::menu::items(&HashMap::new(), items)) } fn nav_model(&self) -> Option<&segmented_button::SingleSelectModel> { @@ -3218,12 +2961,10 @@ impl Application for App { Message::Config(config) => { if config != self.config { log::info!("update config"); - // Show details and military time are preserved for existing instances + // Show details is preserved for existing instances let show_details = self.config.show_details; - let military_time = self.config.tab.military_time; self.config = config; self.config.show_details = show_details; - self.config.tab.military_time = military_time; return self.update_config(); } } @@ -3491,10 +3232,9 @@ impl Application for App { path, mime, selected, - set_default, .. } => { - let available_apps = self.mime_app_cache.get_apps_for_mime(&mime, true); + let available_apps = self.get_apps_for_mime(&mime); if let Some((app, _)) = available_apps.get(selected) { if let Some(mut command) = @@ -3510,11 +3250,6 @@ impl Application for App { None, ); } - // Yoda: persist as default if the user asked for it. - if set_default { - self.mime_app_cache - .set_default(mime.clone(), app.id.clone()); - } } Err(err) => { log::warn!( @@ -3626,7 +3361,7 @@ impl Application for App { return dialog.update(dialog_message); } } - Message::Key(window_id, modifiers, key, physical_key, text) => { + Message::Key(window_id, modifiers, key, text) => { #[cfg(all(feature = "wayland", feature = "desktop-applet"))] let in_surface_ids = self.surface_ids.values().any(|id| *id == window_id); #[cfg(not(all(feature = "wayland", feature = "desktop-applet")))] @@ -3634,7 +3369,7 @@ impl Application for App { if self.core.main_window_id() == Some(window_id) || in_surface_ids { let entity = self.tab_model.active(); for (key_bind, action) in &self.key_binds { - if key_bind.matches(modifiers, &key, Some(&physical_key)) { + if key_bind.matches(modifiers, &key) { return self.update(action.message(Some(entity))); } } @@ -4137,7 +3872,6 @@ impl Application for App { .and_then(|mime| { self.mime_app_cache.get(&mime).first().cloned() }), - set_default: false, }, Some(CONFIRM_OPEN_WITH_BUTTON_ID.clone()), ); @@ -4149,13 +3883,6 @@ impl Application for App { *selected = index; } } - Message::OpenWithToggleDefault(enabled) => { - if let Some(DialogPage::OpenWith { set_default, .. }) = - self.dialog_pages.front_mut() - { - *set_default = enabled; - } - } Message::Paste(entity_opt) => { let entity = entity_opt.unwrap_or_else(|| self.tab_model.active()); if let Some(tab) = self.tab_model.data_mut::(entity) @@ -4502,9 +4229,6 @@ impl Application for App { let paths: Box<[_]> = self.selected_paths(entity_opt).collect(); return self.operation(Operation::RemoveFromRecents { paths }); } - Message::ReloadMimeAppCache => { - self.mime_app_cache.reload(); - } Message::RescanRecents => { return self.rescan_recents(); } @@ -4635,86 +4359,6 @@ impl Application for App { config_set!(show_recents, show_recents); return self.update_config(); } - Message::ToolbarAdd(action) => { - let mut tb = self.config.toolbar.clone(); - if !tb.contains(&action) { - tb.push(action); - } - config_set!(toolbar, tb); - return self.update_config(); - } - Message::ToolbarRemove(action) => { - let mut tb = self.config.toolbar.clone(); - tb.retain(|a| a != &action); - config_set!(toolbar, tb); - return self.update_config(); - } - Message::ToolbarReorder { src, target } => { - let mut tb = self.config.toolbar.clone(); - if let (Some(src_idx), Some(tgt_idx)) = ( - tb.iter().position(|a| a == &src), - tb.iter().position(|a| a == &target), - ) && src_idx != tgt_idx - { - // Pull src out, then insert before the target's new position. - let item = tb.remove(src_idx); - let new_tgt = if src_idx < tgt_idx { - tgt_idx - 1 - } else { - tgt_idx - }; - tb.insert(new_tgt, item); - config_set!(toolbar, tb); - return self.update_config(); - } - return Task::none(); - } - Message::ToolbarMoveUp(action) => { - let mut tb = self.config.toolbar.clone(); - if let Some(i) = tb.iter().position(|a| a == &action) - && i > 0 - { - tb.swap(i, i - 1); - config_set!(toolbar, tb); - return self.update_config(); - } - return Task::none(); - } - Message::ToolbarMoveDown(action) => { - let mut tb = self.config.toolbar.clone(); - if let Some(i) = tb.iter().position(|a| a == &action) - && i + 1 < tb.len() - { - tb.swap(i, i + 1); - config_set!(toolbar, tb); - return self.update_config(); - } - return Task::none(); - } - Message::ToolbarReset => { - config_set!(toolbar, default_toolbar()); - return self.update_config(); - } - Message::ToolbarTabActivate(entity) => { - // Dispatch the stored ToolbarAction's message, then clear - // the "active" selection so the button doesn't stay - // highlighted after a click (we use segmented_button for - // layout/drag but toolbar buttons are action-firing, not - // a mutual-exclusive choice). - let action = self.toolbar_model.data::(entity).copied(); - self.toolbar_model.deactivate(); - if let Some(action) = action { - let (_, _, msg) = toolbar_action_ui(action); - return self.update(msg); - } - return Task::none(); - } - Message::ToolbarTabReorder(event) => { - let _ = self - .toolbar_model - .reorder(event.dragged, event.target, event.position); - return self.sync_toolbar_config_from_model(); - } Message::SetTypeToSearch(type_to_search) => { config_set!(type_to_search, type_to_search); return self.update_config(); @@ -4890,7 +4534,6 @@ impl Application for App { commands.push(self.update(Message::CheckClipboard)); commands.push(self.update(Message::Surface( cosmic::surface::action::app_popup( - |_: &Self| cosmic::surface::action::LiveSettings::default(), move |app: &mut Self| -> SctkPopupSettings { let anchor_rect = Rectangle { x: point.x as i32, @@ -4945,14 +4588,6 @@ impl Application for App { tab::Command::DropFiles(to, from) => { commands.push(self.update(Message::PasteContents(to, from))); } - tab::Command::ClearRecents => { - match recently_used_xbel::clear_recently_used() { - Ok(()) => {} - Err(err) => { - log::warn!("failed to clear recents history: {}", err); - } - } - } tab::Command::EmptyTrash => { return self.push_dialog( DialogPage::EmptyTrash, @@ -5475,7 +5110,6 @@ impl Application for App { .and_then(|mime| { self.mime_app_cache.get(&mime).first().cloned() }), - set_default: false, }, None, ); @@ -5585,7 +5219,7 @@ impl Application for App { Ok(item) => { self.context_page = ContextPage::Preview( None, - PreviewKind::Custom(PreviewItem(Box::new(item))), + PreviewKind::Custom(PreviewItem(item)), ); self.set_show_context(true); } @@ -5892,7 +5526,7 @@ impl Application for App { let cosmic_theme::Spacing { space_xxs, space_s, .. - } = theme::spacing(); + } = theme::active().cosmic().spacing; let dialog = match dialog_page { DialogPage::Compress { @@ -6031,7 +5665,7 @@ impl Application for App { } DialogPage::FailedOperations(ids) => { let errors: Vec = ids - .iter() + .into_iter() .filter_map(|id| match self.failed_operations.get(id) { Some((operation, _, err)) => Some(format!("{operation:#?}\n{err}")), _ => None, @@ -6319,7 +5953,7 @@ impl Application for App { mime, selected, store_opt, - set_default, + .. } => { let name = match path.file_name() { Some(file_name) => file_name.to_str(), @@ -6327,7 +5961,7 @@ impl Application for App { }; let mut column = widget::list_column(); - let available_apps = self.mime_app_cache.get_apps_for_mime(mime, true); + let available_apps = self.get_apps_for_mime(mime); let item_height = 32.0; let mut displayed_default = false; let mut last_kind = MimeAppMatch::Exact; @@ -6348,8 +5982,8 @@ impl Application for App { widget::mouse_area( widget::button::custom( widget::row::with_children([ - icon(app.icon()).size(32).into(), - if app.is_default(mime) && !displayed_default { + icon(app.icon.clone()).size(32).into(), + if app.is_default && !displayed_default { displayed_default = true; widget::text::body(fl!( "default-app", @@ -6404,21 +6038,7 @@ impl Application for App { } else { Length::Shrink } - })) - // Yoda: let the user make this choice stick. A plain row - // instead of settings::item::builder because the latter - // returns a section Item, not an Element usable in .control(). - .control( - widget::row::with_children([ - widget::text::body(fl!("open-with-set-default")).into(), - widget::space::horizontal().into(), - widget::toggler(*set_default) - .on_toggle(Message::OpenWithToggleDefault) - .into(), - ]) - .spacing(space_s) - .align_y(Alignment::Center), - ); + })); if let Some(app) = store_opt { dialog = dialog.tertiary_action( @@ -6524,7 +6144,7 @@ impl Application for App { dialog .primary_action( - widget::button::suggested(fl!("rename-confirm")) + widget::button::suggested(fl!("rename")) .on_press_maybe(complete_maybe.clone()), ) .secondary_action( @@ -6668,7 +6288,7 @@ impl Application for App { let cosmic_theme::Spacing { space_xs, space_s, .. - } = theme::spacing(); + } = theme::active().cosmic().spacing; let mut title = String::new(); let mut total_progress = 0.0; @@ -6824,11 +6444,8 @@ impl Application for App { /// Creates a view after each update. fn view(&self) -> Element<'_, Self::Message> { let cosmic_theme::Spacing { - space_xxs, - space_xs, - space_s, - .. - } = theme::spacing(); + space_xxs, space_s, .. + } = theme::active().cosmic().spacing; let mut tab_column = widget::column::with_capacity(4); @@ -6871,36 +6488,6 @@ impl Application for App { ); } - // Yoda phase 3: Dolphin-style quick actions toolbar via - // segmented_button::horizontal — the same widget that powers the - // tab bar, so its built-in drag reorder works reliably (unlike the - // generic dnd_source+dnd_destination pairing we tried earlier). - // Short click = action (ToolbarTabActivate → dispatch the stored - // ToolbarAction's message). Drag past threshold = reorder - // (ToolbarTabReorder → model.reorder + sync to config). - if !self.config.toolbar.is_empty() { - // Use Control style (no TabBar underline, no bottom border) - // and let each button shrink to its icon. Spacing = space_xs - // keeps the buttons visually separated so it looks like an - // icon toolbar rather than a conjoined segmented control. - let toolbar = widget::segmented_button::horizontal(&self.toolbar_model) - .style(theme::SegmentedButton::Control) - .button_height(32) - .button_spacing(space_xs) - .button_alignment(Alignment::Center) - .minimum_button_width(32) - .maximum_button_width(32) - .enable_tab_drag(String::from("x-cosmic-files/toolbar-dnd")) - .on_reorder(Message::ToolbarTabReorder) - .tab_drag_threshold(8.) - .on_activate(Message::ToolbarTabActivate); - tab_column = tab_column.push( - widget::container(toolbar) - .width(Length::Shrink) - .padding([space_xxs, space_s]), - ); - } - let entity = self.tab_model.active(); if let Some(tab) = self.tab_model.data::(entity) { let tab_view = tab @@ -7048,14 +6635,11 @@ impl Application for App { }, Event::Keyboard(KeyEvent::KeyPressed { key, - physical_key, modifiers, text, .. }) => match status { - event::Status::Ignored => { - Some(Message::Key(window_id, modifiers, key, physical_key, text)) - } + event::Status::Ignored => Some(Message::Key(window_id, modifiers, key, text)), event::Status::Captured => None, }, Event::Keyboard(KeyEvent::ModifiersChanged(modifiers)) => { @@ -7187,22 +6771,6 @@ impl Application for App { }, ) }), - #[cfg(feature = "desktop")] - Subscription::run(|| { - stream::channel( - 1, - |mut output: futures::channel::mpsc::Sender| async move { - mime_app::watch(move || { - futures::executor::block_on(async { - _ = output.send(Message::ReloadMimeAppCache).await; - }) - }) - .await; - - std::future::pending().await - }, - ) - }), Subscription::run_with(TypeId::of::(), |_| { stream::channel( 1, @@ -7469,17 +7037,21 @@ impl Application for App { // Ideally, tests would use the cap-std crate which limits path traversal. #[cfg(test)] pub(crate) mod test_utils { - use std::cmp::Ordering; - use std::fs::File; - use std::io::{self, Write}; - use std::iter; - use std::path::Path; + use std::{ + cmp::Ordering, + fs::File, + io::{self, Write}, + iter, + path::Path, + }; use log::{debug, trace}; use tempfile::{TempDir, tempdir}; - use crate::config::{IconSizes, TabConfig, ThumbCfg}; - use crate::tab::Item; + use crate::{ + config::{IconSizes, TabConfig, ThumbCfg}, + tab::Item, + }; use super::*; diff --git a/src/archive.rs b/src/archive.rs index d51b01b..ba11cbb 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -1,14 +1,16 @@ -use crate::mime_icon::mime_for_path; -use crate::operation::{Controller, OpReader, OperationError, OperationErrorType}; +use crate::{ + mime_icon::mime_for_path, + operation::{Controller, OpReader, OperationError, OperationErrorType, sync_to_disk}, +}; use cosmic::iced::futures; -use jiff::Zoned; -use jiff::civil::DateTime; -use jiff::tz::TimeZone; -use std::collections::HashSet; -use std::fs; -use std::io::{self, Read, Write}; -use std::path::{Path, PathBuf}; -use std::time::SystemTime; +use jiff::{Zoned, civil::DateTime, tz::TimeZone}; +use std::{ + collections::HashSet, + fs, + io::{self, Read, Write}, + path::{Path, PathBuf}, + time::SystemTime, +}; use zip::result::ZipError; pub const SUPPORTED_ARCHIVE_TYPES: &[&str] = &[ @@ -45,7 +47,7 @@ pub fn extract( new_dir: &Path, password: &Option, controller: &Controller, -) -> Result<(Vec, HashSet), OperationError> { +) -> Result<(), OperationError> { let mime = mime_for_path(path, None, false); let password = password.as_deref(); match mime.essence_str() { @@ -55,15 +57,13 @@ pub fn extract( .map(flate2::read::GzDecoder::new) .map(tar::Archive::new) .and_then(|mut archive| archive.unpack(new_dir)) - .map_err(|e| OperationError::from_err(e, controller)) - .map(|_| Default::default()) + .map_err(|e| OperationError::from_err(e, controller))?; } "application/x-tar" => OpReader::new(path, controller.clone()) .map(io::BufReader::new) .map(tar::Archive::new) .and_then(|mut archive| archive.unpack(new_dir)) - .map_err(|e| OperationError::from_err(e, controller)) - .map(|_| Default::default()), + .map_err(|e| OperationError::from_err(e, controller))?, "application/zip" => fs::File::open(path) .map(io::BufReader::new) .map(zip::ZipArchive::new) @@ -77,7 +77,7 @@ pub fn extract( OperationError::from_kind(OperationErrorType::PasswordRequired, controller) } _ => OperationError::from_err(e, controller), - }), + })?, #[cfg(feature = "bzip2")] "application/x-bzip" | "application/x-bzip-compressed-tar" @@ -87,8 +87,7 @@ pub fn extract( .map(bzip2::read::BzDecoder::new) .map(tar::Archive::new) .and_then(|mut archive| archive.unpack(new_dir)) - .map_err(|e| OperationError::from_err(e, controller)) - .map(|_| Default::default()), + .map_err(|e| OperationError::from_err(e, controller))?, #[cfg(feature = "lzma-rust2")] "application/x-xz" | "application/x-xz-compressed-tar" => { OpReader::new(path, controller.clone()) @@ -96,14 +95,14 @@ pub fn extract( .map(|reader| lzma_rust2::XzReader::new(reader, true)) .map(tar::Archive::new) .and_then(|mut archive| archive.unpack(new_dir)) - .map_err(|e| OperationError::from_err(e, controller)) - .map(|_| Default::default()) + .map_err(|e| OperationError::from_err(e, controller))?; } _ => Err(OperationError::from_err( format!("unsupported mime type {mime:?}"), controller, - )), + ))?, } + Ok(()) } // From https://docs.rs/zip/latest/zip/read/struct.ZipArchive.html#method.extract, with cancellation and progress added @@ -112,9 +111,8 @@ fn zip_extract>( directory: P, password: Option<&str>, controller: Controller, -) -> zip::result::ZipResult<(Vec, HashSet)> { - use std::ffi::OsString; - use std::fs; +) -> zip::result::ZipResult<()> { + use std::{ffi::OsString, fs}; use zip::result::ZipError; fn make_writable_dir_all>( @@ -285,7 +283,10 @@ fn zip_extract>( } } - Ok((written_files, target_dirs)) + // Flush files to disk + futures::executor::block_on(async { sync_to_disk(written_files, target_dirs).await }); + + Ok(()) } fn zip_date_time_to_system_time(date_time: zip::DateTime) -> Option { diff --git a/src/channel.rs b/src/channel.rs index 2a295f9..e91bc35 100644 --- a/src/channel.rs +++ b/src/channel.rs @@ -1,9 +1,13 @@ // Copyright 2025 System76 // SPDX-License-Identifier: MPL-2.0 -use std::collections::VecDeque; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, Mutex}; +use std::{ + collections::VecDeque, + sync::{ + Arc, Mutex, + atomic::{AtomicBool, Ordering}, + }, +}; /// Create a channel backed by `tokio::sync::Notify` and a sync mutex with a vec deque. pub fn channel() -> (Sender, Receiver) { diff --git a/src/clipboard.rs b/src/clipboard.rs index 7d06be5..5892071 100644 --- a/src/clipboard.rs +++ b/src/clipboard.rs @@ -2,10 +2,12 @@ // SPDX-License-Identifier: GPL-3.0-only use cosmic::iced::clipboard::mime::{AllowedMimeTypes, AsMimeTypes}; -use std::borrow::Cow; -use std::error::Error; -use std::path::{Path, PathBuf}; -use std::str; +use std::{ + borrow::Cow, + error::Error, + path::{Path, PathBuf}, + str, +}; use url::Url; #[derive(Clone, Copy, Debug)] @@ -130,11 +132,9 @@ impl TryFrom<(Vec, String)> for ClipboardPaste { match mime.as_str() { "text/uri-list" => { let text = str::from_utf8(&data)?; + let lines = text.lines(); - for line in text.lines().filter(|line| { - let line = line.trim(); - !line.is_empty() && !line.starts_with('#') - }) { + for line in text.lines() { let url = Url::parse(line)?; match url.to_file_path() { Ok(path) => paths.push(path), diff --git a/src/config.rs b/src/config.rs index 8f493c0..0ce9c22 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,18 +1,20 @@ // SPDX-License-Identifier: GPL-3.0-only -use std::any::TypeId; -use std::num::NonZeroU16; -use std::path::PathBuf; +use std::{any::TypeId, num::NonZeroU16, path::PathBuf}; -use cosmic::cosmic_config::cosmic_config_derive::CosmicConfigEntry; -use cosmic::cosmic_config::{self, CosmicConfigEntry}; -use cosmic::iced::Subscription; -use cosmic::{Application, theme}; +use cosmic::{ + Application, + cosmic_config::{self, CosmicConfigEntry, cosmic_config_derive::CosmicConfigEntry}, + iced::Subscription, + theme, +}; use serde::{Deserialize, Serialize}; -use crate::FxOrderMap; -use crate::app::App; -use crate::tab::{HeadingOptions, Location, View}; +use crate::{ + FxOrderMap, + app::App, + tab::{HeadingOptions, Location, View}, +}; pub use crate::context_action::{ContextActionPreset, ContextActionSelection}; @@ -170,11 +172,6 @@ pub struct Config { pub show_details: bool, pub show_recents: bool, pub tab: TabConfig, - /// Yoda phase 3: Dolphin-style quick actions toolbar. An ordered list - /// of enabled buttons — position in the vec drives the toolbar order. - /// Reorder in Settings via drag-drop; items not in the vec are - /// hidden. Default = the minimal-6 set from phase 1. - pub toolbar: Vec, pub type_to_search: TypeToSearch, } @@ -239,97 +236,11 @@ impl Default for Config { show_details: false, show_recents: true, tab: TabConfig::default(), - toolbar: default_toolbar(), type_to_search: TypeToSearch::Recursive, } } } -/// Yoda phase 3: ordered enum of quick-action toolbar buttons. -/// The Config stores `Vec` so the user can pick BOTH -/// visibility (just include/exclude the variant) AND order (position in -/// the vec). Drag-drop reorder in the Settings page moves items around. -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] -pub enum ToolbarAction { - LocationUp, - Reload, - NewFolder, - NewFile, - Rename, - Delete, - Cut, - Copy, - Paste, - ToggleShowHidden, - OpenTerminal, -} - -impl ToolbarAction { - /// Stable list of every supported action. Ordered roughly by logical - /// grouping (location → create/edit → clipboard → view/misc) so that - /// the default enabled set follows a sensible shape and the Settings - /// row for a not-yet-enabled action lands in a predictable spot. - pub const ALL: &'static [Self] = &[ - Self::LocationUp, - Self::Reload, - Self::NewFolder, - Self::NewFile, - Self::Rename, - Self::Delete, - Self::Cut, - Self::Copy, - Self::Paste, - Self::ToggleShowHidden, - Self::OpenTerminal, - ]; - - /// u8 discriminant used to carry the action over a DnD mime payload. - pub const fn to_u8(self) -> u8 { - match self { - Self::LocationUp => 0, - Self::Reload => 1, - Self::NewFolder => 2, - Self::NewFile => 3, - Self::Rename => 4, - Self::Delete => 5, - Self::Cut => 6, - Self::Copy => 7, - Self::Paste => 8, - Self::ToggleShowHidden => 9, - Self::OpenTerminal => 10, - } - } - - pub const fn from_u8(v: u8) -> Option { - match v { - 0 => Some(Self::LocationUp), - 1 => Some(Self::Reload), - 2 => Some(Self::NewFolder), - 3 => Some(Self::NewFile), - 4 => Some(Self::Rename), - 5 => Some(Self::Delete), - 6 => Some(Self::Cut), - 7 => Some(Self::Copy), - 8 => Some(Self::Paste), - 9 => Some(Self::ToggleShowHidden), - 10 => Some(Self::OpenTerminal), - _ => None, - } - } -} - -/// Default set shown on a fresh install — same "minimal 6" as phase 1/2. -pub fn default_toolbar() -> Vec { - vec![ - ToolbarAction::NewFolder, - ToolbarAction::Rename, - ToolbarAction::Delete, - ToolbarAction::Cut, - ToolbarAction::Copy, - ToolbarAction::Paste, - ] -} - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, CosmicConfigEntry, Deserialize, Serialize)] #[serde(default)] pub struct DesktopConfig { diff --git a/src/context_action.rs b/src/context_action.rs index 34dfb6e..86f3bc6 100644 --- a/src/context_action.rs +++ b/src/context_action.rs @@ -4,8 +4,7 @@ use std::path::PathBuf; use serde::{Deserialize, Serialize}; -use crate::mime_app; -use crate::spawn_detached::spawn_detached; +use crate::{mime_app, spawn_detached::spawn_detached}; #[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] pub enum ContextActionSelection { @@ -47,7 +46,7 @@ impl ContextActionPreset { } for step in &self.steps { - let Some(commands) = mime_app::exec_to_command(step, &self.name, None, paths) else { + let Some(commands) = mime_app::exec_to_command(step, paths) else { log::warn!( "failed to parse context action {:?}: invalid Exec {:?}", self.name, diff --git a/src/dialog.rs b/src/dialog.rs index c760472..cac5907 100644 --- a/src/dialog.rs +++ b/src/dialog.rs @@ -1,46 +1,58 @@ // Copyright 2023 System76 // SPDX-License-Identifier: GPL-3.0-only -use cosmic::app::cosmic::Cosmic; -use cosmic::app::{Core, Task, context_drawer}; -use cosmic::iced::core::SmolStr; -use cosmic::iced::core::widget::operation; -use cosmic::iced::futures::{self, SinkExt}; -use cosmic::iced::keyboard::key::{Named, Physical}; -use cosmic::iced::keyboard::{Event as KeyEvent, Key, Modifiers}; -use cosmic::iced::platform_specific::shell::{self as iced_winit, SurfaceIdWrapper}; -use cosmic::iced::widget::scrollable; -use cosmic::iced::widget::scrollable::AbsoluteOffset; -use cosmic::iced::{ - self, Alignment, Event, Length, Size, Subscription, event, mouse, stream, window, +use cosmic::{ + Application, ApplicationExt, Element, + app::{Core, Task, context_drawer, cosmic::Cosmic}, + cosmic_config, cosmic_theme, executor, + iced::core::widget::operation, + iced::platform_specific::shell::{self as iced_winit, SurfaceIdWrapper}, + iced::widget::scrollable::AbsoluteOffset, + iced::{ + self, Alignment, Event, Length, Size, Subscription, + core::SmolStr, + event, + futures::{self, SinkExt}, + keyboard::{Event as KeyEvent, Key, Modifiers, key::Named}, + mouse, stream, + widget::scrollable, + window, + }, + theme, + widget::{ + self, Operation, + menu::{Action as MenuAction, KeyBind, key_bind::Modifier}, + segmented_button, + }, }; -use cosmic::widget::menu::key_bind::Modifier; -use cosmic::widget::menu::{Action as MenuAction, KeyBind}; -use cosmic::widget::{self, Operation, segmented_button}; -use cosmic::{Application, ApplicationExt, Element, cosmic_config, cosmic_theme, executor, theme}; use mime_guess::{Mime, mime}; -use notify_debouncer_full::notify::{self, RecommendedWatcher}; -use notify_debouncer_full::{DebouncedEvent, Debouncer, RecommendedCache, new_debouncer}; +use notify_debouncer_full::{ + DebouncedEvent, Debouncer, RecommendedCache, new_debouncer, + notify::{self, RecommendedWatcher}, +}; use recently_used_xbel::update_recently_used; use rustc_hash::{FxHashMap, FxHashSet}; -use std::any::TypeId; -use std::collections::{HashMap, VecDeque}; -use std::path::PathBuf; -use std::time::{self, Instant}; -use std::{env, fmt, fs}; +use std::{ + any::TypeId, + collections::{HashMap, VecDeque}, + env, fmt, fs, + path::PathBuf, + time::{self, Instant}, +}; -use crate::app::{ - Action, ContextPage, Message as AppMessage, PreviewItem, PreviewKind, REPLACE_BUTTON_ID, +use crate::{ + app::{ + Action, ContextPage, Message as AppMessage, PreviewItem, PreviewKind, REPLACE_BUTTON_ID, + }, + config::{Config, DialogConfig, Favorite, TIME_CONFIG_ID, ThumbCfg, TimeConfig, TypeToSearch}, + fl, home_dir, + key_bind::key_binds, + localize::LANGUAGE_SORTER, + menu, + mounter::{MOUNTERS, MounterItem, MounterItems, MounterKey, MounterMessage}, + tab::{self, ItemMetadata, Location, SearchLocation, Tab}, + zoom::{zoom_in_view, zoom_out_view, zoom_to_default}, }; -use crate::config::{ - Config, DialogConfig, Favorite, TIME_CONFIG_ID, ThumbCfg, TimeConfig, TypeToSearch, -}; -use crate::key_bind::key_binds; -use crate::localize::LANGUAGE_SORTER; -use crate::mounter::{MOUNTERS, MounterItem, MounterItems, MounterKey, MounterMessage}; -use crate::tab::{self, ItemMetadata, Location, SearchLocation, Tab}; -use crate::zoom::{zoom_in_view, zoom_out_view, zoom_to_default}; -use crate::{fl, home_dir, menu, mime_icon}; #[derive(Clone, Debug)] pub struct DialogMessage(cosmic::Action); @@ -456,7 +468,7 @@ enum Message { Escape, Filename(String), Filter(usize), - Key(Modifiers, Key, Physical, Option), + Key(Modifiers, Key, Option), ModifiersChanged(Modifiers), MounterItems(MounterKey, MounterItems), Mouse(window::Id, mouse::Button), @@ -475,7 +487,7 @@ enum Message { TabMessage(tab::Message), TabRescan( Location, - Option>, + Option, Vec, Option>, ), @@ -575,7 +587,7 @@ impl App { space_s, space_l, .. - } = theme::spacing(); + } = theme::active().cosmic().spacing; let is_condensed = self.core().is_condensed(); let mut col = widget::column::with_capacity(2).spacing(space_xxs); @@ -732,17 +744,11 @@ impl App { fn rescan_tab(&self, selection_paths: Option>) -> Task { let location = self.tab.location.clone(); let icon_sizes = self.tab.config.icon_sizes; - #[cfg(feature = "gvfs")] let mounter_items = self.mounter_items.clone(); Task::future(async move { let location2 = location.clone(); match tokio::task::spawn_blocking(move || location2.scan(icon_sizes)).await { - Ok((parent_item_opt, items)) => { - #[cfg(feature = "gvfs")] - let mut items = items; - #[cfg(not(feature = "gvfs"))] - let items = items; - + Ok((parent_item_opt, mut items)) => { #[cfg(feature = "gvfs")] { let mounter_paths: Box<[_]> = mounter_items @@ -831,10 +837,9 @@ impl App { fn update_config(&mut self) -> Task { self.core.window.show_context = self.flags.config.dialog.show_details; - let config = self.flags.config.dialog_tab(); - self.tab.config.view = config.view; + self.tab.config = self.flags.config.dialog_tab(); self.update_nav_model(); - self.update(Message::TabMessage(tab::Message::Config(config))) + self.update(Message::TabMessage(tab::Message::Config(self.tab.config))) } fn with_dialog_config(&mut self, f: F) -> Task { @@ -897,8 +902,6 @@ impl App { if let Some(path) = favorite.path_opt() { let name = if matches!(favorite, Favorite::Home) { fl!("home") - } else if let Favorite::Network { name, .. } = favorite { - name.clone() } else if let Some(file_name) = path.file_name().and_then(|x| x.to_str()) { file_name.to_string() } else { @@ -1122,7 +1125,7 @@ impl Application for App { } fn dialog(&self) -> Option> { - let cosmic_theme::Spacing { space_xxs, .. } = theme::spacing(); + let cosmic_theme::Spacing { space_xxs, .. } = theme::active().cosmic().spacing; //TODO: should gallery view just be a dialog? if self.tab.gallery { @@ -1400,10 +1403,7 @@ impl Application for App { Message::Config(config) => { if config != self.flags.config { log::info!("update config"); - // Don't overwrite military time - let military_time = self.flags.config.tab.military_time; self.flags.config = config; - self.flags.config.tab.military_time = military_time; return self.update_config(); } } @@ -1456,16 +1456,16 @@ impl Application for App { } return self.rescan_tab(None); } - Message::Key(modifiers, key, physical_key, text) => { + Message::Key(modifiers, key, text) => { for (key_bind, action) in &self.key_binds { - if key_bind.matches(modifiers, &key, Some(&physical_key)) { + if key_bind.matches(modifiers, &key) { return self.update(Message::from(action.message())); } } // Check key binds from accept label if let Some(key_bind) = &self.accept_label.key_bind_opt - && key_bind.matches(modifiers, &key, Some(&physical_key)) + && key_bind.matches(modifiers, &key) { return self.update(if self.flags.kind.save() { Message::Save(false) @@ -1801,7 +1801,6 @@ impl Application for App { let autosize_id = widget::Id::unique(); commands.push(self.update(Message::Surface( cosmic::surface::action::app_popup( - |_: &Self| cosmic::surface::action::LiveSettings::default(), move |app: &mut Self| -> SctkPopupSettings { let anchor_rect = Rectangle { x: point.x as i32, @@ -1926,13 +1925,11 @@ impl Application for App { items.retain(|item| { // Directories are always shown item.metadata.is_dir() - // Check for mime type match (first because it is faster) || mimes.iter().any(|filter_mime| { if filter_mime.subtype() == mime::STAR { filter_mime.type_() == item.mime.type_() } else { *filter_mime == item.mime - || mime_icon::is_mime_subclass_of(&item.mime, filter_mime) } }) // Check for glob match (last because it is slower) @@ -2020,7 +2017,7 @@ impl Application for App { /// Creates a view after each update. fn view(&self) -> Element<'_, Message> { - let cosmic_theme::Spacing { space_xxs, .. } = theme::spacing(); + let cosmic_theme::Spacing { space_xxs, .. } = theme::active().cosmic().spacing; let mut col = widget::column::with_capacity(2); @@ -2059,14 +2056,11 @@ impl Application for App { }, Event::Keyboard(KeyEvent::KeyPressed { key, - physical_key, modifiers, text, .. }) => match status { - event::Status::Ignored => { - Some(Message::Key(modifiers, key, physical_key, text)) - } + event::Status::Ignored => Some(Message::Key(modifiers, key, text)), event::Status::Captured => { if key == Key::Named(Named::Escape) { Some(Message::Escape) diff --git a/src/key_bind.rs b/src/key_bind.rs index d3ddd59..57a9dbf 100644 --- a/src/key_bind.rs +++ b/src/key_bind.rs @@ -1,10 +1,11 @@ -use cosmic::iced::core::keyboard::key::Named; -use cosmic::iced::keyboard::Key; -use cosmic::widget::menu::key_bind::{KeyBind, Modifier}; +use cosmic::{ + iced::core::keyboard::key::Named, + iced::keyboard::Key, + widget::menu::key_bind::{KeyBind, Modifier}, +}; use std::collections::HashMap; -use crate::app::Action; -use crate::tab; +use crate::{app::Action, tab}; //TODO: load from config pub fn key_binds(mode: &tab::Mode) -> HashMap { @@ -30,16 +31,12 @@ pub fn key_binds(mode: &tab::Mode) -> HashMap { bind!([], Key::Named(Named::F5), Reload); bind!([], Key::Named(Named::Home), SelectFirst); bind!([], Key::Named(Named::End), SelectLast); - bind!([], Key::Named(Named::PageDown), ItemPageDown); - bind!([], Key::Named(Named::PageUp), ItemPageUp); bind!([Shift], Key::Named(Named::ArrowDown), ItemDown); bind!([Shift], Key::Named(Named::ArrowLeft), ItemLeft); bind!([Shift], Key::Named(Named::ArrowRight), ItemRight); bind!([Shift], Key::Named(Named::ArrowUp), ItemUp); bind!([Shift], Key::Named(Named::Home), SelectFirst); bind!([Shift], Key::Named(Named::End), SelectLast); - bind!([Shift], Key::Named(Named::PageDown), ItemPageDown); - bind!([Shift], Key::Named(Named::PageUp), ItemPageUp); bind!([Ctrl, Shift], Key::Character("n".into()), NewFolder); bind!([], Key::Named(Named::Enter), Open); bind!([Ctrl], Key::Character(" ".into()), Preview); diff --git a/src/large_image.rs b/src/large_image.rs index 1d78bc5..8686a97 100644 --- a/src/large_image.rs +++ b/src/large_image.rs @@ -1,7 +1,9 @@ use cosmic::widget; use image::ImageReader; -use std::collections::{HashMap, HashSet}; -use std::path::{Path, PathBuf}; +use std::{ + collections::{HashMap, HashSet}, + path::{Path, PathBuf}, +}; /// Bytes per pixel in RGBA format (Red, Green, Blue, Alpha = 4 bytes) pub const RGBA_BYTES_PER_PIXEL: u64 = 4; diff --git a/src/lib.rs b/src/lib.rs index 44b87f6..3e89861 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,16 +1,15 @@ // Copyright 2023 System76 // SPDX-License-Identifier: GPL-3.0-only -use cosmic::app::Settings; -use cosmic::iced::Limits; -use std::path::PathBuf; -use std::{env, fs, process}; -use tracing_subscriber::layer::SubscriberExt; -use tracing_subscriber::util::SubscriberInitExt; +use cosmic::{app::Settings, iced::Limits}; +use std::{env, fs, path::PathBuf, process}; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; -use crate::app::{App, Flags}; -use crate::config::{Config, State}; -use crate::tab::Location; +use crate::{ + app::{App, Flags}, + config::{Config, State}, + tab::Location, +}; pub mod app; mod archive; @@ -38,7 +37,6 @@ mod zoom; pub(crate) type FxOrderMap = ordermap::OrderMap; -#[cfg(feature = "gvfs")] pub(crate) fn err_str(err: T) -> String { err.to_string() } diff --git a/src/load_image.rs b/src/load_image.rs index 88ceb1b..d54fe7f 100644 --- a/src/load_image.rs +++ b/src/load_image.rs @@ -1,10 +1,11 @@ use cosmic::iced::{core as iced_core, widget as iced_widget}; use iced_core::event::Event; +use iced_core::layout; +use iced_core::mouse; +use iced_core::overlay; +use iced_core::renderer; use iced_core::widget::{Operation, Tree}; -use iced_core::{ - Clipboard, Element, Layout, Length, Rectangle, Shell, Vector, Widget, layout, mouse, overlay, - renderer, -}; +use iced_core::{Clipboard, Element, Layout, Length, Rectangle, Shell, Vector, Widget}; pub fn loaded_image<'a, Message: 'static, Theme>( handle: ::Handle, diff --git a/src/localize.rs b/src/localize.rs index b569807..f561a42 100644 --- a/src/localize.rs +++ b/src/localize.rs @@ -1,10 +1,13 @@ // SPDX-License-Identifier: GPL-3.0-only -use i18n_embed::fluent::{FluentLanguageLoader, fluent_language_loader}; -use i18n_embed::{DefaultLocalizer, LanguageLoader, Localizer}; -use icu::collator::options::CollatorOptions; -use icu::collator::preferences::CollationNumericOrdering; -use icu::collator::{Collator, CollatorBorrowed, CollatorPreferences}; +use i18n_embed::{ + DefaultLocalizer, LanguageLoader, Localizer, + fluent::{FluentLanguageLoader, fluent_language_loader}, +}; +use icu::collator::{ + Collator, CollatorBorrowed, CollatorPreferences, options::CollatorOptions, + preferences::CollationNumericOrdering, +}; use icu::locale::Locale; use rust_embed::RustEmbed; use std::sync::LazyLock; diff --git a/src/menu.rs b/src/menu.rs index 8439655..89e4a02 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -1,28 +1,30 @@ // SPDX-License-Identifier: GPL-3.0-only -use cosmic::app::Core; -use cosmic::iced::advanced::widget::text::Style as TextStyle; -use cosmic::iced::keyboard::Modifiers; -use cosmic::iced::{Alignment, Background, Border, Length}; -use cosmic::widget::menu::key_bind::KeyBind; -use cosmic::widget::menu::{self, ItemHeight, ItemWidth, MenuBar}; -use cosmic::widget::{ - self, Row, button, column, container, divider, responsive_menu_bar, space, text, +use cosmic::{ + Element, + app::Core, + iced::{ + Alignment, Background, Border, Length, advanced::widget::text::Style as TextStyle, + keyboard::Modifiers, + }, + theme, + widget::{ + self, Row, button, column, container, divider, + menu::{self, ItemHeight, ItemWidth, MenuBar, key_bind::KeyBind}, + responsive_menu_bar, space, text, + }, }; -use cosmic::{Element, theme}; -#[cfg(feature = "desktop")] use i18n_embed::LanguageLoader; use mime_guess::Mime; -use std::collections::HashMap; -use std::sync::LazyLock; +use std::{collections::HashMap, sync::LazyLock}; -use crate::app::{Action, Message}; -use crate::config::{Config, ContextActionPreset}; -use crate::fl; -use crate::tab::{ - self, HeadingOptions, ItemMetadata, Location, LocationMenuAction, SearchLocation, Tab, +use crate::{ + app::{Action, Message}, + config::{Config, ContextActionPreset}, + fl, + tab::{self, HeadingOptions, Location, LocationMenuAction, SearchLocation, Tab}, + trash::{Trash, TrashExt}, }; -use crate::trash::{Trash, TrashExt}; static MENU_ID: LazyLock = LazyLock::new(|| cosmic::widget::Id::new("responsive-menu")); @@ -36,7 +38,7 @@ macro_rules! menu_button { .height(Length::Fixed(24.0)) .align_y(Alignment::Center) ) - .padding([theme::spacing().space_xxs, 16]) + .padding([theme::active().cosmic().spacing.space_xxs, 16]) .width(Length::Fill) .class(theme::Button::MenuItem) ); @@ -70,19 +72,17 @@ pub fn context_menu<'a>( String::new() }; fn key_style(theme: &cosmic::Theme) -> TextStyle { - let mut color = theme.cosmic().background(false).component.on; + let mut color = theme.cosmic().background.component.on; color.alpha *= 0.75; TextStyle { color: Some(color.into()), - ..Default::default() } } fn disabled_style(theme: &cosmic::Theme) -> TextStyle { - let mut color = theme.cosmic().background(false).component.on; + let mut color = theme.cosmic().background.component.on; color.alpha *= 0.5; TextStyle { color: Some(color.into()), - ..Default::default() } } @@ -110,25 +110,18 @@ pub fn context_menu<'a>( let (sort_name, sort_direction, _) = tab.sort_options(); let sort_item = |label, variant| { - let key = find_key(&Action::ToggleSort(variant)); - let leading: Element<'a, tab::Message> = if sort_name == variant { - let icon_name = if sort_direction { - "view-sort-ascending-symbolic" - } else { - "view-sort-descending-symbolic" - }; - widget::icon::from_name(icon_name).size(14).into() - } else { - space::horizontal().width(Length::Fixed(14.0)).into() - }; - menu_button!( - leading, - space::horizontal().width(Length::Fixed(theme::spacing().space_xxs.into())), - text::body(label), - space::horizontal(), - text::body(key).class(theme::Text::Custom(key_style)) + menu_item( + format!( + "{} {}", + label, + match (sort_name == variant, sort_direction) { + (true, true) => "\u{2B07}", + (true, false) => "\u{2B06}", + _ => "", + } + ), + Action::ToggleSort(variant), ) - .on_press(tab::Message::ContextAction(Action::ToggleSort(variant))) .into() }; @@ -138,7 +131,6 @@ pub fn context_menu<'a>( let mut selected_desktop_entry = None; let mut selected_types: Vec = vec![]; let mut selected_mount_point = 0; - let mut any_trash_item = false; if let Some(items) = tab.items_opt() { for item in items { if item.selected { @@ -151,17 +143,15 @@ pub fn context_menu<'a>( Some(Location::Trash) | Some(Location::Search(SearchLocation::Trash, ..)) => { selected_trash_only = true } - Some(Location::Path(path)) + Some(Location::Path(path)) => { if selected == 1 - && path.extension().and_then(|s| s.to_str()) == Some("desktop") => - { - selected_desktop_entry = Some(&**path); + && path.extension().and_then(|s| s.to_str()) == Some("desktop") + { + selected_desktop_entry = Some(&**path); + } } _ => (), } - if matches!(&item.metadata, ItemMetadata::Trash { .. }) { - any_trash_item = true; - } selected_types.push(item.mime.clone()); } } @@ -206,11 +196,11 @@ pub fn context_menu<'a>( if !Trash::is_empty() { children.push(menu_item(fl!("empty-trash"), Action::EmptyTrash).into()); } - } else if let Some(_entry) = selected_desktop_entry { + } else if let Some(entry) = selected_desktop_entry { children.push(menu_item(fl!("open"), Action::Open).into()); #[cfg(feature = "desktop")] { - children.extend(_entry.desktop_actions.into_iter().enumerate().map( + children.extend(entry.desktop_actions.into_iter().enumerate().map( |(i, action)| menu_item(action.name, Action::ExecEntryAction(i)).into(), )); } @@ -283,38 +273,27 @@ pub fn context_menu<'a>( //TODO: Print? children.push(menu_item(fl!("show-details"), Action::Preview).into()); - if any_trash_item { + if matches!(tab.mode, tab::Mode::App) { children.push(divider::horizontal::light().into()); + children.push(menu_item(fl!("add-to-sidebar"), Action::AddToSidebar).into()); + } + children.push(divider::horizontal::light().into()); + if tab.location.is_recents() { children.push( - menu_item(fl!("restore-from-trash"), Action::RestoreFromTrash).into(), + menu_item(fl!("remove-from-recents"), Action::RemoveFromRecents).into(), ); children.push(divider::horizontal::light().into()); - children.push(menu_item(fl!("delete-permanently"), Action::Delete).into()); - } else { - if matches!(tab.mode, tab::Mode::App) { - children.push(divider::horizontal::light().into()); - children - .push(menu_item(fl!("add-to-sidebar"), Action::AddToSidebar).into()); - } - children.push(divider::horizontal::light().into()); - if tab.location.is_recents() { + } + if selected_mount_point == 0 { + if modifiers.shift() && !modifiers.control() { children.push( - menu_item(fl!("remove-from-recents"), Action::RemoveFromRecents).into(), + menu_item(fl!("delete-permanently"), Action::PermanentlyDelete).into(), ); - children.push(divider::horizontal::light().into()); - } - if selected_mount_point == 0 { - if modifiers.shift() && !modifiers.control() { - children.push( - menu_item(fl!("delete-permanently"), Action::PermanentlyDelete) - .into(), - ); - } else { - children.push(menu_item(fl!("move-to-trash"), Action::Delete).into()); - } - } else if selected == 1 { - children.push(menu_item(fl!("eject"), Action::Eject).into()); + } else { + children.push(menu_item(fl!("move-to-trash"), Action::Delete).into()); } + } else if selected == 1 { + children.push(menu_item(fl!("eject"), Action::Eject).into()); } } else { //TODO: need better designs for menu with no selection @@ -418,12 +397,6 @@ pub fn context_menu<'a>( if tab.mode.multiple() { children.push(menu_item(fl!("select-all"), Action::SelectAll).into()); } - if !Trash::is_empty() { - if !children.is_empty() { - children.push(divider::horizontal::light().into()); - } - children.push(menu_item(fl!("empty-trash"), Action::EmptyTrash).into()); - } if !children.is_empty() { children.push(divider::horizontal::light().into()); } @@ -448,7 +421,7 @@ pub fn context_menu<'a>( //TODO: move style to libcosmic .style(|theme| { let cosmic = theme.cosmic(); - let component = &cosmic.background(false).component; + let component = &cosmic.background.component; container::Style { icon_color: Some(component.on.into()), text_color: Some(component.on.into()), @@ -606,7 +579,7 @@ pub fn dialog_menu( ]) .item_height(ItemHeight::Dynamic(40)) .item_width(ItemWidth::Uniform(360)) - .spacing(theme::spacing().space_xxxs.into()) + .spacing(theme::active().cosmic().spacing.space_xxxs.into()) .into() } @@ -661,7 +634,7 @@ pub fn menu_bar<'a>( responsive_menu_bar() .item_height(ItemHeight::Dynamic(40)) .item_width(ItemWidth::Uniform(360)) - .spacing(theme::spacing().space_xxxs.into()) + .spacing(theme::active().cosmic().spacing.space_xxxs.into()) .into_element( core, key_binds, @@ -842,7 +815,7 @@ pub fn location_context_menu<'a>(ancestor_index: usize) -> Element<'a, tab::Mess .padding(1) .style(|theme| { let cosmic = theme.cosmic(); - let component = &cosmic.background(false).component; + let component = &cosmic.background.component; container::Style { icon_color: Some(component.on.into()), text_color: Some(component.on.into()), diff --git a/src/mime_app.rs b/src/mime_app.rs index 8fd8a60..4a55cdf 100644 --- a/src/mime_app.rs +++ b/src/mime_app.rs @@ -1,171 +1,155 @@ // Copyright 2023 System76 // SPDX-License-Identifier: GPL-3.0-only -use bstr::{BString, ByteSlice, ByteVec}; +#[cfg(feature = "desktop")] +use cosmic::desktop; use cosmic::widget; pub use mime_guess::Mime; -#[cfg(feature = "desktop")] -use notify_debouncer_full::notify; -use rustc_hash::{FxHashMap, FxHashSet}; -use std::ffi::OsStr; -use std::os::unix::ffi::OsStrExt; -use std::path::{Path, PathBuf}; -use std::sync::atomic::AtomicBool; -use std::sync::{Arc, RwLock, atomic}; -use std::time::{self, Instant}; -use std::{fs, io, process}; +use rustc_hash::FxHashMap; +use std::{ + cmp::Ordering, + ffi::OsStr, + fs, io, + path::{Path, PathBuf}, + process, + time::Instant, +}; -#[cfg(feature = "desktop")] -pub async fn watch(mut emitter: impl FnMut() + 'static + Send) { - let watcher_result = notify_debouncer_full::new_debouncer( - time::Duration::from_millis(250), - Some(time::Duration::from_millis(250)), - move |event_res: notify_debouncer_full::DebounceEventResult| { - let Ok(events) = event_res else { - return; - }; - - if events.iter().any(|event| { - event.kind.is_create() || event.kind.is_modify() || event.kind.is_remove() - }) { - emitter(); - } - }, - ); - - if let Ok(mut watcher) = watcher_result { - let system_paths = cosmic_mime_apps::list_paths(); - let local_paths = (|| { - let base_dirs = xdg::BaseDirectories::new(); - let Some(home) = base_dirs.get_config_home() else { - return Err(std::io::Error::other("XDG config home not set")); - }; - - let Ok(desktop) = std::env::var("XDG_CURRENT_DESKTOP") else { - return Err(std::io::Error::other("XDG_CURRENT_DESKTOP unset")); - }; - - let default_mimeapps = home.join("mimeapps.list"); - let desktop_mimeapps = - home.join([&desktop.to_ascii_lowercase(), "-mimeapps.list"].concat()); - - Ok([desktop_mimeapps, default_mimeapps]) - })() - .ok(); - - for path in system_paths - .iter() - .chain(local_paths.as_ref().into_iter().flatten()) - { - _ = watcher.watch(path.as_path(), notify::RecursiveMode::NonRecursive); - } - - std::future::pending().await - } -} +// Supported exec key field codes +const EXEC_HANDLERS: [&str; 4] = ["%f", "%F", "%u", "%U"]; +// Deprecated field codes. The spec advises to ignore these handlers. +const DEPRECATED_HANDLERS: [&str; 6] = ["%d", "%D", "%n", "%N", "%v", "%m"]; pub fn exec_to_command( exec: &str, - entry_name: &str, - entry_path: Option<&Path>, path_opt: &[impl AsRef], ) -> Option> { - let arguments = shlex::split(exec)?; + let args_vec = shlex::split(exec)?; + let program = args_vec.first()?; + // Skip program to make indexing easier + let args_vec = &args_vec[1..]; - if arguments.is_empty() { - tracing::error!("command does not contain any arguments"); - return None; - } - - let mut commands = Vec::new(); - - let paths = path_opt + // Base Command instance(s) + // 1. We may need to launch multiple of the same process. + // 2. Each of those processes will need to be passed args from exec. + // 3. Each of those args may appear in any order. + // 4. Arg order should be preserved. + // + // So, we'll go through exec in two passes. The first pass handles paths (%f etc) and args up + // to the field code followed by the second which passes extra, non-% args to each processes. + // + // While it'd be marginally faster to process everything in one pass, that's problematic: + // 1. path_opt may need to be cloned because it may be moved on each iteration (borrowck + // doesn't know we'll only use it once) + // 2. We have to keep track of which modifier (%f etc) we've used/seen already + // 3. We have to keep track of which processes received non-modifier args which gets messy fast + // 4. `exec` is likely small so looping over it twice is not a big deal + let field_code_pos = args_vec .iter() - .map(AsRef::as_ref) - .map(Some) - // Add a single `None` if no path was given. - .chain(std::iter::repeat_n( - None, - if path_opt.is_empty() { 1 } else { 0 }, - )); + .position(|arg| EXEC_HANDLERS.contains(&arg.as_str())); + let args_handler = field_code_pos.and_then(|i| args_vec.get(i)); + // msrv + // .inspect(|handler| log::trace!("Found paths handler: {handler} for exec: {exec}")); + // Number of args before the field code. + // This won't be an off by one err below because take is not zero indexed. + let field_code_pos = field_code_pos.unwrap_or_default(); + let mut processes = match args_handler.map(String::as_str) { + Some("%f") => { + let mut processes = Vec::with_capacity(path_opt.len()); - for path in paths { - let mut batch_process = false; - let mut args = Vec::with_capacity(arguments.len()); - let mut field_code_used = false; - - for argument in arguments.iter().skip(1) { - let mut new_argument = BString::new(Vec::with_capacity(argument.capacity())); - let mut chars = argument.chars(); - while let Some(char) = chars.next() { - // https://specifications.freedesktop.org/desktop-entry/latest/exec-variables.html - if char == '%' { - match chars.next() { - Some('%') => new_argument.push_char(char), - Some('c') => new_argument.push_str(entry_name), - Some('k') => { - if let Some(path) = entry_path { - new_argument.push_str(path.as_os_str().as_bytes()); - } - } - - // %f and %u behave the same in a file manager. - Some('f' | 'u') => { - if let Some(path) = path - && !field_code_used - { - // TODO: files on remote file systems should be copied to a temporary local file. - batch_process = true; - field_code_used = true; - new_argument.push_str(path.as_bytes()); - } - } - - // %F and %U behave the same in a file manager. - Some('F') | Some('U') => { - if !field_code_used && new_argument.is_empty() { - field_code_used = true; - for path in path_opt.iter().map(AsRef::as_ref) { - args.push(BString::new(path.as_bytes().to_owned())); - } - } - } - - _ => (), - } - } else { - new_argument.push_char(char); + for path in path_opt.iter().map(AsRef::as_ref) { + // TODO: %f and %F need to handle non-file URLs (see spec) + if from_file_or_dir(path).is_none() { + log::warn!("Desktop file expects a file path instead of a URL: {path:?}"); } + + // Passing multiple paths to %f should open an instance per path + let mut process = process::Command::new(program); + process.args( + args_vec + .iter() + .map(AsRef::as_ref) + .take(field_code_pos) + .chain(std::iter::once(path)), + ); + processes.push(process); } - if !new_argument.is_empty() { - args.push(new_argument); - } + processes } + Some("%F") => { + // TODO: %f and %F need to handle non-file URLs (see spec) + for invalid in path_opt + .iter() + .map(AsRef::as_ref) + .filter(|&path| from_file_or_dir(path).is_none()) + { + log::warn!("Desktop file expects a file path instead of a URL: {invalid:?}"); + } - let mut command = process::Command::new(&arguments[0]); + // Launch one instance with all args + let mut process = process::Command::new(program); + process.args( + args_vec + .iter() + .map(OsStr::new) + .take(field_code_pos) + .chain(path_opt.iter().map(AsRef::as_ref)), + ); - for arg in args { - match arg.to_os_str() { - Ok(arg) => { - command.arg(arg); - } - Err(_) => { - tracing::error!("invalid string encoding in command"); + vec![process] + } + Some("%u") => path_opt + .iter() + .map(|path| { + let mut process = process::Command::new(program); + process.args( + args_vec + .iter() + .map(OsStr::new) + .take(field_code_pos) + .chain(std::iter::once(path.as_ref())), + ); + process + }) + .collect(), + Some("%U") => { + let mut process = process::Command::new(program); + process.args( + args_vec + .iter() + .map(OsStr::new) + .take(field_code_pos) + .chain(path_opt.iter().map(AsRef::as_ref)), + ); + vec![process] + } + Some(invalid) => unreachable!("All valid variants were checked; got: {invalid}"), + None => vec![process::Command::new(program)], + }; + + // Pass 2: Add remaining arguments that are not % to each process + for arg in args_vec.iter().skip(field_code_pos) { + match arg.as_str() { + // Consume path field codes or fail on codes we don't handle yet + field_code if arg.starts_with('%') => { + if !EXEC_HANDLERS.contains(&field_code) + && !DEPRECATED_HANDLERS.contains(&field_code) + { + log::warn!("unsupported Exec code {field_code:?} in {exec:?}"); return None; } } - } - - commands.push(command); - - if !batch_process { - break; + arg => { + for process in &mut processes { + process.arg(arg); + } + } } } #[cfg(debug_assertions)] - for command in &commands { + for command in &processes { log::debug!( "Parsed program {} with args: {:?}", command.get_program().to_string_lossy(), @@ -173,14 +157,13 @@ pub fn exec_to_command( ); } - Some(commands) + Some(processes) } -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum MimeAppMatch { - Exact, - Related, - Other, +fn from_file_or_dir(path: impl AsRef) -> Option { + url::Url::from_file_path(&path) + .ok() + .or_else(|| url::Url::from_directory_path(&path).ok()) } #[derive(Clone, Debug)] @@ -189,42 +172,14 @@ pub struct MimeApp { pub path: Option, pub name: String, pub exec: Option, - icon_name: Box, - icon: std::sync::OnceLock, - is_default: Arc>>>, - no_display: Arc, + pub icon: widget::icon::Handle, + pub is_default: bool, } impl MimeApp { //TODO: move to libcosmic, support multiple files pub fn command>(&self, path_opt: &[O]) -> Option> { - exec_to_command( - self.exec.as_deref()?, - &self.name, - self.path.as_deref(), - path_opt, - ) - } - - pub fn is_default(&self, mime: &Mime) -> bool { - self.is_default.read().unwrap().contains(mime.essence_str()) - } - - pub fn no_display(&self) -> bool { - self.no_display.load(atomic::Ordering::Relaxed) - } - - pub fn icon(&self) -> widget::icon::Handle { - self.icon - .get_or_init(|| { - let name = &*self.icon_name; - if name.starts_with('/') { - cosmic::widget::icon::from_path(PathBuf::from(name)) - } else { - cosmic::widget::icon::from_name(name).size(32).handle() - } - }) - .clone() + exec_to_command(self.exec.as_deref()?, path_opt) } } @@ -235,10 +190,38 @@ impl AsRef for MimeApp { } } +#[cfg(feature = "desktop")] +impl From<&desktop::DesktopEntryData> for MimeApp { + fn from(app: &desktop::DesktopEntryData) -> Self { + Self { + id: app.id.clone(), + path: app.path.clone(), + name: app.name.clone(), + exec: app.exec.clone(), + icon: match &app.icon { + desktop::fde::IconSource::Name(name) => { + widget::icon::from_name(name.as_str()).size(32).handle() + } + desktop::fde::IconSource::Path(path) => widget::icon::from_path(path.clone()), + }, + is_default: false, + } + } +} + +#[cfg(feature = "desktop")] +fn filename_eq(path_opt: &Option, filename: &str) -> bool { + path_opt + .as_ref() + .and_then(|path| path.file_name()) + .is_some_and(|x| x == filename) +} + pub struct MimeAppCache { - apps: Vec>, - cache: FxHashMap>>, - terminals: Vec>, + apps: Vec, + cache: FxHashMap>, + icons: FxHashMap>, + terminals: Vec, } impl MimeAppCache { @@ -246,273 +229,154 @@ impl MimeAppCache { let mut mime_app_cache = Self { apps: Vec::new(), cache: FxHashMap::default(), + icons: FxHashMap::default(), terminals: Vec::new(), }; mime_app_cache.reload(); mime_app_cache } - pub fn get_apps_for_mime( - &self, - mime_type: &Mime, - include_other: bool, - ) -> Vec<(&Arc, MimeAppMatch)> { - let mut results = Vec::new(); - let mut dedupe = FxHashSet::default(); - - // start with exact matches - results.extend( - self.get(mime_type) - .iter() - .filter(|&mime_app| dedupe.insert(&mime_app.id)) - .map(|mime_app| (mime_app, MimeAppMatch::Exact)), - ); - - let include_mime = match mime_type.type_().as_str() { - "audio" => Some("video/mp4".parse::().expect("video/mp4 mime")), - "text" => Some(mime_guess::mime::TEXT_PLAIN), - _ => None, - }; - - if let Some(mime) = include_mime { - results.extend( - self.get(&mime) - .iter() - .filter(|&mime_app| dedupe.insert(&mime_app.id)) - .map(|mime_app| (mime_app, MimeAppMatch::Exact)), - ); - } - - // grab matches based off of subclass / parent mime type - if let Some(parent_types) = crate::mime_icon::parent_mime_types(mime_type) { - for parent_type in parent_types { - results.extend( - self.get(&parent_type) - .iter() - .filter(|&mime_app| dedupe.insert(&mime_app.id)) - .map(|mime_app| (mime_app, MimeAppMatch::Related)), - ); - } - } - - if include_other { - results.extend({ - let mut apps = self - .apps() - .iter() - .filter(|mime_app| !mime_app.no_display()) - .filter(|&mime_app| dedupe.insert(&mime_app.id)) - .map(|mime_app| (mime_app, MimeAppMatch::Other)) - .collect::>(); - apps.sort_by(|(a, _), (b, _)| { - crate::localize::LANGUAGE_SORTER.compare(&a.name, &b.name) - }); - apps - }); - } - - results - } - #[cfg(not(feature = "desktop"))] pub fn reload(&mut self) {} - /// Reload mime types and their known app associations and defaults. + // Only available when using desktop feature of libcosmic, which only works on Unix-likes #[cfg(feature = "desktop")] pub fn reload(&mut self) { use crate::localize::LANGUAGE_SORTER; - use crate::mime_icon; - use cosmic::desktop::fde; - use std::borrow::Cow; let start = Instant::now(); self.apps.clear(); self.cache.clear(); + self.icons.clear(); self.terminals.clear(); + //TODO: get proper locale? + let locale = &[]; + + // Load desktop applications by supported mime types + //TODO: hashmap for all apps by id? + let all_apps: Box<[_]> = desktop::load_applications(locale, false, None).collect(); + for app in &all_apps { + //TODO: just collect apps that can be executed with a file argument? + if !app.mime_types.is_empty() { + self.apps.push(MimeApp::from(app)); + } + for mime in &app.mime_types { + let apps = self + .cache + .entry(mime.clone()) + .or_insert_with(|| Vec::with_capacity(1)); + if !apps.iter().any(|x| x.id == app.id) { + apps.push(MimeApp::from(app)); + } + } + for category in &app.categories { + if category == "TerminalEmulator" { + self.terminals.push(MimeApp::from(app)); + break; + } + } + } + let mut list = cosmic_mime_apps::List::default(); + let paths = cosmic_mime_apps::list_paths(); list.load_from_paths(&paths); - let locales = fde::get_languages_from_env(); - let desktop_entries = fde::Iter::new(fde::default_paths()).entries(Some(&locales)); - let mime_icon_cache = mime_icon::MIME_ICON_CACHE.lock().unwrap(); - let shared_mime_info = &mime_icon_cache.shared_mime_info; - let mut aliased_mimes = FxHashMap::default(); - for desktop_entry in desktop_entries { - let name = desktop_entry - .name(&locales) - .unwrap_or_else(|| Cow::Borrowed(desktop_entry.id())); - - let app = Arc::new(MimeApp { - id: desktop_entry.appid.clone(), - path: Some(desktop_entry.path.clone()), - name: name.into(), - exec: desktop_entry.exec().map(String::from), - icon_name: desktop_entry.icon().unwrap_or_default().into(), - icon: std::sync::OnceLock::new(), - is_default: Arc::new(RwLock::default()), - no_display: Arc::new(AtomicBool::new(false)), - }); - - tracing::info!(target: "mime-apps", id = app.id, "detected desktop entry"); - - self.apps.push(app.clone()); - - if desktop_entry - .categories() - .into_iter() - .flatten() - .any(|c| c == "TerminalEmulator") - { - self.terminals.push(app.clone()); - } - - // Cache associations defined by the desktop entry. - let mime_types = desktop_entry.mime_type().unwrap_or_else(Vec::new); - let associated_mime_types = mime_types.iter().filter_map(|m| { - m.parse::().ok().map(|mime| { - if let Some(unaliased) = shared_mime_info.unalias_mime_type(&mime) { - aliased_mimes.insert(unaliased.clone(), mime); - return unaliased; - } - - mime - }) - }); - - for mime in associated_mime_types { - let apps = self.cache.entry(mime.clone()).or_default(); - if apps.iter().all(|cached_app| cached_app.id != app.id) { - apps.push(app.clone()); - } - } - } - - // Cache added associations from mimeapps lists. - for (mut added_mime, added_apps) in &list.added_associations { - let _unaliased; - if let Some(unaliased) = shared_mime_info.unalias_mime_type(added_mime) { - aliased_mimes.insert(unaliased.clone(), added_mime.clone()); - _unaliased = unaliased; - added_mime = &_unaliased; - } - - for added_app in added_apps { - if let Some(app) = self - .apps - .iter() - .find(|cached| cached.id.as_str() == added_app.as_ref()) - { - let apps = self.cache.entry(added_mime.clone()).or_default(); - if apps.iter().all(|cached_app| cached_app.id != app.id) { - apps.push(app.clone()); + for (mime, filenames) in list + .added_associations + .iter() + .chain(list.default_apps.iter()) + { + for filename in filenames { + log::trace!("add {mime}={filename}"); + let apps = self + .cache + .entry(mime.clone()) + .or_insert_with(|| Vec::with_capacity(1)); + if !apps.iter().any(|x| filename_eq(&x.path, filename)) { + if let Some(app) = all_apps.iter().find(|&x| filename_eq(&x.path, filename)) { + apps.push(MimeApp::from(app)); + } else { + log::info!( + "failed to add association for {mime:?}: application {filename:?} not found" + ); } } } } - // Remove associations - for (mut removed_mime, removed_apps) in &list.removed_associations { - let _unaliased; - if let Some(unaliased) = shared_mime_info.unalias_mime_type(removed_mime) { - aliased_mimes.insert(unaliased.clone(), removed_mime.clone()); - _unaliased = unaliased; - removed_mime = &_unaliased; - } - - for removed_app in removed_apps { - if let Some(app) = self - .apps - .iter() - .find(|cached| cached.id.as_str() == removed_app.as_ref()) - && let Some(apps) = self.cache.get_mut(removed_mime) - { - apps.retain(|cached_app| cached_app.id != app.id); + for (mime, filenames) in list.removed_associations.iter() { + for filename in filenames { + log::trace!("remove {mime}={filename}"); + if let Some(apps) = self.cache.get_mut(mime) { + apps.retain(|x| !filename_eq(&x.path, filename)); } } } - // Fetch defaults and sort apps by their default precedence. - for (mime, mut apps) in std::mem::take(&mut self.cache).into_iter() { - let defaults = list.default_app_for(&mime); - let aliased_defaults = aliased_mimes - .get(&mime) - .and_then(|mime| list.default_app_for(mime)); - - let cache = self - .cache - .entry(mime.clone()) - .or_insert_with(|| Vec::with_capacity(apps.len())); - - // Sort cached apps for this mime by default precedence. - for default in defaults - .into_iter() - .flatten() - .chain(aliased_defaults.into_iter().flatten()) - { - let default = default.strip_suffix(".desktop").unwrap_or(default.as_ref()); - let mut found_any = false; - apps.retain(|app| { - let found = app.id.as_str() == default; + for (mime, filenames) in list.default_apps.iter() { + for filename in filenames { + log::trace!("default {mime}={filename}"); + if let Some(apps) = self.cache.get_mut(mime) { + let mut found = false; + for app in apps.iter_mut() { + if filename_eq(&app.path, filename) { + app.is_default = true; + found = true; + } else { + app.is_default = false; + } + } if found { - app.is_default - .write() - .unwrap() - .insert(mime.essence_str().into()); - cache.push(app.clone()); - found_any = true; + break; } - - !found - }); - - if !found_any && let Some(app) = self.apps.iter().find(|app| app.id == default) { - app.is_default - .write() - .unwrap() - .insert(mime.essence_str().into()); - cache.push(app.clone()); + log::debug!( + "failed to set default for {mime:?}: application {filename:?} not found" + ); } } - - // Sort remaining apps by name - apps.sort_by(|a, b| LANGUAGE_SORTER.compare(&a.name, &b.name)); - cache.extend_from_slice(&apps); - - tracing::debug!(target: "mime-apps", mime = mime.essence_str(), apps = ?(cache.iter().map(|app| &*app.id).collect::>()), "mime defaults found") } - let associated: rustc_hash::FxHashSet<&str> = self - .cache - .values() - .flatten() - .map(|app| app.id.as_str()) - .collect(); - for app in &self.apps { - app.no_display.store( - !associated.contains(app.id.as_str()), - atomic::Ordering::Relaxed, - ); + // Sort apps by name + self.apps + .sort_by(|a, b| match (a.is_default, b.is_default) { + (true, false) => Ordering::Less, + (false, true) => Ordering::Greater, + _ => LANGUAGE_SORTER.compare(&a.name, &b.name), + }); + for apps in self.cache.values_mut() { + apps.sort_by(|a, b| match (a.is_default, b.is_default) { + (true, false) => Ordering::Less, + (false, true) => Ordering::Greater, + _ => LANGUAGE_SORTER.compare(&a.name, &b.name), + }); } + // Copy icons to special cache + //TODO: adjust dropdown API so this is no longer needed + self.icons.extend(self.cache.iter().map(|(mime, apps)| { + ( + mime.clone(), + apps.iter().map(|app| app.icon.clone()).collect(), + ) + })); + let elapsed = start.elapsed(); - tracing::info!(target: "mime-apps", "loaded mime app cache in {elapsed:?}"); + log::info!("loaded mime app cache in {elapsed:?}"); } - pub fn apps(&self) -> &[Arc] { + pub fn apps(&self) -> &[MimeApp] { &self.apps } - pub fn get(&self, key: &Mime) -> &[Arc] { + pub fn get(&self, key: &Mime) -> &[MimeApp] { self.cache.get(key).map_or(&[], Vec::as_slice) } - pub fn icons(&self, key: &Mime) -> Vec { - self.cache - .get(key) - .map_or_else(Vec::new, |apps| apps.iter().map(|app| app.icon()).collect()) + pub fn icons(&self, key: &Mime) -> &[widget::icon::Handle] { + self.icons.get(key).map_or(&[], Box::as_ref) } fn get_default_terminal(&self) -> Option { @@ -530,19 +394,14 @@ impl MimeAppCache { .map(|string| string.trim().replace(".desktop", "")) } - pub fn terminal(&self) -> Option<&Arc> { + pub fn terminal(&self) -> Option<&MimeApp> { //TODO: consider rules in https://github.com/Vladimir-csp/xdg-terminal-exec // The current approach works but might not adhere to the spec (yet) // Look for and return preferred terminals //TODO: fallback order beyond cosmic-term? - // Yoda: cosmic-yoterm (our fork) wins over upstream cosmic-term if both - // are installed — useful when xdg-mime default is not set. - let mut preference_order = vec![ - "com.aditua.CosmicYoterm".to_string(), - "com.system76.CosmicTerm".to_string(), - ]; + let mut preference_order = vec!["com.system76.CosmicTerm".to_string()]; if let Some(id) = self.get_default_terminal() { preference_order.insert(0, id); @@ -616,43 +475,11 @@ impl Default for MimeAppCache { mod tests { use super::exec_to_command; - #[test] - fn keys_within_words() { - let exec = "/usr/bin/foo --option=%f"; - let paths = ["file1"]; - let commands = exec_to_command(exec, "keys_within_words", None, &paths) - .expect("Should parse valid exec"); - - assert_eq!(1, commands.len()); - let command = commands.first().unwrap(); - - assert_eq!("/usr/bin/foo", command.get_program().to_str().unwrap()); - assert_eq!( - "--option=file1", - command.get_args().next().unwrap().to_str().unwrap() - ); - } - - #[test] - fn no_path_f_field_code() { - let exec = "/usr/bin/foo %f"; - let paths: [&str; 0] = []; - let commands = exec_to_command(exec, "no_path_f_field_code", None, &paths) - .expect("Should parse valid exec"); - - assert_eq!(1, commands.len()); - let command = commands.first().unwrap(); - - assert_eq!("/usr/bin/foo", command.get_program().to_str().unwrap()); - assert_eq!(0, command.get_args().len()); - } - #[test] fn one_path_f_field_code() { let exec = "/usr/bin/foo %f"; let paths = ["file1"]; - let commands = exec_to_command(exec, "one_path_f_field_code", None, &paths) - .expect("Should parse valid exec"); + let commands = exec_to_command(exec, &paths).expect("Should parse valid exec"); assert_eq!(1, commands.len()); let command = commands.first().unwrap(); @@ -667,40 +494,31 @@ mod tests { #[test] #[allow(non_snake_case)] fn one_path_F_field_code() { - let exec = "/usr/bin/cosmic-term -w %F"; - let paths = ["/home/user"]; - let commands = exec_to_command(exec, "one_path_F_field_code", None, &paths) - .expect("Should parse valid exec"); + let exec = "/usr/bin/bar %F"; + let paths = ["cat"]; + let commands = exec_to_command(exec, &paths).expect("Should parse valid exec"); assert_eq!(1, commands.len()); let command = commands.first().unwrap(); - let mut args = command.get_args(); - assert_eq!( - "/usr/bin/cosmic-term", - command.get_program().to_str().unwrap() - ); - assert_eq!("-w", args.next().unwrap().to_str().unwrap()); - assert_eq!(paths[0], args.next().unwrap().to_str().unwrap()); + assert_eq!("/usr/bin/bar", command.get_program().to_str().unwrap()); + assert_eq!("cat", command.get_args().next().unwrap().to_str().unwrap()); } #[test] fn one_path_u_field_code() { - let exec = "/usr/bin/cosmic-term -w %u"; - let paths = ["/home/user"]; - let commands = exec_to_command(exec, "one_path_u_field_code", None, &paths) - .expect("Should parse valid exec"); + let exec = "/usr/bin/foobar %u"; + let paths = ["/home/josh/krumpli"]; + let commands = exec_to_command(exec, &paths).expect("Should parse valid exec"); assert_eq!(1, commands.len()); let command = commands.first().unwrap(); - let mut args = command.get_args(); + assert_eq!("/usr/bin/foobar", command.get_program().to_str().unwrap()); assert_eq!( - "/usr/bin/cosmic-term", - command.get_program().to_str().unwrap() + *paths.first().unwrap(), + command.get_args().next().unwrap().to_str().unwrap() ); - assert_eq!("-w", args.next().unwrap().to_str().unwrap()); - assert_eq!(paths[0], args.next().unwrap().to_str().unwrap()); } #[test] @@ -708,8 +526,7 @@ mod tests { fn one_path_U_field_code() { let exec = "/usr/bin/rmrfbye %U"; let paths = ["/"]; - let commands = exec_to_command(exec, "one_path_U_field_code", None, &paths) - .expect("Should parse valid exec"); + let commands = exec_to_command(exec, &paths).expect("Should parse valid exec"); assert_eq!(1, commands.len()); let command = commands.first().unwrap(); @@ -725,8 +542,7 @@ mod tests { "/usr/share/games/psp/miku.iso", "/usr/share/games/psp/eternia.iso", ]; - let commands = exec_to_command(exec, "mult_path_f_field_code", None, &paths) - .expect("Should parse valid exec"); + let commands = exec_to_command(exec, &paths).expect("Should parse valid exec"); assert_eq!(paths.len(), commands.len()); for (command, path) in commands.into_iter().zip(paths.iter()) { @@ -746,8 +562,7 @@ mod tests { "/usr/share/games/doom2/hr.wad", "/usr/share/games/doom2/hrmus.wad", ]; - let commands = exec_to_command(exec, "mult_path_F_field_code", None, &paths) - .expect("Should parse valid exec"); + let commands = exec_to_command(exec, &paths).expect("Should parse valid exec"); assert_eq!(1, commands.len()); let command = commands.first().unwrap(); @@ -769,8 +584,7 @@ mod tests { "https://redox-os.org/", "https://system76.com/", ]; - let commands = exec_to_command(exec, "mult_path_u_field_code", None, &paths) - .expect("Should parse valid exec"); + let commands = exec_to_command(exec, &paths).expect("Should parse valid exec"); assert_eq!(paths.len(), commands.len()); for (command, path) in commands.into_iter().zip(paths.iter()) { @@ -793,8 +607,7 @@ mod tests { "frieren01.mkv", "rtmp://example.org/this/video/doesnt/exist.avi", ]; - let commands = exec_to_command(exec, "mult_path_U_field_code", None, &paths) - .expect("Should parse valid exec"); + let commands = exec_to_command(exec, &paths).expect("Should parse valid exec"); assert_eq!(1, commands.len()); let command = commands.first().unwrap(); @@ -822,8 +635,7 @@ mod tests { "@@u", ]; let paths = ["file1.rs", "file2.rs"]; - let commands = exec_to_command(exec, "flatpak_style_exec", None, &paths) - .expect("Should parse valid exec"); + let commands = exec_to_command(exec, &paths).expect("Should parse valid exec"); assert_eq!(1, commands.len()); let command = commands.first().unwrap(); @@ -846,8 +658,7 @@ mod tests { "file:///usr/share/games/roguelike/mods/mod1", "file:///usr/share/games/roguelike/mods/mod2", ]; - let commands = exec_to_command(exec, "multiple_field_codes", None, &paths) - .expect("Should parse valid exec"); + let commands = exec_to_command(exec, &paths).expect("Should parse valid exec"); assert_eq!(1, commands.len()); let command = commands.first().unwrap(); @@ -880,8 +691,7 @@ mod tests { ]; let paths = ["rust_game_dev.pdf", "superhero_ferris.epub"]; let args_trailing = ["@@"]; - let commands = exec_to_command(exec, "sandwiched_field_code", None, &paths) - .expect("Should parse valid exec"); + let commands = exec_to_command(exec, &paths).expect("Should parse valid exec"); assert_eq!(1, commands.len()); let command = commands.first().unwrap(); diff --git a/src/mime_icon.rs b/src/mime_icon.rs index 26d899d..8d8d2e5 100644 --- a/src/mime_icon.rs +++ b/src/mime_icon.rs @@ -3,9 +3,11 @@ use cosmic::widget::icon; use mime_guess::Mime; use rustc_hash::FxHashMap; -use std::fs; -use std::path::Path; -use std::sync::{LazyLock, Mutex}; +use std::{ + fs, + path::Path, + sync::{LazyLock, Mutex}, +}; pub const FALLBACK_MIME_ICON: &str = "text-x-generic"; @@ -15,21 +17,28 @@ struct MimeIconKey { size: u16, } -#[derive(Default)] -pub struct MimeIconCache { +struct MimeIconCache { cache: FxHashMap>, #[cfg(unix)] - pub shared_mime_info: xdg_mime::SharedMimeInfo, + shared_mime_info: xdg_mime::SharedMimeInfo, } impl MimeIconCache { + pub fn new() -> Self { + Self { + cache: FxHashMap::default(), + #[cfg(unix)] + shared_mime_info: xdg_mime::SharedMimeInfo::new(), + } + } + #[cfg(not(unix))] pub fn get(&mut self, _key: MimeIconKey) -> Option { None } #[cfg(unix)] - fn get(&mut self, key: MimeIconKey) -> Option { + pub fn get(&mut self, key: MimeIconKey) -> Option { self.cache .entry(key) .or_insert_with_key(|key| { @@ -38,7 +47,7 @@ impl MimeIconCache { return None; } let icon_name = icon_names.remove(0); - let mut named = icon::from_name(icon_name).prefer_svg(true).size(key.size); + let mut named = icon::from_name(icon_name).size(key.size); if !icon_names.is_empty() { let fallback_names = icon_names.into_iter().map(std::borrow::Cow::from).collect(); @@ -49,9 +58,8 @@ impl MimeIconCache { .clone() } } - -pub static MIME_ICON_CACHE: LazyLock> = - LazyLock::new(|| Mutex::new(MimeIconCache::default())); +static MIME_ICON_CACHE: LazyLock> = + LazyLock::new(|| Mutex::new(MimeIconCache::new())); #[cfg(not(unix))] pub fn mime_for_path( @@ -72,7 +80,6 @@ pub fn mime_for_path( let mime_icon_cache = MIME_ICON_CACHE.lock().unwrap(); // Try the shared mime info cache first let mut gb = mime_icon_cache.shared_mime_info.guess_mime_type(); - gb.zero_size(false); if remote { if let Some(file_name) = path.file_name().and_then(std::ffi::OsStr::to_str) { gb.file_name(file_name); @@ -107,10 +114,7 @@ pub fn mime_icon(mime: Mime, size: u16) -> icon::Handle { let mut mime_icon_cache = MIME_ICON_CACHE.lock().unwrap(); match mime_icon_cache.get(MimeIconKey { mime, size }) { Some(handle) => handle, - None => icon::from_name(FALLBACK_MIME_ICON) - .prefer_svg(true) - .size(size) - .handle(), + None => icon::from_name(FALLBACK_MIME_ICON).size(size).handle(), } } @@ -124,11 +128,3 @@ pub fn parent_mime_types(mime: &Mime) -> Option> { let mime_icon_cache = MIME_ICON_CACHE.lock().unwrap(); mime_icon_cache.shared_mime_info.get_parents_aliased(mime) } - -pub fn is_mime_subclass_of(mime_type: &Mime, base: &Mime) -> bool { - let mime_icon_cache = MIME_ICON_CACHE.lock().unwrap(); - - mime_icon_cache - .shared_mime_info - .mime_type_subclass(mime_type, base) -} diff --git a/src/mounter/gvfs.rs b/src/mounter/gvfs.rs index e2c6ba1..d6294b6 100644 --- a/src/mounter/gvfs.rs +++ b/src/mounter/gvfs.rs @@ -1,20 +1,18 @@ -use cosmic::iced::futures::SinkExt; -use cosmic::iced::{Subscription, stream}; -use cosmic::{Task, widget}; -use gio::glib; -use gio::prelude::*; -use std::any::TypeId; -use std::cell::Cell; -use std::future::pending; -use std::hash::Hash; -use std::path::PathBuf; -use std::sync::Arc; +use cosmic::{ + Task, + iced::{Subscription, futures::SinkExt, stream}, + widget, +}; +use gio::{glib, prelude::*}; +use std::{any::TypeId, cell::Cell, future::pending, hash::Hash, path::PathBuf, sync::Arc}; use tokio::sync::mpsc; use super::{Mounter, MounterAuth, MounterItem, MounterItems, MounterMessage}; -use crate::config::IconSizes; -use crate::err_str; -use crate::tab::{self, ChecksumState, DirSize, ItemMetadata, ItemThumbnail, Location}; +use crate::{ + config::IconSizes, + err_str, + tab::{self, DirSize, ItemMetadata, ItemThumbnail, Location}, +}; const TARGET_URI_ATTRIBUTE: &str = "standard::target-uri"; @@ -216,7 +214,6 @@ fn network_scan(uri: &str, sizes: IconSizes) -> Result, String> { //TODO: scan directory size on gvfs mounts? dir_size: DirSize::NotDirectory, cut: false, - checksums: ChecksumState::default(), }); } Ok(items) diff --git a/src/mounter/mod.rs b/src/mounter/mod.rs index a5ee75a..b97f32a 100644 --- a/src/mounter/mod.rs +++ b/src/mounter/mod.rs @@ -1,13 +1,13 @@ -use cosmic::iced::Subscription; -use cosmic::{Task, widget}; -use std::collections::BTreeMap; -use std::fmt; -use std::path::PathBuf; -use std::sync::{Arc, LazyLock}; +use cosmic::{Task, iced::Subscription, widget}; +use std::{ + collections::BTreeMap, + fmt, + path::PathBuf, + sync::{Arc, LazyLock}, +}; use tokio::sync::mpsc; -use crate::config::IconSizes; -use crate::tab; +use crate::{config::IconSizes, tab}; #[cfg(feature = "gvfs")] mod gvfs; @@ -75,10 +75,10 @@ impl MounterItem { } } - pub fn icon(&self, _symbolic: bool) -> Option { + pub fn icon(&self, symbolic: bool) -> Option { match self { #[cfg(feature = "gvfs")] - Self::Gvfs(item) => item.icon(_symbolic), + Self::Gvfs(item) => item.icon(symbolic), Self::None => unreachable!(), } } @@ -103,7 +103,6 @@ impl MounterItem { pub type MounterItems = Vec; #[derive(Clone, Debug)] -#[allow(dead_code)] pub enum MounterMessage { Items(MounterItems), MountResult(MounterItem, Result), diff --git a/src/mouse_area.rs b/src/mouse_area.rs index 73bd710..a57b36a 100644 --- a/src/mouse_area.rs +++ b/src/mouse_area.rs @@ -3,17 +3,21 @@ use std::time::Instant; use crate::tab::DOUBLE_CLICK_DURATION; -use cosmic::iced::core::border::Border; -use cosmic::iced::core::event::Event; -use cosmic::iced::core::mouse::{self, click}; -use cosmic::iced::core::renderer::{self, Quad, Renderer as _}; -use cosmic::iced::core::widget::{Operation, Tree, tree}; -use cosmic::iced::core::{ - Clipboard, Color, Layout, Length, Point, Rectangle, Shell, Size, Vector, Widget, layout, - overlay, touch, +use cosmic::{ + Element, Renderer, Theme, + iced::core::{ + Clipboard, Color, Layout, Length, Point, Rectangle, Shell, Size, Vector, Widget, + border::Border, + event::Event, + layout, + mouse::{self, click}, + overlay, + renderer::{self, Quad, Renderer as _}, + touch, + widget::{Operation, Tree, tree}, + }, + widget::Id, }; -use cosmic::widget::Id; -use cosmic::{Element, Renderer, Theme}; /// Emit messages on mouse events. #[allow(missing_debug_implementations)] diff --git a/src/operation/mod.rs b/src/operation/mod.rs index 62dbba6..b4a66e9 100644 --- a/src/operation/mod.rs +++ b/src/operation/mod.rs @@ -1,15 +1,20 @@ -use crate::app::{ArchiveType, DialogPage, Message, REPLACE_BUTTON_ID}; -use crate::config::IconSizes; -use crate::spawn_detached::spawn_detached; -use crate::{archive, fl, tab}; -use cosmic::iced::futures::channel::mpsc::Sender; -use cosmic::iced::futures::{self, SinkExt, StreamExt, stream}; -use std::borrow::Cow; -use std::fmt::Formatter; -use std::fs; -use std::io::{self, Read, Write}; -use std::path::{Path, PathBuf}; -use std::sync::Arc; +use crate::{ + app::{ArchiveType, DialogPage, Message, REPLACE_BUTTON_ID}, + archive, + config::IconSizes, + fl, + spawn_detached::spawn_detached, + tab, +}; +use cosmic::iced::futures::{self, SinkExt, StreamExt, channel::mpsc::Sender, stream}; +use std::{ + borrow::Cow, + fmt::Formatter, + fs, + io::{self, Read, Write}, + path::{Path, PathBuf}, + sync::Arc, +}; use tokio::sync::{Mutex as TokioMutex, mpsc}; use walkdir::WalkDir; use zip::AesMode::Aes256; @@ -34,7 +39,7 @@ async fn handle_replace( conflict_count: usize, ) -> ReplaceResult { let item_from = match tab::item_from_path(file_from, IconSizes::default()) { - Ok(ok) => Box::new(ok), + Ok(ok) => ok, Err(err) => { log::warn!("{err}"); return ReplaceResult::Cancel; @@ -42,7 +47,7 @@ async fn handle_replace( }; let item_to = match tab::item_from_path(file_to, IconSizes::default()) { - Ok(ok) => Box::new(ok), + Ok(ok) => ok, Err(err) => { log::warn!("{err}"); return ReplaceResult::Cancel; @@ -967,13 +972,11 @@ impl Operation { password, } => { let controller_clone = controller.clone(); - compio::runtime::spawn(async move { - let extracted = compio::runtime::spawn_blocking(move || { + compio::runtime::spawn_blocking( + move || -> Result { let controller = controller_clone; let total_paths = paths.len(); let mut op_sel = OperationSelection::default(); - let mut written_files = Vec::new(); - let mut target_dirs = std::collections::HashSet::new(); for (i, path) in paths.iter().enumerate() { futures::executor::block_on(async { controller @@ -997,32 +1000,16 @@ impl Operation { op_sel.ignored.push(path.clone()); op_sel.selected.push(new_dir.clone()); - let (files, dirs) = crate::archive::extract( - path, - &new_dir, - &password, - &controller, - )?; - written_files.extend(files); - target_dirs.extend(dirs); + crate::archive::extract(path, &new_dir, &password, &controller)?; } } - Ok::<_, OperationError>((op_sel, written_files, target_dirs)) - }) - .await - .map_err(wrap_compio_spawn_error)??; - - let (op_sel, written_files, target_dirs) = extracted; - if !written_files.is_empty() || !target_dirs.is_empty() { - sync_to_disk(written_files, target_dirs).await; - } - - Ok::<_, OperationError>(op_sel) - }) - .await - .map_err(wrap_compio_spawn_error)? + Ok(op_sel) + }, + ) } + .await + .map_err(wrap_compio_spawn_error)?, Self::Move { paths, to, @@ -1156,26 +1143,10 @@ impl Operation { paths.push(item.original_path()); - // Items with .trashinfo id use standard restore; sub-items use manual move - if item - .id - .to_str() - .map_or(false, |s| s.ends_with(".trashinfo")) - { - compio::runtime::spawn_blocking(|| trash::os_limited::restore_all([item])) - .await - .map_err(wrap_compio_spawn_error)? - .map_err(|e| OperationError::from_err(e, &controller))?; - } else { - let from = PathBuf::from(&item.id); - let to = item.original_path(); - if let Some(parent) = to.parent() { - std::fs::create_dir_all(parent) - .map_err(|e| OperationError::from_err(e, &controller))?; - } - std::fs::rename(&from, &to) - .map_err(|e| OperationError::from_err(e, &controller))?; - } + compio::runtime::spawn_blocking(|| trash::os_limited::restore_all([item])) + .await + .map_err(wrap_compio_spawn_error)? + .map_err(|e| OperationError::from_err(e, &controller))?; } Ok(OperationSelection { ignored: Vec::new(), @@ -1272,23 +1243,28 @@ fn wrap_compio_spawn_error(err: Box) -> OperationError #[cfg(test)] mod tests { - use std::fs::{self, File}; - use std::io; - use std::path::PathBuf; + use std::{ + fs::{self, File}, + io, + path::PathBuf, + }; - use cosmic::iced::futures::channel::mpsc; - use cosmic::iced::futures::{StreamExt, future}; + use cosmic::iced::futures::{StreamExt, channel::mpsc, future}; use log::debug; use test_log::test; use tokio::sync; use super::{Controller, Operation, OperationError, OperationSelection, ReplaceResult}; - use crate::app::test_utils::{ - NAME_LEN, NUM_DIRS, NUM_FILES, NUM_HIDDEN, NUM_NESTED, empty_fs, filter_dirs, filter_files, - simple_fs, + use crate::{ + app::{ + DialogPage, Message, + test_utils::{ + NAME_LEN, NUM_DIRS, NUM_FILES, NUM_HIDDEN, NUM_NESTED, empty_fs, filter_dirs, + filter_files, simple_fs, + }, + }, + fl, }; - use crate::app::{DialogPage, Message}; - use crate::fl; /// Simple wrapper around `[Operation::Copy]` pub async fn operation_copy( diff --git a/src/operation/reader.rs b/src/operation/reader.rs index 9f45441..75088df 100644 --- a/src/operation/reader.rs +++ b/src/operation/reader.rs @@ -1,5 +1,4 @@ -use std::path::Path; -use std::{fs, io}; +use std::{fs, io, path::Path}; use crate::operation::OperationError; diff --git a/src/operation/recursive.rs b/src/operation/recursive.rs index 0f09bd6..9a33ebd 100644 --- a/src/operation/recursive.rs +++ b/src/operation/recursive.rs @@ -6,21 +6,15 @@ use crate::operation::{OperationError, sync_to_disk}; use anyhow::Context as AnyhowContext; use compio::BufResult; use compio::buf::{IntoInner, IoBuf}; -use compio::driver::ToSharedFd; -use compio::driver::op::AsyncifyFd; +use compio::driver::{ToSharedFd, op::AsyncifyFd}; use compio::io::{AsyncReadAt, AsyncWriteAt}; use cosmic::iced::futures; -#[cfg(feature = "gvfs")] use futures::{FutureExt, StreamExt}; -use std::cell::Cell; -use std::error::Error; -use std::fs; use std::future::Future; -use std::ops::ControlFlow; -use std::path::PathBuf; use std::pin::Pin; use std::rc::Rc; use std::time::Instant; +use std::{cell::Cell, error::Error, fs, ops::ControlFlow, path::PathBuf}; use walkdir::WalkDir; #[cfg(feature = "gvfs")] @@ -479,12 +473,12 @@ impl Op { progress.total_bytes = metadata.as_ref().map(|m| m.len()); (ctx.on_progress)(self, &progress); - if let Some(metadata) = metadata.as_ref() - && let Err(why) = to_file.set_permissions(metadata.permissions()).await - { - // This error is not propagated upwards as some filesystems do not support setting permissions - if !matches!(why.kind(), std::io::ErrorKind::Unsupported) { - tracing::warn!(?why, "failed to set permissions for {}", self.to.display(),); + if let Some(metadata) = metadata.as_ref() { + if let Err(why) = to_file.set_permissions(metadata.permissions()).await { + // This error is not propagated upwards as some filesystems do not support setting permissions + if !matches!(why.kind(), std::io::ErrorKind::Unsupported) { + tracing::warn!(?why, "failed to set permissions for {}", self.to.display(),); + } } } diff --git a/src/tab.rs b/src/tab.rs index dc3d925..94eacdd 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -1,73 +1,91 @@ #[cfg(feature = "desktop")] use cosmic::desktop::fde::{DesktopEntry, get_languages_from_env}; -use cosmic::iced::advanced::graphics; -use cosmic::iced::advanced::text::{self, Paragraph}; -use cosmic::iced::alignment::Vertical; -use cosmic::iced::clipboard::dnd::DndAction; -use cosmic::iced::core::mouse::ScrollDelta; -use cosmic::iced::core::widget::tree; -use cosmic::iced::futures::{self, SinkExt}; -use cosmic::iced::keyboard::Modifiers; -use cosmic::iced::widget::scrollable::{self, AbsoluteOffset, Viewport}; -use cosmic::iced::widget::{rule, stack}; -use cosmic::iced::{ - Alignment, Border, Color, ContentFit, Length, Point, Rectangle, Size, Subscription, Vector, - padding, stream, window, +use cosmic::{ + Apply, Element, cosmic_theme, font, + iced::core::{mouse::ScrollDelta, widget::tree}, + iced::{ + Alignment, Border, Color, ContentFit, Length, Point, Rectangle, Size, Subscription, Vector, + advanced::{ + graphics, + text::{self, Paragraph}, + }, + alignment::Vertical, + clipboard::dnd::DndAction, + futures::{self, SinkExt}, + keyboard::Modifiers, + padding, stream, + widget::{ + rule, + scrollable::{self, AbsoluteOffset, Viewport}, + stack, + }, + window, + }, + theme, + widget::{ + self, DndDestination, DndSource, Id, RcElementWrapper, Widget, + menu::{action::MenuAction, key_bind::KeyBind}, + space, + }, }; -use cosmic::widget::menu::action::MenuAction; -use cosmic::widget::menu::key_bind::KeyBind; -use cosmic::widget::{self, DndDestination, DndSource, Id, RcElementWrapper, Widget, space}; -use cosmic::{Apply, Element, cosmic_theme, font, theme}; -#[cfg(feature = "desktop")] use i18n_embed::LanguageLoader; -use icu::datetime::input::DateTime; -use icu::datetime::options::TimePrecision; -use icu::datetime::{DateTimeFormatter, DateTimeFormatterPreferences, fieldsets}; -use icu::locale::preferences::extensions::unicode::keywords::HourCycle; +use icu::{ + datetime::{ + DateTimeFormatter, DateTimeFormatterPreferences, fieldsets, input::DateTime, + options::TimePrecision, + }, + locale::preferences::extensions::unicode::keywords::HourCycle, +}; use image::{DynamicImage, ImageReader}; use jiff_icu::ConvertFrom; use mime_guess::{Mime, mime}; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; -use sha2::{Digest, Sha256}; -use std::borrow::Cow; -use std::cell::Cell; -use std::cmp::{Ordering, Reverse}; -use std::collections::{BTreeMap, BTreeSet, HashMap}; -use std::error::Error; -use std::fmt::{self, Display}; -use std::fs::{self, File, Metadata}; -use std::hash::Hash; -use std::io::{BufRead, BufReader, Read}; #[cfg(unix)] use std::os::unix::fs::MetadataExt; -use std::path::{self, Path, PathBuf}; -use std::sync::{Arc, LazyLock, RwLock, atomic}; -use std::time::{Duration, Instant, SystemTime}; +use std::{ + borrow::Cow, + cell::Cell, + cmp::{Ordering, Reverse}, + collections::{BTreeMap, BTreeSet, HashMap}, + error::Error, + fmt::{self, Display}, + fs::{self, File, Metadata}, + hash::Hash, + io::{BufRead, BufReader}, + path::{self, Path, PathBuf}, + sync::{Arc, LazyLock, RwLock, atomic}, + time::{Duration, Instant, SystemTime}, +}; use tempfile::NamedTempFile; use tokio::sync::mpsc; use trash::{TrashItem, TrashItemMetadata, TrashItemSize}; use walkdir::WalkDir; -use crate::app::{Action, PreviewItem, PreviewKind}; -use crate::clipboard::{ClipboardCopy, ClipboardKind, ClipboardPaste}; -use crate::config::{ - ContextActionPreset, DesktopConfig, ICON_SCALE_MAX, ICON_SIZE_GRID, IconSizes, TabConfig, - ThumbCfg, +use crate::{ + FxOrderMap, + app::{Action, PreviewItem, PreviewKind}, + clipboard::{ClipboardCopy, ClipboardKind, ClipboardPaste}, + config::{ + ContextActionPreset, DesktopConfig, ICON_SCALE_MAX, ICON_SIZE_GRID, IconSizes, TabConfig, + ThumbCfg, + }, + dialog::DialogKind, + fl, + large_image::{ + LargeImageManager, decode_large_image, exceeds_memory_limit, should_use_dedicated_worker, + should_use_tiling, + }, + localize::{LANGUAGE_SORTER, LOCALE}, + menu, mime_app, + mime_icon::{mime_for_path, mime_icon}, + mounter::MOUNTERS, + mouse_area, + operation::{Controller, OperationError}, + thumbnail_cacher::{CachedThumbnail, ThumbnailCacher, ThumbnailSize}, + thumbnailer::thumbnailer, + trash::{Trash, TrashExt}, }; -use crate::dialog::DialogKind; -use crate::large_image::{ - LargeImageManager, decode_large_image, exceeds_memory_limit, should_use_dedicated_worker, - should_use_tiling, -}; -use crate::localize::{LANGUAGE_SORTER, LOCALE}; -use crate::mime_icon::{mime_for_path, mime_icon}; -use crate::mounter::MOUNTERS; -use crate::operation::{Controller, OperationError}; -use crate::thumbnail_cacher::{CachedThumbnail, ThumbnailCacher, ThumbnailSize}; -use crate::thumbnailer::thumbnailer; -use crate::trash::{Trash, TrashExt}; -use crate::{FxOrderMap, fl, menu, mime_app, mouse_area}; pub const DOUBLE_CLICK_DURATION: Duration = Duration::from_millis(500); pub const HOVER_DURATION: Duration = Duration::from_millis(1600); @@ -77,11 +95,6 @@ const MAX_SEARCH_LATENCY: Duration = Duration::from_millis(20); const MAX_SEARCH_RESULTS: usize = 200; //TODO: configurable thumbnail size? const THUMBNAIL_SIZE: u32 = (ICON_SIZE_GRID as u32) * (ICON_SCALE_MAX as u32); -/// Maximum bytes of text to pass to the editor for preview; caps shaping work to avoid blocking. -/// Files larger than this get a truncated preview (first N bytes only). -const TEXT_PREVIEW_MAX_BYTES: usize = 256 * 1024; // 256 KiB -/// Maximum file size (bytes) to attempt text preview; files larger than this are skipped entirely. -const TEXT_PREVIEW_MAX_FILE_BYTES: u64 = 8 * 1000 * 1000; // 8 MiB // Thumbnail generation semaphore - limits parallel thumbnail workers // Uses 4 workers for balanced throughput and memory usage @@ -181,7 +194,7 @@ fn button_appearance( appearance.icon_color = Some(Color::from(cosmic.on_bg_component_color())); appearance.text_color = Some(Color::from(cosmic.on_bg_component_color())); if cut { - appearance.text_color = Some(Color::from(cosmic.background(false).component.on_disabled)); + appearance.text_color = Some(Color::from(cosmic.background.component.on_disabled)); } else { appearance.text_color = Some(Color::from(cosmic.on_bg_component_color())); } @@ -192,12 +205,12 @@ fn button_appearance( appearance.background = Some(Color::from(cosmic.bg_color()).into()); appearance.icon_color = Some(Color::from(cosmic.on_bg_color())); if cut { - appearance.text_color = Some(Color::from(cosmic.background(false).component.disabled)); + appearance.text_color = Some(Color::from(cosmic.background.component.disabled)); } else { appearance.text_color = Some(Color::from(cosmic.on_bg_color())); } } else if cut { - appearance.text_color = Some(Color::from(cosmic.background(false).component.on_disabled)); + appearance.text_color = Some(Color::from(cosmic.background.component.on_disabled)); } if focused && accent { appearance.outline_width = 1.0; @@ -276,7 +289,6 @@ fn button_style( pub fn folder_icon(path: &PathBuf, icon_size: u16) -> widget::icon::Handle { widget::icon::from_name(SPECIAL_DIRS.get(path).map_or("folder", |x| *x)) - .prefer_svg(true) .size(icon_size) .handle() } @@ -290,26 +302,6 @@ pub fn folder_icon_symbolic(path: &PathBuf, icon_size: u16) -> widget::icon::Han .handle() } -fn generic_file_icons( - sizes: IconSizes, -) -> ( - widget::icon::Handle, - widget::icon::Handle, - widget::icon::Handle, -) { - ( - widget::icon::from_name("text-x-generic") - .size(sizes.grid()) - .handle(), - widget::icon::from_name("text-x-generic") - .size(sizes.list()) - .handle(), - widget::icon::from_name("text-x-generic") - .size(sizes.list_condensed()) - .handle(), - ) -} - //TODO: replace with Path::has_trailing_sep when stable fn has_trailing_sep(path: &Path) -> bool { path.as_os_str() @@ -566,7 +558,7 @@ pub fn fs_kind(_metadata: &Metadata) -> FsKind { } #[cfg(not(feature = "desktop"))] -fn get_desktop_file_display_name(_path: &Path) -> Option { +fn get_desktop_file_display_name(path: &Path) -> Option { None } @@ -585,7 +577,7 @@ fn get_desktop_file_display_name(path: &Path) -> Option { } #[cfg(not(feature = "desktop"))] -fn get_desktop_file_icon(_path: &Path) -> Option { +fn get_desktop_file_icon(path: &Path) -> Option { None } @@ -609,10 +601,7 @@ fn desktop_icon_handle(icon: &str, size: u16) -> widget::icon::Handle { if icon_path.is_absolute() && icon_path.exists() { widget::icon::from_path(icon_path.to_path_buf()) } else { - widget::icon::from_name(icon) - .prefer_svg(true) - .size(size) - .handle() + widget::icon::from_name(icon).size(size).handle() } } @@ -676,9 +665,9 @@ pub fn item_from_gvfs_info(path: PathBuf, file_info: gio::FileInfo, sizes: IconS folder_icon(&path, sizes.list_condensed()), ) } else { - // Keep the initial directory scan cheap. Opening files still - // recalculates MIME from the real path before launching apps. - let mime = mime_guess::from_path(&path).first_or_octet_stream(); + // ALWAYS assume we're remote for mime guessing here, since gvfs reading can be expensive + // @todo - expose this as a config option? + let mime = mime_for_path(&path, None, true); //TODO: clean this up, implement for trash let icon_name_opt = if mime == "application/x-desktop" { @@ -695,21 +684,28 @@ pub fn item_from_gvfs_info(path: PathBuf, file_info: gio::FileInfo, sizes: IconS desktop_icon_handle(&icon_name, sizes.list_condensed()), ) } else { - let (icon_handle_grid, icon_handle_list, icon_handle_list_condensed) = - generic_file_icons(sizes); ( - mime, - icon_handle_grid, - icon_handle_list, - icon_handle_list_condensed, + mime.clone(), + mime_icon(mime.clone(), sizes.grid()), + mime_icon(mime.clone(), sizes.list()), + mime_icon(mime, sizes.list_condensed()), ) } }; - let children_opt = None; + let mut children_opt = None; let mut dir_size = DirSize::NotDirectory; if is_dir && !remote { dir_size = DirSize::Calculating(Controller::default()); + //TODO: calculate children in the background (and make it cancellable?) + match fs::read_dir(&path) { + Ok(entries) => { + children_opt = Some(entries.count()); + } + Err(err) => { + log::warn!("failed to read directory {}: {}", path.display(), err); + } + } } let display_name = display_name_for_file(&path, &file_info.display_name(), false, is_desktop); @@ -746,7 +742,6 @@ pub fn item_from_gvfs_info(path: PathBuf, file_info: gio::FileInfo, sizes: IconS overlaps_drag_rect: false, dir_size, cut: false, - checksums: ChecksumState::default(), } } @@ -764,10 +759,7 @@ pub fn item_from_entry( sizes: IconSizes, ) -> Item { let mut is_desktop = false; - #[cfg(feature = "gvfs")] let mut is_gvfs = false; - #[cfg(not(feature = "gvfs"))] - let is_gvfs = false; let hidden = name.starts_with('.') || hidden_attribute(&metadata); @@ -815,9 +807,7 @@ pub fn item_from_entry( folder_icon(&path, sizes.list_condensed()), ) } else { - // Keep the initial directory scan cheap. Opening files still - // recalculates MIME from the real path before launching apps. - let mime = mime_guess::from_path(&path).first_or_octet_stream(); + let mime = mime_for_path(&path, Some(&metadata), remote); //TODO: clean this up, implement for trash let icon_name_opt = if mime == "application/x-desktop" { is_desktop = true; @@ -833,21 +823,28 @@ pub fn item_from_entry( desktop_icon_handle(&icon_name, sizes.list_condensed()), ) } else { - let (icon_handle_grid, icon_handle_list, icon_handle_list_condensed) = - generic_file_icons(sizes); ( - mime, - icon_handle_grid, - icon_handle_list, - icon_handle_list_condensed, + mime.clone(), + mime_icon(mime.clone(), sizes.grid()), + mime_icon(mime.clone(), sizes.list()), + mime_icon(mime, sizes.list_condensed()), ) } }; - let children_opt = None; + let mut children_opt = None; let mut dir_size = DirSize::NotDirectory; if metadata.is_dir() && !remote { dir_size = DirSize::Calculating(Controller::default()); + //TODO: calculate children in the background (and make it cancellable?) + match fs::read_dir(&path) { + Ok(entries) => { + children_opt = Some(entries.count()); + } + Err(err) => { + log::warn!("failed to read directory {}: {}", path.display(), err); + } + } } let display_name = display_name_for_file(&path, &name, is_gvfs, is_desktop); @@ -876,7 +873,6 @@ pub fn item_from_entry( overlaps_drag_rect: false, dir_size, cut: false, - checksums: ChecksumState::default(), } } @@ -889,8 +885,6 @@ pub fn item_from_trash_entry( let name = entry.name.to_string_lossy().into_owned(); let display_name = Item::display_name(&name); - let location = crate::trash::trash_item_path(&entry).map(Location::Path); - let (mime, icon_handle_grid, icon_handle_list, icon_handle_list_condensed) = match metadata.size { trash::TrashItemSize::Entries(_) => ( @@ -918,7 +912,7 @@ pub fn item_from_trash_entry( is_mount_point: false, metadata: ItemMetadata::Trash { metadata, entry }, hidden: false, - location_opt: location, + location_opt: None, image_dimensions: (mime.type_() == mime::IMAGE) .then(|| image::image_dimensions(&original_path).ok()) .flatten(), @@ -935,35 +929,9 @@ pub fn item_from_trash_entry( overlaps_drag_rect: false, dir_size: DirSize::NotDirectory, cut: false, - checksums: ChecksumState::default(), } } -fn item_from_trash_child( - path: PathBuf, - name: String, - metadata: fs::Metadata, - sizes: IconSizes, -) -> Option { - let original_path = crate::trash::original_path_for_trash_child(&path)?; - let entry = trash::TrashItem { - id: path.as_os_str().to_os_string(), - name: std::ffi::OsString::from(&name), - original_parent: original_path.parent()?.to_path_buf(), - time_deleted: 0, - }; - let size = if metadata.is_dir() { - trash::TrashItemSize::Entries(0) - } else { - trash::TrashItemSize::Bytes(metadata.len()) - }; - Some(item_from_trash_entry( - entry, - trash::TrashItemMetadata { size }, - sizes, - )) -} - fn get_filename_from_path(path: &Path) -> Result { Ok(match path.file_name() { Some(name_os) => name_os @@ -990,10 +958,7 @@ pub fn item_from_path>(path: P, sizes: IconSizes) -> Result Vec { let mut items = Vec::new(); let mut hidden_files = Box::from([]); - #[cfg(feature = "gvfs")] let mut remote_scannable = false; - #[cfg(not(feature = "gvfs"))] - let remote_scannable = false; #[cfg(feature = "gvfs")] { @@ -1082,12 +1047,7 @@ pub fn scan_path(tab_path: &PathBuf, sizes: IconSizes) -> Vec { }) .ok()?; - let trash = crate::trash::is_trash_path(tab_path); - if trash { - item_from_trash_child(path, name, metadata, sizes) - } else { - Some(item_from_entry(path, name, metadata, sizes)) - } + Some(item_from_entry(path, name, metadata, sizes)) }) .collect(); } @@ -1392,7 +1352,6 @@ pub fn scan_desktop( overlaps_drag_rect: false, dir_size: DirSize::NotDirectory, cut: false, - checksums: ChecksumState::default(), }); } @@ -1599,7 +1558,7 @@ impl Location { } } - pub fn scan(&self, sizes: IconSizes) -> (Option>, Vec) { + pub fn scan(&self, sizes: IconSizes) -> (Option, Vec) { let items = match self { Self::Desktop(path, display, desktop_config) => { scan_desktop(path, display, *desktop_config, sizes) @@ -1615,7 +1574,7 @@ impl Location { }; let parent_item_opt = match self.path_opt() { Some(path) => match item_from_path(path, sizes) { - Ok(item) => Some(Box::new(item)), + Ok(item) => Some(item), Err(err) => { log::warn!("failed to get item for {}: {}", path.display(), err); None @@ -1724,7 +1683,6 @@ pub enum Command { ContextMenu(Option, Option), Delete(Vec), DropFiles(PathBuf, ClipboardPaste), - ClearRecents, EmptyTrash, #[cfg(feature = "desktop")] ExecEntryAction(cosmic::desktop::DesktopEntryData, usize), @@ -1764,7 +1722,6 @@ pub enum Message { EditLocationSubmit, EditLocationTab, OpenInNewTab(PathBuf), - ClearRecents, EmptyTrash, #[cfg(feature = "desktop")] ExecEntryAction(Option, usize), @@ -1776,8 +1733,6 @@ pub enum Message { GoPrevious, ItemDown, ItemLeft, - ItemPageDown, - ItemPageUp, ItemRight, ItemUp, Location(Location), @@ -1814,9 +1769,6 @@ pub enum Message { HighlightDeactivate(usize), HighlightActivate(usize), DirectorySize(PathBuf, DirSize), - Checksums(PathBuf, ChecksumState), - CalculateChecksums(PathBuf), - CopyChecksum(String), ImageDecoded(PathBuf, u32, u32, Vec, Option<(u32, u32)>, u64), // path, width, height, pixels, display_size, generation } @@ -1844,23 +1796,6 @@ pub enum DirSize { Error(String), } -/// Checksums computed for a file. Only SHA256 is currently exposed; see -/// [`calculate_checksums`] for how to add more. -#[derive(Clone, Debug, Default)] -pub struct FileChecksums { - pub sha256: String, -} - -/// State of checksum computation for a file. -#[derive(Clone, Debug, Default)] -pub enum ChecksumState { - #[default] - NotCalculated, - Calculating, - Calculated(FileChecksums), - Error(String), -} - #[derive(Clone, Debug)] pub enum ItemMetadata { Path { @@ -2149,37 +2084,17 @@ impl ItemThumbnail { log::warn!("failed to read {}: {}", path.display(), err); } } - } else if mime.type_() == mime::TEXT && check_size("text", TEXT_PREVIEW_MAX_FILE_BYTES) { - tried_supported_file = true; - if size > 0 { - // Reuse size from metadata above; cap allocation and read - let read_cap = (size.min(TEXT_PREVIEW_MAX_BYTES as u64)) as usize; - let mut buf = vec![0u8; read_cap]; - match File::open(path).and_then(|f| { - let n = Read::read(&mut f.take(read_cap as u64), &mut buf)?; - buf.truncate(n); - Ok(()) - }) { - Ok(()) => { - let text = match std::str::from_utf8(&buf) { - Ok(s) => s.to_string(), - Err(e) => { - // Use only the valid UTF-8 prefix (slice is guaranteed valid by valid_up_to()) - std::str::from_utf8(&buf[..e.valid_up_to()]) - .unwrap_or("") - .to_string() - } - }; - if !text.is_empty() { - return Self::Text(widget::text_editor::Content::with_text(&text)); - } - } - Err(err) => { - log::warn!("failed to read {}: {}", path.display(), err); - } + } else if mime.type_() == mime::TEXT && check_size("text", 8 * 1000 * 1000) { + /*TODO: fix performance issues, widget::text_editor::Content::with_text forces all text to shape, which blocks rendering + match fs::read_to_string(&path) { + Ok(data) => { + return ItemThumbnail::Text(widget::text_editor::Content::with_text(&data)); + } + Err(err) => { + log::warn!("failed to read {}: {}", path.display(), err); } } - // size == 0: empty file or unknown size; skip read and allocation + */ } // If we weren't able to create a thumbnail, but we should have @@ -2312,7 +2227,6 @@ pub struct Item { pub cut: bool, pub overlaps_drag_rect: bool, pub dir_size: DirSize, - pub checksums: ChecksumState, } impl Item { @@ -2364,7 +2278,7 @@ impl Item { } fn preview(&self) -> Element<'_, Message> { - let spacing = cosmic::theme::spacing(); + let spacing = cosmic::theme::active().cosmic().spacing; // This loads the image only if thumbnailing worked let icon = widget::icon::icon(self.icon_handle_grid.clone()) .content_fit(ContentFit::Contain) @@ -2425,7 +2339,7 @@ impl Item { space_xxxs, space_m, .. - } = theme::spacing(); + } = theme::active().cosmic().spacing; let mut column = widget::column::with_capacity(4).spacing(space_m); @@ -2443,24 +2357,20 @@ impl Item { ))); let mut settings = Vec::new(); if let Some(mime_app_cache) = mime_app_cache_opt { - let mime_apps = mime_app_cache.get_apps_for_mime(&self.mime, false); + let mime_apps = mime_app_cache.get(&self.mime); if !mime_apps.is_empty() { - let (names, icons) = mime_apps - .iter() - .map(|(app, _)| (Cow::Owned(app.name.clone()), app.icon())) - .collect::<(Vec<_>, Vec<_>)>(); settings.push( widget::settings::item::builder(fl!("open-with")).control( Element::from( widget::dropdown( - names, - mime_apps.iter().position(|(x, _)| x.is_default(&self.mime)), + mime_apps, + mime_apps.iter().position(|x| x.is_default), move |index| index, ) - .icons(Cow::Owned(icons)), + .icons(Cow::Borrowed(mime_app_cache.icons(&self.mime))), ) - .map(move |index| { - let mime_app = &mime_apps[index].0; + .map(|index| { + let mime_app = &mime_apps[index]; Message::SetOpenWith(self.mime.clone(), mime_app.id.clone()) }), ), @@ -2589,55 +2499,6 @@ impl Item { } column = column.push(details); - if let Some(metadata) = self.file_metadata() - && !metadata.is_dir() - && let Some(path) = self.path_opt() - { - let control: Element<'_, Message> = match &self.checksums { - ChecksumState::NotCalculated => widget::button::standard(fl!("calculate")) - .on_press(Message::CalculateChecksums(path.clone())) - .into(), - ChecksumState::Calculating => widget::row::with_capacity(2) - .align_y(Alignment::Center) - .spacing(space_xxxs) - .push(widget::indeterminate_circular().size(16.0)) - .push(widget::text::body(fl!("calculating"))) - .into(), - ChecksumState::Calculated(checksums) => { - let value = checksums.sha256.clone(); - // Middle-ellipsize the digest to fit, full value on hover. - let value_text = widget::tooltip( - widget::text::body(value.clone()) - .font(cosmic::font::mono()) - .width(Length::Fill) - .wrapping(text::Wrapping::None) - .ellipsize(text::Ellipsize::Middle(text::EllipsizeHeightLimit::Lines( - 1, - ))), - widget::text::body(value.clone()), - widget::tooltip::Position::Bottom, - ); - let copy_button = widget::button::icon( - widget::icon::from_name("edit-copy-symbolic").size(16), - ) - .on_press(Message::CopyChecksum(value.clone())) - .tooltip(fl!("copy")); - widget::row::with_capacity(2) - .align_y(Alignment::Center) - .spacing(space_xxxs) - .push(value_text) - .push(copy_button) - .into() - } - ChecksumState::Error(err) => { - widget::text::body(format!("{}: {}", fl!("error"), err)).into() - } - }; - settings.push( - widget::settings::item::builder(fl!("checksum", kind = "SHA256")).control(control), - ); - } - if let Some(path) = self.path_opt() && self.selected { @@ -2656,7 +2517,7 @@ impl Item { } pub fn replace_view(&self, heading: String, military_time: bool) -> Element<'_, Message> { - let cosmic_theme::Spacing { space_xxxs, .. } = theme::spacing(); + let cosmic_theme::Spacing { space_xxxs, .. } = theme::active().cosmic().spacing; let mut row = widget::row::with_capacity(2).spacing(space_xxxs); row = row.push(self.preview()); @@ -2796,7 +2657,7 @@ pub struct Tab { pub sort_name: HeadingOptions, pub sort_direction: bool, pub gallery: bool, - pub(crate) parent_item_opt: Option>, + pub(crate) parent_item_opt: Option, pub(crate) items_opt: Option>, pub dnd_hovered: Option<(Location, Instant)>, pub(crate) scrollable_id: widget::Id, @@ -2835,32 +2696,6 @@ async fn calculate_dir_size(path: &Path, controller: Controller) -> Result Result { - let path = path.to_path_buf(); - tokio::task::spawn_blocking(move || { - let mut file = File::open(&path).map_err(|e| e.to_string())?; - let mut sha256_hasher = Sha256::new(); - - let mut buffer = [0u8; 8192]; - loop { - let bytes_read = file.read(&mut buffer).map_err(|e| e.to_string())?; - if bytes_read == 0 { - break; - } - sha256_hasher.update(&buffer[..bytes_read]); - } - - Ok(FileChecksums { - sha256: format!("{:x}", sha256_hasher.finalize()), - }) - }) - .await - .map_err(|e| e.to_string())? -} - fn folder_name>(path: P) -> (String, bool) { let path = path.as_ref(); let mut found_home = false; @@ -3156,10 +2991,10 @@ impl Tab { return None; }; let search_items = after - .iter_mut() + .into_iter() .enumerate() .map(|(i, item)| (i + start, item)) - .chain(until.iter_mut().enumerate()); + .chain(until.into_iter().enumerate()); if forward { Self::select_first_prefix_match(prefix_lower, search_items) @@ -3176,7 +3011,7 @@ impl Tab { items: impl Iterator, ) -> Option { for (i, item) in items { - if item.name.to_lowercase().starts_with(prefix) { + if item.name.to_lowercase().starts_with(&prefix) { item.selected = true; return Some(i); } @@ -3280,14 +3115,6 @@ impl Tab { item.pos_opt.get() } - fn dehighlight_all(&mut self) { - if let Some(items) = self.items_opt.as_mut() { - for item in items.iter_mut() { - item.highlighted = false; - } - } - } - pub(crate) fn select_focus_scroll(&mut self) -> Option { let items = self.items_opt.as_ref()?; let item = items.get(self.select_focus?)?; @@ -3323,20 +3150,6 @@ impl Tab { } } - fn rows_per_page(&self) -> usize { - let viewport_height = self.item_view_size_opt.get().map_or(0.0, |s| s.height); - let row_height = self - .select_focus - .and_then(|i| self.items_opt.as_ref()?.get(i)) - .and_then(|item| item.rect_opt.get()) - .map_or(0.0, |r| r.height); - if row_height > 0.0 && viewport_height > 0.0 { - (viewport_height / row_height).floor() as usize - } else { - 1 - } - } - fn select_range_start_pos_opt(&self) -> Option<(usize, usize)> { let items = self.items_opt.as_ref()?; let item = items.get(self.select_range.map(|r| r.0)?)?; @@ -3794,7 +3607,7 @@ impl Tab { match item_from_path(&path, IconSizes::default()) { Ok(item) => { commands.push(Command::Preview(PreviewKind::Custom( - PreviewItem(Box::new(item)), + PreviewItem(item), ))); } Err(err) => { @@ -3884,9 +3697,6 @@ impl Tab { Message::OpenInNewTab(path) => { commands.push(Command::OpenInNewTab(path)); } - Message::ClearRecents => { - commands.push(Command::ClearRecents); - } Message::EmptyTrash => { commands.push(Command::EmptyTrash); } @@ -3992,7 +3802,6 @@ impl Tab { } } Message::ItemDown => { - self.dehighlight_all(); if let Some(edit_location) = &mut self.edit_location { edit_location.select(true); } else if self.gallery { @@ -4034,95 +3843,7 @@ impl Tab { } } } - Message::ItemPageDown => { - self.dehighlight_all(); - if let Some((row, col)) = self.select_focus_pos_opt().or(self.select_last_pos_opt()) - { - if self.select_focus.is_none() { - self.select_position(row, col, mod_shift); - } - - let rows_per_page = self.rows_per_page().max(1); - let target_row = row.saturating_add(rows_per_page); - - if !self.select_position(target_row, col, mod_shift) { - // Fall back to the last item at or before target_row - let best = self.items_opt.as_ref().and_then(|items| { - items - .iter() - .filter_map(|item| item.pos_opt.get()) - .filter(|(r, _)| *r <= target_row) - .max() - }); - if let Some((best_row, best_col)) = best { - self.select_position(best_row, best_col, mod_shift); - } - } - } else { - self.select_position(0, 0, mod_shift); - } - if let Some(offset) = self.select_focus_scroll() { - commands.push(Command::Iced( - scrollable::scroll_to( - self.scrollable_id.clone(), - AbsoluteOffset { - x: Some(offset.x), - y: Some(offset.y), - }, - ) - .into(), - )); - } - if let Some(id) = self.select_focus_id() { - commands.push(Command::Iced(widget::button::focus(id).into())); - } - } - Message::ItemPageUp => { - self.dehighlight_all(); - if let Some((row, col)) = - self.select_focus_pos_opt().or(self.select_first_pos_opt()) - { - if self.select_focus.is_none() { - self.select_position(row, col, mod_shift); - } - - let rows_per_page = self.rows_per_page().max(1); - let target_row = row.saturating_sub(rows_per_page); - - if !self.select_position(target_row, col, mod_shift) { - // Fall back to the first item at or after target_row - let best = self.items_opt.as_ref().and_then(|items| { - items - .iter() - .filter_map(|item| item.pos_opt.get()) - .filter(|(r, _)| *r >= target_row) - .min() - }); - if let Some((best_row, best_col)) = best { - self.select_position(best_row, best_col, mod_shift); - } - } - } else { - self.select_position(0, 0, mod_shift); - } - if let Some(offset) = self.select_focus_scroll() { - commands.push(Command::Iced( - scrollable::scroll_to( - self.scrollable_id.clone(), - AbsoluteOffset { - x: Some(offset.x), - y: Some(offset.y), - }, - ) - .into(), - )); - } - if let Some(id) = self.select_focus_id() { - commands.push(Command::Iced(widget::button::focus(id).into())); - } - } Message::ItemLeft => { - self.dehighlight_all(); if self.gallery { commands.append(&mut self.update(Message::GalleryPrevious, modifiers)); } else { @@ -4181,7 +3902,6 @@ impl Tab { } } Message::ItemRight => { - self.dehighlight_all(); if self.gallery { commands.append(&mut self.update(Message::GalleryNext, modifiers)); } else { @@ -4223,7 +3943,6 @@ impl Tab { } } Message::ItemUp => { - self.dehighlight_all(); if let Some(edit_location) = &mut self.edit_location { edit_location.select(false); } else if self.gallery { @@ -4613,7 +4332,7 @@ impl Tab { Message::ShiftPermissions(path_mode_opt, shift, bits) => match path_mode_opt { Some((path, mode)) => commands.push(Command::SetPermissions( path, - set_mode_part(mode, shift, bits), + set_mode_part(mode, shift, bits.try_into().unwrap()), )), // Shift permissions on all selected items None => { @@ -4624,9 +4343,13 @@ impl Tab { #[cfg(unix)] if let (Some(path), Some(mode)) = ( item.path_opt(), - item.file_metadata().map(|metadata| metadata.mode()), + item.file_metadata() + .and_then(|metadata| Some(metadata.mode())), ) { - permissions.push((path.clone(), set_mode_part(mode, shift, bits))); + permissions.push(( + path.clone(), + set_mode_part(mode, shift, bits.try_into().unwrap()), + )); } } commands.push(Command::SetMultiplePermissions(permissions)); @@ -4800,52 +4523,6 @@ impl Tab { } } } - Message::Checksums(path, checksum_state) => { - let location = Location::Path(path); - if let Some(ref mut item) = self.parent_item_opt - && item.location_opt.as_ref() == Some(&location) - { - item.checksums = checksum_state.clone(); - } - if let Some(ref mut items) = self.items_opt { - for item in items.iter_mut() { - if item.location_opt.as_ref() == Some(&location) { - item.checksums = checksum_state; - break; - } - } - } - } - Message::CalculateChecksums(path) => { - let location = Location::Path(path.clone()); - if let Some(ref mut item) = self.parent_item_opt - && item.location_opt.as_ref() == Some(&location) - { - item.checksums = ChecksumState::Calculating; - } - if let Some(ref mut items) = self.items_opt { - for item in items.iter_mut() { - if item.location_opt.as_ref() == Some(&location) { - item.checksums = ChecksumState::Calculating; - break; - } - } - } - commands.push(Command::Iced( - cosmic::Task::future(async move { - match calculate_checksums(&path).await { - Ok(checksums) => { - Message::Checksums(path, ChecksumState::Calculated(checksums)) - } - Err(err) => Message::Checksums(path, ChecksumState::Error(err)), - } - }) - .into(), - )); - } - Message::CopyChecksum(value) => { - commands.push(Command::Iced(cosmic::iced::clipboard::write(value).into())); - } } // Scroll to top if needed @@ -5088,7 +4765,7 @@ impl Tab { space_xs, space_m, .. - } = theme::spacing(); + } = theme::active().cosmic().spacing; //TODO: display error messages when image not found? let mut name_opt = None; @@ -5286,7 +4963,7 @@ impl Tab { space_s, space_m, .. - } = theme::spacing(); + } = theme::active().cosmic().spacing; let size = self.size_opt.get().unwrap_or(Size::new(0.0, 0.0)); @@ -5621,7 +5298,7 @@ impl Tab { } pub fn empty_view(&self, has_hidden: bool) -> Element<'_, Message> { - let cosmic_theme::Spacing { space_xxs, .. } = theme::spacing(); + let cosmic_theme::Spacing { space_xxs, .. } = theme::active().cosmic().spacing; mouse_area::MouseArea::new(widget::column::with_children([widget::container( match self.mode { @@ -5661,7 +5338,7 @@ impl Tab { space_xxs, space_xxxs, .. - } = theme::spacing(); + } = theme::active().cosmic().spacing; let TabConfig { show_hidden, @@ -5771,7 +5448,8 @@ impl Tab { widget::button::custom( widget::icon::icon(item.icon_handle_grid.clone()) .content_fit(ContentFit::Contain) - .size(icon_sizes.grid()), + .size(icon_sizes.grid()) + .width(Length::Shrink), ) .padding(space_xxxs) .class(button_style( @@ -6006,7 +5684,7 @@ impl Tab { ) { let cosmic_theme::Spacing { space_s, space_xxs, .. - } = theme::spacing(); + } = theme::active().cosmic().spacing; let TabConfig { show_hidden, @@ -6408,7 +6086,7 @@ impl Tab { space_xxs, space_xs, .. - } = theme::spacing(); + } = theme::active().cosmic().spacing; let location_view_opt = if matches!(self.mode, Mode::Desktop) { None @@ -6538,24 +6216,6 @@ impl Tab { ); } } - Location::Recents | Location::Search(SearchLocation::Recents, ..) => { - if let Some(items) = self.items_opt() - && !items.is_empty() - { - tab_column = tab_column.push( - widget::layer_container(widget::row::with_children([ - widget::space::horizontal().into(), - widget::button::standard(fl!("clear-recents-history")) - .on_press(Message::ClearRecents) - .into(), - ])) - .padding([space_xxs, space_xs]) - .layer(cosmic_theme::Layer::Primary) - .apply(widget::container) - .padding([0, 0, 7, 0]), - ); - } - } Location::Network(uri, _display_name, _path) if uri == "network:///" => { tab_column = tab_column.push( widget::layer_container(widget::row::with_children([ @@ -6622,7 +6282,7 @@ impl Tab { space_xxxs, space_m, .. - } = theme::spacing(); + } = theme::active().cosmic().spacing; let mut column = widget::column::with_capacity(4).spacing(space_m); @@ -6755,35 +6415,33 @@ impl Tab { let mut settings = Vec::new(); // Only allow modifying open-with if all mime types are the same - if mime_types.len() == 1 - && let Some(mime) = mime_types - .first() + if mime_types.len() == 1 { + if let Some(mime) = mime_types + .get(0) .and_then(|(mime, _)| mime.parse::().ok()) - && let Some(mime_app_cache) = mime_app_cache_opt - { - let mime_apps = mime_app_cache.get_apps_for_mime(&mime, false); - if !mime_apps.is_empty() { - let mime_closure = mime.clone(); - let (names, icons) = mime_apps - .iter() - .map(|(app, _)| (Cow::Owned(app.name.clone()), app.icon())) - .collect::<(Vec<_>, Vec<_>)>(); - settings.push( - widget::settings::item::builder(fl!("open-with")).control( - Element::from( - widget::dropdown( - names, - mime_apps.iter().position(|(x, _)| x.is_default(&mime)), - move |index| (index, mime_closure.clone()), - ) - .icons(Cow::Owned(icons)), - ) - .map(move |(index, mime)| { - let mime_app = &mime_apps[index].0; - Message::SetOpenWith(mime, mime_app.id.clone()) - }), - ), - ); + { + if let Some(mime_app_cache) = mime_app_cache_opt { + let mime_apps = mime_app_cache.get(&mime); + if !mime_apps.is_empty() { + let mime_closure = mime.clone(); + settings.push( + widget::settings::item::builder(fl!("open-with")).control( + Element::from( + widget::dropdown( + mime_apps, + mime_apps.iter().position(|x| x.is_default), + move |index| (index, mime_closure.clone()), + ) + .icons(Cow::Borrowed(mime_app_cache.icons(&mime))), + ) + .map(|(index, mime)| { + let mime_app = &mime_apps[index]; + Message::SetOpenWith(mime, mime_app.id.clone()) + }), + ), + ); + } + } } } @@ -7388,25 +7046,21 @@ fn text_editor_class( #[cfg(test)] mod tests { - use std::path::PathBuf; - use std::{fs, io}; + use std::{fs, io, path::PathBuf}; - use cosmic::iced::mouse::ScrollDelta; - use cosmic::iced::runtime::keyboard::Modifiers; - use cosmic::widget; + use cosmic::{iced::mouse::ScrollDelta, iced::runtime::keyboard::Modifiers, widget}; use log::{debug, trace}; - use mime_guess::mime; use tempfile::TempDir; use test_log::test; - use super::{ - ItemMetadata, ItemThumbnail, Location, Message, Tab, respond_to_scroll_direction, scan_path, + use super::{Location, Message, Tab, respond_to_scroll_direction, scan_path}; + use crate::{ + app::test_utils::{ + NAME_LEN, NUM_DIRS, NUM_FILES, NUM_HIDDEN, NUM_NESTED, assert_eq_tab_path, empty_fs, + eq_path_item, filter_dirs, read_dir_sorted, simple_fs, tab_click_new, + }, + config::{IconSizes, TabConfig, ThumbCfg}, }; - use crate::app::test_utils::{ - NAME_LEN, NUM_DIRS, NUM_FILES, NUM_HIDDEN, NUM_NESTED, assert_eq_tab_path, empty_fs, - eq_path_item, filter_dirs, read_dir_sorted, simple_fs, tab_click_new, - }; - use crate::config::{IconSizes, TabConfig, ThumbCfg}; // Boilerplate for tab tests. Checks if simulated clicks selected items. fn tab_selects_item( @@ -7819,89 +7473,4 @@ mod tests { } } } - - #[test] - fn item_thumbnail_text_preview_small_utf8_returns_text() -> io::Result<()> { - let dir = TempDir::new()?; - let path = dir.path().join("preview.txt"); - fs::write(&path, "Hello, world!")?; - let metadata = fs::metadata(&path)?; - let item_metadata = ItemMetadata::Path { - metadata, - children_opt: None, - }; - let thumb = ItemThumbnail::new( - &path, - item_metadata, - mime::TEXT_PLAIN, - 128, - 100 * 1024 * 1024, - 1, - 8, - ); - assert!( - matches!(thumb, ItemThumbnail::Text(_)), - "small text file should produce Text thumbnail" - ); - Ok(()) - } - - #[test] - fn item_thumbnail_text_preview_empty_file_returns_not_image() -> io::Result<()> { - let dir = TempDir::new()?; - let path = dir.path().join("empty.txt"); - fs::File::create(&path)?; - let metadata = fs::metadata(&path)?; - let item_metadata = ItemMetadata::Path { - metadata, - children_opt: None, - }; - let thumb = ItemThumbnail::new( - &path, - item_metadata, - mime::TEXT_PLAIN, - 128, - 100 * 1024 * 1024, - 1, - 8, - ); - assert!( - matches!(thumb, ItemThumbnail::NotImage), - "empty text file should produce NotImage (no read)" - ); - Ok(()) - } - - #[test] - fn item_thumbnail_text_preview_invalid_utf8_uses_valid_prefix() -> io::Result<()> { - let dir = TempDir::new()?; - let path = dir.path().join("invalid_utf8.txt"); - // Valid UTF-8 "ab" then invalid byte sequence then "c" - fs::write(&path, b"ab\xff\xfe\xfdc")?; - let metadata = fs::metadata(&path)?; - let item_metadata = ItemMetadata::Path { - metadata, - children_opt: None, - }; - let thumb = ItemThumbnail::new( - &path, - item_metadata, - mime::TEXT_PLAIN, - 128, - 100 * 1024 * 1024, - 1, - 8, - ); - match &thumb { - ItemThumbnail::Text(content) => { - // Text editor content may add a trailing newline - assert_eq!(content.text().trim_end(), "ab"); - } - _ => panic!( - "expected Text thumbnail with valid prefix only, got {:?}", - thumb - ), - } - Ok(()) - } } diff --git a/src/thumbnail_cacher.rs b/src/thumbnail_cacher.rs index e42d343..e4d616e 100644 --- a/src/thumbnail_cacher.rs +++ b/src/thumbnail_cacher.rs @@ -1,14 +1,16 @@ use image::DynamicImage; use md5::{Digest, Md5}; use rustc_hash::FxHashMap; -use std::error::Error; -use std::fs::{self, File}; -use std::io::{self, BufReader, BufWriter}; #[cfg(unix)] use std::os::unix::fs::PermissionsExt; -use std::path::{Path, PathBuf}; -use std::sync::LazyLock; -use std::time::UNIX_EPOCH; +use std::{ + error::Error, + fs::{self, File}, + io::{self, BufReader, BufWriter}, + path::{Path, PathBuf}, + sync::LazyLock, + time::UNIX_EPOCH, +}; use tempfile::NamedTempFile; use url::Url; diff --git a/src/thumbnailer.rs b/src/thumbnailer.rs index 8e61447..f7786ed 100644 --- a/src/thumbnailer.rs +++ b/src/thumbnailer.rs @@ -5,12 +5,12 @@ use cosmic::desktop::fde::GenericEntry; use mime_guess::Mime; use rustc_hash::FxHashMap; -#[cfg(feature = "desktop")] -use std::{fs, time::Instant}; use std::{ + fs, path::Path, process, sync::{LazyLock, Mutex}, + time::Instant, }; #[derive(Clone, Debug)] diff --git a/src/trash.rs b/src/trash.rs index c0b3548..ce37c83 100644 --- a/src/trash.rs +++ b/src/trash.rs @@ -1,29 +1,11 @@ use cosmic::widget; use regex::Regex; -use std::collections::HashSet; -use std::path::{Path, PathBuf}; +use std::{collections::HashSet, path::PathBuf}; -use crate::config::IconSizes; -use crate::tab::{Item, SearchItem}; - -fn percent_decode(s: &str) -> Option { - let (mut r, mut b) = (String::with_capacity(s.len()), s.bytes()); - while let Some(c) = b.next() { - if c == b'%' { - let (hi, lo) = (b.next()?, b.next()?); - let h = |x: u8| match x { - b'0'..=b'9' => Some(x - b'0'), - b'a'..=b'f' => Some(x - b'a' + 10), - b'A'..=b'F' => Some(x - b'A' + 10), - _ => None, - }; - r.push((h(hi)? << 4 | h(lo)?) as char); - } else { - r.push(c as char); - } - } - Some(r) -} +use crate::{ + config::IconSizes, + tab::{Item, SearchItem}, +}; pub trait TrashExt { fn is_empty() -> bool { @@ -45,7 +27,7 @@ pub trait TrashExt { Vec::new() } - fn scan_search bool + Sync>(_callback: F, _regex: &Regex) {} + fn scan_search bool + Sync>(callback: F, regex: &Regex) {} fn icon(icon_size: u16) -> widget::icon::Handle { widget::icon::from_name(if Self::is_empty() { @@ -68,46 +50,6 @@ pub trait TrashExt { } } -/// Derive the actual filesystem path of a trashed item from its .trashinfo path -/// (or return the id directly if it's already a filesystem path). -pub fn trash_item_path(item: &trash::TrashItem) -> Option { - let id_path = Path::new(&item.id); - if id_path.extension().map_or(false, |e| e == "trashinfo") { - let trash_root = id_path.parent()?.parent()?; - let file_name = id_path.file_stem()?; - Some(trash_root.join("files").join(file_name)) - } else { - Some(PathBuf::from(&item.id)) - } -} - -/// For a path inside a trash `files/` directory, reconstruct the original path -/// by reading the parent `.trashinfo` file. -/// -/// Given `~/.local/share/Trash/files/folder/sub/file.txt`: -/// - The top-level trashed item is `folder` -/// - Read `~/.local/share/Trash/info/folder.trashinfo` to get the original path -/// - Compute: `/sub/file.txt` -pub fn original_path_for_trash_child(p: &Path) -> Option { - let files = p.ancestors().find(|a| a.ends_with("files"))?; - let root = files.parent()?; - let top = p.strip_prefix(files).ok()?.components().next()?; - let info = - std::fs::read_to_string(root.join("info").join(top).with_extension("trashinfo")).ok()?; - let orig = percent_decode(info.lines().find_map(|l| l.strip_prefix("Path="))?.trim())?; - let rel = p.strip_prefix(files.join(top)).ok()?; - let mut result = PathBuf::from(&orig); - if !rel.as_os_str().is_empty() { - result.push(rel); - } - Some(result) -} - -/// Check whether a path is inside any trash `files/` directory. -pub fn is_trash_path(path: &Path) -> bool { - path.ancestors().any(|a| a.ends_with("files")) -} - pub struct Trash; // This config statement is from trash::os_limited @@ -139,8 +81,7 @@ impl TrashExt for Trash { } fn scan(sizes: IconSizes) -> Vec { - use crate::localize::LANGUAGE_SORTER; - use crate::tab::item_from_trash_entry; + use crate::{localize::LANGUAGE_SORTER, tab::item_from_trash_entry}; use std::cmp::Ordering; let entries = match trash::os_limited::list() { @@ -201,12 +142,4 @@ impl TrashExt for Trash { not(target_os = "android") ) )))] -impl TrashExt for Trash { - fn scan_search bool + Sync>(callback: F, regex: &Regex) { - log::warn!( - "searching trash not supported on this platform for pattern {:?}", - regex.as_str() - ); - drop(callback); - } -} +impl TrashExt for Trash {} diff --git a/src/zoom.rs b/src/zoom.rs index 89ae5b8..600d0b5 100644 --- a/src/zoom.rs +++ b/src/zoom.rs @@ -1,7 +1,6 @@ use std::num::NonZeroU16; -use crate::config::IconSizes; -use crate::tab::View; +use crate::{config::IconSizes, tab::View}; static DEFAULT_ZOOM: NonZeroU16 = NonZeroU16::new(100).unwrap(); static MIN_ZOOM: NonZeroU16 = NonZeroU16::new(50).unwrap();