diff --git a/Cargo.lock b/Cargo.lock index 99dc07a0..a16f7ff4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,27 +17,6 @@ version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" -[[package]] -name = "appendlist" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e149dc73cd30538307e7ffa2acd3d2221148eaeed4871f246657b1c3eaa1cbd2" - -[[package]] -name = "approx" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278" -dependencies = [ - "num-traits", -] - -[[package]] -name = "arc-swap" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f" - [[package]] name = "async-broadcast" version = "0.4.0" @@ -271,16 +250,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cgmath" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a98d30140e3296250832bbaaff83b27dcd6fa3cc70fb6f1f3e5c9c0023b5317" -dependencies = [ - "approx", - "num-traits", -] - [[package]] name = "chrono" version = "0.4.19" @@ -366,8 +335,8 @@ dependencies = [ name = "cosmic-applet-graphics" version = "0.1.0" dependencies = [ - "cosmic-panel-config", "gtk4", + "libcosmic-applet", "once_cell", "relm4-macros", "tokio", @@ -379,10 +348,10 @@ name = "cosmic-applet-network" version = "0.1.0" dependencies = [ "cosmic-dbus-networkmanager", - "cosmic-panel-config", "futures-util", "gtk4", "itertools", + "libcosmic-applet", "libcosmic-widgets", "once_cell", "relm4-macros", @@ -396,11 +365,11 @@ name = "cosmic-applet-notifications" version = "0.1.0" dependencies = [ "cascade", - "cosmic-panel-config", "futures", "gtk4", "libcosmic-applet", "once_cell", + "relm4-macros", "serde", "zbus", "zbus_names", @@ -427,9 +396,9 @@ name = "cosmic-applet-status-area" version = "0.1.0" dependencies = [ "cascade", - "cosmic-panel-config", "futures", "gtk4", + "libcosmic-applet", "once_cell", "serde", "zbus", @@ -443,9 +412,9 @@ version = "0.1.0" dependencies = [ "cascade", "chrono", - "cosmic-panel-config", "futures", "gtk4", + "libcosmic-applet", "once_cell", "serde", "zbus", @@ -509,16 +478,16 @@ dependencies = [ [[package]] name = "cosmic-panel-config" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-panel?branch=rework_0.30#b5834088e8e4ef097830d27eb03925dc78262d37" +source = "git+https://github.com/pop-os/cosmic-panel#791937b3515534f4df9bb47c1a6bd5189ff00644" dependencies = [ "anyhow", "gtk4", "ron", "serde", "slog", - "smithay-client-toolkit", + "wayland-protocols", "xdg", - "xdg-shell-wrapper", + "xdg-shell-wrapper-config", ] [[package]] @@ -672,43 +641,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" -[[package]] -name = "drm" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "408e87132bd0d8a13a3b418b9d51fb92973b764d1d40785947d233ab2945fd27" -dependencies = [ - "bitflags", - "drm-ffi", - "drm-fourcc", - "nix 0.22.3", -] - -[[package]] -name = "drm-ffi" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "198d1b7fdb33b75e9bd08ba6842ddb730760f7eeea25552acc88c5403c4f0652" -dependencies = [ - "drm-sys", - "nix 0.22.3", -] - -[[package]] -name = "drm-fourcc" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" - -[[package]] -name = "drm-sys" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5f45fcdd3b2f3c13fadea11b2a4eda2023e7de55021da039eac4a3beecfe91c" -dependencies = [ - "libc", -] - [[package]] name = "easy-parallel" version = "3.2.0" @@ -1159,17 +1091,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "gl_generator" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" -dependencies = [ - "khronos_api", - "log", - "xml-rs", -] - [[package]] name = "glib" version = "0.15.12" @@ -1500,16 +1421,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "indexmap" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" -dependencies = [ - "autocfg", - "hashbrown", -] - [[package]] name = "instant" version = "0.1.12" @@ -1563,12 +1474,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "khronos_api" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" - [[package]] name = "lazy_static" version = "1.4.0" @@ -1735,15 +1640,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" -[[package]] -name = "memmap2" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b6c2ebff6180198788f5db08d7ce3bc1d0b617176678831a7510825973e357" -dependencies = [ - "libc", -] - [[package]] name = "memoffset" version = "0.6.5" @@ -1753,12 +1649,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "mio" version = "0.8.4" @@ -1830,16 +1720,6 @@ dependencies = [ "memoffset", ] -[[package]] -name = "nom" -version = "7.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "num-derive" version = "0.3.3" @@ -2225,9 +2105,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.6" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "aho-corasick", "memchr", @@ -2236,14 +2116,14 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.26" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "relm4" version = "0.5.0-beta.1" -source = "git+https://github.com/relm4/relm4?branch=next#2caad49d8a554c8ecf20d2bc3bf13827ff5c2b46" +source = "git+https://github.com/relm4/relm4?branch=next#746d244004e23764294b23519f6f8be1002c1ceb" dependencies = [ "async-broadcast", "async-oneshot", @@ -2254,12 +2134,13 @@ dependencies = [ "once_cell", "relm4-macros", "tokio", + "tracing", ] [[package]] name = "relm4-macros" version = "0.5.0-beta.1" -source = "git+https://github.com/relm4/relm4?branch=next#2caad49d8a554c8ecf20d2bc3bf13827ff5c2b46" +source = "git+https://github.com/relm4/relm4?branch=next#746d244004e23764294b23519f6f8be1002c1ceb" dependencies = [ "proc-macro2", "quote", @@ -2350,12 +2231,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scan_fmt" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b53b0a5db882a8e2fdaae0a43f7b39e7e9082389e978398bdf223a55b581248" - [[package]] name = "scoped-tls" version = "1.0.0" @@ -2462,12 +2337,6 @@ dependencies = [ "opaque-debug", ] -[[package]] -name = "shlex" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" - [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -2489,28 +2358,6 @@ version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" -[[package]] -name = "slog-scope" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f95a4b4c3274cd2869549da82b57ccc930859bdbf5bcea0424bc5f140b3c786" -dependencies = [ - "arc-swap", - "lazy_static", - "slog", -] - -[[package]] -name = "slog-stdlog" -version = "4.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6706b2ace5bbae7291d3f8d2473e2bfab073ccd7d03670946197aec98471fa3e" -dependencies = [ - "log", - "slog", - "slog-scope", -] - [[package]] name = "slotmap" version = "1.0.6" @@ -2526,58 +2373,6 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" -[[package]] -name = "smithay" -version = "0.3.0" -source = "git+https://github.com/smithay/smithay?branch=fix/egl_zero_sized_buffers#bb79a79a6cf8246d857f30e3f2ceee35ab058238" -dependencies = [ - "appendlist", - "bitflags", - "calloop", - "cgmath", - "downcast-rs", - "drm", - "drm-ffi", - "drm-fourcc", - "gl_generator", - "indexmap", - "lazy_static", - "libc", - "libloading", - "nix 0.22.3", - "once_cell", - "rand", - "scan_fmt", - "slog", - "slog-stdlog", - "tempfile", - "thiserror", - "wayland-backend", - "wayland-protocols 0.30.0-beta.5", - "wayland-protocols-wlr", - "wayland-server", - "wayland-sys 0.30.0-beta.5", - "xkbcommon", -] - -[[package]] -name = "smithay-client-toolkit" -version = "0.15.4" -source = "git+https://github.com/wash2/client-toolkit.git#ebcf9b3ed6454b050621e021f4bf4136fc810965" -dependencies = [ - "bitflags", - "calloop", - "dlib", - "lazy_static", - "log", - "memmap2", - "nix 0.22.3", - "pkg-config", - "wayland-client 0.29.4", - "wayland-cursor", - "wayland-protocols 0.29.4", -] - [[package]] name = "socket2" version = "0.4.4" @@ -2756,6 +2551,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" dependencies = [ "cfg-if", + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2970,7 +2766,7 @@ dependencies = [ "nix 0.24.1", "scoped-tls", "smallvec", - "wayland-sys 0.30.0-beta.5", + "wayland-sys 0.30.0-beta.7", ] [[package]] @@ -2983,7 +2779,6 @@ dependencies = [ "downcast-rs", "libc", "nix 0.22.3", - "scoped-tls", "wayland-commons", "wayland-scanner 0.29.4", "wayland-sys 0.29.4", @@ -3017,27 +2812,6 @@ dependencies = [ "wayland-sys 0.29.4", ] -[[package]] -name = "wayland-cursor" -version = "0.29.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c52758f13d5e7861fc83d942d3d99bf270c83269575e52ac29e5b73cb956a6bd" -dependencies = [ - "nix 0.22.3", - "wayland-client 0.29.4", - "xcursor", -] - -[[package]] -name = "wayland-egl" -version = "0.29.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83281d69ee162b59031c666385e93bde4039ec553b90c4191cdb128ceea29a3a" -dependencies = [ - "wayland-client 0.29.4", - "wayland-sys 0.29.4", -] - [[package]] name = "wayland-protocols" version = "0.29.4" @@ -3050,31 +2824,6 @@ dependencies = [ "wayland-scanner 0.29.4", ] -[[package]] -name = "wayland-protocols" -version = "0.30.0-beta.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9f0d8437907ef09d984290034c4ae387e25a20da7b58be49537afa054fe9a8" -dependencies = [ - "bitflags", - "wayland-backend", - "wayland-scanner 0.30.0-beta.5", - "wayland-server", -] - -[[package]] -name = "wayland-protocols-wlr" -version = "0.1.0-beta.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2c177888ec1668c25de67acbb87575efec1f071ed39322e74bbb4849649cd5b" -dependencies = [ - "bitflags", - "wayland-backend", - "wayland-protocols 0.30.0-beta.5", - "wayland-scanner 0.30.0-beta.5", - "wayland-server", -] - [[package]] name = "wayland-scanner" version = "0.29.4" @@ -3098,41 +2847,23 @@ dependencies = [ "xml-rs", ] -[[package]] -name = "wayland-server" -version = "0.30.0-beta.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13891361d1a0f6b85ca5f95d7fac6f7e2070d28c7442430082a63c40ae53d70e" -dependencies = [ - "bitflags", - "downcast-rs", - "log", - "nix 0.24.1", - "thiserror", - "wayland-backend", - "wayland-scanner 0.30.0-beta.5", -] - [[package]] name = "wayland-sys" version = "0.29.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9341df79a8975679188e37dab3889bfa57c44ac2cb6da166f519a81cbe452d4" dependencies = [ - "dlib", "pkg-config", ] [[package]] name = "wayland-sys" -version = "0.30.0-beta.5" +version = "0.30.0-beta.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3789e5a2e1c61b83b7a382f52ff8651d0a6544074e6012d4721f8e22335247de" +checksum = "f62b62672d36b6cf2f7d936f95c9f5894c0609190fa789c2ce46b73912baf239" dependencies = [ "dlib", - "libc", "log", - "memoffset", "pkg-config", ] @@ -3229,15 +2960,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "xcursor" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" -dependencies = [ - "nom", -] - [[package]] name = "xdg" version = "2.4.1" @@ -3248,32 +2970,12 @@ dependencies = [ ] [[package]] -name = "xdg-shell-wrapper" +name = "xdg-shell-wrapper-config" version = "0.1.0" -source = "git+https://github.com/pop-os/xdg-shell-wrapper?branch=rework-0.30#9b26291502c5e6d3b969e22f4b80fc57c0e3a6f4" +source = "git+https://github.com/pop-os/xdg-shell-wrapper#e523530fd900ae1985e664cce84c4066b23afea1" dependencies = [ - "anyhow", - "calloop", - "itertools", - "libc", - "once_cell", - "ron", "serde", - "shlex", - "slog", - "smithay", - "smithay-client-toolkit", - "tempfile", - "wayland-egl", -] - -[[package]] -name = "xkbcommon" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda0ea5f7ddabd51deeeda7799bee06274112f577da7dd3d954b8eda731b2fce" -dependencies = [ - "libc", + "wayland-protocols", ] [[package]] diff --git a/applets/cosmic-app-list/Cargo.toml b/applets/cosmic-app-list/Cargo.toml index e14917c2..10dfc0d4 100644 --- a/applets/cosmic-app-list/Cargo.toml +++ b/applets/cosmic-app-list/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"], branch = "rework_0.30"} +cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"] } cascade = "1.0.0" gtk4 = { git = "https://github.com/gtk-rs/gtk4-rs", features = ["v4_4"] } gio = { git = "https://github.com/gtk-rs/gtk-rs-core" } diff --git a/applets/cosmic-applet-audio/src/main.rs b/applets/cosmic-applet-audio/src/main.rs index 938e1956..b1881f0a 100644 --- a/applets/cosmic-applet-audio/src/main.rs +++ b/applets/cosmic-applet-audio/src/main.rs @@ -76,90 +76,93 @@ fn app(application: &Application) { }); pa.connect().unwrap(); // XXX unwrap view! { - window = libcosmic_applet::Applet { + window = libcosmic_applet::AppletWindow { set_application: Some(application), set_title: Some("COSMIC Network Applet"), - // TODO: adjust based on volume, mute - set_button_icon_name: "multimedia-volume-control-symbolic", #[wrap(Some)] - set_popover_child: window_box = &GtkBox { - set_orientation: Orientation::Vertical, - set_spacing: 24, - append: output_box = &GtkBox { - set_orientation: Orientation::Horizontal, - set_spacing: 16, - append: output_icon = &Image { - set_icon_name: Some("audio-speakers-symbolic"), - }, - append: output_volume = &Scale::with_range(Orientation::Horizontal, 0., 100., 1.) { - set_format_value_func: |_, value| { - format!("{:.0}%", value) - }, - set_value_pos: PositionType::Right, - set_hexpand: true - } - }, - append: input_box = &GtkBox { - set_orientation: Orientation::Horizontal, - set_spacing: 16, - append: input_icon = &Image { - set_icon_name: Some("audio-input-microphone-symbolic"), - }, - append: input_volume = &Scale::with_range(Orientation::Horizontal, 0., 100., 1.) { - set_format_value_func: |_, value| { - format!("{:.0}%", value) - }, - set_value_pos: PositionType::Right, - set_hexpand: true - } - }, - append: _sep = &Separator { - set_orientation: Orientation::Horizontal, - }, - append: output_list_box = &GtkBox { + set_child = &libcosmic_applet::AppletButton { + // TODO: adjust based on volume, mute + set_button_icon_name: "multimedia-volume-control-symbolic", + #[wrap(Some)] + set_popover_child: window_box = &GtkBox { set_orientation: Orientation::Vertical, - append: current_output_button = &Button { - #[wrap(Some)] - set_child: current_output = &Label {}, - connect_clicked[outputs_revealer] => move |_| { - outputs_revealer.set_reveal_child(!outputs_revealer.reveals_child()); + set_spacing: 24, + append: output_box = &GtkBox { + set_orientation: Orientation::Horizontal, + set_spacing: 16, + append: output_icon = &Image { + set_icon_name: Some("audio-speakers-symbolic"), + }, + append: output_volume = &Scale::with_range(Orientation::Horizontal, 0., 100., 1.) { + set_format_value_func: |_, value| { + format!("{:.0}%", value) + }, + set_value_pos: PositionType::Right, + set_hexpand: true } }, - append: outputs_revealer = &Revealer { - set_transition_type: RevealerTransitionType::SlideDown, - #[wrap(Some)] - set_child: outputs = &ListBox { - set_selection_mode: SelectionMode::None, - set_activate_on_single_click: true - } - } - }, - append: _sep = &Separator { - set_orientation: Orientation::Horizontal, - }, - append: input_list_box = &GtkBox { - set_orientation: Orientation::Vertical, - append: current_input_button = &Button { - #[wrap(Some)] - set_child: current_input = &Label {}, - connect_clicked[inputs_revealer] => move |_| { - inputs_revealer.set_reveal_child(!inputs_revealer.reveals_child()); + append: input_box = &GtkBox { + set_orientation: Orientation::Horizontal, + set_spacing: 16, + append: input_icon = &Image { + set_icon_name: Some("audio-input-microphone-symbolic"), + }, + append: input_volume = &Scale::with_range(Orientation::Horizontal, 0., 100., 1.) { + set_format_value_func: |_, value| { + format!("{:.0}%", value) + }, + set_value_pos: PositionType::Right, + set_hexpand: true } }, - append: inputs_revealer = &Revealer { - set_transition_type: RevealerTransitionType::SlideDown, - #[wrap(Some)] - set_child: inputs = &ListBox { - set_selection_mode: SelectionMode::None, - set_activate_on_single_click: true + append: _sep = &Separator { + set_orientation: Orientation::Horizontal, + }, + append: output_list_box = &GtkBox { + set_orientation: Orientation::Vertical, + append: current_output_button = &Button { + #[wrap(Some)] + set_child: current_output = &Label {}, + connect_clicked[outputs_revealer] => move |_| { + outputs_revealer.set_reveal_child(!outputs_revealer.reveals_child()); + } + }, + append: outputs_revealer = &Revealer { + set_transition_type: RevealerTransitionType::SlideDown, + #[wrap(Some)] + set_child: outputs = &ListBox { + set_selection_mode: SelectionMode::None, + set_activate_on_single_click: true + } } + }, + append: _sep = &Separator { + set_orientation: Orientation::Horizontal, + }, + append: input_list_box = &GtkBox { + set_orientation: Orientation::Vertical, + append: current_input_button = &Button { + #[wrap(Some)] + set_child: current_input = &Label {}, + connect_clicked[inputs_revealer] => move |_| { + inputs_revealer.set_reveal_child(!inputs_revealer.reveals_child()); + } + }, + append: inputs_revealer = &Revealer { + set_transition_type: RevealerTransitionType::SlideDown, + #[wrap(Some)] + set_child: inputs = &ListBox { + set_selection_mode: SelectionMode::None, + set_activate_on_single_click: true + } + } + }, + append: _sep = &Separator { + set_orientation: Orientation::Horizontal, + }, + append: playing_apps = &ListBox { + set_selection_mode: SelectionMode::None, } - }, - append: _sep = &Separator { - set_orientation: Orientation::Horizontal, - }, - append: playing_apps = &ListBox { - set_selection_mode: SelectionMode::None, } } } diff --git a/applets/cosmic-applet-battery/src/main.rs b/applets/cosmic-applet-battery/src/main.rs index 616712ed..66a5c3e9 100644 --- a/applets/cosmic-applet-battery/src/main.rs +++ b/applets/cosmic-applet-battery/src/main.rs @@ -57,6 +57,7 @@ struct AppModel { kbd_backlight: Option>, } +#[derive(Debug)] enum AppMsg { SetDisplayBrightness(f64), SetKeyboardBrightness(f64), @@ -77,115 +78,118 @@ impl SimpleComponent for AppModel { type Output = (); view! { - libcosmic_applet::Applet { - #[watch] - set_button_icon_name: &model.icon_name, + libcosmic_applet::AppletWindow { #[wrap(Some)] - set_popover_child = >k4::Box { - set_orientation: gtk4::Orientation::Vertical, + set_child = &libcosmic_applet::AppletButton { + #[watch] + set_button_icon_name: &model.icon_name, + #[wrap(Some)] + set_popover_child = >k4::Box { + set_orientation: gtk4::Orientation::Vertical, - // Battery - gtk4::Box { - set_orientation: gtk4::Orientation::Horizontal, - gtk4::Image { - #[watch] - set_icon_name: Some(&model.icon_name), - }, + // Battery gtk4::Box { - set_orientation: gtk4::Orientation::Vertical, - gtk4::Label { - set_halign: gtk4::Align::Start, - set_label: "Battery", - }, - gtk4::Label { - set_halign: gtk4::Align::Start, - // XXX time to full, fully changed, etc. + set_orientation: gtk4::Orientation::Horizontal, + gtk4::Image { #[watch] - set_label: &format!("{} until empty ({:.0}%)", format_duration(model.time_remaining), model.battery_percent), + set_icon_name: Some(&model.icon_name), + }, + gtk4::Box { + set_orientation: gtk4::Orientation::Vertical, + gtk4::Label { + set_halign: gtk4::Align::Start, + set_label: "Battery", + }, + gtk4::Label { + set_halign: gtk4::Align::Start, + // XXX time to full, fully changed, etc. + #[watch] + set_label: &format!("{} until empty ({:.0}%)", format_duration(model.time_remaining), model.battery_percent), + }, }, }, - }, - gtk4::Separator { - }, + gtk4::Separator { + }, - // Limit charging - gtk4::Box { - set_orientation: gtk4::Orientation::Horizontal, + // Limit charging gtk4::Box { - set_orientation: gtk4::Orientation::Vertical, - gtk4::Label { - set_halign: gtk4::Align::Start, - set_label: "Limit Battery Charging", + set_orientation: gtk4::Orientation::Horizontal, + gtk4::Box { + set_orientation: gtk4::Orientation::Vertical, + gtk4::Label { + set_halign: gtk4::Align::Start, + set_label: "Limit Battery Charging", + }, + gtk4::Label { + set_halign: gtk4::Align::Start, + set_label: "Increase the lifespan of your battery by setting a maximum charge value of 80%." + }, + }, + gtk4::Switch { + set_valign: gtk4::Align::Center, + }, + }, + + gtk4::Separator { + }, + + // Brightness + gtk4::Box { + #[watch] + set_visible: model.backlight.is_some(), + set_orientation: gtk4::Orientation::Horizontal, + gtk4::Image { + set_icon_name: Some("display-brightness-symbolic"), + }, + gtk4::Scale { + set_hexpand: true, + set_adjustment: >k4::Adjustment::new(0., 0., 1., 1., 1., 0.), + #[watch] + set_value: model.display_brightness, + connect_change_value[sender] => move |_, _, value| { + sender.input(AppMsg::SetDisplayBrightness(value)); + gtk4::Inhibit(false) + }, }, gtk4::Label { - set_halign: gtk4::Align::Start, - set_label: "Increase the lifespan of your battery by setting a maximum charge value of 80%." + #[watch] + set_label: &format!("{:.0}%", model.display_brightness * 100.), }, }, - gtk4::Switch { - set_valign: gtk4::Align::Center, - }, - }, - - gtk4::Separator { - }, - - // Brightness - gtk4::Box { - #[watch] - set_visible: model.backlight.is_some(), - set_orientation: gtk4::Orientation::Horizontal, - gtk4::Image { - set_icon_name: Some("display-brightness-symbolic"), - }, - gtk4::Scale { - set_hexpand: true, - set_adjustment: >k4::Adjustment::new(0., 0., 1., 1., 1., 0.), + gtk4::Box { #[watch] - set_value: model.display_brightness, - connect_change_value[sender] => move |_, _, value| { - sender.input(AppMsg::SetDisplayBrightness(value)); - gtk4::Inhibit(false) + set_visible: model.kbd_backlight.is_some(), + set_orientation: gtk4::Orientation::Horizontal, + gtk4::Image { + set_icon_name: Some("keyboard-brightness-symbolic"), + }, + gtk4::Scale { + set_hexpand: true, + set_adjustment: >k4::Adjustment::new(0., 0., 1., 1., 1., 0.), + #[watch] + set_value: model.keyboard_brightness, + connect_change_value[sender] => move |_, _, value| { + sender.input(AppMsg::SetKeyboardBrightness(value)); + gtk4::Inhibit(false) + }, + }, + gtk4::Label { + #[watch] + set_label: &format!("{:.0}%", model.keyboard_brightness * 100.), }, }, - gtk4::Label { - #[watch] - set_label: &format!("{:.0}%", model.display_brightness * 100.), - }, - }, - gtk4::Box { - #[watch] - set_visible: model.kbd_backlight.is_some(), - set_orientation: gtk4::Orientation::Horizontal, - gtk4::Image { - set_icon_name: Some("keyboard-brightness-symbolic"), - }, - gtk4::Scale { - set_hexpand: true, - set_adjustment: >k4::Adjustment::new(0., 0., 1., 1., 1., 0.), - #[watch] - set_value: model.keyboard_brightness, - connect_change_value[sender] => move |_, _, value| { - sender.input(AppMsg::SetKeyboardBrightness(value)); - gtk4::Inhibit(false) - }, - }, - gtk4::Label { - #[watch] - set_label: &format!("{:.0}%", model.keyboard_brightness * 100.), - }, - }, - gtk4::Separator { - }, + gtk4::Separator { + }, - gtk4::Button { - set_label: "Power Settings...", - connect_clicked => move |_| { - // XXX open subpanel - let _ = Command::new("cosmic-settings").spawn(); - // TODO hide + gtk4::Button { + set_label: "Power Settings...", + connect_clicked => move |_| { + // XXX open subpanel + let _ = Command::new("cosmic-settings").spawn(); + // TODO hide + } } } } diff --git a/applets/cosmic-applet-graphics/Cargo.toml b/applets/cosmic-applet-graphics/Cargo.toml index e8e6069e..9fa48c03 100644 --- a/applets/cosmic-applet-graphics/Cargo.toml +++ b/applets/cosmic-applet-graphics/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" [dependencies] gtk4 = { git = "https://github.com/gtk-rs/gtk4-rs", features = ["v4_2"] } +libcosmic-applet = { path = "../../libcosmic-applet" } once_cell = "1.9.0" relm4-macros = { git = "https://github.com/Relm4/Relm4.git", branch = "next" } tokio = { version = "1.16.1", features = ["full"] } zbus = "2.1.1" -cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"], branch = "rework_0.30"} diff --git a/applets/cosmic-applet-graphics/src/main.rs b/applets/cosmic-applet-graphics/src/main.rs index f9f77cad..97f4327b 100644 --- a/applets/cosmic-applet-graphics/src/main.rs +++ b/applets/cosmic-applet-graphics/src/main.rs @@ -11,28 +11,15 @@ pub mod mode_box; use self::{dbus::PowerDaemonProxy, graphics::Graphics, mode_box::ModeSelection}; use gtk4::{ - gdk::Display, - gio::ApplicationFlags, glib::{self, clone, MainContext, PRIORITY_DEFAULT}, prelude::*, - Align, CssProvider, Label, ListBox, ListBoxRow, Orientation, Overlay, Separator, Spinner, - StyleContext, STYLE_PROVIDER_PRIORITY_APPLICATION, + Align, Label, ListBox, ListBoxRow, Orientation, Overlay, Separator, Spinner, }; use once_cell::sync::Lazy; use tokio::runtime::Runtime; -use cosmic_panel_config::CosmicPanelConfig; static RT: Lazy = Lazy::new(|| Runtime::new().expect("failed to build tokio runtime")); -fn main() { - let application = gtk4::Application::new( - Some("com.system76.cosmic.applets.graphics"), - ApplicationFlags::default(), - ); - application.connect_activate(build_ui); - application.run(); -} - async fn get_current_graphics() -> zbus::Result { let connection = zbus::Connection::system().await?; let proxy = PowerDaemonProxy::new(&connection).await?; @@ -53,7 +40,9 @@ fn row_clicked(_: &ListBox, row: &ListBoxRow) { selector.emit_activate(); } -fn build_ui(application: >k4::Application) { +fn main() { + gtk4::init().unwrap(); + let provider = gtk4::CssProvider::new(); provider.load_from_data(include_bytes!("style.css")); gtk4::StyleContext::add_provider_for_display( @@ -62,141 +51,119 @@ fn build_ui(application: >k4::Application) { gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION, ); - let window = gtk4::ApplicationWindow::builder() - .application(application) - .title("COSMIC Graphics Applet") - .decorated(false) - .resizable(false) - .width_request(1) - .height_request(1) - .css_classes(vec!["root_window".to_string()]) - .build(); - let config = CosmicPanelConfig::load_from_env().unwrap_or_default(); - let popover = gtk4::builders::PopoverBuilder::new() - .autohide(true) - .has_arrow(false) - .build(); - let button = gtk4::Button::new(); - button.add_css_class("panel_icon"); - button.connect_clicked(glib::clone!(@weak popover => move |_| { - popover.show(); - })); - // TODO cleanup - let image = gtk4::Image::from_icon_name("input-gaming"); - image.add_css_class("panel_icon"); - image.set_pixel_size(config.get_applet_icon_size().try_into().unwrap()); - button.set_child(Some(&image)); - let current_graphics = RT + let current_graphics = RT .block_on(get_current_graphics()) .expect("failed to connect to system76-power"); - view! { - icon_box = gtk4::Box { - set_orientation: Orientation::Vertical, - set_spacing: 0, - add_css_class: "icon_box", - } - } let (tx, rx) = MainContext::channel::(PRIORITY_DEFAULT); view! { - main_overlay = Overlay { - add_overlay: loading_box = >k4::Box { - append: loading_explain_box = >k4::Box { - set_orientation: Orientation::Vertical, - set_halign: Align::Center, - set_valign: Align::Center, - append: loading_spinner = &Spinner { - set_halign: Align::Center, - }, - append: loading_explain = &Label { - set_label: "Please wait while your graphics mode is set...", - set_halign: Align::Center, - }, - }, - set_halign: Align::Center, - set_valign: Align::Center, - set_hexpand: true, - set_vexpand: true, - set_visible: false, - add_css_class: "loading-overlay", - }, + window = libcosmic_applet::AppletWindow { + set_title: Some("COSMIC Graphics Applet"), #[wrap(Some)] - set_child: main_box = >k4::Box { - set_orientation: Orientation::Vertical, - set_spacing: 10, - set_margin_top: 20, - set_margin_bottom: 20, - set_margin_start: 24, - set_margin_end: 24, - append: mode_label = &Label { - set_text: "Graphics Mode" - }, - append: separator = &Separator { - set_orientation: Orientation::Horizontal - }, - append: graphics_modes_list = &ListBox { - connect_row_activated: row_clicked, - append: integrated_selector = &ModeSelection { - set_title: "Integrated Graphics", - set_description: "Disables external displays. Requires Restart.", - set_active: (current_graphics == Graphics::Integrated), - connect_toggled: clone!(@strong tx => move |_| { - tx.send(true).expect("failed to send to main context"); - let tx = tx.clone(); - RT.spawn(async move { - set_graphics(Graphics::Integrated).await.expect("failed to set graphics mode"); - tx.send(false).expect("failed to send to main context"); - }); - }) - }, - append: nvidia_selector = &ModeSelection { - set_title: "NVIDIA Graphics", - set_group: Some(&integrated_selector), - set_active: (current_graphics == Graphics::Nvidia), - connect_toggled: clone!(@strong tx => move |_| { - tx.send(true).expect("failed to send to main context"); - let tx = tx.clone(); - RT.spawn(async move { - set_graphics(Graphics::Nvidia).await.expect("failed to set graphics mode"); - tx.send(false).expect("failed to send to main context"); - }); - }) - }, - append: hybrid_selector = &ModeSelection { - set_title: "Hybrid Graphics", - set_description: "Requires Restart.", - set_group: Some(&integrated_selector), - set_active: (current_graphics == Graphics::Hybrid), - connect_toggled: clone!(@strong tx => move |_| { - tx.send(true).expect("failed to send to main context"); - let tx = tx.clone(); - RT.spawn(async move { - set_graphics(Graphics::Hybrid).await.expect("failed to set graphics mode"); - tx.send(false).expect("failed to send to main context"); - }); - }) - }, - append: compute_selector = &ModeSelection { - set_title: "Compute Graphics", - set_description: "Disables external displays. Requires Restart.", - set_group: Some(&integrated_selector), - set_active: (current_graphics == Graphics::Compute), - connect_toggled: clone!(@strong tx => move |_| { - tx.send(true).expect("failed to send to main context"); - let tx = tx.clone(); - RT.spawn(async move { - set_graphics(Graphics::Compute).await.expect("failed to set graphics mode"); - tx.send(false).expect("failed to send to main context"); - }); - }) + set_child = &libcosmic_applet::AppletButton { + set_button_icon_name: "input-gaming", + #[wrap(Some)] + set_popover_child: main_overlay = &Overlay { + add_overlay: loading_box = >k4::Box { + append: loading_explain_box = >k4::Box { + set_orientation: Orientation::Vertical, + set_halign: Align::Center, + set_valign: Align::Center, + append: loading_spinner = &Spinner { + set_halign: Align::Center, + }, + append: loading_explain = &Label { + set_label: "Please wait while your graphics mode is set...", + set_halign: Align::Center, + }, + }, + set_halign: Align::Center, + set_valign: Align::Center, + set_hexpand: true, + set_vexpand: true, + set_visible: false, + add_css_class: "loading-overlay", }, + #[wrap(Some)] + set_child: main_box = >k4::Box { + set_orientation: Orientation::Vertical, + set_spacing: 10, + set_margin_top: 20, + set_margin_bottom: 20, + set_margin_start: 24, + set_margin_end: 24, + append: mode_label = &Label { + set_text: "Graphics Mode" + }, + append: separator = &Separator { + set_orientation: Orientation::Horizontal + }, + append: graphics_modes_list = &ListBox { + connect_row_activated: row_clicked, + append: integrated_selector = &ModeSelection { + set_title: "Integrated Graphics", + set_description: "Disables external displays. Requires Restart.", + set_active: (current_graphics == Graphics::Integrated), + connect_toggled: clone!(@strong tx => move |_| { + tx.send(true).expect("failed to send to main context"); + let tx = tx.clone(); + RT.spawn(async move { + set_graphics(Graphics::Integrated).await.expect("failed to set graphics mode"); + tx.send(false).expect("failed to send to main context"); + }); + }) + }, + append: nvidia_selector = &ModeSelection { + set_title: "NVIDIA Graphics", + set_group: Some(&integrated_selector), + set_active: (current_graphics == Graphics::Nvidia), + connect_toggled: clone!(@strong tx => move |_| { + tx.send(true).expect("failed to send to main context"); + let tx = tx.clone(); + RT.spawn(async move { + set_graphics(Graphics::Nvidia).await.expect("failed to set graphics mode"); + tx.send(false).expect("failed to send to main context"); + }); + }) + }, + append: hybrid_selector = &ModeSelection { + set_title: "Hybrid Graphics", + set_description: "Requires Restart.", + set_group: Some(&integrated_selector), + set_active: (current_graphics == Graphics::Hybrid), + connect_toggled: clone!(@strong tx => move |_| { + tx.send(true).expect("failed to send to main context"); + let tx = tx.clone(); + RT.spawn(async move { + set_graphics(Graphics::Hybrid).await.expect("failed to set graphics mode"); + tx.send(false).expect("failed to send to main context"); + }); + }) + }, + append: compute_selector = &ModeSelection { + set_title: "Compute Graphics", + set_description: "Disables external displays. Requires Restart.", + set_group: Some(&integrated_selector), + set_active: (current_graphics == Graphics::Compute), + connect_toggled: clone!(@strong tx => move |_| { + tx.send(true).expect("failed to send to main context"); + let tx = tx.clone(); + RT.spawn(async move { + set_graphics(Graphics::Compute).await.expect("failed to set graphics mode"); + tx.send(false).expect("failed to send to main context"); + }); + }) + }, + } + } } } } } + rx.attach( None, clone!(@weak loading_box, @weak loading_spinner => @default-return Continue(true), move |val| { @@ -205,11 +172,9 @@ fn build_ui(application: >k4::Application) { Continue(true) }), ); - popover.set_child(Some(&main_overlay)); - - icon_box.append(&button); - icon_box.append(&popover); - window.set_child(Some(&icon_box)); window.show(); + + let main_loop = glib::MainLoop::new(None, false); + main_loop.run(); } diff --git a/applets/cosmic-applet-graphics/src/style.css b/applets/cosmic-applet-graphics/src/style.css index 8a91f3eb..ca16e327 100644 --- a/applets/cosmic-applet-graphics/src/style.css +++ b/applets/cosmic-applet-graphics/src/style.css @@ -2,32 +2,3 @@ background-color: #2f2f2f; opacity: 0.85; } - -image.panel_icon { - padding-left: 0px; - padding-right: 0px; - padding-top: 0px; - padding-bottom: 0px; -} - -button.panel_icon { - border-radius: 12px; - transition: 100ms; - padding: 4px; - border-color: transparent; - background: transparent; - outline-color: transparent; -} - -button.panel_icon:hover { - border-radius: 12px; - transition: 100ms; - padding: 4px; - border-color: rgba(255, 255, 255, 0.1); - outline-color: rgba(255, 255, 255, 0.1); - background: rgba(255, 255, 255, 0.1); -} - -window.root_window { - background: transparent; -} \ No newline at end of file diff --git a/applets/cosmic-applet-network/Cargo.toml b/applets/cosmic-applet-network/Cargo.toml index a8002743..f7b83b82 100644 --- a/applets/cosmic-applet-network/Cargo.toml +++ b/applets/cosmic-applet-network/Cargo.toml @@ -14,5 +14,5 @@ relm4-macros = { git = "https://github.com/Relm4/Relm4.git", branch = "next" } slotmap = "1.0.6" tokio = { version = "1.15.0", features = ["full"] } zbus = "2.0.1" +libcosmic-applet = { path = "../../libcosmic-applet" } libcosmic-widgets = { git = "https://github.com/pop-os/libcosmic", branch = "relm4-next" } -cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"], branch = "rework_0.30"} diff --git a/applets/cosmic-applet-network/src/main.rs b/applets/cosmic-applet-network/src/main.rs index 02580632..20ca0bf6 100644 --- a/applets/cosmic-applet-network/src/main.rs +++ b/applets/cosmic-applet-network/src/main.rs @@ -7,90 +7,43 @@ pub mod task; pub mod ui; pub mod widgets; -use cosmic_panel_config::CosmicPanelConfig; -use gtk4::{gio::ApplicationFlags, glib, prelude::*, Orientation, Separator}; +use gtk4::{glib, prelude::*, Orientation, Separator}; use once_cell::sync::Lazy; use tokio::runtime::Runtime; static RT: Lazy = Lazy::new(|| Runtime::new().expect("failed to build tokio runtime")); fn main() { - let application = gtk4::Application::new( - Some("com.system76.cosmic.applets.network"), - ApplicationFlags::default(), - ); - application.connect_activate(build_ui); - application.run(); -} - -fn build_ui(application: >k4::Application) { - let provider = gtk4::CssProvider::new(); - provider.load_from_data(include_bytes!("style.css")); - gtk4::StyleContext::add_provider_for_display( - >k4::gdk::Display::default().expect("Could not connect to a display."), - &provider, - gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION, - ); - - let window = gtk4::ApplicationWindow::builder() - .application(application) - .title("COSMIC Network Applet") - .decorated(false) - .resizable(false) - .width_request(1) - .height_request(1) - .css_classes(vec!["root_window".to_string()]) - .build(); + gtk4::init().unwrap(); view! { - main_box = gtk4::Box { - set_orientation: Orientation::Vertical, - set_spacing: 10, - set_margin_top: 20, - set_margin_bottom: 20, - set_margin_start: 24, - set_margin_end: 24 + window = libcosmic_applet::AppletWindow { + set_title: Some("COSMIC Network Applet"), + #[wrap(Some)] + set_child: button = &libcosmic_applet::AppletButton { + set_button_icon_name: "preferences-system-network", + #[wrap(Some)] + set_popover_child: main_box = >k4::Box { + set_orientation: Orientation::Vertical, + set_spacing: 10, + set_margin_top: 20, + set_margin_bottom: 20, + set_margin_start: 24, + set_margin_end: 24 + } + } } } - let config = CosmicPanelConfig::load_from_env().unwrap_or_default(); - let popover = gtk4::builders::PopoverBuilder::new() - .autohide(true) - .has_arrow(false) - .build(); - - let button = gtk4::Button::new(); - button.add_css_class("panel_icon"); - button.connect_clicked(glib::clone!(@weak popover => move |_| { - popover.show(); - })); - - // TODO cleanup - let image = gtk4::Image::from_icon_name("preferences-system-network"); - image.add_css_class("panel_icon"); - image.set_pixel_size(config.get_applet_icon_size().try_into().unwrap()); - button.set_child(Some(&image)); - - view! { - icon_box = gtk4::Box { - set_orientation: Orientation::Vertical, - set_spacing: 0, - add_css_class: "icon_box", - } - } - - popover.set_child(Some(&main_box)); - - icon_box.append(&button); - icon_box.append(&popover); - - ui::current_networks::add_current_networks(&main_box, &image); + ui::current_networks::add_current_networks(&main_box, &button); main_box.append(&Separator::new(Orientation::Horizontal)); ui::toggles::add_toggles(&main_box); let available_wifi_separator = Separator::new(Orientation::Horizontal); main_box.append(&available_wifi_separator); available_wifi_separator.hide(); ui::available_wifi::add_available_wifi(&main_box, available_wifi_separator); - window.set_child(Some(&icon_box)); window.show(); + + let main_loop = glib::MainLoop::new(None, false); + main_loop.run(); } diff --git a/applets/cosmic-applet-network/src/style.css b/applets/cosmic-applet-network/src/style.css deleted file mode 100644 index 7b11fdc0..00000000 --- a/applets/cosmic-applet-network/src/style.css +++ /dev/null @@ -1,28 +0,0 @@ -image.panel_icon { - padding-left: 0px; - padding-right: 0px; - padding-top: 0px; - padding-bottom: 0px; -} - -button.panel_icon { - border-radius: 12px; - transition: 100ms; - padding: 4px; - border-color: transparent; - background: transparent; - outline-color: transparent; -} - -button.panel_icon:hover { - border-radius: 12px; - transition: 100ms; - padding: 4px; - border-color: rgba(255, 255, 255, 0.1); - outline-color: rgba(255, 255, 255, 0.1); - background: rgba(255, 255, 255, 0.1); -} - -window.root_window { - background: transparent; -} diff --git a/applets/cosmic-applet-network/src/ui/current_networks.rs b/applets/cosmic-applet-network/src/ui/current_networks.rs index 0f389ece..5c1b85f1 100644 --- a/applets/cosmic-applet-network/src/ui/current_networks.rs +++ b/applets/cosmic-applet-network/src/ui/current_networks.rs @@ -18,7 +18,7 @@ use gtk4::{ use std::{cell::RefCell, net::IpAddr, rc::Rc}; use zbus::Connection; -pub fn add_current_networks(target: >k4::Box, icon_image: >k4::Image) { +pub fn add_current_networks(target: >k4::Box, icon_image: &libcosmic_applet::AppletButton) { let networks_list = ListBox::builder().show_separators(true).build(); let entries = Rc::>>::default(); let (tx, rx) = MainContext::channel::>(PRIORITY_DEFAULT); @@ -38,7 +38,7 @@ fn display_active_connections( connections: Vec, target: &ListBox, entries: &mut Vec, - icon_image: >k4::Image, + icon_image: &libcosmic_applet::AppletButton, ) { for old_entry in entries.drain(..) { target.remove(&old_entry); @@ -51,7 +51,7 @@ fn display_active_connections( speed, ip_addresses, } => { - icon_image.set_icon_name(Some("network-wired-symbolic")); + icon_image.set_button_icon_name("network-wired-symbolic"); render_wired_connection(name, speed, ip_addresses) } ActiveConnectionInfo::WiFi { @@ -62,7 +62,7 @@ fn display_active_connections( wpa_flags, } => continue, ActiveConnectionInfo::Vpn { name, ip_addresses } => { - icon_image.set_icon_name(Some("network-vpn-symbolic")); + icon_image.set_button_icon_name("network-vpn-symbolic"); render_vpn(name, ip_addresses) } }; diff --git a/applets/cosmic-applet-notifications/Cargo.toml b/applets/cosmic-applet-notifications/Cargo.toml index b1870684..a6c752a4 100644 --- a/applets/cosmic-applet-notifications/Cargo.toml +++ b/applets/cosmic-applet-notifications/Cargo.toml @@ -10,8 +10,8 @@ futures = "0.3" gtk4 = { git = "https://github.com/gtk-rs/gtk4-rs" } libcosmic-applet = { path = "../../libcosmic-applet" } once_cell = "1.12" +relm4-macros = { git = "https://github.com/Relm4/Relm4.git", branch = "next" } serde = "1" zbus = "2.0.1" zbus_names = "2" zvariant = "3" -cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"], branch = "rework_0.30"} diff --git a/applets/cosmic-applet-notifications/src/main.rs b/applets/cosmic-applet-notifications/src/main.rs index e9dc63d7..e31923ed 100644 --- a/applets/cosmic-applet-notifications/src/main.rs +++ b/applets/cosmic-applet-notifications/src/main.rs @@ -1,5 +1,5 @@ -use cascade::cascade; use gtk4::{glib, prelude::*}; +use relm4_macros::view; mod dbus_service; mod deref_cell; @@ -19,18 +19,20 @@ fn main() { let notification_list = NotificationList::new(¬ifications); - let window = cascade! { - libcosmic_applet::Applet::new(); - ..set_button_icon_name("user-invisible-symbolic"); // TODO - ..set_popover_child(Some(¬ification_list)); - ..show(); - }; + view! { + window = libcosmic_applet::AppletWindow { + #[wrap(Some)] + set_child: applet_button = &libcosmic_applet::AppletButton { + set_button_icon_name: "user-invisible-symbolic", // TODO + set_popover_child: Some(¬ification_list) + } + } + } + window.show(); // XXX show in correct place - cascade! { - NotificationPopover::new(¬ifications); - ..set_parent(&window.child().unwrap()); // XXX better way? - }; + let notification_popover = NotificationPopover::new(¬ifications); + notification_popover.set_parent(&applet_button); let main_loop = glib::MainLoop::new(None, false); main_loop.run(); diff --git a/applets/cosmic-applet-power/src/main.rs b/applets/cosmic-applet-power/src/main.rs index 0f131f37..d4bab867 100644 --- a/applets/cosmic-applet-power/src/main.rs +++ b/applets/cosmic-applet-power/src/main.rs @@ -24,34 +24,37 @@ fn main() { fn build_ui(application: >k4::Application) { view! { - window = libcosmic_applet::Applet { + window = libcosmic_applet::AppletWindow { set_title: Some("COSMIC Power Applet"), set_application: Some(application), // TODO adjust battery icon based on charge - set_button_icon_name: "system-shutdown-symbolic", #[wrap(Some)] - set_popover_child: main_box = >k4::Box { - set_orientation: Orientation::Vertical, - set_spacing: 10, - set_margin_top: 20, - set_margin_bottom: 20, - set_margin_start: 24, - set_margin_end: 24, - append: settings_button = &Button { - #[wrap(Some)] - set_child = &Label { - set_label: "Settings...", - set_halign: Align::Start, - set_hexpand: true + set_child = &libcosmic_applet::AppletButton { + set_button_icon_name: "system-shutdown-symbolic", + #[wrap(Some)] + set_popover_child: main_box = >k4::Box { + set_orientation: Orientation::Vertical, + set_spacing: 10, + set_margin_top: 20, + set_margin_bottom: 20, + set_margin_start: 24, + set_margin_end: 24, + append: settings_button = &Button { + #[wrap(Some)] + set_child = &Label { + set_label: "Settings...", + set_halign: Align::Start, + set_hexpand: true + }, + connect_clicked => move |_| { + let _ = Command::new("cosmic-settings").spawn(); + } }, - connect_clicked => move |_| { - let _ = Command::new("cosmic-settings").spawn(); - } - }, - append = &Separator {}, - append: &ui::session::build(), - append: second_separator = &Separator {}, - append: &ui::system::build(), + append = &Separator {}, + append: &ui::session::build(), + append: second_separator = &Separator {}, + append: &ui::system::build(), + } } } } diff --git a/applets/cosmic-applet-status-area/Cargo.toml b/applets/cosmic-applet-status-area/Cargo.toml index a13295a3..e61daf1a 100644 --- a/applets/cosmic-applet-status-area/Cargo.toml +++ b/applets/cosmic-applet-status-area/Cargo.toml @@ -8,9 +8,9 @@ license = "GPL-3.0-or-later" cascade = "1" futures = "0.3" gtk4 = { git = "https://github.com/gtk-rs/gtk4-rs" } +libcosmic-applet = { path = "../../libcosmic-applet" } once_cell = "1.12" serde = "1" zbus = "2.0.1" zbus_names = "2" zvariant = "3" -cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"], branch = "rework_0.30"} diff --git a/applets/cosmic-applet-status-area/src/main.rs b/applets/cosmic-applet-status-area/src/main.rs index f584acc5..29cfa29e 100644 --- a/applets/cosmic-applet-status-area/src/main.rs +++ b/applets/cosmic-applet-status-area/src/main.rs @@ -1,3 +1,4 @@ +use cascade::cascade; use gtk4::{glib, prelude::*}; mod dbus_service; @@ -14,24 +15,12 @@ fn main() { // XXX Implement DBus service somewhere other than applet? glib::MainContext::default().spawn_local(status_notifier_watcher::start()); - let provider = gtk4::CssProvider::new(); - provider.load_from_data(include_bytes!("style.css")); - gtk4::StyleContext::add_provider_for_display( - >k4::gdk::Display::default().expect("Could not connect to a display."), - &provider, - gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION, - ); - let status_area = StatusArea::new(); - gtk4::Window::builder() - .decorated(false) - .child(&status_area) - .resizable(false) - .width_request(1) - .height_request(1) - .css_classes(vec!["root_window".to_string()]) - .build() - .show(); + cascade! { + libcosmic_applet::AppletWindow::new(); + ..set_child(Some(&status_area)); + ..show(); + }; let main_loop = glib::MainLoop::new(None, false); main_loop.run(); diff --git a/applets/cosmic-applet-status-area/src/status_menu.rs b/applets/cosmic-applet-status-area/src/status_menu.rs index bc827e00..56bf2c72 100644 --- a/applets/cosmic-applet-status-area/src/status_menu.rs +++ b/applets/cosmic-applet-status-area/src/status_menu.rs @@ -19,7 +19,7 @@ struct Menu { #[derive(Default)] pub struct StatusMenuInner { - menu_button: DerefCell, + menu_button: DerefCell, vbox: DerefCell, item: DerefCell>, dbus_menu: DerefCell>, @@ -43,17 +43,10 @@ impl ObjectImpl for StatusMenuInner { gtk4::Box::new(gtk4::Orientation::Vertical, 0); }; - let popover = cascade! { - gtk4::Popover::new(); - ..set_child(Some(&vbox)); - }; - let menu_button = cascade! { - gtk4::MenuButton::new(); - ..add_css_class("panel_icon"); - ..set_has_frame(false); + libcosmic_applet::AppletButton::new(); ..set_parent(obj); - ..set_popover(Some(&popover)); + ..set_popover_child(Some(&vbox)); }; self.menu_button.set(menu_button); @@ -88,7 +81,7 @@ impl StatusMenu { .await?; let obj = glib::Object::new::(&[]).unwrap(); let icon_name = item.icon_name().await?; - obj.inner().menu_button.set_icon_name(&icon_name); + obj.inner().menu_button.set_button_icon_name(&icon_name); let menu = item.menu().await?; let menu = DBusMenuProxy::builder(&connection) diff --git a/applets/cosmic-applet-status-area/src/style.css b/applets/cosmic-applet-status-area/src/style.css deleted file mode 100644 index 8a91f3eb..00000000 --- a/applets/cosmic-applet-status-area/src/style.css +++ /dev/null @@ -1,33 +0,0 @@ -.loading-overlay { - background-color: #2f2f2f; - opacity: 0.85; -} - -image.panel_icon { - padding-left: 0px; - padding-right: 0px; - padding-top: 0px; - padding-bottom: 0px; -} - -button.panel_icon { - border-radius: 12px; - transition: 100ms; - padding: 4px; - border-color: transparent; - background: transparent; - outline-color: transparent; -} - -button.panel_icon:hover { - border-radius: 12px; - transition: 100ms; - padding: 4px; - border-color: rgba(255, 255, 255, 0.1); - outline-color: rgba(255, 255, 255, 0.1); - background: rgba(255, 255, 255, 0.1); -} - -window.root_window { - background: transparent; -} \ No newline at end of file diff --git a/applets/cosmic-applet-time/Cargo.toml b/applets/cosmic-applet-time/Cargo.toml index 18a93dd2..3f869646 100644 --- a/applets/cosmic-applet-time/Cargo.toml +++ b/applets/cosmic-applet-time/Cargo.toml @@ -9,9 +9,9 @@ cascade = "1" chrono = "0.4" futures = "0.3" gtk4 = { git = "https://github.com/gtk-rs/gtk4-rs", features = [ "v4_6" ] } +libcosmic-applet = { path = "../../libcosmic-applet" } once_cell = "1.12" serde = "1" zbus = "2.0.1" zbus_names = "2" zvariant = "3" -cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"], branch = "rework_0.30"} diff --git a/applets/cosmic-applet-time/src/main.rs b/applets/cosmic-applet-time/src/main.rs index 6233b522..bbb29413 100644 --- a/applets/cosmic-applet-time/src/main.rs +++ b/applets/cosmic-applet-time/src/main.rs @@ -1,3 +1,4 @@ +use cascade::cascade; use gtk4::{glib, prelude::*}; mod deref_cell; @@ -7,25 +8,11 @@ use time_button::TimeButton; fn main() { gtk4::init().unwrap(); - let provider = gtk4::CssProvider::new(); - provider.load_from_data(include_bytes!("style.css")); - gtk4::StyleContext::add_provider_for_display( - >k4::gdk::Display::default().expect("Could not connect to a display."), - &provider, - gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION, - ); - - let time_button = TimeButton::new(); - - gtk4::Window::builder() - .decorated(false) - .child(&time_button) - .resizable(false) - .width_request(1) - .height_request(1) - .css_classes(vec!["root_window".to_string()]) - .build() - .show(); + cascade! { + libcosmic_applet::AppletWindow::new(); + ..set_child(Some(&TimeButton::new())); + ..show(); + }; let main_loop = glib::MainLoop::new(None, false); main_loop.run(); diff --git a/applets/cosmic-applet-time/src/style.css b/applets/cosmic-applet-time/src/style.css deleted file mode 100644 index 8a91f3eb..00000000 --- a/applets/cosmic-applet-time/src/style.css +++ /dev/null @@ -1,33 +0,0 @@ -.loading-overlay { - background-color: #2f2f2f; - opacity: 0.85; -} - -image.panel_icon { - padding-left: 0px; - padding-right: 0px; - padding-top: 0px; - padding-bottom: 0px; -} - -button.panel_icon { - border-radius: 12px; - transition: 100ms; - padding: 4px; - border-color: transparent; - background: transparent; - outline-color: transparent; -} - -button.panel_icon:hover { - border-radius: 12px; - transition: 100ms; - padding: 4px; - border-color: rgba(255, 255, 255, 0.1); - outline-color: rgba(255, 255, 255, 0.1); - background: rgba(255, 255, 255, 0.1); -} - -window.root_window { - background: transparent; -} \ No newline at end of file diff --git a/applets/cosmic-applet-time/src/time_button.rs b/applets/cosmic-applet-time/src/time_button.rs index c05369b2..d2bcb16d 100644 --- a/applets/cosmic-applet-time/src/time_button.rs +++ b/applets/cosmic-applet-time/src/time_button.rs @@ -11,7 +11,7 @@ use crate::deref_cell::DerefCell; #[derive(Default)] pub struct TimeButtonInner { calendar: DerefCell, - button: DerefCell, + button: DerefCell, label: DerefCell, } @@ -40,21 +40,15 @@ impl ObjectImpl for TimeButtonInner { })); }; - let popover = cascade! { - gtk4::Popover::new(); - ..set_child(Some(&cascade! { + let button = cascade! { + libcosmic_applet::AppletButton::new(); + ..set_parent(obj); + ..connect_activate(clone!(@strong obj => move |_| obj.opening())); + ..set_button_child(Some(&label)); + ..set_popover_child(Some(&cascade! { gtk4::Box::new(gtk4::Orientation::Horizontal, 0); ..append(&calendar); })); - ..connect_show(clone!(@strong obj => move |_| obj.opening())); - }; - - let button = cascade! { - gtk4::MenuButton::new(); - ..set_child(Some(&label)); - ..set_has_frame(false); - ..set_parent(obj); - ..set_popover(Some(&popover)); }; self.calendar.set(calendar); diff --git a/applets/cosmic-applet-workspaces/Cargo.toml b/applets/cosmic-applet-workspaces/Cargo.toml index 2e4fc124..0e93d347 100644 --- a/applets/cosmic-applet-workspaces/Cargo.toml +++ b/applets/cosmic-applet-workspaces/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"], branch = "rework_0.30"} +cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"] } cascade = "1.0.0" gtk4 = { git = "https://github.com/gtk-rs/gtk4-rs", features = ["v4_4"] } once_cell = "1.9.0" diff --git a/applets/cosmic-applet-workspaces/src/main.rs b/applets/cosmic-applet-workspaces/src/main.rs index 681a452b..5a715a5a 100644 --- a/applets/cosmic-applet-workspaces/src/main.rs +++ b/applets/cosmic-applet-workspaces/src/main.rs @@ -1,5 +1,6 @@ // SPDX-License-Identifier: MPL-2.0-only +use calloop::channel::SyncSender; use gtk4::{ gdk::Display, gio::{self, ApplicationFlags}, @@ -13,7 +14,6 @@ use tokio::sync::mpsc; use utils::{Activate, WorkspaceEvent}; use wayland::State; use window::CosmicWorkspacesWindow; -use calloop::channel::SyncSender; mod localize; mod utils; diff --git a/applets/cosmic-applet-workspaces/src/wayland.rs b/applets/cosmic-applet-workspaces/src/wayland.rs index 60073f5b..5c98deb3 100644 --- a/applets/cosmic-applet-workspaces/src/wayland.rs +++ b/applets/cosmic-applet-workspaces/src/wayland.rs @@ -92,8 +92,8 @@ pub fn spawn_workspaces(tx: glib::Sender) -> SyncSender { running: true, }; let loop_handle = event_loop.handle(); - loop_handle.insert_source(workspaces_rx, |e, _, state| { - match e { + loop_handle + .insert_source(workspaces_rx, |e, _, state| match e { Event::Msg(WorkspaceEvent::Activate(id)) => { if let Some(w) = state .workspace_groups @@ -136,15 +136,16 @@ pub fn spawn_workspaces(tx: glib::Sender) -> SyncSender { } } } - Event::Closed => if let Some(workspace_manager) = &mut state.workspace_manager { - for g in &mut state.workspace_groups { - g.workspace_group_handle.destroy(); + Event::Closed => { + if let Some(workspace_manager) = &mut state.workspace_manager { + for g in &mut state.workspace_groups { + g.workspace_group_handle.destroy(); + } + workspace_manager.stop(); } - workspace_manager.stop(); - }, - } - - }).unwrap(); + } + }) + .unwrap(); while state.running { event_loop .dispatch(Duration::from_millis(16), &mut state) diff --git a/applets/cosmic-applet-workspaces/src/workspace_button/mod.rs b/applets/cosmic-applet-workspaces/src/workspace_button/mod.rs index 4b8d1c03..4c447474 100644 --- a/applets/cosmic-applet-workspaces/src/workspace_button/mod.rs +++ b/applets/cosmic-applet-workspaces/src/workspace_button/mod.rs @@ -43,9 +43,7 @@ impl WorkspaceButton { new_button.connect_clicked(move |_| { let id_clone = id.clone(); if !is_active { - let _ = TX.get() - .unwrap() - .send(WorkspaceEvent::Activate(id_clone)); + let _ = TX.get().unwrap().send(WorkspaceEvent::Activate(id_clone)); } }); diff --git a/applets/cosmic-applet-workspaces/src/workspace_list/mod.rs b/applets/cosmic-applet-workspaces/src/workspace_list/mod.rs index a5e54193..24ab6462 100644 --- a/applets/cosmic-applet-workspaces/src/workspace_list/mod.rs +++ b/applets/cosmic-applet-workspaces/src/workspace_list/mod.rs @@ -61,9 +61,7 @@ impl WorkspaceList { .build(); scroll_controller.connect_scroll(|_, dx, dy| { - let _ = TX.get() - .unwrap() - .send(WorkspaceEvent::Scroll(dx + dy)); + let _ = TX.get().unwrap().send(WorkspaceEvent::Scroll(dx + dy)); Inhibit::default() }); diff --git a/applets/cosmic-panel-button/Cargo.toml b/applets/cosmic-panel-button/Cargo.toml index 6eea9089..4c8f05b0 100644 --- a/applets/cosmic-panel-button/Cargo.toml +++ b/applets/cosmic-panel-button/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"], branch = "rework_0.30"} +cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"] } cascade = "1.0.0" gtk4 = { git = "https://github.com/gtk-rs/gtk4-rs", features = ["v4_4"] } once_cell = "1.9.0" diff --git a/libcosmic-applet/Cargo.toml b/libcosmic-applet/Cargo.toml index 1115c73b..509d5871 100644 --- a/libcosmic-applet/Cargo.toml +++ b/libcosmic-applet/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"], branch = "rework_0.30"} +cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"] } gtk4 = { git = "https://github.com/gtk-rs/gtk4-rs", features = ["v4_6"] } once_cell = "1.12.0" relm4-macros = { git = "https://github.com/Relm4/Relm4.git", branch = "next" } diff --git a/libcosmic-applet/src/button.rs b/libcosmic-applet/src/button.rs new file mode 100644 index 00000000..6c1c997c --- /dev/null +++ b/libcosmic-applet/src/button.rs @@ -0,0 +1,143 @@ +use cosmic_panel_config::CosmicPanelConfig; +use gtk4::{glib, prelude::*, subclass::prelude::*}; +use relm4_macros::view; + +use crate::deref_cell::DerefCell; + +static STYLE: &str = " +button.cosmic_applet_button { + border-radius: 12px; + transition: 100ms; + padding: 4px; + border-color: transparent; + background: transparent; + outline-color: transparent; +} +"; + +#[derive(Default)] +pub struct AppletButtonInner { + menu_button: DerefCell, + panel_config: DerefCell, + popover: DerefCell, +} + +#[glib::object_subclass] +impl ObjectSubclass for AppletButtonInner { + const NAME: &'static str = "CosmicAppletButton"; + type Type = AppletButton; + type ParentType = gtk4::Widget; +} + +impl ObjectImpl for AppletButtonInner { + fn constructed(&self, obj: &AppletButton) { + view! { + menu_button = gtk4::MenuButton { + set_parent: obj, + add_css_class: "cosmic_applet_button", + set_has_frame: false, + #[wrap(Some)] + set_popover: popover = >k4::Popover { + // TODO: change if it can be positioned correctly? + set_has_arrow: false, + } + }, + provider = gtk4::CssProvider { + load_from_data: STYLE.as_bytes(), + } + } + obj.set_layout_manager(Some(>k4::BinLayout::new())); + obj.style_context() + .add_provider(&provider, gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION); + + self.menu_button.set(menu_button); + self.popover.set(popover); + self.panel_config + .set(CosmicPanelConfig::load_from_env().unwrap_or_default()); + } + + fn dispose(&self, _obj: &AppletButton) { + self.menu_button.unparent(); + } +} + +impl WidgetImpl for AppletButtonInner { + fn compute_expand(&self, _obj: &AppletButton, hexpand: &mut bool, vexpand: &mut bool) { + *hexpand = self + .menu_button + .compute_expand(gtk4::Orientation::Horizontal); + *vexpand = self.menu_button.compute_expand(gtk4::Orientation::Vertical); + } + + fn request_mode(&self, _obj: &AppletButton) -> gtk4::SizeRequestMode { + self.menu_button.request_mode() + } +} + +impl WindowImpl for AppletButtonInner {} + +glib::wrapper! { + pub struct AppletButton(ObjectSubclass) + @extends gtk4::Widget; +} + +impl Default for AppletButton { + fn default() -> Self { + Self::new() + } +} + +impl AppletButton { + pub fn new() -> Self { + glib::Object::new(&[]).unwrap() + } + + fn inner(&self) -> &AppletButtonInner { + AppletButtonInner::from_instance(self) + } + + // TODO: avoid multiple instances? + pub fn panel_config(&self) -> &CosmicPanelConfig { + &*self.inner().panel_config + } + + pub fn set_button_child(&self, child: Option<&impl IsA>) { + self.inner().menu_button.set_child(child); + } + + pub fn set_button_icon_name(&self, name: &str) { + let image = gtk4::Image::from_icon_name(name); + image.set_pixel_size( + self.panel_config() + .get_applet_icon_size() + .try_into() + .unwrap(), + ); // XXX unwrap + self.set_button_child(Some(&image)); + } + + pub fn set_button_label(&self, label: &str) { + self.inner().menu_button.set_label(label); + } + + pub fn set_popover_child(&self, child: Option<&impl IsA>) { + self.inner().popover.set_child(child); + } + + pub fn popdown(&self) { + self.inner().popover.popdown(); + } + + pub fn popup(&self) { + self.inner().popover.popup(); + } + + // XXX better API? Actual signal + pub fn connect_activate(&self, f: F) -> glib::SignalHandlerId { + self.inner() + .menu_button + .connect_activate(glib::clone!(@weak self as _self => move |_| { + f(&_self) + })) + } +} diff --git a/libcosmic-applet/src/lib.rs b/libcosmic-applet/src/lib.rs index 79103465..517c18ad 100644 --- a/libcosmic-applet/src/lib.rs +++ b/libcosmic-applet/src/lib.rs @@ -2,8 +2,11 @@ use cosmic_panel_config::CosmicPanelConfig; use gtk4::{glib, prelude::*, subclass::prelude::*}; use relm4_macros::view; +mod button; +pub use button::AppletButton; mod deref_cell; -use deref_cell::DerefCell; +mod window; +pub use window::AppletWindow; // TODO make sure style fits different panel colors? // TODO abstraction to start main loop? Work with relm4. @@ -11,118 +14,4 @@ use deref_cell::DerefCell; // TODO orientation, etc. // TODO make image size dependent on CosmicPanelConfig? // TODO way to have multiple applets with this style, for system tray. - -static STYLE: &str = " -window.cosmic_applet_window { - background: transparent; -} - -button.cosmic_applet_button { - border-radius: 12px; - transition: 100ms; - padding: 4px; - border-color: transparent; - background: transparent; - outline-color: transparent; -} -"; - -#[derive(Default)] -pub struct AppletInner { - panel_config: DerefCell, - menu_button: DerefCell, - popover: DerefCell, -} - -#[glib::object_subclass] -impl ObjectSubclass for AppletInner { - const NAME: &'static str = "CosmicApplet"; - type Type = Applet; - type ParentType = gtk4::Window; -} - -impl ObjectImpl for AppletInner { - fn constructed(&self, obj: &Applet) { - let window = || obj; - view! { - window() { - add_css_class: "cosmic_applet_window", - set_decorated: false, - set_resizable: false, - set_width_request: 1, - set_height_request: 1, - #[wrap(Some)] - set_child: menu_button = >k4::MenuButton { - add_css_class: "cosmic_applet_button", - set_has_frame: false, - #[wrap(Some)] - set_popover: popover = >k4::Popover { - // TODO: change if it can be positioned correctly? - set_has_arrow: false, - } - } - } - } - - let provider = gtk4::CssProvider::new(); - provider.load_from_data(STYLE.as_bytes()); - obj.style_context() - .add_provider(&provider, gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION); - - self.menu_button.set(menu_button); - self.popover.set(popover); - self.panel_config - .set(CosmicPanelConfig::load_from_env().unwrap_or_default()); - } -} - -impl WidgetImpl for AppletInner {} -impl WindowImpl for AppletInner {} - -glib::wrapper! { - pub struct Applet(ObjectSubclass) - @extends gtk4::Widget, gtk4::Window; -} - -impl Default for Applet { - fn default() -> Self { - Self::new() - } -} - -impl Applet { - pub fn new() -> Self { - glib::Object::new(&[]).unwrap() - } - - fn inner(&self) -> &AppletInner { - AppletInner::from_instance(self) - } - - pub fn panel_config(&self) -> &CosmicPanelConfig { - &*self.inner().panel_config - } - - pub fn set_button_child(&self, child: Option<&impl IsA>) { - self.inner().menu_button.set_child(child); - } - - pub fn set_button_icon_name(&self, name: &str) { - let image = gtk4::Image::from_icon_name(name); - image.set_pixel_size( - self.panel_config() - .get_applet_icon_size() - .try_into() - .unwrap(), - ); // XXX unwrap - self.set_button_child(Some(&image)); - } - - pub fn set_button_label(&self, label: &str) { - self.inner().menu_button.set_label(label); - } - - pub fn set_popover_child(&self, child: Option<&impl IsA>) { - self.inner().popover.set_child(child); - } -} +// TODO also handle non-popover button? Is GtkMenuButton particularly special, or just use a toggle button? diff --git a/libcosmic-applet/src/window.rs b/libcosmic-applet/src/window.rs new file mode 100644 index 00000000..257658b3 --- /dev/null +++ b/libcosmic-applet/src/window.rs @@ -0,0 +1,58 @@ +use gtk4::{glib, prelude::*, subclass::prelude::*}; +use relm4_macros::view; + +static STYLE: &str = " +window.cosmic_applet_window { + background: transparent; +} +"; + +#[derive(Default)] +pub struct AppletWindowInner; + +#[glib::object_subclass] +impl ObjectSubclass for AppletWindowInner { + const NAME: &'static str = "CosmicAppletWindow"; + type Type = AppletWindow; + type ParentType = gtk4::Window; +} + +impl ObjectImpl for AppletWindowInner { + fn constructed(&self, obj: &AppletWindow) { + let window = || obj; + view! { + window() { + add_css_class: "cosmic_applet_window", + set_decorated: false, + set_resizable: false, + set_width_request: 1, + set_height_request: 1, + }, + provider = gtk4::CssProvider { + load_from_data: STYLE.as_bytes(), + } + } + obj.style_context() + .add_provider(&provider, gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION); + } +} + +impl WidgetImpl for AppletWindowInner {} +impl WindowImpl for AppletWindowInner {} + +glib::wrapper! { + pub struct AppletWindow(ObjectSubclass) + @extends gtk4::Widget, gtk4::Window; +} + +impl Default for AppletWindow { + fn default() -> Self { + Self::new() + } +} + +impl AppletWindow { + pub fn new() -> Self { + glib::Object::new(&[]).unwrap() + } +}