diff --git a/Cargo.lock b/Cargo.lock index 9d3016e..363f49a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,22 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ab_glyph" +version = "0.2.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e53b0a3d5760cd2ba9b787ae0c6440ad18ee294ff71b05e3381c900a7d16cfd" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" + [[package]] name = "accesskit" version = "0.12.2" @@ -22,14 +38,12 @@ source = "git+https://github.com/wash2/accesskit.git?branch=winit-0.29#5f9b61c82 dependencies = [ "accesskit", "accesskit_consumer", - "async-channel", - "async-executor", - "async-task", "atspi", "futures-lite 1.13.0", - "futures-util", "once_cell", "serde", + "tokio", + "tokio-stream", "zbus 3.15.2", ] @@ -66,6 +80,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", + "getrandom", "once_cell", "version_check", "zerocopy", @@ -104,6 +119,33 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3aa2999eb46af81abb65c2d30d446778d7e613b60bbf4e174a027e80f90a3c14" +[[package]] +name = "android-activity" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" +dependencies = [ + "android-properties", + "bitflags 2.5.0", + "cc", + "cesu8", + "jni", + "jni-sys", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -151,9 +193,9 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" dependencies = [ "windows-sys 0.52.0", ] @@ -258,7 +300,7 @@ dependencies = [ "wayland-backend", "wayland-client", "wayland-protocols 0.31.2", - "zbus 4.2.2", + "zbus 4.3.0", ] [[package]] @@ -273,12 +315,12 @@ dependencies = [ [[package]] name = "async-broadcast" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258b52a1aa741b9f09783b2d86cf0aeeb617bbf847f6933340a39644227acbdb" +checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e" dependencies = [ "event-listener 5.3.1", - "event-listener-strategy 0.5.2", + "event-listener-strategy", "futures-core", "pin-project-lite", ] @@ -290,7 +332,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", - "event-listener-strategy 0.5.2", + "event-listener-strategy", "futures-core", "pin-project-lite", ] @@ -335,7 +377,7 @@ version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" dependencies = [ - "async-lock 3.3.0", + "async-lock 3.4.0", "blocking", "futures-lite 2.3.0", ] @@ -362,17 +404,17 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" +checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" dependencies = [ - "async-lock 3.3.0", + "async-lock 3.4.0", "cfg-if", "concurrent-queue", "futures-io", "futures-lite 2.3.0", "parking", - "polling 3.7.0", + "polling 3.7.2", "rustix 0.38.34", "slab", "tracing", @@ -390,12 +432,12 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener 4.0.3", - "event-listener-strategy 0.4.0", + "event-listener 5.3.1", + "event-listener-strategy", "pin-project-lite", ] @@ -405,7 +447,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" dependencies = [ - "async-io 2.3.2", + "async-io 2.3.3", "blocking", "futures-lite 2.3.0", ] @@ -429,13 +471,13 @@ dependencies = [ [[package]] name = "async-process" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a53fc6301894e04a92cb2584fedde80cb25ba8e02d9dc39d4a87d036e22f397d" +checksum = "f7eda79bbd84e29c2b308d1dc099d7de8dcc7035e48f4bf5dc4a531a44ff5e2a" dependencies = [ "async-channel", - "async-io 2.3.2", - "async-lock 3.3.0", + "async-io 2.3.3", + "async-lock 3.4.0", "async-signal", "async-task", "blocking", @@ -460,12 +502,12 @@ dependencies = [ [[package]] name = "async-signal" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afe66191c335039c7bb78f99dc7520b0cbb166b3a1cb33a03f53d8a1c6f2afda" +checksum = "794f185324c2f00e771cd9f1ae8b5ac68be2ca7abb129a87afd6e86d228bc54d" dependencies = [ - "async-io 2.3.2", - "async-lock 3.3.0", + "async-io 2.3.3", + "async-lock 3.4.0", "atomic-waker", "cfg-if", "futures-core", @@ -607,6 +649,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bit-set" version = "0.5.3" @@ -676,6 +724,25 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7" +dependencies = [ + "objc-sys", +] + +[[package]] +name = "block2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" +dependencies = [ + "block-sys", + "objc2", +] + [[package]] name = "blocking" version = "1.6.1" @@ -691,19 +758,19 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe5b10e214954177fb1dc9fbd20a1a2608fe99e6c832033bdc7cea287a20d77" +checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" dependencies = [ "borsh-derive", - "cfg_aliases 0.1.1", + "cfg_aliases 0.2.1", ] [[package]] name = "borsh-derive" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a8646f94ab393e43e8b35a2558b1624bed28b97ee09c5d15456e3c9463f46d" +checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" dependencies = [ "once_cell", "proc-macro-crate 3.1.0", @@ -766,9 +833,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.16.0" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78834c15cb5d5efe3452d58b1e8ba890dd62d21907f867f383358198e56ebca5" +checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" dependencies = [ "bytemuck_derive", ] @@ -812,6 +879,20 @@ dependencies = [ "displaydoc", ] +[[package]] +name = "calloop" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" +dependencies = [ + "bitflags 2.5.0", + "log", + "polling 3.7.2", + "rustix 0.38.34", + "slab", + "thiserror", +] + [[package]] name = "calloop" version = "0.13.0" @@ -820,19 +901,44 @@ checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ "bitflags 2.5.0", "log", - "polling 3.7.0", + "polling 3.7.2", "rustix 0.38.34", "slab", "thiserror", ] +[[package]] +name = "calloop" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c58a38167d6fba8c67cce63c4a91f2a73ca42cbdaf6fb9ba164f1e07b43ecc10" +dependencies = [ + "bitflags 2.5.0", + "log", + "polling 3.7.2", + "rustix 0.38.34", + "slab", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" +dependencies = [ + "calloop 0.12.4", + "rustix 0.38.34", + "wayland-backend", + "wayland-client", +] + [[package]] name = "calloop-wayland-source" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" dependencies = [ - "calloop", + "calloop 0.13.0", "rustix 0.38.34", "wayland-backend", "wayland-client", @@ -840,15 +946,21 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" dependencies = [ "jobserver", "libc", "once_cell", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfb" version = "0.7.3" @@ -898,15 +1010,16 @@ dependencies = [ "iana-time-zone", "js-sys", "num-traits", + "serde", "wasm-bindgen", "windows-targets 0.52.5", ] [[package]] name = "clap" -version = "4.5.4" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" dependencies = [ "clap_builder", "clap_derive", @@ -914,9 +1027,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" dependencies = [ "anstream", "anstyle", @@ -926,9 +1039,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -938,9 +1051,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "clipboard-win" @@ -954,7 +1067,7 @@ dependencies = [ [[package]] name = "clipboard_macos" version = "0.1.0" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-7#a5be70405574e98c292537fd3b01a1352550b9bf" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-8#7c59b07b9172d8e0401f7e06609e1050575309c9" dependencies = [ "objc", "objc-foundation", @@ -964,7 +1077,7 @@ dependencies = [ [[package]] name = "clipboard_wayland" version = "0.2.2" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-7#a5be70405574e98c292537fd3b01a1352550b9bf" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-8#7c59b07b9172d8e0401f7e06609e1050575309c9" dependencies = [ "dnd", "mime", @@ -974,7 +1087,7 @@ dependencies = [ [[package]] name = "clipboard_x11" version = "0.4.2" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-7#a5be70405574e98c292537fd3b01a1352550b9bf" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-8#7c59b07b9172d8e0401f7e06609e1050575309c9" dependencies = [ "thiserror", "x11rb", @@ -1099,6 +1212,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "concat-in-place" version = "1.1.0" @@ -1206,7 +1329,7 @@ dependencies = [ [[package]] name = "cosmic-bg-config" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-bg#cb1a7f05967360a29a30f382dec1b339a6f70b02" +source = "git+https://github.com/pop-os/cosmic-bg#2259f5ac81099a8215d5ff69cba1ec0d1fd850d1" dependencies = [ "colorgrad", "cosmic-config", @@ -1231,7 +1354,7 @@ dependencies = [ [[package]] name = "cosmic-comp-config" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-comp#f4eefcb2a180c704b86cb49335f16d57a19a8ac5" +source = "git+https://github.com/pop-os/cosmic-comp#254c583b5dc1c9435a51d1817facb1f0c2125637" dependencies = [ "cosmic-config", "input", @@ -1241,10 +1364,10 @@ dependencies = [ [[package]] name = "cosmic-config" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#ebf5c2738b98ffc68f2930354949f0b0e954d861" +source = "git+https://github.com/pop-os/libcosmic#5c6fa840f4e75ce94075cb1c8d22623077821193" dependencies = [ "atomicwrites", - "calloop", + "calloop 0.14.0", "cosmic-config-derive", "cosmic-settings-daemon", "dirs 5.0.1", @@ -1258,13 +1381,13 @@ dependencies = [ "tokio", "tracing", "xdg", - "zbus 4.2.2", + "zbus 4.3.0", ] [[package]] name = "cosmic-config-derive" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#ebf5c2738b98ffc68f2930354949f0b0e954d861" +source = "git+https://github.com/pop-os/libcosmic#5c6fa840f4e75ce94075cb1c8d22623077821193" dependencies = [ "quote", "syn 1.0.109", @@ -1273,7 +1396,7 @@ dependencies = [ [[package]] name = "cosmic-panel-config" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-panel#568f3392d3b50e4e8fb5f87064a3baa91e96e231" +source = "git+https://github.com/pop-os/cosmic-panel#d7a3ff64d134805b712f513cca307214f6b5e9d5" dependencies = [ "anyhow", "cosmic-config", @@ -1306,7 +1429,7 @@ source = "git+https://github.com/pop-os/cosmic-randr#8ad117e7c57848f113fbc87986e dependencies = [ "cosmic-protocols", "futures-lite 2.3.0", - "indexmap", + "indexmap 2.2.6", "tachyonix", "thiserror", "tokio", @@ -1338,9 +1461,11 @@ dependencies = [ "color-eyre", "cosmic-bg-config", "cosmic-comp-config", + "cosmic-config", "cosmic-panel-config", "cosmic-randr", "cosmic-randr-shell", + "cosmic-settings-config", "cosmic-settings-page", "cosmic-settings-system", "cosmic-settings-time", @@ -1377,7 +1502,21 @@ dependencies = [ "udev", "url", "xkb-data", - "zbus 4.2.2", + "zbus 4.3.0", +] + +[[package]] +name = "cosmic-settings-config" +version = "0.1.0" +source = "git+https://github.com/pop-os/cosmic-settings-daemon#ebb2bd61e309bf8363a78284647b9da363139ed6" +dependencies = [ + "cosmic-config", + "heck 0.5.0", + "serde", + "serde_with", + "thiserror", + "tracing", + "xkbcommon", ] [[package]] @@ -1385,7 +1524,7 @@ name = "cosmic-settings-daemon" version = "0.1.0" source = "git+https://github.com/pop-os/dbus-settings-bindings#1fdfcc8045e6732fc54b2c945008e89999a6cf71" dependencies = [ - "zbus 4.2.2", + "zbus 4.3.0", ] [[package]] @@ -1445,8 +1584,8 @@ dependencies = [ [[package]] name = "cosmic-text" -version = "0.11.2" -source = "git+https://github.com/pop-os/cosmic-text.git#7677ba388cbce3cc1488f0cf0cc5bfe8194f55d3" +version = "0.12.0" +source = "git+https://github.com/pop-os/cosmic-text.git#a03ec6b75f0ea8fd6264d6cd05afcec3c2213f8f" dependencies = [ "bitflags 2.5.0", "fontdb", @@ -1468,7 +1607,7 @@ dependencies = [ [[package]] name = "cosmic-theme" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#ebf5c2738b98ffc68f2930354949f0b0e954d861" +source = "git+https://github.com/pop-os/libcosmic#5c6fa840f4e75ce94075cb1c8d22623077821193" dependencies = [ "almost", "cosmic-config", @@ -1642,6 +1781,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + [[package]] name = "derivative" version = "2.2.0" @@ -1764,7 +1913,7 @@ dependencies = [ [[package]] name = "dnd" version = "0.1.0" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-7#a5be70405574e98c292537fd3b01a1352550b9bf" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-8#7c59b07b9172d8e0401f7e06609e1050575309c9" dependencies = [ "bitflags 2.5.0", "mime", @@ -1843,9 +1992,9 @@ dependencies = [ [[package]] name = "enumflags2" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3278c9d5fb675e0a51dabcf4c0d355f692b064171535ba72361be1528a9d8e8d" +checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" dependencies = [ "enumflags2_derive", "serde", @@ -1853,9 +2002,9 @@ dependencies = [ [[package]] name = "enumflags2_derive" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" +checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", @@ -1886,9 +2035,9 @@ checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" [[package]] name = "etagere" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306960881d6c46bd0dd6b7f07442a441418c08d0d3e63d8d080b0f64c6343e4e" +checksum = "0e2f1e3be19fb10f549be8c1bf013e8675b4066c445e36eb76d2ebb2f54ee495" dependencies = [ "euclid", "svg_fmt", @@ -1920,17 +2069,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "event-listener" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - [[package]] name = "event-listener" version = "5.3.1" @@ -1942,16 +2080,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "event-listener-strategy" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" -dependencies = [ - "event-listener 4.0.3", - "pin-project-lite", -] - [[package]] name = "event-listener-strategy" version = "0.5.2" @@ -2643,6 +2771,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -2664,9 +2798,9 @@ checksum = "f558a64ac9af88b5ba400d99b579451af0d39c6d360980045b91aac966d705e2" [[package]] name = "hostname1-zbus" version = "0.1.0" -source = "git+https://github.com/pop-os/dbus-settings-bindings#badfc6a0bbe7c93927fe32692795699a675ae4c4" +source = "git+https://github.com/pop-os/dbus-settings-bindings#1fdfcc8045e6732fc54b2c945008e89999a6cf71" dependencies = [ - "zbus 4.2.2", + "zbus 4.3.0", ] [[package]] @@ -2679,7 +2813,7 @@ dependencies = [ "serde", "serde_derive", "thiserror", - "toml 0.8.13", + "toml 0.8.14", "unic-langid", ] @@ -2765,7 +2899,7 @@ dependencies = [ [[package]] name = "iced" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#ebf5c2738b98ffc68f2930354949f0b0e954d861" +source = "git+https://github.com/pop-os/libcosmic#5c6fa840f4e75ce94075cb1c8d22623077821193" dependencies = [ "dnd", "iced_accessibility", @@ -2774,6 +2908,7 @@ dependencies = [ "iced_renderer", "iced_sctk", "iced_widget", + "iced_winit", "image 0.24.9", "mime", "thiserror", @@ -2783,7 +2918,7 @@ dependencies = [ [[package]] name = "iced_accessibility" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#ebf5c2738b98ffc68f2930354949f0b0e954d861" +source = "git+https://github.com/pop-os/libcosmic#5c6fa840f4e75ce94075cb1c8d22623077821193" dependencies = [ "accesskit", "accesskit_unix", @@ -2792,7 +2927,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#ebf5c2738b98ffc68f2930354949f0b0e954d861" +source = "git+https://github.com/pop-os/libcosmic#5c6fa840f4e75ce94075cb1c8d22623077821193" dependencies = [ "bitflags 2.5.0", "dnd", @@ -2814,7 +2949,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#ebf5c2738b98ffc68f2930354949f0b0e954d861" +source = "git+https://github.com/pop-os/libcosmic#5c6fa840f4e75ce94075cb1c8d22623077821193" dependencies = [ "futures", "iced_core", @@ -2827,7 +2962,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#ebf5c2738b98ffc68f2930354949f0b0e954d861" +source = "git+https://github.com/pop-os/libcosmic#5c6fa840f4e75ce94075cb1c8d22623077821193" dependencies = [ "bitflags 2.5.0", "bytemuck", @@ -2851,7 +2986,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#ebf5c2738b98ffc68f2930354949f0b0e954d861" +source = "git+https://github.com/pop-os/libcosmic#5c6fa840f4e75ce94075cb1c8d22623077821193" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2863,7 +2998,7 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#ebf5c2738b98ffc68f2930354949f0b0e954d861" +source = "git+https://github.com/pop-os/libcosmic#5c6fa840f4e75ce94075cb1c8d22623077821193" dependencies = [ "dnd", "iced_accessibility", @@ -2877,7 +3012,7 @@ dependencies = [ [[package]] name = "iced_sctk" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#ebf5c2738b98ffc68f2930354949f0b0e954d861" +source = "git+https://github.com/pop-os/libcosmic#5c6fa840f4e75ce94075cb1c8d22623077821193" dependencies = [ "enum-repr", "float-cmp", @@ -2903,7 +3038,7 @@ dependencies = [ [[package]] name = "iced_style" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#ebf5c2738b98ffc68f2930354949f0b0e954d861" +source = "git+https://github.com/pop-os/libcosmic#5c6fa840f4e75ce94075cb1c8d22623077821193" dependencies = [ "iced_core", "once_cell", @@ -2913,7 +3048,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#ebf5c2738b98ffc68f2930354949f0b0e954d861" +source = "git+https://github.com/pop-os/libcosmic#5c6fa840f4e75ce94075cb1c8d22623077821193" dependencies = [ "bytemuck", "cosmic-text", @@ -2930,7 +3065,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#ebf5c2738b98ffc68f2930354949f0b0e954d861" +source = "git+https://github.com/pop-os/libcosmic#5c6fa840f4e75ce94075cb1c8d22623077821193" dependencies = [ "bitflags 2.5.0", "bytemuck", @@ -2956,7 +3091,7 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#ebf5c2738b98ffc68f2930354949f0b0e954d861" +source = "git+https://github.com/pop-os/libcosmic#5c6fa840f4e75ce94075cb1c8d22623077821193" dependencies = [ "dnd", "iced_renderer", @@ -2971,10 +3106,39 @@ dependencies = [ ] [[package]] -name = "icu_calendar" -version = "1.5.0" +name = "iced_winit" +version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic#5c6fa840f4e75ce94075cb1c8d22623077821193" +dependencies = [ + "dnd", + "iced_graphics", + "iced_runtime", + "iced_style", + "log", + "thiserror", + "tracing", + "web-sys", + "winapi", + "window_clipboard", + "winit", +] + +[[package]] +name = "icrate" +version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4231cddf3dcbfc21e04bb52768f18e11a077d2935774eabdf7b239bb83bf3882" +checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" +dependencies = [ + "block2", + "dispatch", + "objc2", +] + +[[package]] +name = "icu_calendar" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7defdcb785245edd773a38b56f0ccef39065cdc4509a7d85435f6edea0fd58c5" dependencies = [ "calendrical_calculations", "displaydoc", @@ -3160,6 +3324,17 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + [[package]] name = "indexmap" version = "2.2.6" @@ -3168,6 +3343,7 @@ checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.5", + "serde", ] [[package]] @@ -3264,7 +3440,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "windows-sys 0.48.0", ] @@ -3305,6 +3481,28 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + [[package]] name = "jobserver" version = "0.1.31" @@ -3428,7 +3626,7 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libcosmic" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#ebf5c2738b98ffc68f2930354949f0b0e954d861" +source = "git+https://github.com/pop-os/libcosmic#5c6fa840f4e75ce94075cb1c8d22623077821193" dependencies = [ "apply", "ashpd", @@ -3463,7 +3661,7 @@ dependencies = [ "tracing", "unicode-segmentation", "url", - "zbus 4.2.2", + "zbus 4.3.0", ] [[package]] @@ -3503,6 +3701,17 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "libredox" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" +dependencies = [ + "bitflags 2.5.0", + "libc", + "redox_syscall 0.4.1", +] + [[package]] name = "libredox" version = "0.1.3" @@ -3689,9 +3898,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -3770,7 +3979,7 @@ dependencies = [ [[package]] name = "mime" version = "0.1.0" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-7#a5be70405574e98c292537fd3b01a1352550b9bf" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-8#7c59b07b9172d8e0401f7e06609e1050575309c9" dependencies = [ "smithay-clipboard", ] @@ -3783,9 +3992,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", "simd-adler32", @@ -3819,7 +4028,7 @@ dependencies = [ "bitflags 2.5.0", "codespan-reporting", "hexf-parse", - "indexmap", + "indexmap 2.2.6", "log", "num-traits", "rustc-hash", @@ -3829,6 +4038,36 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "ndk" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +dependencies = [ + "bitflags 2.5.0", + "jni-sys", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys", +] + [[package]] name = "new_debug_unreachable" version = "1.0.6" @@ -3947,6 +4186,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-derive" version = "0.4.2" @@ -4005,10 +4250,31 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", ] +[[package]] +name = "num_enum" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "objc" version = "0.2.7" @@ -4030,6 +4296,28 @@ dependencies = [ "objc_id", ] +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" + [[package]] name = "objc_exception" version = "0.1.2" @@ -4069,6 +4357,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "orbclient" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f0d54bde9774d3a51dcf281a5def240c71996bc6ca05d2c847ec8b2b216166" +dependencies = [ + "libredox 0.0.2", +] + [[package]] name = "ordered-multimap" version = "0.7.3" @@ -4119,6 +4416,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "owned_ttf_parser" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b41438d2fc63c46c74a2203bf5ccd82c41ba04347b2fcf5754f230b167067d5" +dependencies = [ + "ttf-parser 0.21.1", +] + [[package]] name = "owo-colors" version = "3.5.0" @@ -4199,7 +4505,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "smallvec", "windows-targets 0.52.5", ] @@ -4278,9 +4584,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464db0c665917b13ebb5d453ccdec4add5658ee1adc7affc7677615356a8afaf" +checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" dependencies = [ "atomic-waker", "fastrand 2.1.0", @@ -4324,13 +4630,13 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.0" +version = "3.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3" +checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi", + "hermit-abi 0.4.0", "pin-project-lite", "rustix 0.38.34", "tracing", @@ -4343,6 +4649,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -4400,9 +4712,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.84" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] @@ -4564,11 +4876,12 @@ dependencies = [ [[package]] name = "ravif" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc13288f5ab39e6d7c9d501759712e6969fcc9734220846fc9ed26cae2cc4234" +checksum = "85be49d628515bb99a01c44200009f0a4167c252f036445b975b35daf952258c" dependencies = [ "avif-serialize", + "bitstream-io", "imgref", "loop9", "quick-error", @@ -4628,6 +4941,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -4639,9 +4961,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ "bitflags 2.5.0", ] @@ -4653,20 +4975,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom", - "libredox", + "libredox 0.1.3", "thiserror", ] [[package]] name = "regex" -version = "1.10.4" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -4680,13 +5002,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax 0.8.4", ] [[package]] @@ -4697,9 +5019,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rend" @@ -4800,7 +5122,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ - "base64", + "base64 0.21.7", "bitflags 2.5.0", "serde", "serde_derive", @@ -4977,6 +5299,19 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sctk-adwaita" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b2eaf3a5b264a521b988b2e73042e742df700c4f962cde845d1541adb46550" +dependencies = [ + "ab_glyph", + "log", + "memmap2 0.9.4", + "smithay-client-toolkit 0.18.1", + "tiny-skia", +] + [[package]] name = "seahash" version = "4.1.0" @@ -5036,7 +5371,7 @@ version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ - "indexmap", + "indexmap 2.2.6", "itoa", "ryu", "serde", @@ -5062,6 +5397,36 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.2.6", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "sha1" version = "0.10.6" @@ -5179,8 +5544,8 @@ source = "git+https://github.com/smithay/client-toolkit//?rev=3bed072#3bed072b96 dependencies = [ "bitflags 2.5.0", "bytemuck", - "calloop", - "calloop-wayland-source", + "calloop 0.13.0", + "calloop-wayland-source 0.3.0", "cursor-icon", "libc", "log", @@ -5199,6 +5564,31 @@ dependencies = [ "xkeysym", ] +[[package]] +name = "smithay-client-toolkit" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" +dependencies = [ + "bitflags 2.5.0", + "calloop 0.12.4", + "calloop-wayland-source 0.2.0", + "cursor-icon", + "libc", + "log", + "memmap2 0.9.4", + "rustix 0.38.34", + "thiserror", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols 0.31.2", + "wayland-protocols-wlr 0.2.0", + "wayland-scanner", + "xkeysym", +] + [[package]] name = "smithay-client-toolkit" version = "0.19.1" @@ -5207,8 +5597,8 @@ checksum = "837d3067369e24aeda699a5d9fc5aa14ca14a84dd70aeed7156bfa04a5605b32" dependencies = [ "bitflags 2.5.0", "bytemuck", - "calloop", - "calloop-wayland-source", + "calloop 0.13.0", + "calloop-wayland-source 0.3.0", "cursor-icon", "libc", "log", @@ -5490,7 +5880,7 @@ dependencies = [ "cfg-expr", "heck 0.5.0", "pkg-config", - "toml 0.8.13", + "toml 0.8.14", "version-compare", ] @@ -5598,6 +5988,37 @@ dependencies = [ "weezl", ] +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "timedate-zbus" version = "0.1.0" @@ -5710,6 +6131,17 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" version = "0.5.11" @@ -5721,14 +6153,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.13" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.13", + "toml_edit 0.22.14", ] [[package]] @@ -5746,7 +6178,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap", + "indexmap 2.2.6", "toml_datetime", "winnow 0.5.40", ] @@ -5757,22 +6189,22 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap", + "indexmap 2.2.6", "toml_datetime", "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.22.13" +version = "0.22.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" dependencies = [ - "indexmap", + "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.9", + "winnow 0.6.13", ] [[package]] @@ -5992,9 +6424,9 @@ checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" @@ -6004,9 +6436,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -6026,7 +6458,7 @@ version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b0a51b72ab80ca511d126b77feeeb4fb1e972764653e61feac30adc161a756" dependencies = [ - "base64", + "base64 0.21.7", "log", "pico-args", "usvg-parser", @@ -6089,9 +6521,9 @@ checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" @@ -6304,6 +6736,19 @@ dependencies = [ "wayland-scanner", ] +[[package]] +name = "wayland-protocols-plasma" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" +dependencies = [ + "bitflags 2.5.0", + "wayland-backend", + "wayland-client", + "wayland-protocols 0.31.2", + "wayland-scanner", +] + [[package]] name = "wayland-protocols-wlr" version = "0.2.0" @@ -6428,7 +6873,7 @@ dependencies = [ "bitflags 2.5.0", "cfg_aliases 0.1.1", "codespan-reporting", - "indexmap", + "indexmap 2.2.6", "log", "naga", "once_cell", @@ -6536,7 +6981,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "window_clipboard" version = "0.4.1" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-7#a5be70405574e98c292537fd3b01a1352550b9bf" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-8#7c59b07b9172d8e0401f7e06609e1050575309c9" dependencies = [ "clipboard-win", "clipboard_macos", @@ -6598,13 +7043,22 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "749f0da9cc72d82e600d8d2e44cadd0b9eedb9038f71a1c58556ac1c5791813b" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" dependencies = [ "windows-targets 0.52.5", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -6623,6 +7077,21 @@ dependencies = [ "windows-targets 0.52.5", ] +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -6654,6 +7123,12 @@ dependencies = [ "windows_x86_64_msvc 0.52.5", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -6666,6 +7141,12 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -6678,6 +7159,12 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -6696,6 +7183,12 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -6708,6 +7201,12 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -6720,6 +7219,12 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -6732,6 +7237,12 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -6744,6 +7255,53 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +[[package]] +name = "winit" +version = "0.29.10" +source = "git+https://github.com/pop-os/winit.git?branch=winit-0.29#bdc66109acc85c912264c9e4b864520345bdb45f" +dependencies = [ + "ahash 0.8.11", + "android-activity", + "atomic-waker", + "bitflags 2.5.0", + "bytemuck", + "calloop 0.12.4", + "cfg_aliases 0.1.1", + "core-foundation", + "core-graphics", + "cursor-icon", + "icrate", + "js-sys", + "libc", + "log", + "memmap2 0.9.4", + "ndk", + "ndk-sys", + "objc2", + "once_cell", + "orbclient", + "percent-encoding", + "raw-window-handle", + "redox_syscall 0.3.5", + "rustix 0.38.34", + "sctk-adwaita", + "smithay-client-toolkit 0.18.1", + "smol_str", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols 0.31.2", + "wayland-protocols-plasma", + "web-sys", + "web-time", + "windows-sys 0.48.0", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + [[package]] name = "winnow" version = "0.5.40" @@ -6755,9 +7313,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.9" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86c949fede1d13936a99f14fafd3e76fd642b556dd2ce96287fbe2e0151bfac6" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" dependencies = [ "memchr", ] @@ -6777,6 +7335,17 @@ dependencies = [ "tap", ] +[[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.1" @@ -6812,12 +7381,12 @@ checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" [[package]] name = "xdg-home" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e5a325c3cb8398ad6cf859c1135b25dd29e186679cf2da7581d9679f63b38e" +checksum = "ca91dcf8f93db085f3a0a29358cd0b9d670915468f4290e8b85d118a34211ab8" dependencies = [ "libc", - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -6865,9 +7434,9 @@ dependencies = [ [[package]] name = "xkeysym" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "054a8e68b76250b253f671d1268cb7f1ae089ec35e195b2efb2a4e9a836d0621" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" dependencies = [ "bytemuck", ] @@ -6964,16 +7533,16 @@ dependencies = [ [[package]] name = "zbus" -version = "4.2.2" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989c3977a7aafa97b12b9a35d21cdcff9b0d2289762b14683f45d66b1ba6c48f" +checksum = "23915fcb26e7a9a9dc05fd93a9870d336d6d032cd7e8cebf1c5c37666489fdd5" dependencies = [ - "async-broadcast 0.7.0", + "async-broadcast 0.7.1", "async-executor", "async-fs 2.1.2", - "async-io 2.3.2", - "async-lock 3.3.0", - "async-process 2.2.2", + "async-io 2.3.3", + "async-lock 3.4.0", + "async-process 2.2.3", "async-recursion", "async-task", "async-trait", @@ -6996,7 +7565,7 @@ dependencies = [ "uds_windows", "windows-sys 0.52.0", "xdg-home", - "zbus_macros 4.2.2", + "zbus_macros 4.3.0", "zbus_names 3.0.0", "zvariant 4.1.1", ] @@ -7017,9 +7586,9 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "4.2.2" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe9de53245dcf426b7be226a4217dd5e339080e5d46e64a02d6e5dcbf90fca1" +checksum = "02bcca0b586d2f8589da32347b4784ba424c4891ed86aa5b50d5e88f6b2c4f5d" dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 2c36202..3489fb8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,8 +2,9 @@ members = ["cosmic-settings", "page", "pages/*"] default-members = ["cosmic-settings"] resolver = "2" -rust-version = "1.71.0" -sunrise_sunset = "1.0.1" + +[workspace.package] +rust-version = "1.75.0" [workspace.dependencies] cosmic-randr = { git = "https://github.com/pop-os/cosmic-randr" } @@ -11,7 +12,7 @@ tokio = { version = "1.37.0", features = ["macros"] } [workspace.dependencies.libcosmic] git = "https://github.com/pop-os/libcosmic" -features = ["dbus-config", "single-instance", "tokio", "wayland", "wgpu", "xdg-portal"] +features = ["dbus-config", "single-instance", "multi-window", "tokio", "wayland", "wgpu", "xdg-portal"] [workspace.dependencies.cosmic-config] git = "https://github.com/pop-os/libcosmic" @@ -34,8 +35,13 @@ git = "https://github.com/smithay/client-toolkit/" package = "smithay-client-toolkit" rev = "3bed072" +[profile.dev] +opt-level = 3 +lto = false + [profile.release] opt-level = 3 +lto = "thin" [patch.'https://github.com/smithay/client-toolkit/'] smithay-client-toolkit = { git = "https://github.com/smithay/client-toolkit//", rev = "3bed072" } diff --git a/cosmic-settings/Cargo.toml b/cosmic-settings/Cargo.toml index 1becf66..0bc1c4d 100644 --- a/cosmic-settings/Cargo.toml +++ b/cosmic-settings/Cargo.toml @@ -3,7 +3,6 @@ name = "cosmic-settings" version = "0.1.0" edition = "2021" license = "GPL-3.0" -rust-version = "1.65.0" [dependencies] anyhow = "1.0" @@ -14,9 +13,11 @@ clap = { version = "4.4.18", features = ["derive"] } color-eyre = "0.6.2" cosmic-bg-config.workspace = true cosmic-comp-config.workspace = true +cosmic-config.workspace = true cosmic-panel-config.workspace = true cosmic-randr-shell.workspace = true cosmic-randr.workspace = true +cosmic-settings-config = { git = "https://github.com/pop-os/cosmic-settings-daemon" } cosmic-settings-page = { path = "../page" } cosmic-settings-system = { path = "../pages/system" } cosmic-settings-time = { path = "../pages/time" } diff --git a/cosmic-settings/src/app.rs b/cosmic-settings/src/app.rs index f7631e6..5dfd79c 100644 --- a/cosmic-settings/src/app.rs +++ b/cosmic-settings/src/app.rs @@ -312,6 +312,10 @@ impl cosmic::Application for SettingsApp { page::update!(self.pages, message, desktop::Page); } + crate::pages::Message::DesktopOptions(message) => { + page::update!(self.pages, message, desktop::options::Page); + } + crate::pages::Message::DesktopWallpaper(message) => { if let Some(page) = self.pages.page_mut::() { return page.update(message).map(Into::into); @@ -334,6 +338,66 @@ impl cosmic::Application for SettingsApp { } } + crate::pages::Message::KeyboardShortcuts(message) => { + if let Some(page) = self.pages.page_mut::() { + return page.update(message).map(Into::into); + } + } + + crate::pages::Message::CustomShortcuts(message) => { + if let Some(page) = self + .pages + .page_mut::() + { + return page.update(message).map(Into::into); + } + } + + crate::pages::Message::ManageWindowShortcuts(message) => { + if let Some(page) = self + .pages + .page_mut::() + { + return page.update(message).map(Into::into); + } + } + + crate::pages::Message::MoveWindowShortcuts(message) => { + if let Some(page) = self + .pages + .page_mut::() + { + return page.update(message).map(Into::into); + } + } + + crate::pages::Message::NavShortcuts(message) => { + if let Some(page) = self + .pages + .page_mut::() + { + return page.update(message).map(Into::into); + } + } + + crate::pages::Message::SystemShortcuts(message) => { + if let Some(page) = self + .pages + .page_mut::() + { + return page.update(message).map(Into::into); + } + } + + crate::pages::Message::TilingShortcuts(message) => { + if let Some(page) = self + .pages + .page_mut::() + { + return page.update(message).map(Into::into); + } + } + crate::pages::Message::Input(message) => { if let Some(page) = self.pages.page_mut::() { return page.update(message).map(Into::into); @@ -641,7 +705,9 @@ impl SettingsApp { let page_info = &self.pages.info[self.active_page]; let mut column_widgets = Vec::with_capacity(1 + content.len()); - column_widgets.push(if let Some(parent) = page_info.parent { + column_widgets.push(if let Some(custom_header) = page.header() { + custom_header.map(Message::from) + } else if let Some(parent) = page_info.parent { let page_header = crate::widget::sub_page_header( page_info.title.as_str(), self.pages.info[parent].title.as_str(), diff --git a/cosmic-settings/src/main.rs b/cosmic-settings/src/main.rs index 0529fe9..5831b65 100644 --- a/cosmic-settings/src/main.rs +++ b/cosmic-settings/src/main.rs @@ -5,6 +5,7 @@ #![allow(clippy::cast_sign_loss)] #![allow(clippy::cast_possible_truncation)] #![allow(clippy::cast_lossless)] +#![allow(clippy::too_many_lines)] pub mod app; use std::str::FromStr; diff --git a/cosmic-settings/src/pages/desktop/appearance.rs b/cosmic-settings/src/pages/desktop/appearance.rs index 840889e..9a217aa 100644 --- a/cosmic-settings/src/pages/desktop/appearance.rs +++ b/cosmic-settings/src/pages/desktop/appearance.rs @@ -64,7 +64,7 @@ enum ContextView { } #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] -struct IconTheme { +pub struct IconTheme { // COSMIC uses the file name of the folder containing the theme id: String, // GTK uses the name of the theme as specified in its index file @@ -1073,7 +1073,7 @@ impl page::Page for Page { fn on_enter( &mut self, _: page::Entity, - sender: tokio::sync::mpsc::Sender, + _sender: tokio::sync::mpsc::Sender, ) -> Command { command::future(fetch_icon_themes()).map(crate::pages::Message::Appearance) } diff --git a/cosmic-settings/src/pages/desktop/options.rs b/cosmic-settings/src/pages/desktop/options.rs index 4ae1181..3108efd 100644 --- a/cosmic-settings/src/pages/desktop/options.rs +++ b/cosmic-settings/src/pages/desktop/options.rs @@ -1,21 +1,60 @@ // Copyright 2023 System76 // SPDX-License-Identifier: GPL-3.0-only -use super::Message; use cosmic::{ iced::Length, theme, - widget::{button, container, horizontal_space, icon, row, settings, toggler}, + widget::{self, button, container, horizontal_space, icon, row, settings, toggler}, Apply, Element, }; +use cosmic_config::{ConfigGet, ConfigSet}; +use cosmic_settings_config::{shortcuts, Action, Binding, Shortcuts}; use cosmic_settings_page::Section; use cosmic_settings_page::{self as page, section}; use slab::Slab; use slotmap::SlotMap; -#[derive(Default)] -pub struct Page; +#[derive(Copy, Clone, Debug)] +pub enum Message { + SuperKey(usize), +} + +pub struct Page { + pub super_key_selections: Vec, + pub super_key_active: Option, +} + +impl Default for Page { + fn default() -> Self { + Page { + super_key_selections: vec![ + fl!("super-key", "launcher"), + fl!("super-key", "workspaces"), + fl!("super-key", "applications"), + ], + super_key_active: super_key_active_config(), + } + } +} + +impl Page { + pub fn update(&mut self, message: Message) { + match message { + Message::SuperKey(id) => { + let action = match id { + 0 => shortcuts::action::System::Launcher, + 1 => shortcuts::action::System::WorkspaceOverview, + 2 => shortcuts::action::System::AppLibrary, + _ => return, + }; + + self.super_key_active = Some(id); + super_key_set(action); + } + } + } +} impl page::Page for Page { #[allow(clippy::too_many_lines)] @@ -47,30 +86,26 @@ impl page::AutoBind for Page { pub fn super_key_action() -> Section { let mut descriptions = Slab::new(); - let launcher = descriptions.insert(fl!("super-key-action", "launcher")); - let workspaces = descriptions.insert(fl!("super-key-action", "workspaces")); - let applications = descriptions.insert(fl!("super-key-action", "applications")); + let super_key = descriptions.insert(fl!("super-key")); + let _launcher = descriptions.insert(fl!("super-key", "launcher")); + let _workspaces = descriptions.insert(fl!("super-key", "workspaces")); + let _applications = descriptions.insert(fl!("super-key", "applications")); Section::default() - .title(fl!("super-key-action")) .descriptions(descriptions) - .view::(move |_binder, _page, section| { + .view::(move |_binder, page, section| { let descriptions = §ion.descriptions; settings::view_section(§ion.title) - .add(settings::item( - &descriptions[launcher], - horizontal_space(Length::Fill), - )) - .add(settings::item( - &descriptions[workspaces], - horizontal_space(Length::Fill), - )) - .add(settings::item( - &descriptions[applications], - horizontal_space(Length::Fill), - )) - .into() + .add( + settings::item::builder(&descriptions[super_key]).control(widget::dropdown( + &page.super_key_selections, + page.super_key_active, + Message::SuperKey, + )), + ) + .apply(Element::from) + .map(crate::pages::Message::DesktopOptions) }) } @@ -95,7 +130,7 @@ pub fn window_controls() -> Section { toggler( None, desktop.cosmic_tk.show_minimize, - Message::ShowMinimizeButton, + super::Message::ShowMinimizeButton, ), )) .add(settings::flex_item( @@ -103,7 +138,7 @@ pub fn window_controls() -> Section { toggler( None, desktop.cosmic_tk.show_maximize, - Message::ShowMaximizeButton, + super::Message::ShowMaximizeButton, ), )) .apply(Element::from) @@ -117,7 +152,8 @@ pub fn panel_dock_links() -> Section { .view::(move |binder, _page, section| { // TODO probably a way of getting the entity and its info let mut settings = settings::view_section(§ion.title); - settings = if let Some((panel_entity, panel_info)) = + + if let Some((panel_entity, panel_info)) = binder.info.iter().find(|(_, v)| v.id == "panel") { let control = row::with_children(vec![ @@ -125,7 +161,7 @@ pub fn panel_dock_links() -> Section { icon::from_name("go-next-symbolic").size(16).into(), ]); - settings.add( + settings = settings.add( settings::item::builder(panel_info.title.clone()) .description(panel_info.description.clone()) .control(control) @@ -135,10 +171,8 @@ pub fn panel_dock_links() -> Section { .apply(button) .style(theme::Button::Transparent) .on_press(crate::pages::Message::Page(panel_entity)), - ) - } else { - settings - }; + ); + } settings = if let Some((dock_entity, dock_info)) = binder.info.iter().find(|(_, v)| v.id == "dock") @@ -166,3 +200,39 @@ pub fn panel_dock_links() -> Section { Element::from(settings) }) } + +fn super_key_active_config() -> Option { + let super_binding = Binding::new(shortcuts::Modifiers::new().logo(), None); + + let config = shortcuts::context().ok()?; + let shortcuts = shortcuts::shortcuts(&config); + + let new_id = shortcuts + .iter() + .find(|(binding, _action)| binding == &&super_binding) + .and_then(|(_, action)| match action { + Action::System(shortcuts::action::System::Launcher) => Some(0), + Action::System(shortcuts::action::System::WorkspaceOverview) => Some(1), + Action::System(shortcuts::action::System::AppLibrary) => Some(2), + _ => None, + }); + + new_id +} + +fn super_key_set(action: shortcuts::action::System) { + let Ok(config) = shortcuts::context() else { + return; + }; + + let Ok(mut shortcuts) = config.get::("custom") else { + return; + }; + + shortcuts.0.insert( + Binding::new(shortcuts::Modifiers::new().logo(), None), + Action::System(action), + ); + + _ = config.set("custom", &shortcuts); +} diff --git a/cosmic-settings/src/pages/desktop/wallpaper/mod.rs b/cosmic-settings/src/pages/desktop/wallpaper/mod.rs index 27e3513..e4ea013 100644 --- a/cosmic-settings/src/pages/desktop/wallpaper/mod.rs +++ b/cosmic-settings/src/pages/desktop/wallpaper/mod.rs @@ -211,7 +211,7 @@ impl page::Page for Page { fn on_enter( &mut self, _page: page::Entity, - sender: tokio::sync::mpsc::Sender, + _sender: tokio::sync::mpsc::Sender, ) -> Command { let current_folder = self.config.current_folder().to_owned(); diff --git a/cosmic-settings/src/pages/display/mod.rs b/cosmic-settings/src/pages/display/mod.rs index afb844d..fb39aed 100644 --- a/cosmic-settings/src/pages/display/mod.rs +++ b/cosmic-settings/src/pages/display/mod.rs @@ -311,8 +311,8 @@ impl Page { Message::Mirroring(mirroring) => match mirroring { Mirroring::Disable => (), - Mirroring::Mirror(target_display) => (), - Mirroring::Project(target_display) => (), + Mirroring::Mirror(_target_display) => (), + Mirroring::Project(_target_display) => (), Mirroring::ProjectToAll => (), }, @@ -411,12 +411,12 @@ impl Page { } /// Changes the color depth of the active display. - pub fn set_color_depth(&mut self, depth: ColorDepth) -> Command { + pub fn set_color_depth(&mut self, _depth: ColorDepth) -> Command { unimplemented!() } /// Changes the color profile of the active display. - pub fn set_color_profile(&mut self, profile: usize) -> Command { + pub fn set_color_profile(&mut self, _profile: usize) -> Command { unimplemented!() } diff --git a/cosmic-settings/src/pages/input/keyboard/mod.rs b/cosmic-settings/src/pages/input/keyboard/mod.rs index 2691a6f..31db20e 100644 --- a/cosmic-settings/src/pages/input/keyboard/mod.rs +++ b/cosmic-settings/src/pages/input/keyboard/mod.rs @@ -1,3 +1,5 @@ +pub mod shortcuts; + use std::cmp; use cosmic::{ @@ -404,11 +406,11 @@ impl Page { } } - SourceContext::Settings(id) => { + SourceContext::Settings(_id) => { eprintln!("settings not implemented"); } - SourceContext::ViewLayout(id) => { + SourceContext::ViewLayout(_id) => { eprintln!("view layout not implemented"); } } diff --git a/cosmic-settings/src/pages/input/keyboard/shortcuts.rs b/cosmic-settings/src/pages/input/keyboard/shortcuts.rs deleted file mode 100644 index 6e0efa9..0000000 --- a/cosmic-settings/src/pages/input/keyboard/shortcuts.rs +++ /dev/null @@ -1,47 +0,0 @@ -use cosmic::widget::{column, settings}; -use cosmic::{Apply, Element}; -use cosmic_settings_page::Section; -use cosmic_settings_page::{self as page, section}; -use slab::Slab; -use slotmap::SlotMap; - -#[derive(Default)] -pub struct Page; - -//crate::app::Message::Page - -impl page::Page for Page { - fn content( - &self, - sections: &mut SlotMap>, - ) -> Option { - Some(vec![sections.insert(shortcuts())]) - } - - fn info(&self) -> page::Info { - page::Info::new("keyboard-shortcuts", "input-keyboard-symbolic") - .title(fl!("keyboard-shortcuts")) - .description(fl!("keyboard-shortcuts", "desc")) - } -} - -impl page::AutoBind for Page {} - -fn shortcuts() -> Section { - let descriptions = Slab::new(); - - Section::default() - .descriptions(descriptions) - .view::(move |_binder, _page, section| { - // TODO need something more custom - /* - settings::view_section(§ion.title) - .apply(Element::from) - .map(crate::pages::Message::Input) - */ - column() - .push(settings::view_section(§ion.title)) - .apply(Element::from) - .map(crate::pages::Message::Input) - }) -} diff --git a/cosmic-settings/src/pages/input/keyboard/shortcuts/common.rs b/cosmic-settings/src/pages/input/keyboard/shortcuts/common.rs new file mode 100644 index 0000000..2565158 --- /dev/null +++ b/cosmic-settings/src/pages/input/keyboard/shortcuts/common.rs @@ -0,0 +1,588 @@ +use cosmic::iced::alignment::Horizontal; +use cosmic::iced::{Alignment, Length}; +use cosmic::prelude::CollectionWidget; +use cosmic::widget::{self, button, icon, settings, text}; +use cosmic::{command, theme, Apply, Command, Element}; +use cosmic_config::{ConfigGet, ConfigSet}; +use cosmic_settings_config::shortcuts::{self, Action, Binding, Shortcuts}; +use slab::Slab; +use std::borrow::Cow; +use std::io; +use std::str::FromStr; + +#[derive(Clone, Debug)] +pub enum ShortcutMessage { + AddKeybinding, + ApplyReplace, + CancelReplace, + DeleteBinding(usize), + DeleteShortcut(usize), + EditBinding(usize, bool), + InputBinding(usize, String), + ResetBindings, + ShowShortcut(usize, String), + SubmitBinding(usize), +} + +#[derive(Debug)] +pub struct ShortcutBinding { + pub id: widget::Id, + pub binding: Binding, + pub input: String, + pub editing: bool, + pub is_default: bool, +} + +#[must_use] +#[derive(Debug)] +pub struct ShortcutModel { + pub action: Action, + pub bindings: Slab, + pub description: String, + pub modified: u16, +} + +impl ShortcutModel { + pub fn new(defaults: &Shortcuts, shortcuts: &Shortcuts, action: Action) -> Self { + let (bindings, modified) = + shortcuts + .shortcuts(&action) + .fold((Slab::new(), 0), |(mut slab, modified), binding| { + let is_default = defaults.0.get(binding) == Some(&action); + + slab.insert(ShortcutBinding { + id: widget::Id::unique(), + binding: binding.clone(), + input: String::new(), + editing: false, + is_default, + }); + + (slab, if is_default { modified } else { modified + 1 }) + }); + + Self { + description: super::localize_action(&action), + modified: defaults.0.iter().filter(|(_, a)| **a == action).fold( + modified, + |modified, (binding, _)| { + if bindings.iter().any(|(_, model)| model.binding == *binding) { + modified + } else { + modified + 1 + } + }, + ), + action, + bindings, + } + } +} + +#[must_use] +pub struct Model { + pub defaults: Shortcuts, + pub replace_dialog: Option<(usize, Binding, Action, String)>, + pub shortcut_models: Slab, + pub shortcut_context: Option, + pub config: cosmic_config::Config, + pub custom: bool, + pub actions: fn(&Shortcuts, &Shortcuts) -> Slab, +} + +impl Default for Model { + fn default() -> Self { + Self { + defaults: Shortcuts::default(), + replace_dialog: None, + shortcut_models: Slab::new(), + shortcut_context: None, + config: shortcuts::context().unwrap(), + custom: false, + actions: |_, _| Slab::new(), + } + } +} + +impl Model { + pub fn actions(mut self, actions: fn(&Shortcuts, &Shortcuts) -> Slab) -> Self { + self.actions = actions; + self + } + + pub fn custom(mut self) -> Self { + self.custom = true; + self + } + + /// Adds a new binding to the shortcuts config + pub(super) fn config_add(&self, action: Action, binding: Binding) { + let mut shortcuts = self.shortcuts_config(); + shortcuts.0.insert(binding, action); + self.shortcuts_config_set(shortcuts); + } + + /// Check if a binding is already set + pub(super) fn config_contains(&self, binding: &Binding) -> Option { + self.shortcuts_system_config() + .0 + .get(binding) + .cloned() + .filter(|action| *action != Action::Disable) + } + + /// Removes a binding from the shortcuts config + pub(super) fn config_remove(&self, binding: &Binding) { + let mut shortcuts = self.shortcuts_config(); + shortcuts.0.retain(|b, _| b != binding); + self.shortcuts_config_set(shortcuts); + } + + pub(super) fn context_drawer(&self) -> Option> { + self.shortcut_context + .as_ref() + .map(|id| context_drawer(&self.shortcut_models, *id, self.custom)) + } + + pub(super) fn dialog(&self) -> Option> { + if let Some(&(id, _, _, ref action)) = self.replace_dialog.as_ref() { + if let Some(short_id) = self.shortcut_context { + if let Some(model) = self.shortcut_models.get(short_id) { + if let Some(shortcut) = model.bindings.get(id) { + let primary_action = button::suggested(fl!("replace")) + .on_press(ShortcutMessage::ApplyReplace); + + let secondary_action = button::standard(fl!("cancel")) + .on_press(ShortcutMessage::CancelReplace); + + let dialog = widget::dialog(fl!("replace-shortcut-dialog")) + .icon(icon::from_name("dialog-warning").size(64)) + .body(fl!( + "replace-shortcut-dialog", + "desc", + shortcut = shortcut.input.clone(), + name = shortcut + .binding + .description + .as_ref() + .unwrap_or(action) + .to_owned() + )) + .primary_action(primary_action) + .secondary_action(secondary_action); + + return Some(dialog.into()); + } + } + } + } + + None + } + + pub(super) fn on_enter(&mut self) { + let mut shortcuts = self.config.get::("defaults").unwrap_or_default(); + + self.defaults = shortcuts.clone(); + + if let Ok(custom) = self.config.get::("custom") { + for (binding, action) in custom.0 { + shortcuts.0.remove(&binding); + shortcuts.0.insert(binding, action); + } + } + + self.shortcut_models = (self.actions)(&self.defaults, &shortcuts); + } + + pub(super) fn on_clear(&mut self) { + self.shortcut_models.clear(); + } + + /// Gets the custom configuration for keyboard shortcuts. + pub(super) fn shortcuts_config(&self) -> Shortcuts { + match self.config.get::("custom") { + Ok(shortcuts) => shortcuts, + Err(cosmic_config::Error::GetKey(_, why)) if why.kind() == io::ErrorKind::NotFound => { + Shortcuts::default() + } + Err(why) => { + tracing::error!(?why, "unable to get the current shortcuts config"); + Shortcuts::default() + } + } + } + + /// Gets the system configuration for keyboard shortcuts. + pub(super) fn shortcuts_system_config(&self) -> Shortcuts { + let mut shortcuts = self.config.get::("defaults").unwrap_or_default(); + + if let Ok(custom) = self.config.get::("custom") { + shortcuts.0.extend(custom.0); + } + + shortcuts + } + + /// Writes a new configuration to the keyboard shortcuts config file. + pub(super) fn shortcuts_config_set(&self, shortcuts: Shortcuts) { + if let Err(why) = self.config.set("custom", shortcuts) { + tracing::error!(?why, "failed to write shortcuts config"); + } + } + + #[allow(clippy::too_many_lines)] + pub(super) fn update(&mut self, message: ShortcutMessage) -> Command { + match message { + ShortcutMessage::AddKeybinding => { + if let Some(short_id) = self.shortcut_context { + if let Some(model) = self.shortcut_models.get_mut(short_id) { + // If an empty entry exists, focus it instead of creating a new input. + for (_, shortcut) in &mut model.bindings { + if shortcut.binding.is_set() + || Binding::from_str(&shortcut.input).is_ok() + { + continue; + } + + shortcut.input.clear(); + + return widget::text_input::focus(shortcut.id.clone()); + } + + // Create a new input and focus it. + let id = widget::Id::unique(); + model.bindings.insert(ShortcutBinding { + id: id.clone(), + binding: Binding::default(), + input: String::new(), + editing: true, + is_default: false, + }); + + return widget::text_input::focus(id); + } + } + } + + ShortcutMessage::ApplyReplace => { + if let Some((id, new_binding, ..)) = self.replace_dialog.take() { + if let Some(short_id) = self.shortcut_context { + // Remove conflicting bindings that are saved on disk. + self.config_remove(&new_binding); + + // Clear any binding that matches this in the current model + for (_, model) in &mut self.shortcut_models { + if let Some(id) = model + .bindings + .iter() + .find(|(_, shortcut)| shortcut.binding == new_binding) + .map(|(id, _)| id) + { + model.bindings.remove(id); + break; + } + } + + // Update the current model and save the binding to disk. + if let Some(model) = self.shortcut_models.get_mut(short_id) { + if let Some(shortcut) = model.bindings.get_mut(id) { + let prev_binding = shortcut.binding.clone(); + + shortcut.binding = new_binding.clone(); + shortcut.input.clear(); + shortcut.editing = false; + + let action = model.action.clone(); + self.config_remove(&prev_binding); + self.config_add(action, new_binding); + } + } + + self.on_enter(); + } + } + } + + ShortcutMessage::CancelReplace => self.replace_dialog = None, + + ShortcutMessage::DeleteBinding(id) => { + if let Some(short_id) = self.shortcut_context { + if let Some(model) = self.shortcut_models.get_mut(short_id) { + let shortcut = model.bindings.remove(id); + if shortcut.is_default { + self.config_add(Action::Disable, shortcut.binding.clone()); + } else { + self.config_remove(&shortcut.binding); + } + + self.on_enter(); + } + } + } + + ShortcutMessage::DeleteShortcut(id) => { + let model = self.shortcut_models.remove(id); + for (_, shortcut) in model.bindings { + self.config_remove(&shortcut.binding); + self.on_enter(); + } + } + + ShortcutMessage::EditBinding(id, enable) => { + if let Some(short_id) = self.shortcut_context { + if let Some(model) = self.shortcut_models.get_mut(short_id) { + if let Some(shortcut) = model.bindings.get_mut(id) { + shortcut.editing = enable; + if enable { + shortcut.input = shortcut.binding.to_string(); + return widget::text_input::select_all(shortcut.id.clone()); + } + } + } + } + } + + ShortcutMessage::InputBinding(id, text) => { + if let Some(short_id) = self.shortcut_context { + if let Some(model) = self.shortcut_models.get_mut(short_id) { + if let Some(shortcut) = model.bindings.get_mut(id) { + shortcut.input = text; + } + } + } + } + + // Removes all bindings from the active shortcut context, and reloads the shortcuts model. + ShortcutMessage::ResetBindings => { + if let Some(short_id) = self.shortcut_context { + if let Some(model) = self.shortcut_models.get(short_id) { + for (_, shortcut) in &model.bindings { + self.config_remove(&shortcut.binding); + } + + if let Ok(defaults) = self.config.get::("defaults") { + for (binding, action) in defaults.0 { + if action == model.action { + self.config_remove(&binding); + } + } + } + } + + self.on_enter(); + } + } + + ShortcutMessage::ShowShortcut(id, description) => { + self.shortcut_context = Some(id); + self.replace_dialog = None; + + let mut commands = vec![command::message(crate::app::Message::OpenContextDrawer( + description.into(), + ))]; + + if let Some(model) = self.shortcut_models.get(0) { + if let Some(shortcut) = model.bindings.get(0) { + commands.push(widget::text_input::focus(shortcut.id.clone())); + commands.push(widget::text_input::select_all(shortcut.id.clone())); + } + } + + return Command::batch(commands); + } + + ShortcutMessage::SubmitBinding(id) => { + if let Some(short_id) = self.shortcut_context { + let mut apply_binding = None; + + // Check for conflicts with the new binding. + if let Some(model) = self.shortcut_models.get_mut(short_id) { + if let Some(shortcut) = model.bindings.get_mut(id) { + match Binding::from_str(&shortcut.input) { + Ok(new_binding) => { + if !new_binding.is_set() { + shortcut.input.clear(); + return Command::none(); + } + + if let Some(action) = self.config_contains(&new_binding) { + let action_str = super::localize_action(&action); + self.replace_dialog = + Some((id, new_binding, action, action_str)); + return Command::none(); + } + + apply_binding = Some(new_binding); + } + + Err(why) => { + tracing::error!(why, "keybinding input invalid"); + } + } + } + } + + // Apply if no conflict was found. + if let Some(new_binding) = apply_binding { + if let Some(model) = self.shortcut_models.get_mut(short_id) { + if let Some(shortcut) = model.bindings.get_mut(id) { + let prev_binding = shortcut.binding.clone(); + + shortcut.binding = new_binding.clone(); + shortcut.input.clear(); + shortcut.editing = false; + + let action = model.action.clone(); + self.config_remove(&prev_binding); + self.config_add(action, new_binding); + self.on_enter(); + } + } + } + } + } + } + + Command::none() + } + + pub(super) fn view(&self) -> Element { + self.shortcut_models + .iter() + .map(|(id, shortcut)| shortcut_item(self.custom, id, shortcut)) + .fold(widget::list_column(), widget::ListColumn::add) + .into() + } +} + +fn context_drawer( + shortcuts: &Slab, + id: usize, + show_action: bool, +) -> Element { + let model = &shortcuts[id]; + + let action = show_action.then(|| { + let description = if let Action::Spawn(command) = &model.action { + Cow::Borrowed(command.as_str()) + } else { + Cow::Owned(super::localize_action(&model.action)) + }; + + text::body(description) + }); + + let bindings = model.bindings.iter().enumerate().fold( + widget::list_column().spacing(8), + |section, (_, (bind_id, shortcut))| { + let text: Cow<'_, str> = if !shortcut.editing && shortcut.binding.is_set() { + Cow::Owned(shortcut.binding.to_string()) + } else { + Cow::Borrowed(&shortcut.input) + }; + + let input = widget::editable_input("", text, shortcut.editing, move |enable| { + ShortcutMessage::EditBinding(bind_id, enable) + }) + .select_on_focus(true) + .on_input(move |text| ShortcutMessage::InputBinding(bind_id, text)) + .on_submit(ShortcutMessage::SubmitBinding(bind_id)) + .padding([0, 12]) + .id(shortcut.id.clone()) + .into(); + + let delete_button = widget::button::icon(icon::from_name("edit-delete-symbolic")) + .on_press(ShortcutMessage::DeleteBinding(bind_id)) + .into(); + + let flex_control = + settings::flex_item_row(vec![input, delete_button]).align_items(Alignment::Center); + + section.add(flex_control) + }, + ); + + // TODO: Detect when it is necessary + let reset_keybinding_button = if show_action { + None + } else { + let button = widget::button::standard(fl!("reset-to-default")) + .on_press(ShortcutMessage::ResetBindings); + Some(button) + }; + + let add_keybinding_button = + widget::button::standard(fl!("add-keybinding")).on_press(ShortcutMessage::AddKeybinding); + + let button_container = widget::row::with_capacity(2) + .push_maybe(reset_keybinding_button) + .push(add_keybinding_button) + .spacing(12) + .apply(widget::container) + .width(Length::Fill) + .align_x(Horizontal::Right); + + widget::column::with_capacity(if show_action { 3 } else { 2 }) + .spacing(32) + .push_maybe(action) + .push(bindings) + .push(button_container) + .into() +} + +/// Display a shortcut as a list item +fn shortcut_item(custom: bool, id: usize, data: &ShortcutModel) -> Element { + #[derive(Copy, Clone, Debug)] + enum LocalMessage { + Remove, + Show, + } + + let bindings = data + .bindings + .iter() + .take(3) + .filter(|(_, shortcut)| shortcut.binding.is_set()) + .map(|(_, shortcut)| widget::text::body(shortcut.binding.to_string()).into()) + .collect::>(); + + let shortcuts: Element = if bindings.is_empty() { + widget::text::body(fl!("disabled")).into() + } else { + widget::column::with_children(bindings) + .align_items(Alignment::End) + .into() + }; + + let modified = if data.modified == 0 { + None + } else { + Some(widget::text::body(fl!("modified", count = data.modified))) + }; + + let control = widget::row::with_capacity(4) + .push_maybe(modified) + .push(shortcuts) + .push(icon::from_name("go-next-symbolic").size(16)) + .push_maybe(custom.then(|| { + widget::button::icon(icon::from_name("edit-delete-symbolic")) + .on_press(LocalMessage::Remove) + })) + .align_items(Alignment::Center) + .spacing(8); + + settings::item::builder(&data.description) + .flex_control(control) + .spacing(16) + .apply(widget::container) + .style(theme::Container::List) + .apply(widget::button) + .style(theme::Button::Transparent) + .on_press(LocalMessage::Show) + .apply(Element::from) + .map(move |message| match message { + LocalMessage::Show => ShortcutMessage::ShowShortcut(id, data.description.clone()), + LocalMessage::Remove => ShortcutMessage::DeleteShortcut(id), + }) +} diff --git a/cosmic-settings/src/pages/input/keyboard/shortcuts/custom.rs b/cosmic-settings/src/pages/input/keyboard/shortcuts/custom.rs new file mode 100644 index 0000000..482261c --- /dev/null +++ b/cosmic-settings/src/pages/input/keyboard/shortcuts/custom.rs @@ -0,0 +1,440 @@ +use std::str::FromStr; + +use super::{ShortcutBinding, ShortcutMessage, ShortcutModel}; +use cosmic::iced::alignment::Horizontal; +use cosmic::iced::Length; +use cosmic::widget::{self, button, icon}; +use cosmic::{Apply, Command, Element}; +use cosmic_settings_config::shortcuts::{Action, Shortcuts}; +use cosmic_settings_config::Binding; +use cosmic_settings_page::{self as page, section, Section}; +use slab::Slab; +use slotmap::SlotMap; + +pub struct Page { + model: super::Model, + add_shortcut: AddShortcut, + replace_dialog: Vec<(Binding, Action, String)>, + command_id: widget::Id, + name_id: widget::Id, +} + +impl Default for Page { + fn default() -> Self { + Self { + model: super::Model::default().custom().actions(bindings), + add_shortcut: AddShortcut::default(), + replace_dialog: Vec::new(), + command_id: widget::Id::unique(), + name_id: widget::Id::unique(), + } + } +} + +#[derive(Clone, Debug)] +pub enum Message { + /// Adds a new key binding input + AddKeybinding, + /// Add a new custom shortcut to the config + AddShortcut, + /// Update the command text input + CommandInput(String), + /// Toggle editing of the key text input + EditCombination, + /// Toggle editability of the key text input + KeyEditing(usize, bool), + /// Update the key text input + KeyInput(usize, String), + /// Update the name text input + NameInput(String), + /// Enter key pressed in the name text input + NameSubmit, + /// Apply a requested shortcut replace operation + ReplaceApply, + /// Cancel a requested shortcut replace operation + ReplaceCancel, + /// Emit a generic shortcut message + Shortcut(ShortcutMessage), + /// Open the add shortcut context drawer + ShortcutContext, +} + +#[derive(Default)] +struct AddShortcut { + pub active: bool, + pub name: String, + pub command: String, + pub keys: Slab<(String, widget::Id, bool)>, +} + +impl AddShortcut { + pub fn enable(&mut self) { + self.active = true; + self.name.clear(); + self.command.clear(); + + if self.keys.is_empty() { + self.keys + .insert((String::new(), widget::Id::unique(), false)); + } else { + while self.keys.len() > 1 { + self.keys.remove(self.keys.len() - 1); + } + + self.keys[0].0.clear(); + } + } +} + +impl Page { + pub fn update(&mut self, message: Message) -> Command { + match message { + Message::CommandInput(text) => { + self.add_shortcut.command = text; + } + + Message::KeyInput(id, text) => { + self.add_shortcut.keys[id].0 = text; + } + + Message::KeyEditing(id, enable) => { + self.add_shortcut.keys[id].2 = enable; + } + + Message::NameInput(text) => { + self.add_shortcut.name = text; + } + + Message::AddKeybinding => { + // If an empty entry exists, focus it instead of creating a new input. + for (_, (binding, id, _)) in &mut self.add_shortcut.keys { + if Binding::from_str(binding).is_ok() { + continue; + } + + binding.clear(); + + return widget::text_input::focus(id.clone()); + } + + let new_id = widget::Id::unique(); + self.add_shortcut + .keys + .insert((String::new(), new_id.clone(), true)); + return Command::batch(vec![ + widget::text_input::focus(new_id.clone()), + widget::text_input::select_all(new_id), + ]); + } + + Message::AddShortcut => { + let name = self.add_shortcut.name.trim(); + let command = self.add_shortcut.command.trim(); + + if name.is_empty() || command.is_empty() { + return Command::none(); + } + + let mut addable_bindings = Vec::new(); + + for (_, (keys, ..)) in &self.add_shortcut.keys { + if keys.is_empty() { + continue; + } + + let Ok(binding) = Binding::from_str(keys) else { + return Command::none(); + }; + + if !binding.is_set() { + return Command::none(); + } + + if let Some(action) = self.model.config_contains(&binding) { + let action_str = super::localize_action(&action); + self.replace_dialog.push((binding, action, action_str)); + continue; + } + + addable_bindings.push(binding); + } + + for binding in addable_bindings { + self.add_shortcut(binding); + } + + self.model.on_enter(); + } + + Message::EditCombination => { + let (_, id, editing) = &mut self.add_shortcut.keys[0]; + *editing = true; + return Command::batch(vec![ + widget::text_input::focus(id.clone()), + widget::text_input::select_all(id.clone()), + ]); + } + + Message::NameSubmit => { + if !self.add_shortcut.name.trim().is_empty() { + return widget::text_input::focus(self.command_id.clone()); + } + } + + Message::ReplaceApply => { + if let Some((binding, ..)) = self.replace_dialog.pop() { + self.model.config_remove(&binding); + self.add_shortcut(binding); + + if self.replace_dialog.is_empty() { + self.model.on_enter(); + } + } + } + + Message::ReplaceCancel => { + _ = self.replace_dialog.pop(); + if self.replace_dialog.is_empty() { + self.model.on_enter(); + } + } + + Message::Shortcut(message) => { + if let ShortcutMessage::ShowShortcut(..) = message { + self.add_shortcut.active = false; + } + + return self.model.update(message); + } + + Message::ShortcutContext => { + self.add_shortcut.enable(); + return Command::batch(vec![ + cosmic::command::message(crate::app::Message::OpenContextDrawer( + fl!("custom-shortcuts", "context").into(), + )), + widget::text_input::focus(self.name_id.clone()), + ]); + } + } + + Command::none() + } + + fn add_keybinding_context(&self) -> Element<'_, Message> { + let name_input = widget::text_input("", &self.add_shortcut.name) + .padding([6, 12]) + .on_input(Message::NameInput) + .on_submit(Message::NameSubmit) + .id(self.name_id.clone()); + + let command_input = widget::text_input("", &self.add_shortcut.command) + .padding([6, 12]) + .on_input(Message::CommandInput) + .on_submit(Message::EditCombination) + .id(self.command_id.clone()); + + let name_control = widget::column() + .spacing(4) + .push(widget::text::body(fl!("shortcut-name"))) + .push(name_input); + + let command_control = widget::column() + .spacing(4) + .push(widget::text::body(fl!("command"))) + .push(command_input); + + let input_fields = widget::column() + .spacing(12) + .push(name_control) + .push(command_control) + .padding([16, 24]); + + let keys = self.add_shortcut.keys.iter().fold( + widget::list_column().spacing(0), + |column, (id, (text, widget_id, editing))| { + let key_combination = widget::editable_input( + fl!("type-key-combination"), + text, + *editing, + move |enable| Message::KeyEditing(id, enable), + ) + .padding([0, 12]) + .on_input(move |input| Message::KeyInput(id, input)) + .on_submit(Message::AddKeybinding) + .id(widget_id.clone()) + .apply(widget::container) + .padding([8, 24]); + + column.add(key_combination) + }, + ); + + let controls = widget::list_column().add(input_fields).add(keys).spacing(0); + + let add_keybinding_button = widget::button::standard(fl!("add-keybinding")) + .on_press(Message::AddShortcut) + .apply(widget::container) + .width(Length::Fill) + .align_x(Horizontal::Right); + + widget::column() + .spacing(32) + .push(controls) + .push(add_keybinding_button) + .into() + } + + fn add_shortcut(&mut self, mut binding: Binding) { + self.add_shortcut.active = !self.replace_dialog.is_empty(); + binding.description = Some(self.add_shortcut.name.clone()); + let new_action = Action::Spawn(self.add_shortcut.command.clone()); + self.model.config_add(new_action, binding); + } +} + +impl page::Page for Page { + fn info(&self) -> page::Info { + page::Info::new("custom-shortcuts", "input-keyboard-symbolic") + .title(fl!("custom-shortcuts")) + } + + fn content( + &self, + sections: &mut SlotMap>, + ) -> Option { + Some(vec![sections.insert(shortcuts())]) + } + + fn dialog(&self) -> Option> { + // Check if a new shortcut is being added that requires a replace dialog. + if let Some((binding, _action, action_str)) = self.replace_dialog.last() { + let primary_action = button::suggested(fl!("replace")).on_press(Message::ReplaceApply); + + let secondary_action = button::standard(fl!("cancel")).on_press(Message::ReplaceCancel); + + let dialog = widget::dialog(fl!("replace-shortcut-dialog")) + .icon(icon::from_name("dialog-warning").size(64)) + .body(fl!( + "replace-shortcut-dialog", + "desc", + shortcut = binding.to_string(), + name = action_str.clone() + )) + .primary_action(primary_action) + .secondary_action(secondary_action) + .apply(Element::from) + .map(crate::pages::Message::CustomShortcuts); + + return Some(dialog); + } + + // Check if a keybinding is being added that requires a replace dialog. + self.model + .dialog() + .map(|el| el.map(|m| crate::pages::Message::CustomShortcuts(Message::Shortcut(m)))) + } + + fn context_drawer(&self) -> Option> { + if self.add_shortcut.active { + Some(self.add_keybinding_context()) + } else { + self.model + .context_drawer() + .map(|el| el.map(Message::Shortcut)) + } + .map(|el| el.map(crate::pages::Message::CustomShortcuts)) + } + + fn on_enter( + &mut self, + _page: cosmic_settings_page::Entity, + _sender: tokio::sync::mpsc::Sender, + ) -> Command { + self.model.on_enter(); + Command::none() + } + + fn on_leave(&mut self) -> Command { + self.model.on_clear(); + Command::none() + } +} + +impl page::AutoBind for Page {} + +fn bindings(_defaults: &Shortcuts, keybindings: &Shortcuts) -> Slab { + keybindings + .iter() + .fold(Slab::new(), |mut slab, (binding, action)| { + if let Action::Spawn(command) = action { + let description = binding + .description + .clone() + .unwrap_or_else(|| command.to_owned()); + + let new_binding = ShortcutBinding { + id: widget::Id::unique(), + binding: binding.clone(), + input: String::new(), + editing: false, + is_default: false, + }; + + if let Some((_, existing_model)) = + slab.iter_mut().find(|(_, m)| &m.action == action) + { + existing_model.description = description; + existing_model.bindings.insert(new_binding); + } else { + slab.insert(ShortcutModel { + action: action.clone(), + bindings: { + let mut slab = Slab::new(); + slab.insert(new_binding); + slab + }, + description, + modified: 0, + }); + } + } + + slab + }) +} + +fn shortcuts() -> Section { + let descriptions = Slab::new(); + + // TODO: Add shortcuts to descriptions + + Section::default() + .descriptions(descriptions) + .view::(move |_binder, page, _section| { + let content = if page.model.shortcut_models.is_empty() { + widget::settings::view_section("") + .add(widget::settings::item_row(vec![widget::text::body(fl!( + "custom-shortcuts", + "none" + )) + .into()])) + .into() + } else { + page.model.view().map(Message::Shortcut) + }; + + let add_shortcut = widget::button::standard(fl!("custom-shortcuts", "add")) + .on_press(Message::ShortcutContext) + .apply(widget::container) + .width(Length::Fill) + .align_x(Horizontal::Right); + + widget::column() + .push(content) + .push(add_shortcut) + .spacing(24) + .apply(Element::from) + .map(crate::pages::Message::CustomShortcuts) + }) +} diff --git a/cosmic-settings/src/pages/input/keyboard/shortcuts/manage_windows.rs b/cosmic-settings/src/pages/input/keyboard/shortcuts/manage_windows.rs new file mode 100644 index 0000000..7f31612 --- /dev/null +++ b/cosmic-settings/src/pages/input/keyboard/shortcuts/manage_windows.rs @@ -0,0 +1,99 @@ +use super::{ShortcutMessage, ShortcutModel}; +use cosmic::{Command, Element}; +use cosmic_settings_config::shortcuts::action::ResizeDirection; +use cosmic_settings_config::shortcuts::Action; +use cosmic_settings_page::{self as page, section, Section}; +use slab::Slab; + +pub struct Page { + model: super::Model, +} + +impl Default for Page { + fn default() -> Self { + Self { + model: super::Model::default().actions(|defaults, keybindings| { + actions().iter().fold(Slab::new(), |mut slab, action| { + slab.insert(ShortcutModel::new(defaults, keybindings, action.clone())); + slab + }) + }), + } + } +} + +impl Page { + pub fn update(&mut self, message: ShortcutMessage) -> Command { + self.model.update(message) + } +} + +impl page::Page for Page { + fn info(&self) -> page::Info { + page::Info::new("manage-windows", "input-keyboard-symbolic").title(fl!("manage-windows")) + } + + fn content( + &self, + sections: &mut slotmap::SlotMap>, + ) -> Option { + Some(vec![sections.insert(shortcuts())]) + } + + fn context_drawer(&self) -> Option> { + self.model + .context_drawer() + .map(|el| el.map(crate::pages::Message::ManageWindowShortcuts)) + } + + fn dialog(&self) -> Option> { + self.model + .dialog() + .map(|el| el.map(crate::pages::Message::ManageWindowShortcuts)) + } + + fn on_enter( + &mut self, + _page: cosmic_settings_page::Entity, + _sender: tokio::sync::mpsc::Sender, + ) -> Command { + self.model.on_enter(); + + Command::none() + } + + fn on_leave(&mut self) -> Command { + self.model.on_clear(); + Command::none() + } +} + +impl page::AutoBind for Page {} + +#[must_use] +pub const fn actions() -> &'static [Action] { + &[ + Action::Close, + Action::Maximize, + Action::Minimize, + Action::Resizing(ResizeDirection::Inwards), + Action::Resizing(ResizeDirection::Outwards), + Action::ToggleSticky, + ] +} +fn shortcuts() -> Section { + let mut descriptions = Slab::new(); + + // Make these searchable in the global settings search. + for action in actions() { + descriptions.insert(super::localize_action(action)); + } + + Section::default() + .descriptions(descriptions) + .view::(move |_binder, page, _section| { + page.model + .view() + .map(crate::pages::Message::ManageWindowShortcuts) + }) +} diff --git a/cosmic-settings/src/pages/input/keyboard/shortcuts/mod.rs b/cosmic-settings/src/pages/input/keyboard/shortcuts/mod.rs new file mode 100644 index 0000000..0805fe9 --- /dev/null +++ b/cosmic-settings/src/pages/input/keyboard/shortcuts/mod.rs @@ -0,0 +1,620 @@ +mod common; +pub use common::{Model, ShortcutBinding, ShortcutMessage, ShortcutModel}; + +pub mod custom; +pub mod manage_windows; +pub mod move_window; +pub mod nav; +pub mod system; +pub mod tiling; + +use cosmic::iced::Length; +use cosmic::widget::{self, icon, settings, text}; +use cosmic::{command, theme, Apply, Command, Element}; +use cosmic_config::ConfigGet; +use cosmic_settings_config::shortcuts::action::{ + Direction, FocusDirection, Orientation, ResizeDirection, +}; +use cosmic_settings_config::shortcuts::{self, Action, Shortcuts}; +use cosmic_settings_page::Section; +use cosmic_settings_page::{self as page, section}; +use shortcuts::action::System as SystemAction; +use slab::Slab; +use slotmap::{DefaultKey, Key, SecondaryMap, SlotMap}; + +pub struct Page { + modified: Modified, + search: Search, + search_model: Model, + shortcuts_context: Option, + sub_pages: SubPages, +} + +#[derive(Default)] +struct Modified { + manage_windows: u16, + move_windows: u16, + nav: u16, + system: u16, + window_tiling: u16, + custom: u16, +} + +struct SubPages { + custom: page::Entity, + manage_window: page::Entity, + move_window: page::Entity, + nav: page::Entity, + system: page::Entity, + window_tiling: page::Entity, +} + +#[derive(Default)] +struct Search { + input: String, + actions: SlotMap, + localized: SecondaryMap, + shortcuts: Shortcuts, + defaults: Shortcuts, +} + +#[derive(Clone, Debug)] +pub enum Message { + Category(Category), + Search(String), + SearchShortcut(ShortcutMessage), +} + +#[derive(Clone, Copy, Debug)] +pub enum Category { + Custom, + ManageWindow, + MoveWindow, + Nav, + System, + WindowTiling, +} + +impl Default for Page { + fn default() -> Self { + Self { + modified: Modified::default(), + search: Search::default(), + search_model: Model::default(), + shortcuts_context: None, + sub_pages: SubPages { + custom: page::Entity::null(), + manage_window: page::Entity::null(), + move_window: page::Entity::null(), + nav: page::Entity::null(), + system: page::Entity::null(), + window_tiling: page::Entity::null(), + }, + } + } +} + +impl page::Page for Page { + fn content( + &self, + sections: &mut SlotMap>, + ) -> Option { + Some(vec![sections.insert(shortcuts())]) + } + + fn info(&self) -> page::Info { + page::Info::new("keyboard-shortcuts", "input-keyboard-symbolic") + .title(fl!("keyboard-shortcuts")) + .description(fl!("keyboard-shortcuts", "desc")) + } + + fn context_drawer(&self) -> Option> { + if self.search_model.shortcut_models.is_empty() { + None + } else { + self.search_model.context_drawer().map(|el| { + el.map(|msg| crate::pages::Message::KeyboardShortcuts(Message::SearchShortcut(msg))) + }) + } + } + + fn dialog(&self) -> Option> { + if self.search_model.shortcut_models.is_empty() { + None + } else { + self.search_model.dialog().map(|el| { + el.map(|msg| crate::pages::Message::KeyboardShortcuts(Message::SearchShortcut(msg))) + }) + } + } + + fn on_enter( + &mut self, + _page: cosmic_settings_page::Entity, + _sender: tokio::sync::mpsc::Sender, + ) -> Command { + if self.shortcuts_context.is_none() { + self.shortcuts_context = cosmic_settings_config::shortcuts::context().ok(); + } + + if let Some(context) = self.shortcuts_context.as_ref() { + let mut defaults = context.get::("defaults").unwrap_or_default(); + let custom = context.get::("custom").unwrap_or_default(); + + for (custom_binding, custom_action) in &custom.0 { + // Skip bindings for the super key + if custom_binding.is_super() { + continue; + } + + // Check if a custom binding overrides a default binding, or is in addition to it. + match defaults.0.get(custom_binding) { + Some(default_action) if default_action == custom_action => continue, + _ => (), + } + + match action_category(custom_action) { + Some(Category::ManageWindow) => self.modified.manage_windows += 1, + Some(Category::MoveWindow) => self.modified.move_windows += 1, + Some(Category::Nav) => self.modified.nav += 1, + Some(Category::System) => self.modified.system += 1, + Some(Category::WindowTiling) => self.modified.window_tiling += 1, + None | Some(Category::Custom) => (), + } + } + + // Check if default bindings are missing + for (binding, action) in &defaults.0 { + if binding.is_super() { + continue; + } + + match custom.0.get(binding) { + Some(custom_action) if action != custom_action => (), + _ => continue, + }; + + match action_category(action) { + Some(Category::ManageWindow) => self.modified.manage_windows += 1, + Some(Category::MoveWindow) => self.modified.move_windows += 1, + Some(Category::Nav) => self.modified.nav += 1, + Some(Category::System) => self.modified.system += 1, + Some(Category::WindowTiling) => self.modified.window_tiling += 1, + None | Some(Category::Custom) => (), + } + } + + self.search.defaults = defaults.clone(); + defaults.0.extend(custom.0); + self.search.shortcuts = defaults; + } + + Command::none() + } + + fn on_leave(&mut self) -> Command { + self.search.actions.clear(); + self.search.localized.clear(); + self.search.input.clear(); + self.search_model.on_clear(); + self.modified.custom = 0; + self.modified.manage_windows = 0; + self.modified.move_windows = 0; + self.modified.nav = 0; + self.modified.system = 0; + Command::none() + } +} + +impl Page { + pub fn update(&mut self, message: Message) -> Command { + match message { + Message::Category(category) => match category { + Category::Custom => { + command::message(crate::app::Message::Page(self.sub_pages.custom)) + } + + Category::ManageWindow => { + command::message(crate::app::Message::Page(self.sub_pages.manage_window)) + } + + Category::MoveWindow => { + command::message(crate::app::Message::Page(self.sub_pages.move_window)) + } + + Category::Nav => command::message(crate::app::Message::Page(self.sub_pages.nav)), + + Category::System => { + command::message(crate::app::Message::Page(self.sub_pages.system)) + } + + Category::WindowTiling => { + command::message(crate::app::Message::Page(self.sub_pages.window_tiling)) + } + }, + + Message::Search(input) => { + self.search(input); + Command::none() + } + + Message::SearchShortcut(message) => self.search_model.update(message), + } + } + + fn search(&mut self, input: String) { + self.search.input = input; + if self.search.input.is_empty() { + self.search_model.on_clear(); + return; + } + + if self.search.actions.is_empty() { + self.search.cache_localized_actions(); + } + + self.search_model.shortcut_models = self.search.shortcut_models(); + } +} + +impl page::AutoBind for Page { + fn sub_pages( + mut page: cosmic_settings_page::Insert, + ) -> cosmic_settings_page::Insert { + let custom = page.sub_page_with_id::(); + let manage_window = page.sub_page_with_id::(); + let move_window = page.sub_page_with_id::(); + let nav = page.sub_page_with_id::(); + let system = page.sub_page_with_id::(); + let window_tiling = page.sub_page_with_id::(); + + let model = page.model.page_mut::().unwrap(); + model.sub_pages.custom = custom; + model.sub_pages.manage_window = manage_window; + model.sub_pages.move_window = move_window; + model.sub_pages.nav = nav; + model.sub_pages.system = system; + model.sub_pages.window_tiling = window_tiling; + + page + } +} + +impl Search { + fn cache_localized_actions(&mut self) { + self.actions.clear(); + self.localized.clear(); + + for action in all_actions() { + let localized = localize_action(action); + let id = self.actions.insert(action.clone()); + self.localized.insert(id, localized); + } + } + + fn shortcut_models(&mut self) -> Slab { + let input = self.input.to_lowercase(); + self.actions + .iter() + .filter(|(id, _)| self.localized[*id].to_lowercase().contains(&input)) + .fold(Slab::new(), |mut slab, (_, action)| { + slab.insert(ShortcutModel::new( + &self.defaults, + &self.shortcuts, + action.clone(), + )); + + slab + }) + } +} + +fn shortcuts() -> Section { + let mut descriptions = Slab::new(); + + let custom_label = descriptions.insert(fl!("custom")); + let manage_window_label = descriptions.insert(fl!("manage-windows")); + let move_window_label = descriptions.insert(fl!("move-windows")); + let nav_label = descriptions.insert(fl!("nav-shortcuts")); + let system_label = descriptions.insert(fl!("system-shortcut")); + let window_tiling_label = descriptions.insert(fl!("window-tiling")); + + Section::default() + .descriptions(descriptions) + .view::(move |_binder, page, section| { + let descriptions = §ion.descriptions; + + let search = widget::search_input(fl!("type-to-search"), &page.search.input) + .width(314) + .on_clear(Message::Search(String::new())) + .on_input(Message::Search) + .apply(widget::container) + .center_x() + .width(Length::Fill); + + // If the search input is not empty, show the category view, else the search results. + let content = if page.search.input.is_empty() { + settings::view_section("") + .add(category_item( + Category::ManageWindow, + &descriptions[manage_window_label], + page.modified.manage_windows, + )) + .add(category_item( + Category::MoveWindow, + &descriptions[move_window_label], + page.modified.move_windows, + )) + .add(category_item( + Category::Nav, + &descriptions[nav_label], + page.modified.nav, + )) + .add(category_item( + Category::System, + &descriptions[system_label], + page.modified.system, + )) + .add(category_item( + Category::WindowTiling, + &descriptions[window_tiling_label], + page.modified.window_tiling, + )) + .add(category_item( + Category::Custom, + &descriptions[custom_label], + page.modified.custom, + )) + .apply(Element::from) + } else { + page.search_model.view().map(Message::SearchShortcut) + }; + + widget::column::with_capacity(2) + .spacing(32) + .push(search) + .push(content) + .apply(Element::from) + .map(crate::pages::Message::KeyboardShortcuts) + }) +} + +/// Display a category as a list item +fn category_item(category: Category, name: &str, modified: u16) -> Element { + let icon = icon::from_name("go-next-symbolic").size(16); + + let control = if modified == 0 { + Element::from(icon) + } else { + widget::row() + .push(text::body(fl!("modified", count = modified))) + .push(icon) + .into() + }; + + settings::item::builder(name) + .control(control) + .spacing(16) + .apply(widget::container) + .style(theme::Container::List) + .apply(widget::button) + .style(theme::Button::Transparent) + .on_press(Message::Category(category)) + .into() +} + +fn action_category(action: &Action) -> Option { + Some(if manage_windows::actions().contains(action) { + Category::ManageWindow + } else if move_window::actions().contains(action) { + Category::MoveWindow + } else if nav::actions().contains(action) { + Category::Nav + } else if system::actions().contains(action) { + Category::System + } else { + return None; + }) +} + +fn all_actions() -> &'static [Action] { + &[ + Action::Close, + Action::Debug, + Action::Focus(FocusDirection::Down), + Action::Focus(FocusDirection::In), + Action::Focus(FocusDirection::Left), + Action::Focus(FocusDirection::Out), + Action::Focus(FocusDirection::Right), + Action::Focus(FocusDirection::Up), + Action::LastWorkspace, + Action::Maximize, + Action::MigrateWorkspaceToNextOutput, + Action::MigrateWorkspaceToOutput(Direction::Down), + Action::MigrateWorkspaceToOutput(Direction::Left), + Action::MigrateWorkspaceToOutput(Direction::Right), + Action::MigrateWorkspaceToOutput(Direction::Up), + Action::MigrateWorkspaceToPreviousOutput, + Action::Minimize, + Action::Move(Direction::Down), + Action::Move(Direction::Left), + Action::Move(Direction::Right), + Action::Move(Direction::Up), + Action::MoveToLastWorkspace, + Action::MoveToNextOutput, + Action::MoveToNextWorkspace, + Action::MoveToOutput(Direction::Down), + Action::MoveToOutput(Direction::Left), + Action::MoveToOutput(Direction::Right), + Action::MoveToOutput(Direction::Up), + Action::MoveToPreviousOutput, + Action::MoveToPreviousWorkspace, + Action::MoveToWorkspace(1), + Action::MoveToWorkspace(2), + Action::MoveToWorkspace(3), + Action::MoveToWorkspace(4), + Action::MoveToWorkspace(5), + Action::MoveToWorkspace(6), + Action::MoveToWorkspace(7), + Action::MoveToWorkspace(8), + Action::MoveToWorkspace(9), + Action::NextOutput, + Action::NextWorkspace, + Action::Orientation(Orientation::Horizontal), + Action::Orientation(Orientation::Vertical), + Action::PreviousOutput, + Action::PreviousWorkspace, + Action::Resizing(ResizeDirection::Inwards), + Action::Resizing(ResizeDirection::Outwards), + Action::SwapWindow, + Action::SwitchOutput(Direction::Down), + Action::SwitchOutput(Direction::Left), + Action::SwitchOutput(Direction::Right), + Action::SwitchOutput(Direction::Up), + Action::System(SystemAction::AppLibrary), + Action::System(SystemAction::BrightnessDown), + Action::System(SystemAction::BrightnessUp), + Action::System(SystemAction::HomeFolder), + Action::System(SystemAction::KeyboardBrightnessDown), + Action::System(SystemAction::KeyboardBrightnessUp), + Action::System(SystemAction::Launcher), + Action::System(SystemAction::LockScreen), + Action::System(SystemAction::Mute), + Action::System(SystemAction::MuteMic), + Action::System(SystemAction::Screenshot), + Action::System(SystemAction::Terminal), + Action::System(SystemAction::VolumeLower), + Action::System(SystemAction::VolumeRaise), + Action::System(SystemAction::WebBrowser), + Action::System(SystemAction::WindowSwitcher), + Action::System(SystemAction::WorkspaceOverview), + Action::Terminate, + Action::ToggleOrientation, + Action::ToggleStacking, + Action::ToggleSticky, + Action::ToggleTiling, + Action::ToggleWindowFloating, + Action::Workspace(1), + Action::Workspace(2), + Action::Workspace(3), + Action::Workspace(4), + Action::Workspace(5), + Action::Workspace(6), + Action::Workspace(7), + Action::Workspace(8), + Action::Workspace(9), + ] +} + +fn localize_action(action: &Action) -> String { + match action { + Action::Close => fl!("manage-windows", "close"), + Action::Disable => fl!("disabled"), + Action::Focus(FocusDirection::Down) => fl!("nav-shortcuts", "focus", direction = "down"), + Action::Focus(FocusDirection::In) => fl!("nav-shortcuts", "focus", direction = "in"), + Action::Focus(FocusDirection::Left) => fl!("nav-shortcuts", "focus", direction = "left"), + Action::Focus(FocusDirection::Out) => fl!("nav-shortcuts", "focus", direction = "out"), + Action::Focus(FocusDirection::Right) => fl!("nav-shortcuts", "focus", direction = "right"), + Action::Focus(FocusDirection::Up) => fl!("nav-shortcuts", "focus", direction = "up"), + Action::Workspace(i) => fl!("nav-shortcuts", "workspace", num = (*i as usize)), + Action::LastWorkspace => fl!("nav-shortcuts", "last-workspace"), + Action::Maximize => fl!("manage-windows", "maximize"), + Action::Minimize => fl!("manage-windows", "minimize"), + Action::Move(Direction::Down) => fl!("move-windows", "direction", direction = "down"), + Action::Move(Direction::Right) => fl!("move-windows", "direction", direction = "right"), + Action::Move(Direction::Left) => fl!("move-windows", "direction", direction = "left"), + Action::Move(Direction::Up) => fl!("move-windows", "direction", direction = "up"), + Action::MoveToLastWorkspace | Action::SendToLastWorkspace => { + fl!("move-windows", "last-workspace") + } + Action::MoveToNextOutput | Action::SendToNextOutput => fl!("move-windows", "next-display"), + Action::MoveToNextWorkspace | Action::SendToNextWorkspace => { + fl!("move-windows", "next-workspace") + } + Action::MoveToPreviousWorkspace | Action::SendToPreviousWorkspace => { + fl!("move-windows", "prev-workspace") + } + Action::MoveToOutput(Direction::Down) | Action::SendToOutput(Direction::Down) => { + fl!("move-windows", "display", direction = "down") + } + Action::MoveToOutput(Direction::Left) | Action::SendToOutput(Direction::Left) => { + fl!("move-windows", "display", direction = "left") + } + Action::MoveToOutput(Direction::Right) | Action::SendToOutput(Direction::Right) => { + fl!("move-windows", "display", direction = "right") + } + Action::MoveToOutput(Direction::Up) | Action::SendToOutput(Direction::Up) => { + fl!("move-windows", "display", direction = "up") + } + Action::MoveToPreviousOutput | Action::SendToPreviousOutput => { + fl!("move-windows", "prev-display") + } + Action::MoveToWorkspace(i) | Action::SendToWorkspace(i) => { + fl!("move-windows", "workspace-num", num = (*i as usize)) + } + Action::NextOutput => fl!("nav-shortcuts", "next-output"), + Action::NextWorkspace => fl!("nav-shortcuts", "next-workspace"), + Action::Orientation(Orientation::Horizontal) => fl!("window-tiling", "horizontal"), + Action::Orientation(Orientation::Vertical) => fl!("window-tiling", "vertical"), + Action::PreviousOutput => fl!("nav-shortcuts", "prev-output"), + Action::PreviousWorkspace => fl!("nav-shortcuts", "prev-workspace"), + Action::Resizing(ResizeDirection::Inwards) => fl!("manage-windows", "resize-inwards"), + Action::Resizing(ResizeDirection::Outwards) => fl!("manage-windows", "resize-outwards"), + Action::SwapWindow => fl!("window-tiling", "swap-window"), + Action::SwitchOutput(Direction::Down) => fl!("nav-shortcuts", "output", direction = "down"), + Action::SwitchOutput(Direction::Left) => fl!("nav-shortcuts", "output", direction = "left"), + Action::SwitchOutput(Direction::Right) => { + fl!("nav-shortcuts", "output", direction = "right") + } + Action::SwitchOutput(Direction::Up) => fl!("nav-shortcuts", "output", direction = "up"), + Action::ToggleOrientation => fl!("window-tiling", "toggle-orientation"), + Action::ToggleStacking => fl!("window-tiling", "toggle-stacking"), + Action::ToggleSticky => fl!("manage-windows", "toggle-sticky"), + Action::ToggleTiling => fl!("window-tiling", "toggle-tiling"), + Action::ToggleWindowFloating => fl!("window-tiling", "toggle-floating"), + + // Currently unused by any settings pages + Action::Debug => fl!("debug"), + + Action::MigrateWorkspaceToNextOutput => fl!("migrate-workspace-next"), + Action::MigrateWorkspaceToOutput(Direction::Down) => { + fl!("migrate-workspace", direction = "down") + } + Action::MigrateWorkspaceToOutput(Direction::Left) => { + fl!("migrate-workspace", direction = "left") + } + Action::MigrateWorkspaceToOutput(Direction::Right) => { + fl!("migrate-workspace", direction = "right") + } + Action::MigrateWorkspaceToOutput(Direction::Up) => { + fl!("migrate-workspace", direction = "up") + } + Action::MigrateWorkspaceToPreviousOutput => fl!("migrate-workspace-prev"), + + Action::Terminate => fl!("terminate"), + + Action::System(system) => match system { + SystemAction::AppLibrary => fl!("system-shortcut", "app-library"), + SystemAction::BrightnessDown => fl!("system-shortcut", "brightness-down"), + SystemAction::BrightnessUp => fl!("system-shortcut", "brightness-up"), + SystemAction::HomeFolder => fl!("system-shortcut", "home-folder"), + SystemAction::KeyboardBrightnessDown => { + fl!("system-shortcut", "keyboard-brightness-down") + } + SystemAction::KeyboardBrightnessUp => fl!("system-shortcut", "keyboard-brightness-up"), + SystemAction::Launcher => fl!("system-shortcut", "launcher"), + SystemAction::LockScreen => fl!("system-shortcut", "lock-screen"), + SystemAction::Mute => fl!("system-shortcut", "mute"), + SystemAction::MuteMic => fl!("system-shortcut", "mute-mic"), + SystemAction::Screenshot => fl!("system-shortcut", "screenshot"), + SystemAction::Terminal => fl!("system-shortcut", "terminal"), + SystemAction::VolumeLower => fl!("system-shortcut", "volume-lower"), + SystemAction::VolumeRaise => fl!("system-shortcut", "volume-raise"), + SystemAction::WebBrowser => fl!("system-shortcut", "web-browser"), + SystemAction::WindowSwitcher => fl!("system-shortcut", "window-switcher"), + SystemAction::WorkspaceOverview => fl!("system-shortcut", "workspace-overview"), + }, + + Action::Spawn(command) => command.clone(), + } +} diff --git a/cosmic-settings/src/pages/input/keyboard/shortcuts/move_window.rs b/cosmic-settings/src/pages/input/keyboard/shortcuts/move_window.rs new file mode 100644 index 0000000..940a5ac --- /dev/null +++ b/cosmic-settings/src/pages/input/keyboard/shortcuts/move_window.rs @@ -0,0 +1,116 @@ +use super::{ShortcutMessage, ShortcutModel}; +use cosmic::{Command, Element}; +use cosmic_settings_config::shortcuts::action::Direction; +use cosmic_settings_config::shortcuts::Action; +use cosmic_settings_page::{self as page, section, Section}; +use slab::Slab; + +pub struct Page { + model: super::Model, +} + +impl Default for Page { + fn default() -> Self { + Self { + model: super::Model::default().actions(|defaults, keybindings| { + actions().iter().fold(Slab::new(), |mut slab, action| { + slab.insert(ShortcutModel::new(defaults, keybindings, action.clone())); + slab + }) + }), + } + } +} + +impl Page { + pub fn update(&mut self, message: ShortcutMessage) -> Command { + self.model.update(message) + } +} + +impl page::Page for Page { + fn info(&self) -> page::Info { + page::Info::new("move-windows", "input-keyboard-symbolic").title(fl!("move-windows")) + } + + fn content( + &self, + sections: &mut slotmap::SlotMap>, + ) -> Option { + Some(vec![sections.insert(shortcuts())]) + } + + fn context_drawer(&self) -> Option> { + self.model + .context_drawer() + .map(|el| el.map(crate::pages::Message::MoveWindowShortcuts)) + } + + fn dialog(&self) -> Option> { + self.model + .dialog() + .map(|el| el.map(crate::pages::Message::MoveWindowShortcuts)) + } + + fn on_enter( + &mut self, + _page: cosmic_settings_page::Entity, + _sender: tokio::sync::mpsc::Sender, + ) -> Command { + self.model.on_enter(); + + Command::none() + } + + fn on_leave(&mut self) -> Command { + self.model.on_clear(); + Command::none() + } +} + +impl page::AutoBind for Page {} + +#[must_use] +pub const fn actions() -> &'static [Action] { + &[ + Action::Move(Direction::Down), + Action::Move(Direction::Left), + Action::Move(Direction::Right), + Action::Move(Direction::Up), + Action::MoveToPreviousWorkspace, + Action::MoveToNextWorkspace, + Action::MoveToLastWorkspace, + Action::MoveToWorkspace(1), + Action::MoveToWorkspace(2), + Action::MoveToWorkspace(3), + Action::MoveToWorkspace(4), + Action::MoveToWorkspace(5), + Action::MoveToWorkspace(6), + Action::MoveToWorkspace(7), + Action::MoveToWorkspace(8), + Action::MoveToWorkspace(9), + Action::MoveToPreviousOutput, + Action::MoveToNextOutput, + Action::MoveToOutput(Direction::Down), + Action::MoveToOutput(Direction::Left), + Action::MoveToOutput(Direction::Right), + Action::MoveToOutput(Direction::Up), + ] +} + +fn shortcuts() -> Section { + let mut descriptions = Slab::new(); + + // Make these searchable in the global settings search. + for action in actions() { + descriptions.insert(super::localize_action(action)); + } + + Section::default() + .descriptions(descriptions) + .view::(move |_binder, page, _section| { + page.model + .view() + .map(crate::pages::Message::MoveWindowShortcuts) + }) +} diff --git a/cosmic-settings/src/pages/input/keyboard/shortcuts/nav.rs b/cosmic-settings/src/pages/input/keyboard/shortcuts/nav.rs new file mode 100644 index 0000000..93dcf53 --- /dev/null +++ b/cosmic-settings/src/pages/input/keyboard/shortcuts/nav.rs @@ -0,0 +1,107 @@ +use super::{ShortcutMessage, ShortcutModel}; +use cosmic::{Command, Element}; +use cosmic_settings_config::shortcuts::action::{Direction, FocusDirection}; +use cosmic_settings_config::shortcuts::Action; +use cosmic_settings_page::{self as page, section, Section}; +use slab::Slab; + +pub struct Page { + model: super::Model, +} + +impl Default for Page { + fn default() -> Self { + Self { + model: super::Model::default().actions(|defaults, keybindings| { + actions().iter().fold(Slab::new(), |mut slab, action| { + slab.insert(ShortcutModel::new(defaults, keybindings, action.clone())); + slab + }) + }), + } + } +} + +impl Page { + pub fn update(&mut self, message: ShortcutMessage) -> Command { + self.model.update(message) + } +} + +impl page::Page for Page { + fn info(&self) -> page::Info { + page::Info::new("nav-shortcuts", "input-keyboard-symbolic").title(fl!("nav-shortcuts")) + } + + fn content( + &self, + sections: &mut slotmap::SlotMap>, + ) -> Option { + Some(vec![sections.insert(shortcuts())]) + } + + fn context_drawer(&self) -> Option> { + self.model + .context_drawer() + .map(|el| el.map(crate::pages::Message::NavShortcuts)) + } + + fn dialog(&self) -> Option> { + self.model + .dialog() + .map(|el| el.map(crate::pages::Message::NavShortcuts)) + } + + fn on_enter( + &mut self, + _page: cosmic_settings_page::Entity, + _sender: tokio::sync::mpsc::Sender, + ) -> Command { + self.model.on_enter(); + + Command::none() + } + + fn on_leave(&mut self) -> Command { + self.model.on_clear(); + Command::none() + } +} + +impl page::AutoBind for Page {} + +#[must_use] +pub const fn actions() -> &'static [Action] { + &[ + Action::Focus(FocusDirection::Left), + Action::Focus(FocusDirection::Right), + Action::Focus(FocusDirection::Up), + Action::Focus(FocusDirection::Down), + Action::Focus(FocusDirection::In), + Action::Focus(FocusDirection::Out), + Action::PreviousWorkspace, + Action::NextWorkspace, + Action::LastWorkspace, + Action::PreviousOutput, + Action::NextOutput, + Action::SwitchOutput(Direction::Left), + Action::SwitchOutput(Direction::Right), + Action::SwitchOutput(Direction::Up), + Action::SwitchOutput(Direction::Down), + ] +} + +fn shortcuts() -> Section { + let mut descriptions = Slab::new(); + + // Make these searchable in the global settings search. + for action in actions() { + descriptions.insert(super::localize_action(action)); + } + + Section::default() + .descriptions(descriptions) + .view::(move |_binder, page, _section| { + page.model.view().map(crate::pages::Message::NavShortcuts) + }) +} diff --git a/cosmic-settings/src/pages/input/keyboard/shortcuts/system.rs b/cosmic-settings/src/pages/input/keyboard/shortcuts/system.rs new file mode 100644 index 0000000..571f19b --- /dev/null +++ b/cosmic-settings/src/pages/input/keyboard/shortcuts/system.rs @@ -0,0 +1,111 @@ +use super::{ShortcutMessage, ShortcutModel}; +use cosmic::{Command, Element}; +use cosmic_settings_config::shortcuts::action::System as SystemAction; +use cosmic_settings_config::shortcuts::Action; +use cosmic_settings_page::{self as page, section, Section}; +use slab::Slab; + +pub struct Page { + model: super::Model, +} + +impl Default for Page { + fn default() -> Self { + Self { + model: super::Model::default().actions(|defaults, keybindings| { + actions().iter().fold(Slab::new(), |mut slab, action| { + slab.insert(ShortcutModel::new(defaults, keybindings, action.clone())); + slab + }) + }), + } + } +} + +impl Page { + pub fn update(&mut self, message: ShortcutMessage) -> Command { + self.model.update(message) + } +} + +impl page::Page for Page { + fn info(&self) -> page::Info { + page::Info::new("system-shortcut", "input-keyboard-symbolic").title(fl!("system-shortcut")) + } + + fn content( + &self, + sections: &mut slotmap::SlotMap>, + ) -> Option { + Some(vec![sections.insert(shortcuts())]) + } + + fn context_drawer(&self) -> Option> { + self.model + .context_drawer() + .map(|el| el.map(crate::pages::Message::SystemShortcuts)) + } + + fn dialog(&self) -> Option> { + self.model + .dialog() + .map(|el| el.map(crate::pages::Message::SystemShortcuts)) + } + + fn on_enter( + &mut self, + _page: cosmic_settings_page::Entity, + _sender: tokio::sync::mpsc::Sender, + ) -> Command { + self.model.on_enter(); + + Command::none() + } + + fn on_leave(&mut self) -> Command { + self.model.on_clear(); + Command::none() + } +} + +impl page::AutoBind for Page {} + +#[must_use] +pub const fn actions() -> &'static [Action] { + &[ + Action::System(SystemAction::AppLibrary), + Action::System(SystemAction::Launcher), + Action::System(SystemAction::WorkspaceOverview), + Action::System(SystemAction::WindowSwitcher), + Action::System(SystemAction::LockScreen), + Action::System(SystemAction::VolumeLower), + Action::System(SystemAction::VolumeRaise), + Action::System(SystemAction::Mute), + Action::System(SystemAction::MuteMic), + Action::System(SystemAction::BrightnessDown), + Action::System(SystemAction::BrightnessUp), + Action::System(SystemAction::KeyboardBrightnessDown), + Action::System(SystemAction::KeyboardBrightnessUp), + Action::System(SystemAction::Screenshot), + Action::System(SystemAction::Terminal), + Action::System(SystemAction::HomeFolder), + Action::System(SystemAction::WebBrowser), + ] +} + +fn shortcuts() -> Section { + let mut descriptions = Slab::new(); + + // Make these searchable in the global settings search. + for action in actions() { + descriptions.insert(super::localize_action(action)); + } + + Section::default() + .descriptions(descriptions) + .view::(move |_binder, page, _section| { + page.model + .view() + .map(crate::pages::Message::SystemShortcuts) + }) +} diff --git a/cosmic-settings/src/pages/input/keyboard/shortcuts/tiling.rs b/cosmic-settings/src/pages/input/keyboard/shortcuts/tiling.rs new file mode 100644 index 0000000..f22c0c9 --- /dev/null +++ b/cosmic-settings/src/pages/input/keyboard/shortcuts/tiling.rs @@ -0,0 +1,101 @@ +use super::{ShortcutMessage, ShortcutModel}; +use cosmic::{Command, Element}; +use cosmic_settings_config::shortcuts::action::Orientation; +use cosmic_settings_config::shortcuts::Action; +use cosmic_settings_page::{self as page, section, Section}; +use slab::Slab; + +pub struct Page { + model: super::Model, +} + +impl Default for Page { + fn default() -> Self { + Self { + model: super::Model::default().actions(|defaults, keybindings| { + actions().iter().fold(Slab::new(), |mut slab, action| { + slab.insert(ShortcutModel::new(defaults, keybindings, action.clone())); + slab + }) + }), + } + } +} + +impl Page { + pub fn update(&mut self, message: ShortcutMessage) -> Command { + self.model.update(message) + } +} + +impl page::Page for Page { + fn info(&self) -> page::Info { + page::Info::new("window-tiling", "input-keyboard-symbolic").title(fl!("window-tiling")) + } + + fn content( + &self, + sections: &mut slotmap::SlotMap>, + ) -> Option { + Some(vec![sections.insert(shortcuts())]) + } + + fn context_drawer(&self) -> Option> { + self.model + .context_drawer() + .map(|el| el.map(crate::pages::Message::TilingShortcuts)) + } + + fn dialog(&self) -> Option> { + self.model + .dialog() + .map(|el| el.map(crate::pages::Message::TilingShortcuts)) + } + + fn on_enter( + &mut self, + _page: cosmic_settings_page::Entity, + _sender: tokio::sync::mpsc::Sender, + ) -> Command { + self.model.on_enter(); + + Command::none() + } + + fn on_leave(&mut self) -> Command { + self.model.on_clear(); + Command::none() + } +} + +impl page::AutoBind for Page {} + +#[must_use] +pub fn actions() -> &'static [Action] { + &[ + Action::ToggleTiling, + Action::ToggleStacking, + Action::ToggleWindowFloating, + Action::ToggleOrientation, + Action::Orientation(Orientation::Horizontal), + Action::Orientation(Orientation::Horizontal), + Action::SwapWindow, + ] +} + +fn shortcuts() -> Section { + let mut descriptions = Slab::new(); + + // Make these searchable in the global settings search. + for action in actions() { + descriptions.insert(super::localize_action(action)); + } + + Section::default() + .descriptions(descriptions) + .view::(move |_binder, page, _section| { + page.model + .view() + .map(crate::pages::Message::TilingShortcuts) + }) +} diff --git a/cosmic-settings/src/pages/mod.rs b/cosmic-settings/src/pages/mod.rs index 6df8853..88d5c5d 100644 --- a/cosmic-settings/src/pages/mod.rs +++ b/cosmic-settings/src/pages/mod.rs @@ -16,21 +16,28 @@ pub mod time; pub enum Message { About(system::about::Message), Appearance(desktop::appearance::Message), + CustomShortcuts(input::keyboard::shortcuts::custom::Message), DateAndTime(time::date::Message), - Power(power::Message), Desktop(desktop::Message), + DesktopOptions(desktop::options::Message), DesktopWallpaper(desktop::wallpaper::Message), DesktopWorkspaces(desktop::workspaces::Message), Displays(display::Message), Dock(desktop::dock::Message), DockApplet(desktop::dock::applets::Message), External { id: String, message: Vec }, + Input(input::Message), Keyboard(input::keyboard::Message), KeyboardShortcuts(input::keyboard::shortcuts::Message), - Input(input::Message), + ManageWindowShortcuts(input::keyboard::shortcuts::ShortcutMessage), + MoveWindowShortcuts(input::keyboard::shortcuts::ShortcutMessage), + NavShortcuts(input::keyboard::shortcuts::ShortcutMessage), Page(Entity), Panel(desktop::panel::Message), PanelApplet(desktop::panel::applets_inner::Message), + Power(power::Message), + SystemShortcuts(input::keyboard::shortcuts::ShortcutMessage), + TilingShortcuts(input::keyboard::shortcuts::ShortcutMessage), } impl From for crate::Message { diff --git a/cosmic-settings/src/pages/power/backend/mod.rs b/cosmic-settings/src/pages/power/backend/mod.rs index ccd41bc..dd94411 100644 --- a/cosmic-settings/src/pages/power/backend/mod.rs +++ b/cosmic-settings/src/pages/power/backend/mod.rs @@ -99,12 +99,9 @@ impl PowerBackend for S76Backend {} impl SetPowerProfile for S76Backend { async fn set_power_profile(&self, profile: PowerProfile) { - let daemon = match get_s76power_daemon_proxy().await { - Ok(c) => c, - Err(e) => { - tracing::error!("Problem while setting power profile."); - return; - } + let Ok(daemon) = get_s76power_daemon_proxy().await else { + tracing::error!("Problem while setting power profile."); + return; }; match profile { @@ -126,19 +123,15 @@ impl SetPowerProfile for S76Backend { impl GetCurrentPowerProfile for S76Backend { async fn get_current_power_profile(&self) -> PowerProfile { - let daemon = match get_s76power_daemon_proxy().await { - Ok(c) => c, - Err(e) => { - tracing::error!("Problem while getting power profile."); - //Default - return PowerProfile::Balanced; - } + let Ok(daemon) = get_s76power_daemon_proxy().await else { + tracing::error!("Problem while getting power profile."); + return PowerProfile::Balanced; }; match daemon.get_profile().await { Ok(p) => PowerProfile::from_string(p.as_str()), //Default - Err(_) => { + Err(_why) => { tracing::error!("Problem while getting power profile."); //Default PowerProfile::Balanced @@ -173,7 +166,7 @@ impl SetPowerProfile for PPBackend { async fn set_power_profile(&self, profile: PowerProfile) { let daemon = match get_power_profiles_proxy().await { Ok(c) => c, - Err(e) => { + Err(()) => { tracing::error!("Problem while setting power profile."); return; } @@ -198,18 +191,14 @@ impl SetPowerProfile for PPBackend { impl GetCurrentPowerProfile for PPBackend { async fn get_current_power_profile(&self) -> PowerProfile { - let daemon = match get_power_profiles_proxy().await { - Ok(c) => c, - Err(e) => { - tracing::error!("Problem while getting power profile."); - //Default - return PowerProfile::Balanced; - } + let Ok(daemon) = get_power_profiles_proxy().await else { + tracing::error!("Problem while getting power profile."); + return PowerProfile::Balanced; }; let profile = match daemon.active_profile().await { Ok(p) => p, - Err(e) => { + Err(_e) => { tracing::error!("Problem while getting power profile."); //Default return PowerProfile::Balanced; diff --git a/cosmic-settings/src/pages/power/backend/ppdaemon.rs b/cosmic-settings/src/pages/power/backend/ppdaemon.rs index 674febf..d247bba 100644 --- a/cosmic-settings/src/pages/power/backend/ppdaemon.rs +++ b/cosmic-settings/src/pages/power/backend/ppdaemon.rs @@ -1,4 +1,4 @@ -use zbus::{proxy, Connection}; +use zbus::proxy; #[proxy( interface = "org.freedesktop.UPower.PowerProfiles", diff --git a/cosmic-settings/src/pages/power/backend/s76powerdaemon.rs b/cosmic-settings/src/pages/power/backend/s76powerdaemon.rs index 479655c..e8ad435 100644 --- a/cosmic-settings/src/pages/power/backend/s76powerdaemon.rs +++ b/cosmic-settings/src/pages/power/backend/s76powerdaemon.rs @@ -1,4 +1,5 @@ -use zbus::{proxy, Connection}; +use zbus::proxy; + #[proxy( interface = "com.system76.PowerDaemon", default_path = "/com/system76/PowerDaemon", diff --git a/cosmic-settings/src/pages/system/about.rs b/cosmic-settings/src/pages/system/about.rs index a42f7c4..de6fd0b 100644 --- a/cosmic-settings/src/pages/system/about.rs +++ b/cosmic-settings/src/pages/system/about.rs @@ -46,7 +46,7 @@ impl page::Page for Page { fn on_enter( &mut self, _page: page::Entity, - sender: tokio::sync::mpsc::Sender, + _sender: tokio::sync::mpsc::Sender, ) -> Command { command::future(async move { crate::pages::Message::About(Message::Info(Box::new(Info::load()))) diff --git a/i18n/be/cosmic_settings.ftl b/i18n/be/cosmic_settings.ftl index 38f0b26..c997799 100644 --- a/i18n/be/cosmic_settings.ftl +++ b/i18n/be/cosmic_settings.ftl @@ -135,11 +135,6 @@ dock = Док hot-corner = Гарачы вугал .top-left-corner = Уключыць верхні левы гарачы вугал для працоўных прастораў -super-key-action = Дзеянне клавішы Super - .launcher = Запускальнік - .workspaces = Працоўныя прасторы - .applications = Праграмы - top-panel = Верхняя панэль .workspaces = Паказаць кнопку Працоўныя прасторы .applications = Паказаць кнопку Праграмы diff --git a/i18n/cs/cosmic_settings.ftl b/i18n/cs/cosmic_settings.ftl index b58e6a4..f62c865 100644 --- a/i18n/cs/cosmic_settings.ftl +++ b/i18n/cs/cosmic_settings.ftl @@ -23,11 +23,6 @@ notifications = Oznámení desktop-panel-options = Plocha a Panel .desc = Činnost super klávesy, roh obrazovky, nastavení ovládání oken. -super-key-action = Činnost super klávesy - .launcher = Spouštěč - .workspaces = Pracovní plochy - .applications = Applikace - hot-corner = Rohy .top-left-corner = Povolit použití levého horního rohu pro otevření pracovních ploch diff --git a/i18n/de/cosmic_settings.ftl b/i18n/de/cosmic_settings.ftl index ab1c6ff..1e38511 100644 --- a/i18n/de/cosmic_settings.ftl +++ b/i18n/de/cosmic_settings.ftl @@ -26,11 +26,6 @@ notifications = Benachrichtigungen desktop-options = Desktopoptionen .desc = Super Key Aktion, hot corners, Fenstersteuerung. -super-key-action = Super Key Aktion - .launcher = Launcher - .workspaces = Arbeitsbereiche - .applications = Apps - hot-corner = Hot Corner .top-left-corner = Enable top-left hot corner for Workspaces diff --git a/i18n/en/cosmic_settings.ftl b/i18n/en/cosmic_settings.ftl index 271f06c..c8ba886 100644 --- a/i18n/en/cosmic_settings.ftl +++ b/i18n/en/cosmic_settings.ftl @@ -136,10 +136,10 @@ dock = Dock hot-corner = Hot Corner .top-left-corner = Enable top-left hot corner for Workspaces -super-key-action = Super Key Action - .launcher = Launcher - .workspaces = Workspaces - .applications = Applications +super-key = Super key + .launcher = Open Launcher + .workspaces = Open Workspaces + .applications = Open Applications top-panel = Top Panel .workspaces = Show Workspaces Button @@ -401,6 +401,125 @@ type-to-search = Type to search... keyboard-shortcuts = Keyboard Shortcuts .desc = View and customize shortcuts +add-keybinding = Add keybinding +cancel = Cancel +command = Command +custom = Custom +debug = Debug +disabled = Disabled +migrate-workspace-prev = Migrate workspace to previous output +migrate-workspace-next = Migrate workspace to next output +migrate-workspace = Migrate workspace to output { $direction -> + *[down] down + [left] left + [right] right + [up] up +} +navigate = Navigate +replace = Replace +shortcut-name = Shortcut name +system-controls = System controls +terminate = Terminate +toggle-stacking = Toggle window stacking +type-key-combination = Type key combination +unknown = Unknown + +custom-shortcuts = Custom Shortcuts + .add = Add shortcut + .context = Add Custom Shortcut + .none = No custom shortcuts + +modified = { $count } modified + +nav-shortcuts = Navigation + .prev-output = Focus previous output + .next-output = Focus next output + .last-workspace = Focus last workspace + .prev-workspace = Focus previous workspace + .next-workspace = Focus next workspace + .focus = Focus window { $direction -> + *[down] down + [in] in + [left] left + [out] out + [right] right + [up] up + } + .output = Switch to output { $direction -> + *[down] down + [left] left + [right] right + [up] up + } + .workspace = Switch to workspace { $num } + +manage-windows = Manage windows + .close = Close window + .maximize = Maximize window + .minimize = Minimize window + .resize-inwards = Resize window inwards + .resize-outwards = Resize window outwards + .toggle-sticky = Toggle sticky window + +move-windows = Move Windows + .direction = Move window { $direction -> + *[down] down + [left] left + [right] right + [up] up + } + .display = Move window one monitor { $direction -> + *[down] down + [left] left + [right] right + [up] up + } + .workspace = Move window one workspace { $direction -> + *[below] below + [left] left + [right] right + [above] above + } + .workspace-num = Move window to workspace { $num } + .prev-workspace = Move window to prev workspace + .next-workspace = Move window to next workspace + .last-workspace = Move window to last workspace + .next-display = Move window to next display + .prev-display = Move window to prev display + .send-to-prev-workspace = Move window to previous workspace + .send-to-next-workspace = Move window to next workspace + +system-shortcut = System + .app-library = Open the app library + .brightness-down = Decrease display brightness + .brightness-up = Increase display brightness + .home-folder = Open home folder + .keyboard-brightness-down = Decrease keyboard brightness + .keyboard-brightness-up = Increase keyboard brightness + .launcher = Open the launcher + .lock-screen = Lock the screen + .mute = Mute audio output + .mute-mic = Mutes microphone input + .screenshot = Take a screenshot + .terminal = Open a terminal + .volume-lower = Decrease audio output volume + .volume-raise = Increase audio output volume + .web-browser = Opens a web browser + .window-switcher = Switch between open windows + .workspace-overview = Open the workspace overview + +window-tiling = Window tiling + .horizontal = Set horizontal orientation + .vertical = Set vertical orientation + .swap-window = Swap window + .toggle-tiling = Toggle window tiling + .toggle-stacking = Toggle window stacking + .toggle-floating = Toggle window floating + .toggle-orientation = Toggle orientation + +replace-shortcut-dialog = Replace Shortcut? + .desc = { $shortcut } is used by { $name }. If you replace it, { $name } will be disabled. + ## Input: Mouse mouse = Mouse @@ -443,13 +562,13 @@ open-workspaces-view = Open Workspaces Overview ## Power power = Power - .desc = Manage power settings + .desc = Manage power settings power-mode = Power Mode - .performance = High performance - .balanced = Balanced - .battery = Extended battery life - .performance-desc = Peak performance and power usage. - .balanced-desc = Quiet performance and moderate power usage. - .battery-desc = Reduced power usage and silent performance. - .nobackend = Backend not found. Install system76-power or power-profiles-daemon. + .performance = High performance + .balanced = Balanced + .battery = Extended battery life + .performance-desc = Peak performance and power usage. + .balanced-desc = Quiet performance and moderate power usage. + .battery-desc = Reduced power usage and silent performance. + .nobackend = Backend not found. Install system76-power or power-profiles-daemon. diff --git a/i18n/es/cosmic_settings.ftl b/i18n/es/cosmic_settings.ftl index 042e00b..0fa6161 100644 --- a/i18n/es/cosmic_settings.ftl +++ b/i18n/es/cosmic_settings.ftl @@ -136,11 +136,6 @@ dock = Dock hot-corner = Esquina Activa .top-left-corner = Habilitar esquina superior izquierda para Espacios de Trabajo -super-key-action = Acción de la tecla Super - .launcher = Lanzador - .workspaces = Espacios de Trabajo - .applications = Aplicaciones - top-panel = Panel Superior .workspaces = Mostrar botón de Espacios de Trabajo .applications = Mostrar botón de Aplicaciones diff --git a/i18n/fa/cosmic_settings.ftl b/i18n/fa/cosmic_settings.ftl index 0ce2b63..24027dd 100644 --- a/i18n/fa/cosmic_settings.ftl +++ b/i18n/fa/cosmic_settings.ftl @@ -23,11 +23,6 @@ notifications = اعلانات desktop-panel-options = تنظیمات پنل میزکار .desc = عملکرد کلید سوپر، گوشه‌های داغ، گزینه‌های کنترل پنجره. -super-key-action = عملکرد کلید سوپر - .launcher = راه انداز - .workspaces = فضاهای کاری - .applications = برنامه‌ها - hot-corner = گوشه‌داغ .top-left-corner = فعال سازی گوشه‌داغ بالا چپ برای فضاهای کاری diff --git a/i18n/fr/cosmic_settings.ftl b/i18n/fr/cosmic_settings.ftl index 579f3ad..91ce700 100644 --- a/i18n/fr/cosmic_settings.ftl +++ b/i18n/fr/cosmic_settings.ftl @@ -136,11 +136,6 @@ dock = Dock hot-corner = Coin Actif .top-left-corner = Activer le coin actif supérieur gauche pour les Espaces de Travail -super-key-action = Action de la touche Super - .launcher = Lanceur - .workspaces = Espaces de Travail - .applications = Applications - top-panel = Panneau supérieur .workspaces = Afficher le bouton Espace de Travail .applications = Afficher le bouton Applications diff --git a/i18n/hi/cosmic_settings.ftl b/i18n/hi/cosmic_settings.ftl index 5633e65..74ecd94 100644 --- a/i18n/hi/cosmic_settings.ftl +++ b/i18n/hi/cosmic_settings.ftl @@ -27,11 +27,6 @@ notifications = सूचनाएं desktop-options = डेस्कटॉप विकल्प .desc = सुपर की एक्शन, हॉट कॉर्नर, विंडो कंट्रोल विकल्प। -super-key-action = सुपर की एक्शन - .launcher = लांचर - .workspaces = कार्यस्थानों - .applications = अनुप्रयोग - hot-corner = गर्म कोना .top-left-corner = कार्यस्थानों के लिए शीर्ष-बाएँ हॉट कॉर्नर को सक्षम करें diff --git a/i18n/it/cosmic_settings.ftl b/i18n/it/cosmic_settings.ftl index b05882f..615e877 100644 --- a/i18n/it/cosmic_settings.ftl +++ b/i18n/it/cosmic_settings.ftl @@ -125,11 +125,6 @@ dock = Barra delle applicazioni hot-corner = Bordi reattivi .top-left-corner = Abilita bordo reattivo in alto a sinistra per gli spazi di lavoro -super-key-action = Azione tasto Super - .launcher = Launcher - .workspaces = Spazi di lavoro - .applications = Applicazioni - top-panel = Pannello superiore .workspaces = Pulsante "mostra spazi di lavoro" .applications = Pulsante "mostra applicazioni" diff --git a/i18n/ja/cosmic_settings.ftl b/i18n/ja/cosmic_settings.ftl index d6a9f89..7cf021d 100644 --- a/i18n/ja/cosmic_settings.ftl +++ b/i18n/ja/cosmic_settings.ftl @@ -134,11 +134,6 @@ dock = ドック hot-corner = ホットコーナー .top-left-corner = ワークスペースための左上のホットコーナーを有効にする -super-key-action = スーパーキーの行動 - .launcher = ランチャー - .workspaces = ワークスペース - .applications = アプリケーション - top-panel = トップパネル .workspaces = ワークスペースボタンを表示 .applications = アプリケーションボタンを表示 diff --git a/i18n/pl/cosmic_settings.ftl b/i18n/pl/cosmic_settings.ftl index 424797e..5dba954 100644 --- a/i18n/pl/cosmic_settings.ftl +++ b/i18n/pl/cosmic_settings.ftl @@ -141,11 +141,6 @@ dock = Dok hot-corner = Narożniki Funkcyjne .top-left-corner = Włącz Obszary Robocze w lewym górnym narożniku funkcyjnym. -super-key-action = Akcje Klawisza Super - .launcher = Program Startowy - .workspaces = Obszary Robocze - .applications = Aplikacje - top-panel = Górny Panel .workspaces = Pokaż Przycisk Obszarów Roboczych .applications = Pokaż Przycisk Aplikacji diff --git a/i18n/pt-BR/cosmic_settings.ftl b/i18n/pt-BR/cosmic_settings.ftl index 5069c57..c062e5f 100644 --- a/i18n/pt-BR/cosmic_settings.ftl +++ b/i18n/pt-BR/cosmic_settings.ftl @@ -136,11 +136,6 @@ dock = Dock hot-corner = Canto ativo .top-left-corner = Ativar o canto superior esquerdo para áreas de trabalho -super-key-action = Ações da tecla Super - .launcher = Inicializador - .workspaces = Áreas de Trabalho - .applications = Aplicações - top-panel = Painel superior .workspaces = Mostrar Botão de Áreas de Trabalho .applications = Mostrar Botão de Aplicações diff --git a/i18n/pt/cosmic_settings.ftl b/i18n/pt/cosmic_settings.ftl index 9d17623..810e604 100644 --- a/i18n/pt/cosmic_settings.ftl +++ b/i18n/pt/cosmic_settings.ftl @@ -136,11 +136,6 @@ dock = Doca hot-corner = Canto ativo .top-left-corner = Ativar o canto superior esquerdo para as áreas de trabalho -super-key-action = Ação da tecla Super - .launcher = Lançador - .workspaces = Áreas de trabalho - .applications = Aplicações - top-panel = Painel superior .workspaces = Mostrar o botão das áreas de trabalho .applications = Mostrar o botão das aplicações diff --git a/i18n/ro/cosmic_settings.ftl b/i18n/ro/cosmic_settings.ftl index 146381a..1d0828e 100644 --- a/i18n/ro/cosmic_settings.ftl +++ b/i18n/ro/cosmic_settings.ftl @@ -136,11 +136,6 @@ dock = Dock hot-corner = Marginea ecranului .top-left-corner = Activați marginea din stânga sus pentru Spații de lucru -super-key-action = Acțiunea butonului Super - .launcher = Lansator - .workspaces = Spații de lucru - .applications = Aplicații - top-panel = Panoul de sus .workspaces = Afișați butonul pentru Spații de lucru .applications = Afișați butonul pentru aplicații diff --git a/i18n/ru/cosmic_settings.ftl b/i18n/ru/cosmic_settings.ftl index ee91f71..59ec35a 100644 --- a/i18n/ru/cosmic_settings.ftl +++ b/i18n/ru/cosmic_settings.ftl @@ -136,11 +136,6 @@ dock = Док hot-corner = Активные углы .top-left-corner = Открывать рабочие места при наведении в левый верхний угол -super-key-action = Действие кнопки Super - .launcher = Панель запуска - .workspaces = Рабочие места - .applications = Приложения - top-panel = Верхняя панель .workspaces = Отображать кнопку «Рабочие места» .applications = Отображать кнопку «Приложения» diff --git a/i18n/sr-Cyrl/cosmic_settings.ftl b/i18n/sr-Cyrl/cosmic_settings.ftl index 6a2a35c..a9d9707 100644 --- a/i18n/sr-Cyrl/cosmic_settings.ftl +++ b/i18n/sr-Cyrl/cosmic_settings.ftl @@ -121,11 +121,6 @@ dock = Док hot-corner = Лепљиви углови .top-left-corner = Укључити горњи леви лепљиви угао за радне просторе -super-key-action = Улога Super тастера - .launcher = Покретач апликација - .workspaces = Радни простори - .applications = Апликације - top-panel = Горњи панел .workspaces = Дугме за приказивање радних простора .applications = Дугме за приказивање апликација diff --git a/i18n/sr-Latn/cosmic_settings.ftl b/i18n/sr-Latn/cosmic_settings.ftl index dcc9a79..3be0c41 100644 --- a/i18n/sr-Latn/cosmic_settings.ftl +++ b/i18n/sr-Latn/cosmic_settings.ftl @@ -121,11 +121,6 @@ dock = Dok hot-corner = Lepljivi uglovi .top-left-corner = Uključiti gornji levi lepljivi ugao za radne prostore -super-key-action = Uloga Super tastera - .launcher = Pokretač aplikacija - .workspaces = Radni prostori - .applications = Aplikacije - top-panel = Gornji panel .workspaces = Dugme za prikazivanje radnih prostora .applications = Dugme za prikazivanje aplikacija diff --git a/i18n/sv/cosmic_settings.ftl b/i18n/sv/cosmic_settings.ftl index bb535db..b42b21b 100644 --- a/i18n/sv/cosmic_settings.ftl +++ b/i18n/sv/cosmic_settings.ftl @@ -118,11 +118,6 @@ dock = Docka hot-corner = Het hörn .top-left-corner = Aktivera det övre vänstra hörnet för arbetsytor -super-key-action = Supertangent åtgärd - .launcher = Programstartare - .workspaces = Arbetsytor - .applications = Applikationer - top-panel = Övre Panel .workspaces = Visa knappen arbetsytor .applications = Visa knappen applikationer diff --git a/i18n/tr/cosmic_settings.ftl b/i18n/tr/cosmic_settings.ftl index ddd0d93..668145b 100644 --- a/i18n/tr/cosmic_settings.ftl +++ b/i18n/tr/cosmic_settings.ftl @@ -24,11 +24,6 @@ notifications = Bildirimler desktop-panel-options = Masaüstü ve Panel .desc = Logo Tuşu eylemi, hızlı köşeler, pencere kontrol seçenekleri. -super-key-action = Logo Tuşu Eylemi - .launcher = Başlatıcı - .workspaces = Çalışma Alanları - .applications = Uygulamalar - hot-corner = Hızlı Köşe .top-left-corner = Çalışma Alanları için sol-üst hızlı köşeyi etkinleştir diff --git a/i18n/zh-CN/cosmic_settings.ftl b/i18n/zh-CN/cosmic_settings.ftl index e0595ff..0dac49c 100644 --- a/i18n/zh-CN/cosmic_settings.ftl +++ b/i18n/zh-CN/cosmic_settings.ftl @@ -136,11 +136,6 @@ dock = 程序坞 hot-corner = 热区 .top-left-corner = 启用左上角热区来查看工作区概览 -super-key-action = Super 键行为 - .launcher = 启动器 - .workspaces = 工作区概览 - .applications = 应用程序库 - top-panel = 顶部面板 .workspaces = 显示工作区概览按钮 .applications = 显示应用程序库按钮 diff --git a/i18n/zh-TW/cosmic_settings.ftl b/i18n/zh-TW/cosmic_settings.ftl index 349aa2c..8cc40ba 100644 --- a/i18n/zh-TW/cosmic_settings.ftl +++ b/i18n/zh-TW/cosmic_settings.ftl @@ -136,11 +136,6 @@ dock = Dock hot-corner = 螢幕角落熱點 .top-left-corner = 為工作區啟用位於左上方的螢幕角落熱點 -super-key-action = Super 按鍵行為 - .launcher = 啟動器 - .workspaces = 工作區 - .applications = 應用程式 - top-panel = 頂部面板 .workspaces = 顯示工作區按鈕 .applications = 顯示應用程式按鈕 diff --git a/page/src/insert.rs b/page/src/insert.rs index f116c68..84700c4 100644 --- a/page/src/insert.rs +++ b/page/src/insert.rs @@ -38,4 +38,21 @@ impl<'a, Message: 'static> Insert<'a, Message> { self } + + #[allow(clippy::return_self_not_must_use)] + #[allow(clippy::must_use_candidate)] + pub fn sub_page_with_id>(&mut self) -> Entity { + let sub_page = self.model.register::

().id(); + + self.model.info[sub_page].parent = Some(self.id); + + self.model + .sub_pages + .entry(self.id) + .expect("parent page missing") + .and_modify(|v| v.push(sub_page)) + .or_insert_with(|| vec![sub_page]); + + sub_page + } } diff --git a/page/src/lib.rs b/page/src/lib.rs index 00ea19a..bec03f7 100644 --- a/page/src/lib.rs +++ b/page/src/lib.rs @@ -43,6 +43,11 @@ pub trait Page: Downcast { None } + /// Set a custom page header + fn header(&self) -> Option> { + None + } + /// Display an inner app dialog for the page. fn dialog(&self) -> Option> { None @@ -116,6 +121,7 @@ impl Info { #[macro_export] macro_rules! update { ($binder:expr, $message:expr, $page:ty) => {{ + #[allow(unused_must_use)] if let Some(page) = $binder.page_mut::<$page>() { page.update($message); }