diff --git a/Cargo.lock b/Cargo.lock index 1cac6c0d..ed9d9b43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -250,12 +250,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" 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 = "ash" version = "0.38.0+1.3.281" @@ -512,9 +506,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "base64" @@ -705,9 +699,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "by_address" @@ -879,7 +873,6 @@ 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", @@ -889,22 +882,12 @@ 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", "smithay-clipboard", ] -[[package]] -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" version = "0.25.0" @@ -1075,7 +1058,7 @@ dependencies = [ "i18n-embed", "i18n-embed-fl", "image", - "libcosmic", + "libcosmic-yoda", "memmap2 0.9.10", "rust-embed", "rustc-hash 2.1.2", @@ -1093,7 +1076,7 @@ dependencies = [ name = "cosmic-app-list-config" version = "1.0.2" dependencies = [ - "libcosmic", + "libcosmic-yoda", "serde", ] @@ -1108,7 +1091,7 @@ dependencies = [ "cosmic-settings-accessibility-subscription", "i18n-embed", "i18n-embed-fl", - "libcosmic", + "libcosmic-yoda", "rust-embed", "tokio", "tracing", @@ -1123,7 +1106,7 @@ dependencies = [ "cosmic-settings-sound-subscription", "i18n-embed", "i18n-embed-fl", - "libcosmic", + "libcosmic-yoda", "mpris2-zbus", "rust-embed", "serde", @@ -1145,11 +1128,11 @@ dependencies = [ "cosmic-config", "cosmic-settings-daemon-subscription", "cosmic-settings-upower-subscription", - "drm 0.14.1", + "drm", "futures", "i18n-embed", "i18n-embed-fl", - "libcosmic", + "libcosmic-yoda", "rust-embed", "rustc-hash 2.1.2", "serde", @@ -1171,7 +1154,7 @@ dependencies = [ "futures", "i18n-embed", "i18n-embed-fl", - "libcosmic", + "libcosmic-yoda", "rust-embed", "rustc-hash 2.1.2", "tokio", @@ -1187,7 +1170,7 @@ dependencies = [ "cosmic-comp-config", "i18n-embed", "i18n-embed-fl", - "libcosmic", + "libcosmic-yoda", "rust-embed", "tokio", "tracing", @@ -1204,7 +1187,7 @@ dependencies = [ "i18n-embed", "i18n-embed-fl", "image", - "libcosmic", + "libcosmic-yoda", "memmap2 0.9.10", "rust-embed", "rustix 1.1.4", @@ -1227,7 +1210,7 @@ dependencies = [ "i18n-embed", "i18n-embed-fl", "indexmap 2.14.0", - "libcosmic", + "libcosmic-yoda", "nmrs", "rust-embed", "rustc-hash 2.1.2", @@ -1250,7 +1233,7 @@ dependencies = [ "futures-util", "i18n-embed", "i18n-embed-fl", - "libcosmic", + "libcosmic-yoda", "rust-embed", "tokio", "tracing", @@ -1266,7 +1249,7 @@ version = "1.0.2" dependencies = [ "i18n-embed", "i18n-embed-fl", - "libcosmic", + "libcosmic-yoda", "logind-zbus", "rust-embed", "rustix 1.1.4", @@ -1282,7 +1265,7 @@ name = "cosmic-applet-status-area" version = "1.0.2" dependencies = [ "futures", - "libcosmic", + "libcosmic-yoda", "rustc-hash 2.1.2", "serde", "tokio", @@ -1302,7 +1285,7 @@ dependencies = [ "cosmic-protocols", "i18n-embed", "i18n-embed-fl", - "libcosmic", + "libcosmic-yoda", "rust-embed", "rustc-hash 2.1.2", "tokio", @@ -1320,7 +1303,7 @@ dependencies = [ "i18n-embed-fl", "icu", "jiff", - "libcosmic", + "libcosmic-yoda", "logind-zbus", "rust-embed", "timedate-zbus", @@ -1340,7 +1323,7 @@ dependencies = [ "futures", "i18n-embed", "i18n-embed-fl", - "libcosmic", + "libcosmic-yoda", "rust-embed", "tokio", "tracing", @@ -1367,7 +1350,7 @@ dependencies = [ "cosmic-applet-time", "cosmic-applet-workspaces", "cosmic-panel-button", - "libcosmic", + "libcosmic-yoda", "tracing", "tracing-log", "tracing-subscriber", @@ -1385,7 +1368,6 @@ dependencies = [ [[package]] name = "cosmic-client-toolkit" version = "0.2.0" -source = "git+https://github.com/pop-os/cosmic-protocols//?branch=main#c253ec1d6804afbcdf250f5cc37ae1194bba7bd2" dependencies = [ "bitflags 2.11.1", "cosmic-protocols", @@ -1397,8 +1379,7 @@ dependencies = [ [[package]] name = "cosmic-comp-config" -version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-comp.git?rev=5eb5af4#5eb5af46756f2f2bc5e812cf68fe4c4b79efd924" +version = "1.0.0" dependencies = [ "cosmic-config", "input", @@ -1408,7 +1389,6 @@ dependencies = [ [[package]] name = "cosmic-config" version = "1.0.0" -source = "git+https://github.com/pop-os/libcosmic#4fab6c777dbd1a023440f08fb2b729c86492366c" dependencies = [ "atomicwrites", "cosmic-config-derive", @@ -1429,7 +1409,6 @@ dependencies = [ [[package]] name = "cosmic-config-derive" version = "1.0.0" -source = "git+https://github.com/pop-os/libcosmic#4fab6c777dbd1a023440f08fb2b729c86492366c" dependencies = [ "quote", "syn", @@ -1438,7 +1417,6 @@ dependencies = [ [[package]] name = "cosmic-dbus-a11y" version = "0.1.0" -source = "git+https://github.com/pop-os/dbus-settings-bindings#507e342c21d3ce6ae41b1d4f3fa2f0ad5ee23e75" dependencies = [ "zbus", ] @@ -1446,7 +1424,6 @@ dependencies = [ [[package]] name = "cosmic-dbus-networkmanager" version = "0.1.0" -source = "git+https://github.com/pop-os/dbus-settings-bindings#507e342c21d3ce6ae41b1d4f3fa2f0ad5ee23e75" dependencies = [ "bitflags 2.11.1", "derive_builder", @@ -1459,7 +1436,6 @@ dependencies = [ [[package]] name = "cosmic-freedesktop-icons" version = "0.4.0" -source = "git+https://github.com/pop-os/freedesktop-icons#9c562fe3ecf03241a46a60c0078cd6ea10bd75ce" dependencies = [ "bstr", "btoi", @@ -1473,7 +1449,6 @@ dependencies = [ [[package]] name = "cosmic-notifications-config" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-notifications#a899bfbc6715c36b1f02d7a0f4d3601a3ea0295f" dependencies = [ "cosmic-config", "serde", @@ -1482,10 +1457,9 @@ dependencies = [ [[package]] name = "cosmic-notifications-util" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-notifications#a899bfbc6715c36b1f02d7a0f4d3601a3ea0295f" dependencies = [ "fast_image_resize", - "libcosmic", + "libcosmic-yoda", "serde", "tl", "tracing", @@ -1498,7 +1472,7 @@ name = "cosmic-panel-button" version = "1.0.2" dependencies = [ "cosmic-config", - "libcosmic", + "libcosmic-yoda", "rustc-hash 2.1.2", "serde", "tracing", @@ -1509,7 +1483,6 @@ dependencies = [ [[package]] name = "cosmic-panel-config" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-panel#2358f0473bf68b79f54a0906994a218de211de34" dependencies = [ "anyhow", "cosmic-config", @@ -1523,7 +1496,6 @@ dependencies = [ [[package]] name = "cosmic-pipewire" version = "1.0.7" -source = "git+https://github.com/pop-os/cosmic-settings#703a934b096b8681b1b8d16d8625118c8073151a" dependencies = [ "intmap", "libspa", @@ -1537,7 +1509,6 @@ dependencies = [ [[package]] name = "cosmic-protocols" version = "0.2.0" -source = "git+https://github.com/pop-os/cosmic-protocols//?branch=main#c253ec1d6804afbcdf250f5cc37ae1194bba7bd2" dependencies = [ "bitflags 2.11.1", "wayland-backend", @@ -1551,7 +1522,6 @@ dependencies = [ [[package]] name = "cosmic-settings-a11y-manager-subscription" version = "1.0.7" -source = "git+https://github.com/pop-os/cosmic-settings#703a934b096b8681b1b8d16d8625118c8073151a" dependencies = [ "cosmic-protocols", "iced_futures", @@ -1565,7 +1535,6 @@ dependencies = [ [[package]] name = "cosmic-settings-accessibility-subscription" version = "1.0.7" -source = "git+https://github.com/pop-os/cosmic-settings#703a934b096b8681b1b8d16d8625118c8073151a" dependencies = [ "cosmic-dbus-a11y", "futures", @@ -1578,7 +1547,6 @@ 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", @@ -1590,8 +1558,7 @@ dependencies = [ [[package]] name = "cosmic-settings-daemon" -version = "0.1.0" -source = "git+https://github.com/pop-os/dbus-settings-bindings#507e342c21d3ce6ae41b1d4f3fa2f0ad5ee23e75" +version = "0.1.1-yoda.1" dependencies = [ "zbus", ] @@ -1599,7 +1566,6 @@ dependencies = [ [[package]] name = "cosmic-settings-daemon-subscription" version = "1.0.7" -source = "git+https://github.com/pop-os/cosmic-settings#703a934b096b8681b1b8d16d8625118c8073151a" dependencies = [ "futures", "iced_futures", @@ -1612,7 +1578,6 @@ dependencies = [ [[package]] name = "cosmic-settings-network-manager-subscription" version = "1.0.7" -source = "git+https://github.com/pop-os/cosmic-settings#703a934b096b8681b1b8d16d8625118c8073151a" dependencies = [ "bitflags 2.11.1", "cosmic-dbus-networkmanager", @@ -1631,12 +1596,11 @@ dependencies = [ [[package]] name = "cosmic-settings-sound-subscription" version = "1.0.7" -source = "git+https://github.com/pop-os/cosmic-settings#703a934b096b8681b1b8d16d8625118c8073151a" dependencies = [ "cosmic-pipewire", "futures", "intmap", - "libcosmic", + "libcosmic-yoda", "numtoa", "rustix 1.1.4", "tokio", @@ -1646,7 +1610,6 @@ dependencies = [ [[package]] name = "cosmic-settings-upower-subscription" version = "1.0.7" -source = "git+https://github.com/pop-os/cosmic-settings#703a934b096b8681b1b8d16d8625118c8073151a" dependencies = [ "futures", "iced_futures", @@ -1660,8 +1623,6 @@ dependencies = [ [[package]] name = "cosmic-text" version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be17b688510d934ce13f48a2beba700e11583e281e0fda99c22bb256a14eda73" dependencies = [ "bitflags 2.11.1", "fontdb", @@ -1679,18 +1640,19 @@ 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#4fab6c777dbd1a023440f08fb2b729c86492366c" dependencies = [ "almost", "configparser", "cosmic-config", "csscolorparser", "dirs", + "hex_color", "palette", "ron 0.12.1", "serde", @@ -1731,7 +1693,6 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "cryoglyph" version = "0.1.0" -source = "git+https://github.com/iced-rs/cryoglyph.git?rev=e429a025df36ab8145708acb309080ae3deec17a#e429a025df36ab8145708acb309080ae3deec17a" dependencies = [ "cosmic-text", "etagere", @@ -1768,15 +1729,6 @@ dependencies = [ "uncased", ] -[[package]] -name = "ctor" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83cf0d42651b16c6dfe68685716d18480d18a9c39c62d76e8cf3eb6ed5d8bcbf" -dependencies = [ - "dtor", -] - [[package]] name = "cursor-icon" version = "1.2.0" @@ -2058,9 +2010,9 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", @@ -2079,7 +2031,6 @@ 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.11.1", "mime 0.1.0", @@ -2106,20 +2057,6 @@ 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 0.7.1", - "drm-fourcc", - "rustix 0.38.44", -] [[package]] name = "drm" @@ -2129,29 +2066,19 @@ checksum = "80bc8c5c6c2941f70a55c15f8d9f00f9710ebda3ffda98075f996a0e6c92756f" dependencies = [ "bitflags 2.11.1", "bytemuck", - "drm-ffi 0.9.1", + "drm-ffi", "drm-fourcc", "libc", "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 0.6.1", - "rustix 0.38.44", -] - [[package]] name = "drm-ffi" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51a91c9b32ac4e8105dec255e849e0d66e27d7c34d184364fb93e469db08f690" dependencies = [ - "drm-sys 0.8.1", + "drm-sys", "rustix 1.1.4", ] @@ -2161,16 +2088,6 @@ 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 = "drm-sys" version = "0.8.1" @@ -2181,12 +2098,6 @@ dependencies = [ "linux-raw-sys 0.9.4", ] -[[package]] -name = "dtor" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edf234dd1594d6dd434a8fb8cada51ddbbc593e40e4a01556a0b31c62da2775b" - [[package]] name = "dyn-clone" version = "1.0.20" @@ -2195,9 +2106,9 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "either" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" [[package]] name = "endi" @@ -2629,9 +2540,9 @@ checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-timer" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968" [[package]] name = "futures-util" @@ -2660,16 +2571,6 @@ 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" @@ -2791,7 +2692,7 @@ dependencies = [ "log", "presser", "thiserror 2.0.18", - "windows 0.62.2", + "windows 0.61.3", ] [[package]] @@ -2917,6 +2818,17 @@ 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" @@ -3035,7 +2947,6 @@ dependencies = [ [[package]] name = "iced" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#4fab6c777dbd1a023440f08fb2b729c86492366c" dependencies = [ "dnd", "iced_accessibility", @@ -3056,7 +2967,6 @@ dependencies = [ [[package]] name = "iced_accessibility" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#4fab6c777dbd1a023440f08fb2b729c86492366c" dependencies = [ "accesskit", "accesskit_winit", @@ -3065,7 +2975,6 @@ dependencies = [ [[package]] name = "iced_core" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#4fab6c777dbd1a023440f08fb2b729c86492366c" dependencies = [ "bitflags 2.11.1", "bytes", @@ -3082,6 +2991,7 @@ dependencies = [ "serde", "smol_str", "thiserror 2.0.18", + "unicode-segmentation", "web-time", "window_clipboard", ] @@ -3089,7 +2999,6 @@ dependencies = [ [[package]] name = "iced_debug" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#4fab6c777dbd1a023440f08fb2b729c86492366c" dependencies = [ "iced_core", "iced_futures", @@ -3099,7 +3008,6 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#4fab6c777dbd1a023440f08fb2b729c86492366c" dependencies = [ "futures", "iced_core", @@ -3113,7 +3021,6 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#4fab6c777dbd1a023440f08fb2b729c86492366c" dependencies = [ "bitflags 2.11.1", "bytemuck", @@ -3134,7 +3041,6 @@ dependencies = [ [[package]] name = "iced_program" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#4fab6c777dbd1a023440f08fb2b729c86492366c" dependencies = [ "iced_graphics", "iced_runtime", @@ -3143,7 +3049,6 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#4fab6c777dbd1a023440f08fb2b729c86492366c" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -3155,7 +3060,6 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#4fab6c777dbd1a023440f08fb2b729c86492366c" dependencies = [ "bytes", "cosmic-client-toolkit", @@ -3170,7 +3074,6 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#4fab6c777dbd1a023440f08fb2b729c86492366c" dependencies = [ "bytemuck", "cosmic-text", @@ -3187,9 +3090,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#4fab6c777dbd1a023440f08fb2b729c86492366c" dependencies = [ - "as-raw-xcb-connection", "bitflags 2.11.1", "bytemuck", "cosmic-client-toolkit", @@ -3206,19 +3107,16 @@ 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#4fab6c777dbd1a023440f08fb2b729c86492366c" dependencies = [ "cosmic-client-toolkit", "dnd", @@ -3236,7 +3134,6 @@ dependencies = [ [[package]] name = "iced_winit" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#4fab6c777dbd1a023440f08fb2b729c86492366c" dependencies = [ "cosmic-client-toolkit", "cursor-icon", @@ -3792,9 +3689,9 @@ dependencies = [ [[package]] name = "input" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbdc09524a91f9cacd26f16734ff63d7dc650daffadd2b6f84d17a285bd875a9" +checksum = "f9793345a65d71317763a33066b5d8351f8760dde8d4930fe9e39b5f14a7959d" dependencies = [ "bitflags 2.11.1", "input-sys", @@ -3877,9 +3774,9 @@ checksum = "2ceaf4c6c48465bead8cb6a0b7c4ee0c86ecbb31239032b9c66ab9a08d2f3ee1" [[package]] name = "jiff" -version = "0.2.24" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00b5dbd620d61dfdcb6007c9c1f6054ebd75319f163d886a9055cec1155073d" +checksum = "6835eea34fb6321b9b3aa7b685c2b433948c09447e389dc017fdf687d5d11e65" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -3892,9 +3789,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.24" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e000de030ff8022ea1da3f466fbb0f3a809f5e51ed31f6dd931c35181ad8e6d7" +checksum = "3c22e04db9c58f5136eb1757f3d5c49a7b187f49e52185228cbd2f5acdfcc08c" dependencies = [ "proc-macro2", "quote", @@ -3986,9 +3883,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.98" +version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" +checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" dependencies = [ "cfg-if", "futures-util", @@ -4053,9 +3950,9 @@ dependencies = [ [[package]] name = "kqueue-sys" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "285efcf12ef41bec907b3000d5ffaeb54191d4d9d83c0d6157e6cbc2db255e64" +checksum = "07293a4e297ac234359b510362495713f75ea345d5307140414f20c69ffeb087" dependencies = [ "bitflags 2.11.1", "libc", @@ -4101,9 +3998,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] -name = "libcosmic" -version = "1.0.0" -source = "git+https://github.com/pop-os/libcosmic#4fab6c777dbd1a023440f08fb2b729c86492366c" +name = "libcosmic-yoda" +version = "0.1.0-yoda.2" dependencies = [ "apply", "ashpd 0.12.3", @@ -4117,6 +4013,7 @@ dependencies = [ "cosmic-theme", "css-color", "derive_setters", + "enumflags2", "float-cmp 0.10.0", "freedesktop-desktop-entry", "futures", @@ -4182,14 +4079,14 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" +checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" dependencies = [ "bitflags 2.11.1", "libc", "plain", - "redox_syscall 0.7.5", + "redox_syscall 0.8.0", ] [[package]] @@ -4251,12 +4148,6 @@ 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.9.4" @@ -4305,9 +4196,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" [[package]] name = "logind-zbus" @@ -4403,9 +4294,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" [[package]] name = "memmap2" @@ -4452,7 +4343,6 @@ 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", ] @@ -4481,9 +4371,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "log", @@ -4504,7 +4394,6 @@ dependencies = [ [[package]] name = "mpris2-zbus" version = "0.1.0" -source = "git+https://github.com/pop-os/dbus-settings-bindings#507e342c21d3ce6ae41b1d4f3fa2f0ad5ee23e75" dependencies = [ "futures-util", "jiff", @@ -4603,16 +4492,15 @@ dependencies = [ [[package]] name = "nm-secret-agent-manager" version = "0.1.0" -source = "git+https://github.com/pop-os/dbus-settings-bindings#507e342c21d3ce6ae41b1d4f3fa2f0ad5ee23e75" dependencies = [ "zbus", ] [[package]] name = "nmrs" -version = "3.1.3" +version = "3.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5e0c4453d1edf1b13767c4a10905a55c847d942d751cb220a78074f194d523" +checksum = "d907d6da103106d84189d3fd229d9aac921f9131b8ba38b40341c53d24409077" dependencies = [ "async-trait", "base64", @@ -4718,9 +4606,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-derive" @@ -5024,9 +4912,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "orbclient" -version = "0.3.54" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a570f6bca41d29acb2139229a7c873ec99bc9a313bd10804081d89bfac8ff329" +checksum = "5df339f526ea9a60e371768d50efc2f2508c7203290731565d1f7a6f71d21747" dependencies = [ "libc", "libredox", @@ -5245,18 +5133,18 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pin-project" -version = "1.1.12" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf0d9e68100b3a7989b4901972f265cd542e560a3a8a724e1e20322f4d06ce9" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.12" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a990e22f43e84855daf260dded30524ef4a9021cc7541c26540500a50b624389" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", @@ -5558,6 +5446,8 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ + "libc", + "rand_chacha 0.3.1", "rand_core 0.6.4", ] @@ -5567,10 +5457,20 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ - "rand_chacha", + "rand_chacha 0.9.0", "rand_core 0.9.5", ] +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + [[package]] name = "rand_chacha" version = "0.9.0" @@ -5586,6 +5486,9 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] [[package]] name = "rand_core" @@ -5625,6 +5528,16 @@ dependencies = [ "font-types", ] +[[package]] +name = "redox_event" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c07d0d6d291e3a951bd847b1cd4af32fc6243d64116cf7702838c02797688b7" +dependencies = [ + "bitflags 2.11.1", + "libredox", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -5636,9 +5549,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4666a1a60d8412eab19d94f6d13dcc9cea0a5ef4fdf6a5db306537413c661b1b" +checksum = "7c7591fa2c6b601dfcfe5f043f65a1c39fcdf50efefcd7f1572e538c1f4b398d" dependencies = [ "bitflags 2.11.1", ] @@ -6040,9 +5953,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "indexmap 2.14.0", "itoa", @@ -6247,7 +6160,6 @@ 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", @@ -6267,9 +6179,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ "libc", "windows-sys 0.61.2", @@ -6278,14 +6190,11 @@ dependencies = [ [[package]] name = "softbuffer" version = "0.4.1" -source = "git+https://github.com/pop-os/softbuffer?tag=cosmic-4.0#c2b2c19ddb38ff17495643699f97cb1f2064a1be" dependencies = [ - "as-raw-xcb-connection", "bytemuck", "cfg_aliases", "cocoa", "core-graphics", - "drm 0.11.1", "fastrand", "foreign-types", "js-sys", @@ -6295,14 +6204,12 @@ dependencies = [ "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]] @@ -6399,7 +6306,6 @@ dependencies = [ [[package]] name = "switcheroo-control" version = "0.1.0" -source = "git+https://github.com/pop-os/dbus-settings-bindings#507e342c21d3ce6ae41b1d4f3fa2f0ad5ee23e75" dependencies = [ "zbus", ] @@ -6577,7 +6483,6 @@ dependencies = [ [[package]] name = "timedate-zbus" version = "0.1.0" -source = "git+https://github.com/pop-os/dbus-settings-bindings#507e342c21d3ce6ae41b1d4f3fa2f0ad5ee23e75" dependencies = [ "zbus", ] @@ -6608,19 +6513,6 @@ dependencies = [ "strict-num", ] -[[package]] -name = "tiny-xlib" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90a0ca3ee6a69f2ad28fd11621a4c3f03b371f366be500b64df260c4ffbafb4" -dependencies = [ - "as-raw-xcb-connection", - "ctor", - "libloading", - "pkg-config", - "tracing", -] - [[package]] name = "tinystr" version = "0.8.3" @@ -6728,9 +6620,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.11+spec-1.1.0" +version = "0.25.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" dependencies = [ "indexmap 2.14.0", "toml_datetime", @@ -6971,7 +6863,6 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "upower_dbus" version = "0.3.2" -source = "git+https://github.com/pop-os/dbus-settings-bindings#507e342c21d3ce6ae41b1d4f3fa2f0ad5ee23e75" dependencies = [ "serde", "serde_repr", @@ -7103,9 +6994,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.121" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" +checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" dependencies = [ "cfg-if", "once_cell", @@ -7116,9 +7007,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.71" +version = "0.4.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8" +checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f" dependencies = [ "js-sys", "wasm-bindgen", @@ -7126,9 +7017,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.121" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" +checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7136,9 +7027,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.121" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" +checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" dependencies = [ "bumpalo", "proc-macro2", @@ -7149,9 +7040,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.121" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" +checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" dependencies = [ "unicode-ident", ] @@ -7356,9 +7247,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.98" +version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa" +checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" dependencies = [ "js-sys", "wasm-bindgen", @@ -7564,12 +7455,10 @@ 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", @@ -8009,7 +7898,6 @@ 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.11.1", "cfg_aliases", @@ -8029,13 +7917,11 @@ 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.11.1", @@ -8050,7 +7936,6 @@ 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.11.1", "block2 0.6.2", @@ -8072,7 +7957,6 @@ 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.10", "objc2 0.6.4", @@ -8080,14 +7964,12 @@ dependencies = [ "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.11.1", "cursor-icon", @@ -8101,14 +7983,13 @@ 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.11.1", "dpi", "libredox", "orbclient", "raw-window-handle", - "redox_syscall 0.7.5", + "redox_event", "smol_str", "tracing", "winit-core", @@ -8117,7 +7998,6 @@ 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.11.1", "block2 0.6.2", @@ -8137,7 +8017,6 @@ 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.11.1", @@ -8163,7 +8042,6 @@ 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.11.1", @@ -8185,7 +8063,6 @@ 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.11.1", "cursor-icon", @@ -8198,34 +8075,11 @@ 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.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" dependencies = [ "memchr", ] @@ -8339,39 +8193,6 @@ 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 = "xcursor" version = "0.3.10" @@ -8387,7 +8208,6 @@ checksum = "2fb433233f2df9344722454bc7e96465c9d03bff9d77c248f9e7523fe79585b5" [[package]] name = "xdg-shell-wrapper-config" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-panel#2358f0473bf68b79f54a0906994a218de211de34" dependencies = [ "serde", "wayland-protocols-wlr", @@ -8638,18 +8458,18 @@ checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" [[package]] name = "zerocopy" -version = "0.8.48" +version = "0.8.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +checksum = "bce33a6288fa3f072a8c2c7d0f2fdbb90e28298f0135c1f99b96c3db2efcc60b" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.48" +version = "0.8.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +checksum = "8fd425244944f4ab65ccff928e7323354c5a018c75838362fdce749dfad2ee1e" dependencies = [ "proc-macro2", "quote", @@ -8794,3 +8614,11 @@ dependencies = [ "syn", "winnow", ] + +[[patch.unused]] +name = "winit-x11" +version = "0.31.0-beta.2" + +[[patch.unused]] +name = "cosmic-settings-airplane-mode-subscription" +version = "1.0.7" diff --git a/Cargo.toml b/Cargo.toml index 569cb3b4..098b9507 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,11 +25,11 @@ resolver = "3" [workspace.dependencies] anyhow = "1.0.102" -cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "d0e95be" } +cctk = { package = "cosmic-client-toolkit", path = "../cosmic-protocols/client-toolkit" } cosmic-applets-config = { path = "cosmic-applets-config" } -cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", default-features = false, features = [ +cosmic-protocols = { path = "../cosmic-protocols", default-features = false, features = [ "client", -], rev = "d0e95be" } +]} futures = "0.3" futures-util = "0.3" @@ -38,7 +38,7 @@ i18n-embed = { version = "0.16.0", features = [ "desktop-requester", ] } i18n-embed-fl = "0.10" -libcosmic = { git = "https://github.com/pop-os/libcosmic", default-features = false, features = [ +cosmic = { package = "libcosmic-yoda", path = "../libcosmic", default-features = false, features = [ "applet", "applet-token", "dbus-config", @@ -48,6 +48,7 @@ libcosmic = { git = "https://github.com/pop-os/libcosmic", default-features = fa "desktop-systemd-scope", "winit", ] } +cosmic-comp-config = { path = "../cosmic-comp/cosmic-comp-config" } rust-embed = "8.11.0" rust-embed-utils = "8.11.0" rustc-hash = "2.1" @@ -58,7 +59,7 @@ tracing-subscriber = { version = "0.3.22", features = ["env-filter"] } tracing-log = "0.2.0" tokio = { version = "1.49.0", features = ["full"] } # cosmic-config = { path = "../libcosmic/cosmic-config" } -cosmic-config = { git = "https://github.com/pop-os/libcosmic" } +cosmic-config = { path = "../libcosmic/cosmic-config" } serde = { version = "1.0.228", features = ["derive"] } [profile.release] @@ -81,12 +82,51 @@ ignored = ["libcosmic"] # winit = { git = "https://github.com/rust-windowing/winit.git", rev = "241b7a80bba96c91fa3901729cd5dec66abb9be4" } # winit = { path = "../winit" } +[patch."https://github.com/pop-os/libcosmic"] +cosmic-config = { path = "/home/lionel/Projets/COSMIC/libcosmic/cosmic-config" } +cosmic-theme = { path = "/home/lionel/Projets/COSMIC/libcosmic/cosmic-theme" } +iced = { path = "/home/lionel/Projets/COSMIC/libcosmic/iced" } +iced_accessibility = { path = "/home/lionel/Projets/COSMIC/libcosmic/iced/accessibility" } +iced_core = { path = "/home/lionel/Projets/COSMIC/libcosmic/iced/core" } +iced_futures = { path = "/home/lionel/Projets/COSMIC/libcosmic/iced/futures" } +iced_graphics = { path = "/home/lionel/Projets/COSMIC/libcosmic/iced/graphics" } +iced_renderer = { path = "/home/lionel/Projets/COSMIC/libcosmic/iced/renderer" } +iced_runtime = { path = "/home/lionel/Projets/COSMIC/libcosmic/iced/runtime" } +iced_tiny_skia = { path = "/home/lionel/Projets/COSMIC/libcosmic/iced/tiny_skia" } +iced_wgpu = { path = "/home/lionel/Projets/COSMIC/libcosmic/iced/wgpu" } +iced_widget = { path = "/home/lionel/Projets/COSMIC/libcosmic/iced/widget" } +iced_winit = { path = "/home/lionel/Projets/COSMIC/libcosmic/iced/winit" } + [patch."https://github.com/smithay/client-toolkit.git"] sctk = { package = "smithay-client-toolkit", version = "0.20.0" } [patch."https://github.com/pop-os/cosmic-protocols"] -cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols//", branch = "main" } -cosmic-client-toolkit = { git = "https://github.com/pop-os/cosmic-protocols//", branch = "main" } +cosmic-protocols = { path = "/home/lionel/Projets/COSMIC/cosmic-protocols" } +cosmic-client-toolkit = { path = "/home/lionel/Projets/COSMIC/cosmic-protocols/client-toolkit" } + +[patch."https://github.com/pop-os/cosmic-panel"] +cosmic-panel-config = { path = "/home/lionel/Projets/COSMIC/cosmic-panel/cosmic-panel-config" } +xdg-shell-wrapper-config = { path = "/home/lionel/Projets/COSMIC/cosmic-panel/xdg-shell-wrapper-config" } + +[patch."https://github.com/pop-os/cosmic-notifications"] +cosmic-notifications-config = { path = "/home/lionel/Projets/COSMIC/cosmic-notifications/cosmic-notifications-config" } +cosmic-notifications-util = { path = "/home/lionel/Projets/COSMIC/cosmic-notifications/cosmic-notifications-util" } + +[patch."https://github.com/pop-os/cosmic-settings"] +cosmic-settings-a11y-manager-subscription = { path = "/home/lionel/Projets/COSMIC/cosmic-settings/subscriptions/a11y-manager" } +cosmic-settings-accessibility-subscription = { path = "/home/lionel/Projets/COSMIC/cosmic-settings/subscriptions/accessibility" } +cosmic-settings-airplane-mode-subscription = { path = "/home/lionel/Projets/COSMIC/cosmic-settings/subscriptions/airplane-mode" } +cosmic-settings-daemon-subscription = { path = "/home/lionel/Projets/COSMIC/cosmic-settings/subscriptions/settings-daemon" } +cosmic-settings-network-manager-subscription = { path = "/home/lionel/Projets/COSMIC/cosmic-settings/subscriptions/network-manager" } +cosmic-settings-sound-subscription = { path = "/home/lionel/Projets/COSMIC/cosmic-settings/subscriptions/sound" } +cosmic-settings-upower-subscription = { path = "/home/lionel/Projets/COSMIC/cosmic-settings/subscriptions/upower" } + +[patch."https://github.com/pop-os/cosmic-settings/"] +cosmic-settings-airplane-mode-subscription = { path = "/home/lionel/Projets/COSMIC/cosmic-settings/subscriptions/airplane-mode" } +cosmic-settings-network-manager-subscription = { path = "/home/lionel/Projets/COSMIC/cosmic-settings/subscriptions/network-manager" } + +[patch."https://github.com/pop-os/cosmic-text.git"] +cosmic-text = { path = "../cosmic-text" } # [patch.'https://github.com/pop-os/dbus-settings-bindings'] # cosmic-dbus-networkmanager = { path = "../dbus-settings-bindings/networkmanager" } diff --git a/cosmic-app-list/Cargo.toml b/cosmic-app-list/Cargo.toml index 7c398b97..4fb3e699 100644 --- a/cosmic-app-list/Cargo.toml +++ b/cosmic-app-list/Cargo.toml @@ -13,13 +13,13 @@ futures.workspace = true i18n-embed.workspace = true i18n-embed-fl.workspace = true image = { version = "0.25.9", default-features = false } -libcosmic.workspace = true +cosmic.workspace = true memmap2 = "0.9.10" fastrand = "2.3.0" rust-embed.workspace = true rustix.workspace = true rustc-hash.workspace = true -switcheroo-control = { git = "https://github.com/pop-os/dbus-settings-bindings" } +switcheroo-control = { path = "../../dbus-settings-bindings/switcheroo-control" } tokio.workspace = true tracing-log.workspace = true tracing-subscriber.workspace = true diff --git a/cosmic-app-list/cosmic-app-list-config/Cargo.toml b/cosmic-app-list/cosmic-app-list-config/Cargo.toml index 08d87f2e..49e940c5 100644 --- a/cosmic-app-list/cosmic-app-list-config/Cargo.toml +++ b/cosmic-app-list/cosmic-app-list-config/Cargo.toml @@ -6,5 +6,5 @@ edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -libcosmic.workspace = true +cosmic.workspace = true serde = { workspace = true, features = ["derive"] } diff --git a/cosmic-app-list/i18n/en/cosmic_app_list.ftl b/cosmic-app-list/i18n/en/cosmic_app_list.ftl index c412cd51..028a1558 100644 --- a/cosmic-app-list/i18n/en/cosmic_app_list.ftl +++ b/cosmic-app-list/i18n/en/cosmic_app_list.ftl @@ -5,4 +5,15 @@ quit-all = Quit All new-window = New Window run = Run run-on = Run on {$gpu} -run-on-default = (Default) \ No newline at end of file +run-on-default = (Default) +edit-launcher = Edit launcher +launcher-name = Name +launcher-command = Command +launcher-icon = Icon +launcher-icon-theme = Theme +launcher-icon-search = Search icons +launcher-icon-catalog-loading = Loading icons +launcher-icon-catalog-empty = No icons +launcher-icons = icons +save = Save +cancel = Cancel diff --git a/cosmic-app-list/i18n/fr/cosmic_app_list.ftl b/cosmic-app-list/i18n/fr/cosmic_app_list.ftl index 39cac491..16bb7465 100644 --- a/cosmic-app-list/i18n/fr/cosmic_app_list.ftl +++ b/cosmic-app-list/i18n/fr/cosmic_app_list.ftl @@ -6,3 +6,14 @@ new-window = Nouvelle fenêtre run = Exécuter run-on = Lancer avec { $gpu } run-on-default = (Défaut) +edit-launcher = Modifier le lanceur +launcher-name = Nom +launcher-command = Commande +launcher-icon = Icône +launcher-icon-theme = Thème +launcher-icon-search = Rechercher une icône +launcher-icon-catalog-loading = Chargement des icônes +launcher-icon-catalog-empty = Aucune icône +launcher-icons = icônes +save = Enregistrer +cancel = Annuler diff --git a/cosmic-app-list/src/app.rs b/cosmic-app-list/src/app.rs index 932ffd6c..55d815b8 100755 --- a/cosmic-app-list/src/app.rs +++ b/cosmic-app-list/src/app.rs @@ -2,7 +2,8 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::{ - fl, + fl, icon_catalog, + launcher_edit::{self, LauncherEditRequest}, wayland_subscription::{ OutputUpdate, ToplevelRequest, ToplevelUpdate, WaylandImage, WaylandRequest, WaylandUpdate, wayland_subscription, @@ -43,11 +44,11 @@ use cosmic::{ surface, theme::{self, Button, Container}, widget::{ - DndDestination, Image, button, container, divider, dnd_source, + DndDestination, Image, button, container, divider, dnd_source, grid, icon::{self, from_name}, image::Handle, rectangle_tracker::{RectangleTracker, RectangleUpdate, rectangle_tracker_subscription}, - svg, text, + scrollable, svg, text, text_input, }, }; use cosmic::{ @@ -64,6 +65,8 @@ use tokio::time::sleep; use url::Url; static MIME_TYPE: &str = "text/uri-list"; +const MAX_VISIBLE_ICON_CHOICES: usize = 120; +const ICON_CATALOG_COLUMNS: usize = 6; pub fn run() -> cosmic::iced::Result { cosmic::applet::run::(()) @@ -187,6 +190,11 @@ impl DockItem { dot_border_radius: [f32; 4], window_id: window::Id, filter: Option<&dyn Fn(&ToplevelInfo) -> bool>, + // Yoda: multiplier on the computed icon size (1.0 = default, + // >1.0 = magnified e.g. on hover for the macOS Tahoe effect). + // Applied to the icon's rendered width/height only — indicator + // dot and surrounding layout stay at base size. + icon_scale: f32, ) -> Element<'_, Message> { let Self { toplevels, @@ -205,17 +213,35 @@ impl DockItem { }; let toplevel_count = filtered_toplevels.len(); + // Cairo-like : pastille plus petite + atténuée quand toutes les fenêtres + // de cette app sont minimisées. + let all_minimized = toplevel_count > 0 + && filtered_toplevels + .iter() + .all(|(info, _)| info.state.contains(&State::Minimized)); + let app_icon = AppletIconData::new(applet); + // Yoda: scaled icon size for hover magnification. Clamped so + // tiny floats don't round to 0 and huge ones stay within u16. + let scaled_icon_size = ((f32::from(app_icon.icon_size) * icon_scale).round() as i32) + .clamp(1, u16::MAX as i32) as u16; let cosmic_icon = cosmic::widget::icon( fde::IconSource::from_unknown(desktop_info.icon().unwrap_or_default()).as_cosmic_icon(), ) // sets the preferred icon size variant .size(128) - .width(app_icon.icon_size.into()) - .height(app_icon.icon_size.into()); + .width(scaled_icon_size.into()) + .height(scaled_icon_size.into()); let indicator = { + // Padding réduit quand minimisée → pastille plus petite. + let effective_radius = if all_minimized { + (app_icon.dot_radius * 0.55).max(1.0) + } else { + app_icon.dot_radius + }; + let container = if toplevel_count <= 1 { vertical_space().height(Length::Fixed(0.0)) } else { @@ -229,22 +255,34 @@ impl DockItem { } } .apply(container) - .padding(app_icon.dot_radius); + .padding(effective_radius); if toplevel_count == 0 { container } else { - container.class(theme::Container::custom(move |theme| container::Style { - background: if is_focused { - Some(Background::Color(theme.cosmic().accent_color().into())) + container.class(theme::Container::custom(move |theme| { + let cosmic = theme.cosmic(); + let accent: iced::Color = cosmic.accent_color().into(); + let on_bg: iced::Color = cosmic.on_bg_color().into(); + // Teinte neutre atténuée quand toutes les fenêtres sont minimisées. + let muted = iced::Color { a: 0.45, ..on_bg }; + + let fill = if all_minimized { + muted + } else if is_focused { + accent } else { - Some(Background::Color(theme.cosmic().on_bg_color().into())) - }, - border: Border { - radius: dot_border_radius.into(), + on_bg + }; + + container::Style { + background: Some(Background::Color(fill)), + border: Border { + radius: dot_border_radius.into(), + ..Default::default() + }, ..Default::default() - }, - ..Default::default() + } })) } }; @@ -352,10 +390,35 @@ pub struct Popup { popup_type: PopupType, } +#[derive(Debug, Clone)] +struct LauncherEditState { + original_app_id: String, + source_path: PathBuf, + original_name: String, + original_exec: String, + name: String, + exec: String, + icon: String, + terminal: bool, + saving: bool, + error: Option, + icon_catalog: IconCatalogState, +} + +#[derive(Debug, Clone)] +struct IconCatalogState { + theme: String, + query: String, + entries: Vec, + loading: bool, + truncated: bool, +} + #[derive(Clone, Default)] struct CosmicAppList { core: cosmic::app::Core, popup: Option, + launcher_edit: Option, subscription_ctr: u32, item_ctr: u32, desktop_entries: Vec, @@ -374,6 +437,21 @@ struct CosmicAppList { output_list: FxHashMap, locales: Vec, hovered_toplevel: Option, + /// Yoda: which dock icon the pointer is currently over (for hover + /// magnification). None = no dock icon hovered. + hovered_dock_item: Option, + /// Yoda: animated "virtual cursor" center used by the fisheye + /// formula — lerps toward the real hovered icon's center on each + /// AnimTick, so the bell curve slides smoothly from one icon to the + /// next instead of snapping. + anim_hover_center: Option<(f32, f32)>, + /// Yoda: fade-in/out intensity of the magnification effect + /// (0.0 = icons flat, 1.0 = full fisheye). Targets 1.0 while the + /// pointer is over any dock icon, 0.0 otherwise. Lerped on AnimTick. + anim_hover_intensity: f32, + /// Yoda: timestamp of the last AnimTick, for dt-based exponential + /// smoothing. `None` on first tick. + anim_last_tick: Option, overflow_favorites_popup: Option, overflow_active_popup: Option, } @@ -382,13 +460,33 @@ struct CosmicAppList { pub enum PopupType { RightClickMenu, ToplevelList, + LauncherEditor, } #[derive(Debug, Clone)] +#[allow(dead_code)] enum Message { Wayland(WaylandUpdate), PinApp(u32), UnpinApp(u32), + EditLauncher(u32), + LauncherNameChanged(String), + LauncherExecChanged(String), + LauncherIconChanged(String), + LauncherIconSearchChanged(String), + LauncherIconSelected(String), + ReloadLauncherIconCatalog, + LauncherIconCatalogLoaded(icon_catalog::IconCatalog), + SaveLauncherEdit, + CancelLauncherEdit, + LauncherEditSaved(Result), + /// Yoda: pointer entered (Some) or left (None) a dock icon — drives + /// the macOS Tahoe-style hover magnification effect. + DockItemHover(Option), + /// Yoda: ticked at ~60fps by the animation subscription. Advances + /// anim_hover_center + anim_hover_intensity toward their targets so + /// the fisheye effect transitions smoothly instead of snapping. + AnimTick(std::time::Instant), Popup(u32, window::Id), Pressed(window::Id), ToplevelListPopup(u32, window::Id), @@ -626,6 +724,143 @@ pub fn menu_control_padding() -> Padding { [spacing.space_xxs, spacing.space_s].into() } +fn launcher_icon_editor(edit: &LauncherEditState) -> Element<'_, Message> { + let spacing = theme::spacing(); + let selected_icon = edit.icon.trim(); + let query = edit.icon_catalog.query.trim().to_ascii_lowercase(); + let mut total_matches = 0usize; + let mut visible_count = 0usize; + let mut icon_grid = grid() + .width(Length::Fill) + .column_spacing(spacing.space_xxs) + .row_spacing(spacing.space_xxs); + + for entry in edit.icon_catalog.entries.iter().filter(|entry| { + query.is_empty() || entry.name.to_ascii_lowercase().contains(query.as_str()) + }) { + total_matches += 1; + if visible_count >= MAX_VISIBLE_ICON_CHOICES { + continue; + } + + if visible_count > 0 && visible_count % ICON_CATALOG_COLUMNS == 0 { + icon_grid = icon_grid.insert_row(); + } + + let selected = selected_icon == entry.name; + let icon_preview = cosmic::widget::icon( + fde::IconSource::from_unknown(entry.name.as_str()).as_cosmic_icon(), + ) + .size(32) + .width(Length::Fixed(32.0)) + .height(Length::Fixed(32.0)); + + let label = text::caption(entry.name.as_str()) + .ellipsize(Ellipsize::End(EllipsizeHeightLimit::Lines(1))) + .width(Length::Fill) + .center(); + + let tile = column![icon_preview, label] + .align_x(Alignment::Center) + .spacing(4) + .width(Length::Fixed(70.0)); + + let tile_button = button::custom(tile) + .class(if selected { + Button::Suggested + } else { + Button::Image + }) + .selected(selected) + .on_press(Message::LauncherIconSelected(entry.name.clone())) + .padding(6) + .width(Length::Fixed(74.0)) + .height(Length::Fixed(76.0)); + + icon_grid = icon_grid.push(tile_button); + visible_count += 1; + } + + let current_icon = + cosmic::widget::icon(fde::IconSource::from_unknown(edit.icon.as_str()).as_cosmic_icon()) + .size(32) + .width(Length::Fixed(36.0)) + .height(Length::Fixed(36.0)); + + let icon_value = row![ + current_icon, + text_input("", edit.icon.as_str()) + .label(fl!("launcher-icon")) + .on_input(Message::LauncherIconChanged) + .on_submit(|_| Message::SaveLauncherEdit) + .width(Length::Fill) + .size(14), + button::icon(from_name("view-refresh-symbolic")) + .on_press(Message::ReloadLauncherIconCatalog) + .padding(spacing.space_xxs), + ] + .spacing(spacing.space_xs) + .align_y(Alignment::Center); + + let visible_total = if edit.icon_catalog.truncated { + format!( + "{}/{}+ {}", + visible_count, + total_matches, + fl!("launcher-icons") + ) + } else { + format!( + "{}/{} {}", + visible_count, + total_matches, + fl!("launcher-icons") + ) + }; + + let catalog_header = row![ + text::caption(format!( + "{}: {}", + fl!("launcher-icon-theme"), + edit.icon_catalog.theme + )), + horizontal_space(), + text::caption(visible_total), + ] + .align_y(Alignment::Center); + + let catalog_body: Element<_> = if edit.icon_catalog.loading { + container(text::body(fl!("launcher-icon-catalog-loading"))) + .center(Length::Fill) + .height(Length::Fixed(220.0)) + .into() + } else if total_matches == 0 { + container(text::body(fl!("launcher-icon-catalog-empty"))) + .center(Length::Fill) + .height(Length::Fixed(220.0)) + .into() + } else { + scrollable(icon_grid) + .height(Length::Fixed(240.0)) + .width(Length::Fill) + .into() + }; + + column![ + icon_value, + catalog_header, + text_input("", edit.icon_catalog.query.as_str()) + .label(fl!("launcher-icon-search")) + .on_input(Message::LauncherIconSearchChanged) + .width(Length::Fill) + .size(14), + catalog_body, + ] + .spacing(spacing.space_s) + .width(Length::Fill) + .into() +} + fn find_desktop_entries<'a>( desktop_entries: &'a [fde::DesktopEntry], app_ids: &'a [String], @@ -647,6 +882,79 @@ impl CosmicAppList { .collect::>(); } + /// Yoda: macOS-Tahoe fisheye-style magnification. Returns the + /// per-icon size multiplier based on the distance (in pixels) from + /// the currently hovered icon's center to this icon's center. + /// + /// Uses a gaussian bell curve so the hovered icon peaks at + /// 1.0 + PEAK, immediate neighbors still bulge noticeably, and icons + /// further away relax back to 1.0× — that's the smooth neighbour + /// deformation people associate with the macOS Dock. + /// + /// Falls back to binary 1.3×/1.0× when the rectangle tracker hasn't + /// populated yet (first render, or just after layout changes). + /// + /// Uses the animated hover center (anim_hover_center) and intensity + /// (anim_hover_intensity) so inter-icon transitions slide smoothly + /// and the whole effect fades in/out at the dock's edges. + fn icon_scale_for(&self, id: &DockItemId) -> f32 { + const PEAK: f32 = 0.35; + // sigma expressed in multiples of the hovered icon's size — + // 1.4 means the ±1 neighbors sit ~0.7σ away and still bulge + // visibly, while ±3+ has collapsed to ~1.0× (fisheye footprint + // close to 5 icons wide, Tahoe-ish). + const SIGMA_FACTOR: f32 = 1.4; + + // No intensity at all → skip the rest. + if self.anim_hover_intensity < 0.001 { + return 1.0; + } + + // Prefer the animated center (smooth); fall back to the real + // hovered icon's center (first render, before tick fires). + let hover_center = self.anim_hover_center.or_else(|| { + let hovered_id = self.hovered_dock_item.as_ref()?; + let r = self.rectangles.get(hovered_id)?; + Some((r.x + r.width / 2.0, r.y + r.height / 2.0)) + }); + let Some(hover_center) = hover_center else { + // No coords yet — visibly peak on the exact hovered id so + // the very first frame still responds. + return if self.hovered_dock_item.as_ref() == Some(id) { + 1.0 + PEAK * self.anim_hover_intensity + } else { + 1.0 + }; + }; + + let this_rect = match self.rectangles.get(id) { + Some(r) => r, + None => return 1.0, + }; + + let is_horizontal = matches!( + self.core.applet.anchor, + PanelAnchor::Top | PanelAnchor::Bottom + ); + let this_center = if is_horizontal { + this_rect.x + this_rect.width / 2.0 + } else { + this_rect.y + this_rect.height / 2.0 + }; + let hover_axis = if is_horizontal { hover_center.0 } else { hover_center.1 }; + let distance = (this_center - hover_axis).abs(); + let icon_extent = if is_horizontal { + this_rect.width + } else { + this_rect.height + } + .max(1.0); + let sigma = icon_extent * SIGMA_FACTOR; + // exp(-t²) bell curve, t = distance / sigma + let t = distance / sigma; + 1.0 + PEAK * self.anim_hover_intensity * (-t * t).exp() + } + fn is_on_current_monitor_and_workspace(&self, toplevel_info: &ToplevelInfo) -> bool { use cosmic_app_list_config::ToplevelFilter; @@ -691,10 +999,45 @@ impl CosmicAppList { .collect(); } + fn sync_pinned_list_from_config(&mut self) { + for item in self.pinned_list.drain(..) { + if !item.toplevels.is_empty() { + self.active_list.push(item); + } + } + + self.pinned_list = find_desktop_entries(&self.desktop_entries, &self.config.favorites) + .zip(&self.config.favorites) + .map(|(de, original_id)| { + if let Some(p) = self + .active_list + .iter() + .position(|dock_item| dock_item.desktop_info.id() == de.id()) + { + let mut d = self.active_list.remove(p); + d.desktop_info = de.clone(); + d.original_app_id.clone_from(original_id); + d + } else { + self.item_ctr += 1; + DockItem { + id: self.item_ctr, + toplevels: Vec::new(), + desktop_info: de.clone(), + original_app_id: original_id.clone(), + } + } + }) + .collect(); + } + /// Close any open popups. fn close_popups(&mut self) -> Task> { let mut commands = Vec::new(); if let Some(popup) = self.popup.take() { + if popup.popup_type == PopupType::LauncherEditor { + self.launcher_edit = None; + } commands.push(destroy_popup(popup.id)); } if let Some(popup) = self.overflow_active_popup.take() { @@ -1068,6 +1411,198 @@ impl cosmic::Application for CosmicAppList { return destroy_popup(popup_id); } } + Message::EditLauncher(id) => { + let Some(dock_item) = self.pinned_list.iter().find(|t| t.id == id).cloned() else { + return Task::none(); + }; + let Some(exec) = dock_item.desktop_info.exec() else { + return Task::none(); + }; + let Some(existing_popup) = self.popup.as_mut() else { + return Task::none(); + }; + + let original_name = dock_item + .desktop_info + .desktop_entry("Name") + .map(ToString::to_string) + .or_else(|| { + dock_item + .desktop_info + .name(&self.locales) + .map(Cow::into_owned) + }) + .unwrap_or_else(|| dock_item.original_app_id.clone()); + let original_exec = exec.to_string(); + let original_icon = dock_item + .desktop_info + .icon() + .unwrap_or_default() + .to_string(); + let icon_theme = cosmic::icon_theme::default(); + + self.launcher_edit = Some(LauncherEditState { + original_app_id: dock_item.original_app_id.clone(), + source_path: dock_item.desktop_info.path.clone(), + original_name: original_name.clone(), + original_exec: original_exec.clone(), + name: original_name, + exec: original_exec, + icon: original_icon.clone(), + terminal: dock_item.desktop_info.terminal(), + saving: false, + error: None, + icon_catalog: IconCatalogState { + theme: icon_theme.clone(), + query: String::new(), + entries: Vec::new(), + loading: true, + truncated: false, + }, + }); + + existing_popup.dock_item = dock_item; + existing_popup.popup_type = PopupType::LauncherEditor; + + return Task::perform( + icon_catalog::load_icon_catalog(icon_theme, original_icon), + |catalog| cosmic::Action::App(Message::LauncherIconCatalogLoaded(catalog)), + ); + } + Message::LauncherNameChanged(name) => { + if let Some(edit) = self.launcher_edit.as_mut() + && !edit.saving + { + edit.name = name; + edit.error = None; + } + } + Message::LauncherExecChanged(exec) => { + if let Some(edit) = self.launcher_edit.as_mut() + && !edit.saving + { + edit.exec = exec; + edit.error = None; + } + } + Message::LauncherIconChanged(icon) => { + if let Some(edit) = self.launcher_edit.as_mut() + && !edit.saving + { + edit.icon = icon; + edit.error = None; + } + } + Message::LauncherIconSearchChanged(query) => { + if let Some(edit) = self.launcher_edit.as_mut() { + edit.icon_catalog.query = query; + } + } + Message::LauncherIconSelected(icon) => { + if let Some(edit) = self.launcher_edit.as_mut() + && !edit.saving + { + edit.icon = icon; + edit.error = None; + } + } + Message::ReloadLauncherIconCatalog => { + if let Some(edit) = self.launcher_edit.as_mut() { + edit.icon_catalog.theme = cosmic::icon_theme::default(); + edit.icon_catalog.entries.clear(); + edit.icon_catalog.loading = true; + edit.icon_catalog.truncated = false; + + return Task::perform( + icon_catalog::load_icon_catalog( + edit.icon_catalog.theme.clone(), + edit.icon.clone(), + ), + |catalog| cosmic::Action::App(Message::LauncherIconCatalogLoaded(catalog)), + ); + } + } + Message::LauncherIconCatalogLoaded(catalog) => { + if let Some(edit) = self.launcher_edit.as_mut() + && edit.icon_catalog.theme == catalog.theme + { + edit.icon_catalog.entries = catalog.entries; + edit.icon_catalog.loading = false; + edit.icon_catalog.truncated = catalog.truncated; + } + } + Message::SaveLauncherEdit => { + let Some(edit) = self.launcher_edit.as_mut() else { + return Task::none(); + }; + if edit.saving { + return Task::none(); + } + if let Err(error) = + launcher_edit::validate_launcher_fields(&edit.name, &edit.exec, &edit.icon) + { + edit.error = Some(error); + return Task::none(); + } + + let request = LauncherEditRequest { + current_app_id: edit.original_app_id.clone(), + source_path: edit.source_path.clone(), + name: edit.name.clone(), + exec: edit.exec.clone(), + icon: edit.icon.clone(), + terminal: edit.terminal, + replace_localized_name: edit.name.trim() != edit.original_name.trim(), + disable_dbus_activation: edit.exec.trim() != edit.original_exec.trim(), + }; + + edit.saving = true; + edit.error = None; + + return Task::perform(launcher_edit::save_launcher_edit(request), |result| { + cosmic::Action::App(Message::LauncherEditSaved(result)) + }); + } + Message::CancelLauncherEdit => { + return self.close_popups(); + } + Message::LauncherEditSaved(result) => match result { + Ok(result) => { + tracing::info!( + app_id = result.new_app_id, + path = ?result.path, + "saved editable launcher" + ); + + let mut favorites = self.config.favorites.clone(); + let mut favorites_changed = false; + for favorite in &mut favorites { + if *favorite == result.old_app_id && *favorite != result.new_app_id { + *favorite = result.new_app_id.clone(); + favorites_changed = true; + } + } + + if favorites_changed { + self.config.update_pinned( + favorites.clone(), + &Config::new(APP_ID, AppListConfig::VERSION).unwrap(), + ); + self.config.favorites = favorites; + } + + self.update_desktop_entries(); + self.sync_pinned_list_from_config(); + self.launcher_edit = None; + return self.close_popups(); + } + Err(error) => { + if let Some(edit) = self.launcher_edit.as_mut() { + edit.saving = false; + edit.error = Some(error); + } + } + }, Message::Activate(handle) => { if let Some(tx) = self.wayland_sender.as_ref() { let _ = tx.send(WaylandRequest::Toplevel(ToplevelRequest::Activate(handle))); @@ -1520,6 +2055,9 @@ impl cosmic::Application for CosmicAppList { }, Message::ClosePopup => { if let Some(p) = self.popup.take() { + if p.popup_type == PopupType::LauncherEditor { + self.launcher_edit = None; + } return destroy_popup(p.id); } } @@ -1534,42 +2072,16 @@ impl cosmic::Application for CosmicAppList { } Message::ConfigUpdated(config) => { self.config = config; - // drain to active list - for item in self.pinned_list.drain(..) { - if !item.toplevels.is_empty() { - self.active_list.push(item); - } - } - - // pull back configured items into the favorites list - self.pinned_list = - find_desktop_entries(&self.desktop_entries, &self.config.favorites) - .zip(&self.config.favorites) - .map(|(de, original_id)| { - if let Some(p) = self - .active_list - .iter() - // match using heuristic id - .position(|dock_item| dock_item.desktop_info.id() == de.id()) - { - let mut d = self.active_list.remove(p); - // but use the id from the config - d.original_app_id.clone_from(original_id); - d - } else { - self.item_ctr += 1; - DockItem { - id: self.item_ctr, - toplevels: Vec::new(), - desktop_info: de.clone(), - original_app_id: original_id.clone(), - } - } - }) - .collect(); + self.update_desktop_entries(); + self.sync_pinned_list_from_config(); } Message::CloseRequested(id) => { - if Some(id) == self.popup.as_ref().map(|p| p.id) { + if let Some(popup) = &self.popup + && popup.id == id + { + if popup.popup_type == PopupType::LauncherEditor { + self.launcher_edit = None; + } self.popup = None; } if self.overflow_active_popup.is_some_and(|p| p == id) { @@ -1582,6 +2094,52 @@ impl cosmic::Application for CosmicAppList { Message::GpuRequest(gpus) => { self.gpus = gpus; } + Message::DockItemHover(id) => { + self.hovered_dock_item = id; + // Seed the animated center on the very first hover so + // the bell doesn't "fly in" from (0,0). + if self.anim_hover_center.is_none() + && let Some(hovered_id) = self.hovered_dock_item.as_ref() + && let Some(r) = self.rectangles.get(hovered_id) + { + self.anim_hover_center = Some(( + r.x + r.width / 2.0, + r.y + r.height / 2.0, + )); + } + } + Message::AnimTick(now) => { + // dt-based exponential smoothing: reach ~99% of the + // target in ~120ms at 60fps (about 7 ticks). + let dt = self + .anim_last_tick + .map(|prev| now.saturating_duration_since(prev).as_secs_f32()) + .unwrap_or(0.016) + .min(0.1); // clamp so a long pause doesn't snap + self.anim_last_tick = Some(now); + + // Intensity: target 1.0 when any icon is hovered, 0.0 else. + let intensity_target = if self.hovered_dock_item.is_some() { 1.0 } else { 0.0 }; + let tau = 0.060_f32; // time-constant (s); smaller = snappier + let alpha = 1.0 - (-dt / tau).exp(); + self.anim_hover_intensity += (intensity_target - self.anim_hover_intensity) * alpha; + + // Hovered-center smoothing: chase the real rect's center. + if let Some(hovered_id) = self.hovered_dock_item.as_ref() + && let Some(r) = self.rectangles.get(hovered_id) + { + let target = (r.x + r.width / 2.0, r.y + r.height / 2.0); + let current = self.anim_hover_center.unwrap_or(target); + self.anim_hover_center = Some(( + current.0 + (target.0 - current.0) * alpha, + current.1 + (target.1 - current.1) * alpha, + )); + } else if self.anim_hover_intensity < 0.01 { + // Nothing hovered + intensity faded out → forget the + // animated center so the next hover seeds fresh. + self.anim_hover_center = None; + } + } Message::OpenActive => { let create_new = self.overflow_active_popup.is_none(); let mut cmds = vec![self.close_popups()]; @@ -1763,7 +2321,9 @@ impl cosmic::Application for CosmicAppList { .filter(|(info, _)| self.is_on_current_monitor_and_workspace(info)) .any(|y| focused_item.contains(&y.0.foreign_toplevel)); - self.core + let dock_id = dock_item.id; + let icon_scale = self.icon_scale_for(&DockItemId::from(dock_id)); + let tooltip = self.core .applet .applet_tooltip::( dock_item.as_icon( @@ -1776,6 +2336,7 @@ impl cosmic::Application for CosmicAppList { dot_radius, self.core.main_window_id().unwrap(), Some(&|info| self.is_on_current_monitor_and_workspace(info)), + icon_scale, ), dock_item .desktop_info @@ -1785,7 +2346,10 @@ impl cosmic::Application for CosmicAppList { self.popup.is_some(), Message::Surface, None, - ) + ); + cosmic::widget::mouse_area(tooltip) + .on_enter(Message::DockItemHover(Some(DockItemId::from(dock_id)))) + .on_exit(Message::DockItemHover(None)) .into() }) .collect(); @@ -1836,6 +2400,10 @@ impl cosmic::Application for CosmicAppList { dot_radius, self.core.main_window_id().unwrap(), Some(&|info| self.is_on_current_monitor_and_workspace(info)), + // Yoda: no magnification on DnD-preview icons — these + // float around as the user drags, so static 1.0 is + // less visually confusing. + 1.0, ), ); } else if self.is_listening_for_dnd && self.pinned_list.is_empty() { @@ -1875,8 +2443,10 @@ impl cosmic::Application for CosmicAppList { .iter() .filter(|(info, _)| self.is_on_current_monitor_and_workspace(info)) .any(|y| focused_item.contains(&y.0.foreign_toplevel)); + let dock_id = dock_item.id; + let icon_scale = self.icon_scale_for(&DockItemId::from(dock_id)); - self.core + let tooltip = self.core .applet .applet_tooltip( dock_item.as_icon( @@ -1889,6 +2459,7 @@ impl cosmic::Application for CosmicAppList { dot_radius, self.core.main_window_id().unwrap(), Some(&|info| self.is_on_current_monitor_and_workspace(info)), + icon_scale, ), dock_item .desktop_info @@ -1898,7 +2469,10 @@ impl cosmic::Application for CosmicAppList { self.popup.is_some(), Message::Surface, None, - ) + ); + cosmic::widget::mouse_area(tooltip) + .on_enter(Message::DockItemHover(Some(DockItemId::from(dock_id)))) + .on_exit(Message::DockItemHover(None)) .into() }) .collect(); @@ -2179,6 +2753,19 @@ impl cosmic::Application for CosmicAppList { }), ); + if is_pinned && desktop_info.exec().is_some() { + content = content.push( + menu_button( + row![ + icon::icon(from_name("edit-symbolic").into()).size(16), + text::body(fl!("edit-launcher")) + ] + .spacing(8), + ) + .on_press(Message::EditLauncher(*id)), + ); + } + if !toplevels.is_empty() { content = content.push(divider::horizontal::light()); content = match toplevels.len() { @@ -2200,7 +2787,7 @@ impl cosmic::Application for CosmicAppList { //TODO: move style to libcosmic .class(theme::Container::custom(|theme| { let cosmic = theme.cosmic(); - let component = &cosmic.background.component; + let component = &cosmic.background(false).component; container::Style { icon_color: Some(component.on.into()), text_color: Some(component.on.into()), @@ -2225,6 +2812,84 @@ impl cosmic::Application for CosmicAppList { ) .into() } + PopupType::LauncherEditor => { + let Some(edit) = self.launcher_edit.as_ref() else { + return text::body("").into(); + }; + + let spacing = theme::spacing(); + let can_save = !edit.saving + && launcher_edit::validate_launcher_fields( + &edit.name, &edit.exec, &edit.icon, + ) + .is_ok(); + + let mut form = column![ + text::title4(fl!("edit-launcher")), + text_input("", edit.name.as_str()) + .label(fl!("launcher-name")) + .on_input(Message::LauncherNameChanged) + .on_submit(|_| Message::SaveLauncherEdit) + .width(Length::Fill) + .size(14), + text_input("", edit.exec.as_str()) + .label(fl!("launcher-command")) + .on_input(Message::LauncherExecChanged) + .on_submit(|_| Message::SaveLauncherEdit) + .width(Length::Fill) + .size(14), + launcher_icon_editor(edit), + ] + .spacing(spacing.space_s) + .width(Length::Fill); + + if let Some(error) = edit.error.as_ref() { + form = form.push(text::caption(error.as_str()).class( + cosmic::theme::Text::Color(theme.cosmic().destructive_color().into()), + )); + } + + let cancel = + button::custom(text::body(fl!("cancel")).center().width(Length::Fill)) + .on_press_maybe(if edit.saving { + None + } else { + Some(Message::CancelLauncherEdit) + }) + .padding([spacing.space_xxs, spacing.space_s]) + .width(142); + + let save = button::custom(text::body(fl!("save")).center().width(Length::Fill)) + .class(Button::Suggested) + .on_press_maybe(if can_save { + Some(Message::SaveLauncherEdit) + } else { + None + }) + .padding([spacing.space_xxs, spacing.space_s]) + .width(142); + + let actions = row![horizontal_space(), cancel, save] + .spacing(spacing.space_xxs) + .align_y(Alignment::Center); + + let content = column![form, actions] + .spacing(spacing.space_m) + .padding(spacing.space_m) + .width(Length::Fill); + + self.core + .applet + .popup_container(container(content).width(Length::Fill)) + .limits( + Limits::NONE + .min_width(480.) + .min_height(1.) + .max_width(520.) + .max_height(1000.), + ) + .into() + } PopupType::ToplevelList => match self.core.applet.anchor { PanelAnchor::Left | PanelAnchor::Right => { let mut content = @@ -2313,6 +2978,10 @@ impl cosmic::Application for CosmicAppList { dot_radius, id, Some(&|info| self.is_on_current_monitor_and_workspace(info)), + // Yoda: icons in the overflow popup are + // already smaller-grid — keep them at 1.0 + // so the popup doesn't reshuffle on hover. + 1.0, ), dock_item .desktop_info @@ -2421,6 +3090,10 @@ impl cosmic::Application for CosmicAppList { dot_radius, id, Some(&|info| self.is_on_current_monitor_and_workspace(info)), + // Yoda: popup icons stay at 1.0 (hover + // magnification is applied to the main + // dock row only). + 1.0, ), dock_item .desktop_info @@ -2479,7 +3152,21 @@ impl cosmic::Application for CosmicAppList { } fn subscription(&self) -> Subscription { + // Yoda: ~60fps animation ticks for the fisheye magnification. + // Only emitted when an animation is actually in progress (hover + // intensity >0 OR still fading out) — keeps the panel idle when + // the pointer is nowhere near the dock. + let anim_active = self.hovered_dock_item.is_some() + || self.anim_hover_intensity > 0.001; + let anim_subscription = if anim_active { + cosmic::iced::time::every(std::time::Duration::from_millis(16)) + .map(Message::AnimTick) + } else { + Subscription::none() + }; + Subscription::batch([ + anim_subscription, wayland_subscription().map(Message::Wayland), listen_with(|e, _, id| match e { cosmic::iced::core::Event::PlatformSpecific(event::PlatformSpecific::Wayland( diff --git a/cosmic-app-list/src/icon_catalog.rs b/cosmic-app-list/src/icon_catalog.rs new file mode 100644 index 00000000..2cb05e1a --- /dev/null +++ b/cosmic-app-list/src/icon_catalog.rs @@ -0,0 +1,440 @@ +use std::{ + cmp::Ordering, + collections::{HashMap, HashSet, VecDeque}, + fs, + path::{Component, Path, PathBuf}, +}; + +const FALLBACK_THEMES: &[&str] = &["Cosmic", "hicolor", "gnome", "Yaru"]; +const MAX_THEME_CHAIN: usize = 24; +const MAX_SCAN_DEPTH: usize = 5; +const MAX_CATALOG_ENTRIES: usize = 2_500; + +#[derive(Debug, Clone)] +pub struct IconCatalog { + pub theme: String, + pub entries: Vec, + pub truncated: bool, +} + +#[derive(Debug, Clone)] +pub struct IconCatalogEntry { + pub name: String, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +struct CandidateRank { + preferred: u8, + category: u8, + symbolic: u8, + theme_depth: usize, + extension: u8, +} + +impl Ord for CandidateRank { + fn cmp(&self, other: &Self) -> Ordering { + ( + self.preferred, + self.category, + self.symbolic, + self.theme_depth, + self.extension, + ) + .cmp(&( + other.preferred, + other.category, + other.symbolic, + other.theme_depth, + other.extension, + )) + } +} + +impl PartialOrd for CandidateRank { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +#[derive(Debug, Clone)] +struct Candidate { + name: String, + rank: CandidateRank, +} + +pub async fn load_icon_catalog(theme: String, preferred_icon: String) -> IconCatalog { + build_icon_catalog(theme, preferred_icon) +} + +fn build_icon_catalog(theme: String, preferred_icon: String) -> IconCatalog { + let theme = if theme.trim().is_empty() { + "Cosmic".to_string() + } else { + theme + }; + let preferred_name = icon_name_from_value(preferred_icon.trim()); + let theme_chain = theme_chain(&theme); + let mut candidates = HashMap::new(); + + for (theme_depth, theme_name) in theme_chain.iter().enumerate() { + for theme_dir in theme_dirs(theme_name) { + scan_icon_tree( + &theme_dir, + theme_depth, + preferred_name.as_deref(), + &mut candidates, + ); + } + } + + for pixmap_dir in pixmap_dirs() { + scan_icon_tree( + &pixmap_dir, + theme_chain.len() + 1, + preferred_name.as_deref(), + &mut candidates, + ); + } + + let mut entries = candidates.into_values().collect::>(); + entries.sort_by(|a, b| a.rank.cmp(&b.rank).then_with(|| a.name.cmp(&b.name))); + + let truncated = entries.len() > MAX_CATALOG_ENTRIES; + entries.truncate(MAX_CATALOG_ENTRIES); + + IconCatalog { + theme, + entries: entries + .into_iter() + .map(|candidate| IconCatalogEntry { + name: candidate.name, + }) + .collect(), + truncated, + } +} + +fn theme_chain(theme: &str) -> Vec { + let mut queue = VecDeque::from([theme.to_string()]); + let mut seen = HashSet::new(); + let mut chain = Vec::new(); + + while let Some(theme_name) = queue.pop_front() { + let key = theme_name.to_ascii_lowercase(); + if !seen.insert(key) { + continue; + } + + chain.push(theme_name.clone()); + if chain.len() >= MAX_THEME_CHAIN { + break; + } + + for parent in read_theme_inherits(&theme_name) { + queue.push_back(parent); + } + } + + for fallback in FALLBACK_THEMES { + if chain.len() >= MAX_THEME_CHAIN { + break; + } + let key = fallback.to_ascii_lowercase(); + if seen.insert(key) { + chain.push((*fallback).to_string()); + } + } + + chain +} + +fn read_theme_inherits(theme: &str) -> Vec { + theme_dirs(theme) + .into_iter() + .find_map(|dir| fs::read_to_string(dir.join("index.theme")).ok()) + .map(|contents| parse_inherits(&contents)) + .unwrap_or_default() +} + +fn parse_inherits(contents: &str) -> Vec { + let mut in_icon_theme = false; + + for raw_line in contents.lines() { + let line = raw_line.trim(); + if line.is_empty() || line.starts_with('#') { + continue; + } + + if line.starts_with('[') && line.ends_with(']') { + in_icon_theme = line == "[Icon Theme]"; + continue; + } + + if in_icon_theme && let Some(value) = line.strip_prefix("Inherits=") { + return value + .split(',') + .map(str::trim) + .filter(|value| !value.is_empty()) + .map(ToOwned::to_owned) + .collect(); + } + } + + Vec::new() +} + +fn scan_icon_tree( + root: &Path, + theme_depth: usize, + preferred_name: Option<&str>, + candidates: &mut HashMap, +) { + let mut stack = vec![(root.to_path_buf(), 0usize)]; + + while let Some((dir, depth)) = stack.pop() { + if depth > MAX_SCAN_DEPTH { + continue; + } + + let Ok(entries) = fs::read_dir(&dir) else { + continue; + }; + + for entry in entries.filter_map(Result::ok) { + let path = entry.path(); + let Ok(file_type) = entry.file_type() else { + continue; + }; + + if file_type.is_dir() { + stack.push((path, depth + 1)); + } else if (file_type.is_file() || file_type.is_symlink()) + && let Some(candidate) = candidate_from_path(&path, theme_depth, preferred_name) + { + insert_candidate(candidates, candidate); + } + } + } +} + +fn insert_candidate(candidates: &mut HashMap, candidate: Candidate) { + let key = candidate.name.to_ascii_lowercase(); + match candidates.get_mut(&key) { + Some(existing) if candidate.rank < existing.rank => { + *existing = candidate; + } + None => { + candidates.insert(key, candidate); + } + _ => {} + } +} + +fn candidate_from_path( + path: &Path, + theme_depth: usize, + preferred_name: Option<&str>, +) -> Option { + let extension = extension_rank(path)?; + let name = path.file_stem()?.to_str()?.trim(); + if name.is_empty() { + return None; + } + + let symbolic = u8::from(name.ends_with("-symbolic") || path_has_component(path, "symbolic")); + let preferred = u8::from(preferred_name != Some(name)); + + Some(Candidate { + name: name.to_string(), + rank: CandidateRank { + preferred, + category: category_rank(path), + symbolic, + theme_depth, + extension, + }, + }) +} + +fn extension_rank(path: &Path) -> Option { + match path.extension()?.to_str()?.to_ascii_lowercase().as_str() { + "svg" => Some(0), + "png" => Some(1), + "xpm" => Some(2), + _ => None, + } +} + +fn category_rank(path: &Path) -> u8 { + for component in path.components().filter_map(component_str) { + match component { + "apps" | "applications" => return 0, + "categories" => return 1, + "places" => return 2, + "devices" => return 3, + "mimetypes" => return 4, + "actions" => return 5, + "status" => return 6, + _ => {} + } + } + + 7 +} + +fn path_has_component(path: &Path, needle: &str) -> bool { + path.components() + .filter_map(component_str) + .any(|component| component == needle) +} + +fn component_str(component: Component<'_>) -> Option<&str> { + component.as_os_str().to_str() +} + +fn icon_name_from_value(value: &str) -> Option { + if value.is_empty() { + return None; + } + + let path = Path::new(value); + if value.contains('/') { + return path + .file_stem() + .and_then(|name| name.to_str()) + .map(ToOwned::to_owned); + } + + path.file_stem() + .and_then(|name| name.to_str()) + .map(ToOwned::to_owned) + .or_else(|| Some(value.to_string())) +} + +fn theme_dirs(theme: &str) -> Vec { + icon_base_dirs() + .into_iter() + .map(|base| base.join(theme)) + .filter(|path| path.is_dir()) + .collect() +} + +fn icon_base_dirs() -> Vec { + let mut dirs = Vec::new(); + + if let Some(home) = std::env::home_dir() { + push_existing_unique(&mut dirs, home.join(".icons")); + } + + if let Some(data_home) = xdg_data_home() { + push_existing_unique(&mut dirs, data_home.join("icons")); + } + + for data_dir in xdg_data_dirs() { + push_existing_unique(&mut dirs, data_dir.join("icons")); + } + + dirs +} + +fn pixmap_dirs() -> Vec { + let mut dirs = Vec::new(); + + if let Some(data_home) = xdg_data_home() { + push_existing_unique(&mut dirs, data_home.join("pixmaps")); + } + + for data_dir in xdg_data_dirs() { + push_existing_unique(&mut dirs, data_dir.join("pixmaps")); + } + + push_existing_unique(&mut dirs, PathBuf::from("/usr/share/pixmaps")); + dirs +} + +fn xdg_data_home() -> Option { + std::env::var_os("XDG_DATA_HOME") + .filter(|value| !value.is_empty()) + .map(PathBuf::from) + .or_else(|| std::env::home_dir().map(|home| home.join(".local/share"))) +} + +fn xdg_data_dirs() -> Vec { + std::env::var_os("XDG_DATA_DIRS") + .filter(|value| !value.is_empty()) + .map(|value| std::env::split_paths(&value).collect()) + .unwrap_or_else(|| { + vec![ + PathBuf::from("/usr/local/share"), + PathBuf::from("/usr/share"), + ] + }) +} + +fn push_existing_unique(dirs: &mut Vec, path: PathBuf) { + if path.exists() && !dirs.iter().any(|existing| existing == &path) { + dirs.push(path); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parses_inherits_only_from_icon_theme_section() { + let contents = r#" +[Other] +Inherits=Wrong + +[Icon Theme] +Name=Demo +Inherits=Cosmic, hicolor , Adwaita +"#; + + assert_eq!(parse_inherits(contents), ["Cosmic", "hicolor", "Adwaita"]); + } + + #[test] + fn normalizes_icon_names_from_plain_names_and_paths() { + assert_eq!(icon_name_from_value("firefox").as_deref(), Some("firefox")); + assert_eq!( + icon_name_from_value("/usr/share/icons/hicolor/scalable/apps/firefox.svg").as_deref(), + Some("firefox") + ); + } + + #[test] + fn keeps_the_best_duplicate_candidate() { + let mut candidates = HashMap::new(); + insert_candidate( + &mut candidates, + Candidate { + name: "demo".to_string(), + rank: CandidateRank { + preferred: 1, + category: 7, + symbolic: 1, + theme_depth: 4, + extension: 2, + }, + }, + ); + insert_candidate( + &mut candidates, + Candidate { + name: "demo".to_string(), + rank: CandidateRank { + preferred: 0, + category: 0, + symbolic: 0, + theme_depth: 0, + extension: 0, + }, + }, + ); + + assert_eq!(candidates["demo"].rank.preferred, 0); + assert_eq!(candidates["demo"].rank.category, 0); + } +} diff --git a/cosmic-app-list/src/launcher_edit.rs b/cosmic-app-list/src/launcher_edit.rs new file mode 100644 index 00000000..c354e1e6 --- /dev/null +++ b/cosmic-app-list/src/launcher_edit.rs @@ -0,0 +1,378 @@ +// Copyright 2026 System76 +// SPDX-License-Identifier: GPL-3.0-only + +use std::{ + env, + ffi::OsString, + io::ErrorKind, + path::{Path, PathBuf}, +}; + +use tokio::fs; + +#[derive(Clone, Debug)] +pub struct LauncherEditRequest { + pub current_app_id: String, + pub source_path: PathBuf, + pub name: String, + pub exec: String, + pub icon: String, + pub terminal: bool, + pub replace_localized_name: bool, + pub disable_dbus_activation: bool, +} + +#[derive(Clone, Debug)] +pub struct LauncherEditResult { + pub old_app_id: String, + pub new_app_id: String, + pub path: PathBuf, +} + +#[derive(Clone, Debug)] +struct ValidLauncherEdit { + current_app_id: String, + source_path: PathBuf, + name: String, + exec: String, + icon: String, + terminal: bool, + replace_localized_name: bool, + disable_dbus_activation: bool, +} + +pub fn validate_launcher_fields(name: &str, exec: &str, icon: &str) -> Result<(), String> { + validate_required("Name", name)?; + validate_required("Command", exec)?; + validate_optional("Icon", icon)?; + Ok(()) +} + +pub async fn save_launcher_edit( + request: LauncherEditRequest, +) -> Result { + let request = validate_request(request)?; + let (new_app_id, target_path) = + target_launcher_path(&request.current_app_id, &request.source_path)?; + + let source = read_source_desktop_entry(&request).await?; + let rendered = render_editable_desktop_entry(&source, &request); + + let Some(parent) = target_path.parent() else { + return Err("Desktop file target has no parent directory".to_string()); + }; + + fs::create_dir_all(parent) + .await + .map_err(|err| format!("Could not create applications directory: {err}"))?; + + let tmp_path = temporary_path(&target_path)?; + fs::write(&tmp_path, rendered) + .await + .map_err(|err| format!("Could not write temporary desktop file: {err}"))?; + + if let Err(err) = fs::rename(&tmp_path, &target_path).await { + let _ = fs::remove_file(&tmp_path).await; + return Err(format!("Could not install desktop file: {err}")); + } + + Ok(LauncherEditResult { + old_app_id: request.current_app_id, + new_app_id, + path: target_path, + }) +} + +fn validate_request(request: LauncherEditRequest) -> Result { + let name = validate_required("Name", &request.name)?; + let exec = validate_required("Command", &request.exec)?; + let icon = validate_optional("Icon", &request.icon)?; + + Ok(ValidLauncherEdit { + current_app_id: request.current_app_id, + source_path: request.source_path, + name, + exec, + icon, + terminal: request.terminal, + replace_localized_name: request.replace_localized_name, + disable_dbus_activation: request.disable_dbus_activation, + }) +} + +fn validate_required(label: &str, value: &str) -> Result { + let value = validate_optional(label, value)?; + if value.is_empty() { + return Err(format!("{label} cannot be empty")); + } + Ok(value) +} + +fn validate_optional(label: &str, value: &str) -> Result { + if value.contains('\0') || value.contains('\n') || value.contains('\r') { + return Err(format!("{label} cannot contain line breaks")); + } + Ok(value.trim().to_string()) +} + +async fn read_source_desktop_entry(request: &ValidLauncherEdit) -> Result { + if request.source_path.as_os_str().is_empty() { + return Ok(minimal_desktop_entry()); + } + + match fs::read_to_string(&request.source_path).await { + Ok(source) => Ok(source), + Err(err) if err.kind() == ErrorKind::NotFound => Ok(minimal_desktop_entry()), + Err(err) => Err(format!("Could not read source desktop file: {err}")), + } +} + +fn minimal_desktop_entry() -> String { + "[Desktop Entry]\nType=Application\n".to_string() +} + +fn user_applications_dir() -> Result { + if let Some(xdg_data_home) = env::var_os("XDG_DATA_HOME").filter(|value| !value.is_empty()) { + return Ok(PathBuf::from(xdg_data_home).join("applications")); + } + + let Some(home) = env::var_os("HOME").filter(|value| !value.is_empty()) else { + return Err("Neither XDG_DATA_HOME nor HOME is set".to_string()); + }; + + Ok(PathBuf::from(home).join(".local/share/applications")) +} + +fn target_launcher_path(app_id: &str, source_path: &Path) -> Result<(String, PathBuf), String> { + let applications_dir = user_applications_dir()?; + if source_path.starts_with(&applications_dir) { + return Ok((app_id.to_string(), source_path.to_path_buf())); + } + + let desktop_id = normalize_desktop_id(app_id)?; + Ok(( + desktop_id.clone(), + applications_dir.join(format!("{desktop_id}.desktop")), + )) +} + +fn normalize_desktop_id(app_id: &str) -> Result { + if app_id.contains('\0') || app_id.contains('\n') || app_id.contains('\r') { + return Err("Desktop ID cannot contain line breaks".to_string()); + } + + let desktop_id = app_id + .chars() + .map(|c| if c == '/' { '-' } else { c }) + .collect::(); + + if desktop_id.trim().is_empty() { + return Err("Desktop ID cannot be empty".to_string()); + } + + Ok(desktop_id) +} + +fn temporary_path(target_path: &Path) -> Result { + let Some(file_name) = target_path.file_name() else { + return Err("Desktop file target has no filename".to_string()); + }; + + let mut tmp_file_name = OsString::from("."); + tmp_file_name.push(file_name); + tmp_file_name.push(format!(".tmp-{}", std::process::id())); + + Ok(target_path.with_file_name(tmp_file_name)) +} + +fn render_editable_desktop_entry(source: &str, request: &ValidLauncherEdit) -> String { + let mut updates = vec![ + ("Type", "Application".to_string()), + ("Name", request.name.clone()), + ("Exec", request.exec.clone()), + ("Icon", request.icon.clone()), + ( + "Terminal", + if request.terminal { "true" } else { "false" }.to_string(), + ), + ("X-COSMIC-UserEditable", "true".to_string()), + ("X-COSMIC-SourceDesktopId", request.current_app_id.clone()), + ]; + + if !request.source_path.as_os_str().is_empty() { + updates.push(( + "X-COSMIC-SourceDesktopPath", + request.source_path.to_string_lossy().to_string(), + )); + } + + if request.disable_dbus_activation { + updates.push(("DBusActivatable", "false".to_string())); + } + + set_desktop_entry_keys( + source, + &updates, + request.replace_localized_name, + request.disable_dbus_activation, + ) +} + +fn set_desktop_entry_keys( + source: &str, + updates: &[(&str, String)], + replace_localized_name: bool, + remove_try_exec: bool, +) -> String { + let mut out = Vec::new(); + let mut seen = vec![false; updates.len()]; + let mut in_desktop_entry = false; + let mut saw_desktop_entry = false; + + for line in source.lines() { + if let Some(section) = section_name(line) { + if in_desktop_entry { + insert_missing_keys(&mut out, updates, &seen); + } + + in_desktop_entry = section == "Desktop Entry"; + saw_desktop_entry |= in_desktop_entry; + if in_desktop_entry { + seen.fill(false); + } + + out.push(line.to_string()); + continue; + } + + if in_desktop_entry && let Some(key) = desktop_entry_key(line) { + if replace_localized_name && key.starts_with("Name[") { + continue; + } + + if remove_try_exec && key == "TryExec" { + continue; + } + + if let Some(index) = updates + .iter() + .position(|(update_key, _)| *update_key == key) + { + out.push(format!("{}={}", updates[index].0, updates[index].1)); + seen[index] = true; + continue; + } + } + + out.push(line.to_string()); + } + + if in_desktop_entry { + insert_missing_keys(&mut out, updates, &seen); + } + + if !saw_desktop_entry { + let mut with_desktop_entry = Vec::with_capacity(out.len() + updates.len() + 2); + with_desktop_entry.push("[Desktop Entry]".to_string()); + insert_missing_keys( + &mut with_desktop_entry, + updates, + &vec![false; updates.len()], + ); + if !out.is_empty() { + with_desktop_entry.push(String::new()); + with_desktop_entry.extend(out); + } + out = with_desktop_entry; + } + + let mut rendered = out.join("\n"); + rendered.push('\n'); + rendered +} + +fn insert_missing_keys(out: &mut Vec, updates: &[(&str, String)], seen: &[bool]) { + for (index, (key, value)) in updates.iter().enumerate() { + if !seen[index] { + out.push(format!("{key}={value}")); + } + } +} + +fn section_name(line: &str) -> Option<&str> { + let trimmed = line.trim(); + trimmed + .strip_prefix('[') + .and_then(|value| value.strip_suffix(']')) +} + +fn desktop_entry_key(line: &str) -> Option<&str> { + let line = line.trim_start(); + if line.starts_with('#') || line.starts_with(';') { + return None; + } + + line.split_once('=').map(|(key, _)| key.trim_end()) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn request() -> ValidLauncherEdit { + ValidLauncherEdit { + current_app_id: "org.example.App".to_string(), + source_path: PathBuf::from("/usr/share/applications/org.example.App.desktop"), + name: "Example".to_string(), + exec: "example --new".to_string(), + icon: "example-custom".to_string(), + terminal: false, + replace_localized_name: true, + disable_dbus_activation: true, + } + } + + #[test] + fn updates_desktop_entry_without_dropping_action_groups() { + let source = "\ +[Desktop Entry] +Type=Application +Name=Old +Name[fr]=Ancien +Exec=old +TryExec=old +Icon=old +DBusActivatable=true +Actions=new-window; + +[Desktop Action new-window] +Name=New Window +Exec=old --new-window +"; + + let rendered = render_editable_desktop_entry(source, &request()); + + assert!(rendered.contains("Name=Example\n")); + assert!(!rendered.contains("Name[fr]=")); + assert!(rendered.contains("Exec=example --new\n")); + assert!(rendered.contains("Icon=example-custom\n")); + assert!(rendered.contains("DBusActivatable=false\n")); + assert!(!rendered.contains("TryExec=")); + assert!(rendered.contains("[Desktop Action new-window]\n")); + assert!(rendered.contains("Exec=old --new-window\n")); + } + + #[test] + fn preserves_localized_names_when_name_is_unchanged() { + let mut edit = request(); + edit.replace_localized_name = false; + + let rendered = render_editable_desktop_entry( + "[Desktop Entry]\nName=Example\nName[fr]=Exemple\nExec=old\n", + &edit, + ); + + assert!(rendered.contains("Name=Example\n")); + assert!(rendered.contains("Name[fr]=Exemple\n")); + } +} diff --git a/cosmic-app-list/src/lib.rs b/cosmic-app-list/src/lib.rs index 51079cc4..f6893335 100644 --- a/cosmic-app-list/src/lib.rs +++ b/cosmic-app-list/src/lib.rs @@ -2,6 +2,8 @@ // SPDX-License-Identifier: GPL-3.0-only mod app; +mod icon_catalog; +mod launcher_edit; mod localize; mod wayland_handler; mod wayland_subscription; diff --git a/cosmic-app-list/src/wayland_handler.rs b/cosmic-app-list/src/wayland_handler.rs index 03c16973..d27409dc 100644 --- a/cosmic-app-list/src/wayland_handler.rs +++ b/cosmic-app-list/src/wayland_handler.rs @@ -388,7 +388,10 @@ impl CaptureData { }, ) .unwrap(); - self.conn.flush().unwrap(); + if let Err(err) = self.conn.flush() { + tracing::error!("Wayland flush failed during screencopy session create: {err}"); + return None; + } let formats = session .wait_while(|data| data.formats.is_none()) @@ -437,7 +440,10 @@ impl CaptureData { session: capture_session.clone(), }, ); - self.conn.flush().unwrap(); + if let Err(err) = self.conn.flush() { + tracing::error!("Wayland flush failed during screencopy capture: {err}"); + return None; + } // TODO: wait for server to release buffer? let res = session @@ -709,7 +715,10 @@ pub(crate) fn wayland_handler( if app_data.exit { break; } - event_loop.dispatch(None, &mut app_data).unwrap(); + if let Err(err) = event_loop.dispatch(None, &mut app_data) { + tracing::error!("Wayland event loop terminated: {err}"); + break; + } } } diff --git a/cosmic-applet-a11y/Cargo.toml b/cosmic-applet-a11y/Cargo.toml index a5bb12b4..d3550f60 100644 --- a/cosmic-applet-a11y/Cargo.toml +++ b/cosmic-applet-a11y/Cargo.toml @@ -9,7 +9,7 @@ cctk.workspace = true cosmic-protocols.workspace = true i18n-embed-fl.workspace = true i18n-embed.workspace = true -libcosmic.workspace = true +cosmic.workspace = true rust-embed.workspace = true tokio.workspace = true tracing-log.workspace = true @@ -17,9 +17,7 @@ tracing-subscriber.workspace = true tracing.workspace = true [dependencies.cosmic-settings-a11y-manager-subscription] -git = "https://github.com/pop-os/cosmic-settings" -# path = "../../cosmic-settings/subscriptions/a11y-manager" +path = "../../cosmic-settings/subscriptions/a11y-manager" [dependencies.cosmic-settings-accessibility-subscription] -git = "https://github.com/pop-os/cosmic-settings" -# path = "../../cosmic-settings/subscriptions/accessibility" +path = "../../cosmic-settings/subscriptions/accessibility" diff --git a/cosmic-applet-a11y/src/app.rs b/cosmic-applet-a11y/src/app.rs index ad5f2a1e..6a328339 100644 --- a/cosmic-applet-a11y/src/app.rs +++ b/cosmic-applet-a11y/src/app.rs @@ -26,10 +26,9 @@ use cosmic::{ }; use cosmic_settings_a11y_manager_subscription::{ - self as cosmic_a11y_manager, AccessibilityEvent, AccessibilityRequest, ColorFilter, + AccessibilityEvent, AccessibilityRequest, ColorFilter, }; use cosmic_settings_accessibility_subscription::{self as accessibility}; -use std::sync::LazyLock; use tokio::sync::mpsc::UnboundedSender; pub fn run() -> cosmic::iced::Result { @@ -52,6 +51,7 @@ struct CosmicA11yApplet { } #[derive(Debug, Clone)] +#[allow(dead_code)] enum Message { TogglePopup, CloseRequested(window::Id), diff --git a/cosmic-applet-a11y/src/backend/wayland/mod.rs b/cosmic-applet-a11y/src/backend/wayland/mod.rs index fa9796f0..12340588 100644 --- a/cosmic-applet-a11y/src/backend/wayland/mod.rs +++ b/cosmic-applet-a11y/src/backend/wayland/mod.rs @@ -2,13 +2,12 @@ // SPDX-License-Identifier: GPL-3.0-only use anyhow; -use cctk::sctk::reexports::calloop::{self, channel::SyncSender}; +use cctk::sctk::reexports::calloop::{self}; use cosmic::iced::{ self, Subscription, - futures::{self, SinkExt, StreamExt, channel::mpsc}, + futures::{self, SinkExt}, stream, }; -use cosmic_protocols::a11y::v1::client::cosmic_a11y_manager_v1::Filter; use cosmic_settings_a11y_manager_subscription::{ self as thread, AccessibilityEvent, AccessibilityRequest, }; diff --git a/cosmic-applet-audio/Cargo.toml b/cosmic-applet-audio/Cargo.toml index 96d37cad..c0554ebe 100644 --- a/cosmic-applet-audio/Cargo.toml +++ b/cosmic-applet-audio/Cargo.toml @@ -7,9 +7,8 @@ license = "GPL-3.0-only" [dependencies] i18n-embed-fl.workspace = true i18n-embed.workspace = true -libcosmic.workspace = true -mpris2-zbus = { git = "https://github.com/pop-os/dbus-settings-bindings" } -# mpris2-zbus = { path = "../../dbus-settings-bindings/mpris2" } +cosmic.workspace = true +mpris2-zbus = { path = "../../dbus-settings-bindings/mpris2" } rust-embed.workspace = true serde.workspace = true tokio.workspace = true @@ -21,5 +20,4 @@ urlencoding = "2.1.3" zbus.workspace = true [dependencies.cosmic-settings-sound-subscription] -git = "https://github.com/pop-os/cosmic-settings" -# path = "../../cosmic-settings/subscriptions/sound" +path = "../../cosmic-settings/subscriptions/sound" diff --git a/cosmic-applet-audio/i18n/hu/cosmic_applet_audio.ftl b/cosmic-applet-audio/i18n/hu/cosmic_applet_audio.ftl index c26f9fb0..b3fdb11d 100644 --- a/cosmic-applet-audio/i18n/hu/cosmic_applet_audio.ftl +++ b/cosmic-applet-audio/i18n/hu/cosmic_applet_audio.ftl @@ -2,6 +2,6 @@ output = Kimenet input = Bemenet show-media-controls = Médiavezérlők megjelenítése a panelen sound-settings = Hangbeállítások… -disconnected = PulseAudio nincs csatlakozva -no-device = Nincs kiválasztott eszköz +disconnected = A PulseAudio-kapcsolat megszakadt +no-device = Nincs eszköz kiválasztva unknown-artist = Ismeretlen diff --git a/cosmic-applet-audio/src/lib.rs b/cosmic-applet-audio/src/lib.rs index 5f49d0f9..78667f5f 100644 --- a/cosmic-applet-audio/src/lib.rs +++ b/cosmic-applet-audio/src/lib.rs @@ -487,11 +487,31 @@ impl cosmic::Application for Audio { .icon_button(self.output_icon_name()) .on_press_down(Message::TogglePopup); - const WHEEL_STEP: f32 = 5.0; // 5% per wheel event + const WHEEL_STEP: f32 = 5.0; // 5% par cran logique + // Wayland axis_v120 envoie un cran physique en rafale de plusieurs + // ScrollDelta::Pixels (5–8 events ~15–20px), pour ~120px par cran. On + // accumule ces sub-events dans un thread_local et on n'émet qu'au + // passage d'un seuil — sinon `signum()` faisait croire que chaque + // sub-event = un cran, et un seul cran physique faisait chuter le + // volume jusqu'à 0 ("coupe le son"). + const PIXEL_THRESHOLD: f32 = 15.0; // px par cran logique + std::thread_local! { + static PIXEL_ACC: std::cell::Cell = const { std::cell::Cell::new(0.0) }; + } let btn = crate::mouse_area::MouseArea::new(btn).on_mouse_wheel(|delta| { let scroll_vector = match delta { - iced::mouse::ScrollDelta::Lines { y, .. } => y.signum() * WHEEL_STEP, // -1/0/1 - iced::mouse::ScrollDelta::Pixels { y, .. } => y.signum(), // -1/0/1 + iced::mouse::ScrollDelta::Lines { y, .. } => { + PIXEL_ACC.with(|a| a.set(0.0)); + y * WHEEL_STEP + } + iced::mouse::ScrollDelta::Pixels { y, .. } => { + PIXEL_ACC.with(|acc_cell| { + let acc = acc_cell.get() + y; + let steps = (acc / PIXEL_THRESHOLD).trunc(); + acc_cell.set(acc - steps * PIXEL_THRESHOLD); + steps * WHEEL_STEP + }) + } }; if scroll_vector == 0.0 { return Message::Ignore; @@ -499,7 +519,7 @@ impl cosmic::Application for Audio { let new_volume = (self.model.sink_volume as f64 + (scroll_vector as f64)) .clamp(0.0, self.max_sink_volume as f64); - Message::SetSinkVolume(new_volume as u32) + Message::SetSinkVolume(new_volume.round() as u32) }); let playback_buttons = (!self.core.applet.suggested_bounds.as_ref().is_some_and(|c| { diff --git a/cosmic-applet-audio/src/mouse_area.rs b/cosmic-applet-audio/src/mouse_area.rs index 6ae8547a..38306e45 100644 --- a/cosmic-applet-audio/src/mouse_area.rs +++ b/cosmic-applet-audio/src/mouse_area.rs @@ -5,7 +5,7 @@ use cosmic::iced::core::Point; use cosmic::iced::core::{ Clipboard, Element, Layout, Length, Rectangle, Shell, Size, Widget, - event::{self, Event}, + event::Event, layout, mouse, overlay, renderer, touch, widget::{Operation, Tree, tree}, }; diff --git a/cosmic-applet-battery/Cargo.toml b/cosmic-applet-battery/Cargo.toml index 2218f638..fdee2ce1 100644 --- a/cosmic-applet-battery/Cargo.toml +++ b/cosmic-applet-battery/Cargo.toml @@ -12,7 +12,7 @@ drm = "0.14.1" futures.workspace = true i18n-embed-fl.workspace = true i18n-embed.workspace = true -libcosmic.workspace = true +cosmic.workspace = true rust-embed.workspace = true rustc-hash.workspace = true tokio.workspace = true @@ -24,9 +24,7 @@ zbus.workspace = true serde.workspace = true [dependencies.cosmic-settings-upower-subscription] -git = "https://github.com/pop-os/cosmic-settings" -# path = "../../cosmic-settings/subscriptions/upower" +path = "../../cosmic-settings/subscriptions/upower" [dependencies.cosmic-settings-daemon-subscription] -git = "https://github.com/pop-os/cosmic-settings" -# path = "../../cosmic-settings/subscriptions/settings-daemon" +path = "../../cosmic-settings/subscriptions/settings-daemon" diff --git a/cosmic-applet-battery/i18n/hu/cosmic_applet_battery.ftl b/cosmic-applet-battery/i18n/hu/cosmic_applet_battery.ftl index 814d3605..01626a96 100644 --- a/cosmic-applet-battery/i18n/hu/cosmic_applet_battery.ftl +++ b/cosmic-applet-battery/i18n/hu/cosmic_applet_battery.ftl @@ -1,13 +1,13 @@ battery = Akkumulátor -battery-desc = Csökkentett energiafogyasztás és teljesítmény +battery-desc = Csökkentett energiafogyasztás és teljesítmény. balanced = Kiegyensúlyozott -balanced-desc = Normál teljesítmény és akkumulátorhasználat +balanced-desc = Normál teljesítmény és akkumulátorhasználat. performance = Nagy teljesítmény -performance-desc = Nagy teljesítmény és energiafogyasztás -max-charge = Az akkumulátor élettartamának növelése érdekében állítsa a maximális töltési szintet 80%-ra -seconds = másodperc -minutes = perc -hours = óra +performance-desc = Nagy teljesítmény és energiafogyasztás. +max-charge = Az akkumulátor élettartamának növelése érdekében állítsd a maximális töltési szintet 80%-ra +seconds = mp +minutes = p +hours = ó until-empty = a lemerülésig power-settings = Energia- és akkumulátorbeállítások… dgpu-running = A dedikált GPU aktív, ami csökkentheti az akkumulátor élettartamát diff --git a/cosmic-applet-battery/src/app.rs b/cosmic-applet-battery/src/app.rs index 9233a33f..f927bde3 100644 --- a/cosmic-applet-battery/src/app.rs +++ b/cosmic-applet-battery/src/app.rs @@ -40,7 +40,7 @@ use cosmic_settings_upower_subscription::{ }; use rustc_hash::FxHashMap; -use std::{path::PathBuf, sync::LazyLock, time::Duration}; +use std::{path::PathBuf, time::Duration}; use tokio::sync::mpsc::UnboundedSender; // XXX improve @@ -172,6 +172,7 @@ impl CosmicBatteryApplet { } #[derive(Debug, Clone)] +#[allow(dead_code)] enum Message { TogglePopup, CloseRequested(window::Id), @@ -511,7 +512,7 @@ impl cosmic::Application for CosmicBatteryApplet { Task::none() } - fn view(&self) -> Element { + fn view(&self) -> Element<'_, Message> { let is_horizontal = match self.core.applet.anchor { PanelAnchor::Top | PanelAnchor::Bottom => true, PanelAnchor::Left | PanelAnchor::Right => false, diff --git a/cosmic-applet-bluetooth/Cargo.toml b/cosmic-applet-bluetooth/Cargo.toml index 03b67388..f3a8c179 100644 --- a/cosmic-applet-bluetooth/Cargo.toml +++ b/cosmic-applet-bluetooth/Cargo.toml @@ -10,7 +10,7 @@ bluer = { version = "0.17", features = ["bluetoothd", "id"] } futures.workspace = true i18n-embed-fl.workspace = true i18n-embed.workspace = true -libcosmic.workspace = true +cosmic.workspace = true fastrand = "2.3.0" rust-embed.workspace = true rustc-hash.workspace = true diff --git a/cosmic-applet-bluetooth/i18n/hu/cosmic_applet_bluetooth.ftl b/cosmic-applet-bluetooth/i18n/hu/cosmic_applet_bluetooth.ftl index ada54d0b..f12b24b3 100644 --- a/cosmic-applet-bluetooth/i18n/hu/cosmic_applet_bluetooth.ftl +++ b/cosmic-applet-bluetooth/i18n/hu/cosmic_applet_bluetooth.ftl @@ -1,7 +1,7 @@ bluetooth = Bluetooth other-devices = Egyéb Bluetooth-eszközök settings = Bluetooth-beállítások… -connected = Csatlakoztatva +connected = Kapcsolódva confirm-pin = Ellenőrizd, hogy a következő PIN-kód megegyezik-e a(z) { $deviceName } eszközön megjelenő PIN-kóddal confirm = Megerősítés cancel = Mégse diff --git a/cosmic-applet-bluetooth/src/app.rs b/cosmic-applet-bluetooth/src/app.rs index 2ca95ec5..d1d31022 100644 --- a/cosmic-applet-bluetooth/src/app.rs +++ b/cosmic-applet-bluetooth/src/app.rs @@ -24,7 +24,7 @@ use cosmic::{ widget::{button, divider, icon, scrollable, text}, }; use futures::FutureExt; -use std::{collections::HashMap, sync::LazyLock, time::Duration}; +use std::{collections::HashMap, time::Duration}; use tokio::sync::mpsc::Sender; use crate::{ @@ -63,6 +63,7 @@ impl CosmicBluetoothApplet { } #[derive(Debug, Clone)] +#[allow(dead_code)] enum Message { TogglePopup, CloseRequested(window::Id), @@ -145,7 +146,7 @@ impl cosmic::Application for CosmicBluetoothApplet { } Message::BluetoothEvent(e) => match e { BluerEvent::RequestResponse { - req, + req: _, state, err_msg, } => { diff --git a/cosmic-applet-bluetooth/src/bluetooth.rs b/cosmic-applet-bluetooth/src/bluetooth.rs index b3648acd..0083568f 100644 --- a/cosmic-applet-bluetooth/src/bluetooth.rs +++ b/cosmic-applet-bluetooth/src/bluetooth.rs @@ -149,8 +149,6 @@ pub fn bluetooth_subscription( }, BluerSessionEvent::AgentEvent(e) => BluerEvent::AgentEvent(e), - - _ => return, }; _ = output.send(message).await; @@ -199,6 +197,7 @@ pub enum BluerRequest { } #[derive(Debug, Clone)] +#[allow(dead_code)] pub enum BluerEvent { RequestResponse { req: BluerRequest, diff --git a/cosmic-applet-input-sources/Cargo.toml b/cosmic-applet-input-sources/Cargo.toml index 92a7daf3..046a3bfb 100644 --- a/cosmic-applet-input-sources/Cargo.toml +++ b/cosmic-applet-input-sources/Cargo.toml @@ -5,10 +5,10 @@ edition = "2024" license = "GPL-3.0-only" [dependencies] -cosmic-comp-config = { git = "https://github.com/pop-os/cosmic-comp.git", rev = "5eb5af4" } +cosmic-comp-config.workspace = true i18n-embed-fl.workspace = true i18n-embed.workspace = true -libcosmic.workspace = true +cosmic.workspace = true rust-embed.workspace = true tokio.workspace = true tracing-log.workspace = true diff --git a/cosmic-applet-input-sources/src/lib.rs b/cosmic-applet-input-sources/src/lib.rs index 93e84283..2c845de1 100644 --- a/cosmic-applet-input-sources/src/lib.rs +++ b/cosmic-applet-input-sources/src/lib.rs @@ -3,7 +3,6 @@ mod localize; -use cosmic::iced::{Alignment, Length}; use cosmic::{ app, app::Core, @@ -14,16 +13,14 @@ use cosmic::{ iced::{ Rectangle, Task, platform_specific::shell::commands::popup::{destroy_popup, get_popup}, - widget::{column, row}, window::Id, }, - iced::{core::window, runtime::Appearance}, + iced::core::window, prelude::*, surface, theme, widget::{ self, autosize, rectangle_tracker::{RectangleTracker, RectangleUpdate, rectangle_tracker_subscription}, - space, }, }; use cosmic_comp_config::CosmicCompConfig; diff --git a/cosmic-applet-minimize/Cargo.toml b/cosmic-applet-minimize/Cargo.toml index 783be11b..5fd35bd2 100644 --- a/cosmic-applet-minimize/Cargo.toml +++ b/cosmic-applet-minimize/Cargo.toml @@ -9,7 +9,7 @@ anyhow.workspace = true i18n-embed-fl.workspace = true i18n-embed.workspace = true image = { version = "0.25.9", default-features = false } -libcosmic.workspace = true +cosmic.workspace = true memmap2 = "0.9.10" rust-embed.workspace = true rustix.workspace = true diff --git a/cosmic-applet-minimize/src/lib.rs b/cosmic-applet-minimize/src/lib.rs index e40a7551..307762b5 100644 --- a/cosmic-applet-minimize/src/lib.rs +++ b/cosmic-applet-minimize/src/lib.rs @@ -316,7 +316,7 @@ impl cosmic::Application for Minimize { } else { (cross_padding, major_padding) }; - let theme = self.core.system_theme().cosmic(); + let _theme = self.core.system_theme().cosmic(); let icon_buttons = self.apps[..max_icon_count].iter().map(|app| { self.core .applet @@ -420,7 +420,7 @@ impl cosmic::Application for Minimize { (cross_padding, major_padding) }; let theme = self.core.system_theme().cosmic(); - let space_xxs = theme.space_xxs(); + let _space_xxs = theme.space_xxs(); let icon_buttons = self.apps[max_icon_count..].iter().map(|app| { tooltip( Element::from(crate::window_image::WindowImage::new( diff --git a/cosmic-applet-network/Cargo.toml b/cosmic-applet-network/Cargo.toml index 44f08b53..ea265d4e 100644 --- a/cosmic-applet-network/Cargo.toml +++ b/cosmic-applet-network/Cargo.toml @@ -7,12 +7,12 @@ license = "GPL-3.0-or-later" [dependencies] anyhow.workspace = true async-fn-stream = "0.3" -cosmic-dbus-networkmanager = { git = "https://github.com/pop-os/dbus-settings-bindings" } +cosmic-dbus-networkmanager = { path = "../../dbus-settings-bindings/networkmanager" } futures.workspace = true futures-util.workspace = true i18n-embed-fl.workspace = true i18n-embed.workspace = true -libcosmic = { workspace = true, features = [ +cosmic = { workspace = true, features = [ "applet", "applet-token", "tokio", @@ -34,5 +34,4 @@ nmrs = "3.1.3" [dependencies.cosmic-settings-network-manager-subscription] -git = "https://github.com/pop-os/cosmic-settings/" -# path = "../../cosmic-settings/subscriptions/network-manager" +path = "../../cosmic-settings/subscriptions/network-manager" diff --git a/cosmic-applet-network/i18n/hu/cosmic_applet_network.ftl b/cosmic-applet-network/i18n/hu/cosmic_applet_network.ftl index e9a61812..4ad41d3f 100644 --- a/cosmic-applet-network/i18n/hu/cosmic_applet_network.ftl +++ b/cosmic-applet-network/i18n/hu/cosmic_applet_network.ftl @@ -1,16 +1,16 @@ network = Hálózat airplane-mode = Repülőgép-üzemmód airplane-mode-on = A repülőgép-üzemmód be van kapcsolva -turn-off-airplane-mode = Kapcsold ki a Wi-Fi, Bluetooth és mobil szélessáv engedélyezéséhez. +turn-off-airplane-mode = Kapcsold ki a Wi-Fi, Bluetooth és mobil széles sáv engedélyezéséhez. wifi = Wi-Fi identity = Azonosító ipv4 = IPv4-cím ipv6 = IPv6-cím mac = MAC megabits-per-second = Mbps -connected = Csatlakoztatva -connecting = Csatlakozás… -connect = Csatlakozás +connected = Kapcsolódva +connecting = Kapcsolódás +connect = Kapcsolódás cancel = Mégse settings = Hálózati beállítások… visible-wireless-networks = Látható vezeték nélküli hálózatok diff --git a/cosmic-applet-notifications/Cargo.toml b/cosmic-applet-notifications/Cargo.toml index 094cfa14..fbfc8ad5 100644 --- a/cosmic-applet-notifications/Cargo.toml +++ b/cosmic-applet-notifications/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0-only" cosmic-notifications-util = { git = "https://github.com/pop-os/cosmic-notifications" } cosmic-notifications-config = { git = "https://github.com/pop-os/cosmic-notifications" } anyhow.workspace = true -libcosmic.workspace = true +cosmic.workspace = true tokio.workspace = true # cosmic-notifications-util = { path = "../../cosmic-notifications-daemon/cosmic-notifications-util" } # cosmic-notifications-config = { path = "../../cosmic-notifications-daemon/cosmic-notifications-config" } diff --git a/cosmic-applet-notifications/i18n/hu/cosmic_applet_notifications.ftl b/cosmic-applet-notifications/i18n/hu/cosmic_applet_notifications.ftl index ec1f5a91..0ff88aa1 100644 --- a/cosmic-applet-notifications/i18n/hu/cosmic_applet_notifications.ftl +++ b/cosmic-applet-notifications/i18n/hu/cosmic_applet_notifications.ftl @@ -1,14 +1,14 @@ hours-ago = { $duration -> - [0] Most - [one] 1 órával ezelőtt - *[other] { $duration } órával ezelőtt + [0] Épp most + [one] 1 órája + *[other] { $duration } órája } minutes-ago = { $duration -> - [0] Most - [one] 1 perccel ezelőtt - *[other] { $duration } perccel ezelőtt + [0] Épp most + [one] 1 perce + *[other] { $duration } perce } show-less = Kevesebb megjelenítése show-more = { $more } további megjelenítése diff --git a/cosmic-applet-power/Cargo.toml b/cosmic-applet-power/Cargo.toml index 041c0474..d6fae301 100644 --- a/cosmic-applet-power/Cargo.toml +++ b/cosmic-applet-power/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0-only" [dependencies] i18n-embed-fl.workspace = true i18n-embed.workspace = true -libcosmic.workspace = true +cosmic.workspace = true logind-zbus = "5.3.2" rust-embed.workspace = true rustix.workspace = true diff --git a/cosmic-applet-power/i18n/ca/cosmic_applet_power.ftl b/cosmic-applet-power/i18n/ca/cosmic_applet_power.ftl index 2c45ddba..c1084630 100644 --- a/cosmic-applet-power/i18n/ca/cosmic_applet_power.ftl +++ b/cosmic-applet-power/i18n/ca/cosmic_applet_power.ftl @@ -1,2 +1,4 @@ cancel = Cancel·lar confirm = Confirmar +restart = Reinicia +suspend = Suspèn diff --git a/cosmic-applet-power/i18n/hu/cosmic_applet_power.ftl b/cosmic-applet-power/i18n/hu/cosmic_applet_power.ftl index 9019650a..9791f43f 100644 --- a/cosmic-applet-power/i18n/hu/cosmic_applet_power.ftl +++ b/cosmic-applet-power/i18n/hu/cosmic_applet_power.ftl @@ -33,4 +33,4 @@ confirm-body = [lock-screen] zárolni fogja a képernyőt [log-out] kijelentkezik *[other] alkalmazni fogja a kiválasztott műveletet - } { $countdown } másodperc múlva + } { $countdown } másodperc múlva. diff --git a/cosmic-applet-power/src/lib.rs b/cosmic-applet-power/src/lib.rs index 67725fbc..4a5829df 100644 --- a/cosmic-applet-power/src/lib.rs +++ b/cosmic-applet-power/src/lib.rs @@ -16,9 +16,8 @@ use cosmic::{ window, }, surface, theme, - widget::{Space, button, divider, icon, space, text}, + widget::{button, divider, icon, space, text}, }; -use std::sync::LazyLock; use logind_zbus::{ manager::ManagerProxy, @@ -35,9 +34,6 @@ pub mod session_manager; use crate::{cosmic_session::CosmicSessionProxy, session_manager::SessionManagerProxy}; -static SUBSURFACE_ID: LazyLock = - LazyLock::new(|| cosmic::widget::Id::new("subsurface")); - pub fn run() -> cosmic::iced::Result { localize::localize(); @@ -49,7 +45,6 @@ struct Power { icon_name: String, popup: Option, token_tx: Option>, - subsurface_id: window::Id, } #[derive(Debug, Clone, Copy)] @@ -75,6 +70,7 @@ impl PowerAction { } #[derive(Debug, Clone)] +#[allow(dead_code)] enum Message { Action(PowerAction), TogglePopup, @@ -104,7 +100,6 @@ impl cosmic::Application for Power { Self { core, icon_name: "system-shutdown-symbolic".to_string(), - subsurface_id: window::Id::unique(), token_tx: None, popup: Option::default(), }, diff --git a/cosmic-applet-status-area/Cargo.toml b/cosmic-applet-status-area/Cargo.toml index fe85ad48..b222166a 100644 --- a/cosmic-applet-status-area/Cargo.toml +++ b/cosmic-applet-status-area/Cargo.toml @@ -6,7 +6,7 @@ license = "GPL-3.0-only" [dependencies] futures.workspace = true -libcosmic.workspace = true +cosmic.workspace = true serde.workspace = true rustc-hash.workspace = true tokio.workspace = true diff --git a/cosmic-applet-status-area/src/components/app.rs b/cosmic-applet-status-area/src/components/app.rs index 1071d7ac..c9d1acd4 100644 --- a/cosmic-applet-status-area/src/components/app.rs +++ b/cosmic-applet-status-area/src/components/app.rs @@ -11,7 +11,6 @@ use cosmic::{ iced::{ self, Length, Subscription, platform_specific::shell::commands::popup::{destroy_popup, get_popup}, - theme::Style, window, }, surface, @@ -25,6 +24,7 @@ use crate::{ }; #[derive(Clone, Debug)] +#[allow(dead_code)] pub enum Msg { None, Activate(usize), @@ -577,7 +577,7 @@ fn menu_icon_button<'a>( let icon = menu.icon_handle().clone(); let theme = cosmic::theme::active(); - let theme = theme.cosmic(); + let _theme = theme.cosmic(); let suggested = applet.suggested_size(true); let padding = applet.suggested_padding(true).1; @@ -595,7 +595,7 @@ fn menu_icon_button<'a>( .class(if symbolic { cosmic::theme::Svg::Custom(std::rc::Rc::new(|theme| { cosmic::iced::widget::svg::Style { - color: Some(theme.cosmic().background.on.into()), + color: Some(theme.cosmic().background(false).on.into()), } })) } else { diff --git a/cosmic-applet-status-area/src/components/status_menu.rs b/cosmic-applet-status-area/src/components/status_menu.rs index fedd79e4..e706f37b 100644 --- a/cosmic-applet-status-area/src/components/status_menu.rs +++ b/cosmic-applet-status-area/src/components/status_menu.rs @@ -26,6 +26,7 @@ pub struct State { expanded: Option, // TODO handle icon with multiple sizes? icon_handle: icon::Handle, + icon_theme_path: Option, click_event: Option<(i32, bool)>, } @@ -39,6 +40,7 @@ impl State { icon_handle: icon::from_name("application-default") .prefer_svg(true) .handle(), + icon_theme_path: None, click_event: None, }, iced::Task::none(), @@ -63,6 +65,7 @@ impl State { } Msg::Icon(update) => { let icon_name = update.name.unwrap_or_default(); + self.icon_theme_path = update.theme_path; // Use the icon pixmap if an icon was not defined by name. if icon_name.is_empty() { @@ -93,13 +96,18 @@ impl State { self.icon_handle = if Path::new(&icon_name).exists() { icon::from_path(Path::new(&icon_name).to_path_buf()).symbolic(true) } else { - icon::from_name(icon_name) - .prefer_svg(true) - .fallback(Some(IconFallback::Names(vec![ + let mut builder = icon::from_name(icon_name).prefer_svg(true).fallback(Some( + IconFallback::Names(vec![ "application-default".into(), "application-x-executable".into(), - ]))) - .handle() + ]), + )); + + if let Some(ref theme_path) = self.icon_theme_path { + builder = builder.with_extra_paths(vec![theme_path.clone()]); + } + + builder.handle() }; iced::Task::none() diff --git a/cosmic-applet-status-area/src/status_notifier_watcher.rs b/cosmic-applet-status-area/src/status_notifier_watcher.rs index 1bb75d79..5c8b6175 100644 --- a/cosmic-applet-status-area/src/status_notifier_watcher.rs +++ b/cosmic-applet-status-area/src/status_notifier_watcher.rs @@ -10,21 +10,18 @@ //! can be socket-activated and not conflict with anything else running as a status notifier //! watcher. //! -//! The daemon runs as long as as there is at least one client still connected. Which it checks -//! for every `REFRESH_INTERVAL`. +//! The daemon runs as long as there is at least one client still connected. use crate::subscriptions::status_notifier_watcher::server::create_service; use crate::unique_names::UniqueNames; use futures::StreamExt; -use std::{collections::HashSet, time::Duration}; +use std::collections::HashSet; use zbus::fdo; use zbus::message::Header; const DBUS_NAME: &str = "com.system76.CosmicStatusNotifierWatcher"; const OBJECT_PATH: &str = "/CosmicStatusNotifierWatcher"; -const REFRESH_INTERVAL: Duration = Duration::from_secs(60); - /// Run daemon pub fn run() -> cosmic::iced::Result { if let Err(err) = run_inner() { @@ -42,7 +39,7 @@ pub async fn cosmic_register(conn: &zbus::Connection) -> zbus::Result<()> { tokio::spawn(async move { while let Some(value) = stream.next().await { if let Some(_unique_name) = value { - /// Register with new owner + // Register with new owner. let _ = cosmic_watcher.register_applet().await; } } diff --git a/cosmic-applet-status-area/src/subscriptions/status_notifier_item.rs b/cosmic-applet-status-area/src/subscriptions/status_notifier_item.rs index fd51390e..c03f0f54 100644 --- a/cosmic-applet-status-area/src/subscriptions/status_notifier_item.rs +++ b/cosmic-applet-status-area/src/subscriptions/status_notifier_item.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-only use std::hash::Hash; +use std::path::PathBuf; use cosmic::iced::{self, Subscription}; use futures::{FutureExt, StreamExt}; @@ -27,7 +28,7 @@ pub struct Icon { pub struct IconUpdate { pub name: Option, pub pixmap: Option>, - // pub theme_path: Option, + pub theme_path: Option, } impl StatusNotifierItem { @@ -118,11 +119,11 @@ impl StatusNotifierItem { async fn icon_events(item_proxy: StatusNotifierItemProxy<'static>) -> IconUpdate { let icon_name = item_proxy.icon_name().await; let icon_pixmap = item_proxy.icon_pixmap().await; - // let icon_theme_path = item_proxy.icon_theme_path().await.map(PathBuf::from); + let icon_theme_path = item_proxy.icon_theme_path().await.map(PathBuf::from); IconUpdate { name: icon_name.ok(), pixmap: icon_pixmap.ok(), - // theme_path: icon_theme_path.ok().filter(|x| !x.as_os_str().is_empty()), + theme_path: icon_theme_path.ok().filter(|x| !x.as_os_str().is_empty()), } } diff --git a/cosmic-applet-tiling/Cargo.toml b/cosmic-applet-tiling/Cargo.toml index 23e689e0..894be7d4 100644 --- a/cosmic-applet-tiling/Cargo.toml +++ b/cosmic-applet-tiling/Cargo.toml @@ -5,10 +5,10 @@ edition = "2024" license = "GPL-3.0-only" [dependencies] -libcosmic.workspace = true +cosmic.workspace = true anyhow.workspace = true cctk.workspace = true -cosmic-comp-config = { git = "https://github.com/pop-os/cosmic-comp.git", rev = "5eb5af4" } +cosmic-comp-config.workspace = true cosmic-protocols.workspace = true i18n-embed-fl.workspace = true i18n-embed.workspace = true diff --git a/cosmic-applet-tiling/i18n/hu/cosmic_applet_tiling.ftl b/cosmic-applet-tiling/i18n/hu/cosmic_applet_tiling.ftl index 7d622463..a2d0d4bc 100644 --- a/cosmic-applet-tiling/i18n/hu/cosmic_applet_tiling.ftl +++ b/cosmic-applet-tiling/i18n/hu/cosmic_applet_tiling.ftl @@ -3,11 +3,11 @@ tile-current = Jelenlegi munkaterület csempézése shortcuts = Gyorsbillentyűk navigate-windows = Ablakok navigálása move-window = Ablak mozgatása -toggle-floating-window = Az ablakok lebegtetésének be- és kikapcsolása +toggle-floating-window = Lebegő ablak be/ki view-all-shortcuts = Az összes gyorsbillentyű megtekintése… active-hint = Aktív ablak kiemelése gaps = Hézagok -floating-window-exceptions = Lebegő ablak kivételek… +floating-window-exceptions = Lebegőablak-kivételek… window-management-settings = Ablakkezelési beállítások… all-workspaces = Összes munkaterület per-workspace = Munkaterületenként diff --git a/cosmic-applet-tiling/src/window.rs b/cosmic-applet-tiling/src/window.rs index 327d5d75..7da430e3 100644 --- a/cosmic-applet-tiling/src/window.rs +++ b/cosmic-applet-tiling/src/window.rs @@ -26,7 +26,7 @@ use cosmic::{ }; use cosmic_comp_config::{CosmicCompConfig, TileBehavior}; use cosmic_protocols::workspace::v2::client::zcosmic_workspace_handle_v2::TilingState; -use std::{thread, time::Instant}; +use std::thread; use tracing::error; const ID: &str = "com.system76.CosmicAppletTiling"; @@ -46,6 +46,7 @@ pub struct Window { } #[derive(Clone, Debug)] +#[allow(dead_code)] pub enum Message { TogglePopup, PopupClosed(Id), diff --git a/cosmic-applet-time/Cargo.toml b/cosmic-applet-time/Cargo.toml index ff5e6298..bfa73bcb 100644 --- a/cosmic-applet-time/Cargo.toml +++ b/cosmic-applet-time/Cargo.toml @@ -9,7 +9,7 @@ cosmic-applets-config.workspace = true jiff = "0.2" i18n-embed-fl.workspace = true i18n-embed.workspace = true -libcosmic.workspace = true +cosmic.workspace = true rust-embed.workspace = true tokio.workspace = true tracing-log.workspace = true @@ -17,5 +17,5 @@ tracing-subscriber.workspace = true tracing.workspace = true icu = { version = "2.1.1", features = ["compiled_data"] } zbus.workspace = true -timedate-zbus = { git = "https://github.com/pop-os/dbus-settings-bindings" } +timedate-zbus = { path = "../../dbus-settings-bindings/timedate" } logind-zbus = "5.3.2" diff --git a/cosmic-applet-time/src/window.rs b/cosmic-applet-time/src/window.rs index a44d81ee..ddd37d31 100644 --- a/cosmic-applet-time/src/window.rs +++ b/cosmic-applet-time/src/window.rs @@ -94,6 +94,7 @@ pub struct Window { } #[derive(Debug, Clone)] +#[allow(dead_code)] pub enum Message { TogglePopup, CloseRequested(window::Id), @@ -361,7 +362,7 @@ impl cosmic::Application for Window { } fn subscription(&self) -> Subscription { - fn time_subscription(mut show_seconds: watch::Receiver) -> Subscription { + fn time_subscription(show_seconds: watch::Receiver) -> Subscription { struct Wrapper { inner: watch::Receiver, id: &'static str, @@ -376,7 +377,7 @@ impl cosmic::Application for Window { inner: show_seconds, id: "time-sub", }, - |Wrapper { inner, id }| { + |Wrapper { inner, id: _ }| { let mut show_seconds = inner.clone(); stream::channel(1, move |mut output: mpsc::Sender| async move { // Mark this receiver's state as changed so that it always receives an initial diff --git a/cosmic-applet-workspaces/Cargo.toml b/cosmic-applet-workspaces/Cargo.toml index ee9e04db..9d1b7bb9 100644 --- a/cosmic-applet-workspaces/Cargo.toml +++ b/cosmic-applet-workspaces/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" license = "GPL-3.0-only" [dependencies] -libcosmic.workspace = true +cosmic.workspace = true cctk.workspace = true tracing.workspace = true tracing-subscriber.workspace = true diff --git a/cosmic-applet-workspaces/src/components/app.rs b/cosmic-applet-workspaces/src/components/app.rs index dc4ccdc4..a9bafb79 100644 --- a/cosmic-applet-workspaces/src/components/app.rs +++ b/cosmic-applet-workspaces/src/components/app.rs @@ -84,6 +84,7 @@ impl IcedWorkspacesApplet { } #[derive(Debug, Clone)] +#[allow(dead_code)] enum Message { WorkspaceUpdate(WorkspacesUpdate), WorkspacePressed(ExtWorkspaceHandleV1), diff --git a/cosmic-applets/Cargo.toml b/cosmic-applets/Cargo.toml index 2d950afc..97755af8 100644 --- a/cosmic-applets/Cargo.toml +++ b/cosmic-applets/Cargo.toml @@ -23,7 +23,7 @@ cosmic-applet-time = { path = "../cosmic-applet-time" } cosmic-applet-workspaces = { path = "../cosmic-applet-workspaces" } cosmic-applet-input-sources = { path = "../cosmic-applet-input-sources" } cosmic-panel-button = { path = "../cosmic-panel-button" } -libcosmic.workspace = true +cosmic.workspace = true tracing.workspace = true tracing-subscriber.workspace = true tracing-log.workspace = true diff --git a/cosmic-applets/src/main.rs b/cosmic-applets/src/main.rs index f62bbf21..dfd541d1 100644 --- a/cosmic-applets/src/main.rs +++ b/cosmic-applets/src/main.rs @@ -12,26 +12,44 @@ fn main() -> cosmic::iced::Result { }; let start = applet.rfind('/').map_or(0, |v| v + 1); - let cmd = &applet.as_str()[start..]; + let cmd = applet.as_str()[start..].to_string(); tracing::info!("Starting `{cmd}` with version {VERSION}"); - match cmd { - "cosmic-app-list" => cosmic_app_list::run(), - "cosmic-applet-a11y" => cosmic_applet_a11y::run(), - "cosmic-applet-audio" => cosmic_applet_audio::run(), - "cosmic-applet-battery" => cosmic_applet_battery::run(), - "cosmic-applet-bluetooth" => cosmic_applet_bluetooth::run(), - "cosmic-applet-minimize" => cosmic_applet_minimize::run(), - "cosmic-applet-network" => cosmic_applet_network::run(), - "cosmic-applet-notifications" => cosmic_applet_notifications::run(), - "cosmic-applet-power" => cosmic_applet_power::run(), - "cosmic-applet-status-area" => cosmic_applet_status_area::run(), - "cosmic-applet-tiling" => cosmic_applet_tiling::run(), - "cosmic-applet-time" => cosmic_applet_time::run(), - "cosmic-applet-workspaces" => cosmic_applet_workspaces::run(), - "cosmic-applet-input-sources" => cosmic_applet_input_sources::run(), - "cosmic-panel-button" => cosmic_panel_button::run(), - _ => Ok(()), + let cmd_for_run = cmd.clone(); + let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(move || { + match cmd_for_run.as_str() { + "cosmic-app-list" => cosmic_app_list::run(), + "cosmic-applet-a11y" => cosmic_applet_a11y::run(), + "cosmic-applet-audio" => cosmic_applet_audio::run(), + "cosmic-applet-battery" => cosmic_applet_battery::run(), + "cosmic-applet-bluetooth" => cosmic_applet_bluetooth::run(), + "cosmic-applet-minimize" => cosmic_applet_minimize::run(), + "cosmic-applet-network" => cosmic_applet_network::run(), + "cosmic-applet-notifications" => cosmic_applet_notifications::run(), + "cosmic-applet-power" => cosmic_applet_power::run(), + "cosmic-applet-status-area" => cosmic_applet_status_area::run(), + "cosmic-applet-tiling" => cosmic_applet_tiling::run(), + "cosmic-applet-time" => cosmic_applet_time::run(), + "cosmic-applet-workspaces" => cosmic_applet_workspaces::run(), + "cosmic-applet-input-sources" => cosmic_applet_input_sources::run(), + "cosmic-panel-button" => cosmic_panel_button::run(), + _ => Ok(()), + } + })); + + match result { + Ok(r) => r, + Err(payload) => { + let msg = payload + .downcast_ref::<&str>() + .map(|s| s.to_string()) + .or_else(|| payload.downcast_ref::().cloned()) + .unwrap_or_else(|| "".to_string()); + tracing::error!( + "`{cmd}` panicked (likely compositor disconnect), exiting cleanly: {msg}" + ); + Ok(()) + } } } diff --git a/cosmic-panel-button/Cargo.toml b/cosmic-panel-button/Cargo.toml index dc6ffd9a..6719e131 100644 --- a/cosmic-panel-button/Cargo.toml +++ b/cosmic-panel-button/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" license = "GPL-3.0-only" [dependencies] -libcosmic.workspace = true +cosmic.workspace = true rustc-hash.workspace = true tracing.workspace = true tracing-subscriber.workspace = true diff --git a/cosmic-panel-button/src/lib.rs b/cosmic-panel-button/src/lib.rs index 45ee1ca2..5c875719 100644 --- a/cosmic-panel-button/src/lib.rs +++ b/cosmic-panel-button/src/lib.rs @@ -48,7 +48,7 @@ impl Button { icon: cosmic::widget::icon::Handle, ) -> cosmic::widget::Button<'a, Message> { let theme = cosmic::theme::active(); - let theme = theme.cosmic(); + let _theme = theme.cosmic(); let suggested = self.core.applet.suggested_size(icon.symbolic); let (major_padding, applet_padding_minor_axis) = @@ -66,7 +66,7 @@ impl Button { .class(if symbolic { cosmic::theme::Svg::Custom(std::rc::Rc::new(|theme| { cosmic::iced::widget::svg::Style { - color: Some(theme.cosmic().background.on.into()), + color: Some(theme.cosmic().background(false).on.into()), } })) } else { diff --git a/i18n/hu/desktop_entries.ftl b/i18n/hu/desktop_entries.ftl index 637e262e..82b4bfdb 100644 --- a/i18n/hu/desktop_entries.ftl +++ b/i18n/hu/desktop_entries.ftl @@ -40,7 +40,7 @@ cosmic-applet-power-comment = Képernyő zárolása, kijelentkezés, felfüggesz cosmic-app-list-comment = Rögzített alkalmazások indítása és a megnyitott ablakok kezelése cosmic-applet-status-area-comment = Alkalmazásjelzők, melyek menüt is megjeleníthetnek a panelen cosmic-applet-status-area-keywords = COSMIC;kisalkalmazás;alkalmazás;app;jelző;értesítések;tálca;állapot; -cosmic-applet-tiling-comment = Az aktív ablak kiemelésének, valamint az aktuális és munkaterületenkénti automatikus csempézés kezelése +cosmic-applet-tiling-comment = Az aktív ablakkiemelés, valamint a jelenlegi és munkaterületenkénti automatikus csempézés kezelése cosmic-applet-tiling-keywords = COSMIC;kisalkalmazás;csempézés;kiemelés;munkaterületek; cosmic-applet-time-comment = Az aktuális idő megjelenítése a panelen, felugró naptárral cosmic-applet-time-keywords = COSMIC;kisalkalmazás;dátum;idő;naptár; diff --git a/i18n/uk/desktop_entries.ftl b/i18n/uk/desktop_entries.ftl index c6088440..72bfb5ba 100644 --- a/i18n/uk/desktop_entries.ftl +++ b/i18n/uk/desktop_entries.ftl @@ -32,7 +32,7 @@ cosmic-applet-minimize-comment = Керування згорнутими вік cosmic-applet-minimize-keywords = COSMIC;КОСМІК;КОСМОС;КОСМІЧНЕ;Віджет;Віджети;Згорнути;Згорнуті;Вікна;Вікно; cosmic-applet-network-comment = Керування мережевими з’єднаннями cosmic-applet-network-keywords = COSMIC;КОСМІК;КОСМОС;КОСМІЧНЕ;Віджет;Віджети;Мережа;Інтернет; -cosmic-applet-notifications-comment = Керування сповіщеннями та режимом «Не турбувати» +cosmic-applet-notifications-comment = Керування сповіщеннями та режимом Не турбувати cosmic-applet-notifications-keywords = COSMIC;КОСМІК;КОСМОС;КОСМІЧНЕ;Віджет;Віджети;Сповіщення; cosmic-applet-power-comment = Блокування екрана, вихід із сеансу, призупинення, перезапуск і вимкнення cosmic-applet-power-keywords = COSMIC;КОСМІК;КОСМОС;КОСМІЧНЕ;Віджет;Віджети;Сеанс;Користувач;Блокування;Вихід;Перезапуск;Вимкнення;Призупинення;Сон; diff --git a/redeploy.sh b/redeploy.sh new file mode 100755 index 00000000..686bf3cb --- /dev/null +++ b/redeploy.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +# Recompile et déploie le fork local cosmic-applets (multiplexor cosmic-applets + +# binaire séparé cosmic-app-list). +# +# Cibles : /usr/local/bin/cosmic-applets et /usr/local/bin/cosmic-app-list +# (binaires compilés manuellement, hors pacman, qui priment sur ceux du paquet +# via $PATH /usr/local/bin avant /usr/bin). +# +# Branche de déploiement : yoda-dock-magnification (contient les commits +# magnification + le fix Wayland error handling). + +set -euo pipefail + +REPO="/home/lionel/Projets/COSMIC/cosmic-applets" +TARGETS=( + "cosmic-applets" + "cosmic-app-list" + "cosmic-panel-button" +) +BIN_DIR="/usr/local/bin" + +cd "$REPO" + +echo "==> Branche actuelle : $(git branch --show-current)" +echo "==> Build release (workspace)..." +cargo build --release --workspace + +STAMP=$(date +%Y%m%d-%H%M%S) +for bin in "${TARGETS[@]}"; do + src="$REPO/target/release/$bin" + dst="$BIN_DIR/$bin" + + if [[ ! -f "$src" ]]; then + echo "!! Binaire absent après build : $src" >&2 + exit 1 + fi + + if [[ -f "$dst" ]]; then + echo "==> Backup $dst" + sudo cp -a "$dst" "${dst}.bak.${STAMP}" + fi + + echo "==> Install $src -> $dst" + sudo install -m755 "$src" "$dst" +done + +echo "==> Kill des process applet en cours (cosmic-panel relancera à la demande)" +pkill -u "$USER" -f "/usr/local/bin/cosmic-applet" || true +pkill -u "$USER" -f "/usr/local/bin/cosmic-app-list" || true +pkill -u "$USER" -f "/usr/local/bin/cosmic-panel-button" || true + +echo "==> Vérif" +for bin in "${TARGETS[@]}"; do + file "$BIN_DIR/$bin" +done +echo "OK — relogin recommandé pour repartir sur des process applet propres." diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 79d20990..075062e5 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.93" +channel = "1.93.0"