diff --git a/Cargo.lock b/Cargo.lock index 687db0da..05ebb693 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -681,6 +681,14 @@ dependencies = [ "zvariant", ] +[[package]] +name = "cosmic-panel-button" +version = "0.1.0" +dependencies = [ + "freedesktop-desktop-entry", + "libcosmic", +] + [[package]] name = "cosmic-panel-config" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 0ba094e4..5dbf38a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ members = [ "cosmic-applet-power", "cosmic-applet-time", "cosmic-applet-workspaces", + "cosmic-panel-button", ] [profile.release] diff --git a/cosmic-panel-app-button/data/com.system76.CosmicPanelAppButton.desktop b/cosmic-panel-app-button/data/com.system76.CosmicPanelAppButton.desktop index f8963af1..edecafb9 100644 --- a/cosmic-panel-app-button/data/com.system76.CosmicPanelAppButton.desktop +++ b/cosmic-panel-app-button/data/com.system76.CosmicPanelAppButton.desktop @@ -2,7 +2,7 @@ Name=Cosmic Panel App Library Button Comment=Write a GTK + Rust application Type=Application -Exec=cosmic-panel-button --id com.system76.CosmicAppLibrary +Exec=cosmic-panel-button com.system76.CosmicAppLibrary Terminal=false Categories=GNOME;GTK; Keywords=Gnome;GTK; diff --git a/cosmic-panel-button/Cargo.toml b/cosmic-panel-button/Cargo.toml new file mode 100644 index 00000000..3095b77c --- /dev/null +++ b/cosmic-panel-button/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "cosmic-panel-button" +version = "0.1.0" +edition = "2021" +license = "GPL-3.0-or-later" + +[dependencies] +freedesktop-desktop-entry = "0.5.0" +libcosmic = { git = "https://github.com/pop-os/libcosmic/", branch = "master", default-features = false, features = ["tokio", "wayland", "applet"] } diff --git a/cosmic-panel-button/src/main.rs b/cosmic-panel-button/src/main.rs new file mode 100644 index 00000000..ee7570f6 --- /dev/null +++ b/cosmic-panel-button/src/main.rs @@ -0,0 +1,122 @@ +use cosmic::{ + applet::CosmicAppletHelper, + iced::{ + self, + wayland::{InitialSurface, SurfaceIdWrapper}, + Application, + }, + iced_sctk::layout::Limits, + iced_style::application, +}; +use freedesktop_desktop_entry::DesktopEntry; +use std::{env, fs, process::Command}; + +#[derive(Clone, Default)] +struct Desktop { + name: String, + icon: Option, + exec: String, +} + +struct Button { + desktop: Desktop, +} + +#[derive(Debug, Clone)] +enum Msg { + Press, +} + +impl iced::Application for Button { + type Message = Msg; + type Theme = cosmic::Theme; + type Executor = cosmic::SingleThreadExecutor; + type Flags = Desktop; + + fn new(desktop: Desktop) -> (Self, iced::Command) { + (Button { desktop }, iced::Command::none()) + } + + fn title(&self) -> String { + String::from("Button") + } + + fn close_requested(&self, _id: SurfaceIdWrapper) -> Msg { + unimplemented!() + } + + fn style(&self) -> ::Style { + ::Style::Custom(|theme| application::Appearance { + background_color: iced::Color::from_rgba(0.0, 0.0, 0.0, 0.0), + text_color: theme.cosmic().on_bg_color().into(), + }) + } + + fn subscription(&self) -> iced::Subscription { + iced::Subscription::none() + } + + fn update(&mut self, message: Msg) -> iced::Command { + match message { + Msg::Press => { + let _ = Command::new("sh").arg("-c").arg(&self.desktop.exec).spawn(); + iced::Command::none() + } + } + } + + fn view(&self, _id: SurfaceIdWrapper) -> cosmic::Element { + // TODO icon? + cosmic::widget::button(cosmic::theme::Button::Text) + .text(&self.desktop.name) + .on_press(Msg::Press) + .into() + } +} + +pub fn main() -> iced::Result { + let id = env::args() + .skip(1) + .next() + .expect("Requires desktop file id as argument."); + + let filename = format!("{id}.desktop"); + let mut desktop = None; + for mut path in freedesktop_desktop_entry::default_paths() { + path.push(&filename); + if let Ok(bytes) = fs::read_to_string(&path) { + if let Ok(entry) = DesktopEntry::decode(&path, &bytes) { + desktop = Some(Desktop { + name: entry + .name(None) + .map(|x| x.to_string()) + .expect(&format!("Desktop file '{filename}' doesn't have `Name`")), + icon: entry.icon().map(|x| x.to_string()), + exec: entry + .exec() + .map(|x| x.to_string()) + .expect(&format!("Desktop file '{filename}' doesn't have `Exec`")), + }); + break; + } + } + } + let desktop = desktop.expect(&format!( + "Failed to find valid desktop file '{filename}' in search paths" + )); + let helper = CosmicAppletHelper::default(); + let mut settings = iced::Settings { + flags: desktop, + ..helper.window_settings() + }; + match &mut settings.initial_surface { + InitialSurface::XdgWindow(s) => { + s.iced_settings.min_size = Some((1, 1)); + s.iced_settings.max_size = None; + s.autosize = true; + s.size_limits = Limits::NONE.min_height(1).min_width(1); + } + _ => unreachable!(), + }; + Button::run(settings) +} diff --git a/cosmic-panel-workspaces-button/data/com.system76.CosmicPanelWorkspacesButton.desktop b/cosmic-panel-workspaces-button/data/com.system76.CosmicPanelWorkspacesButton.desktop index 3d929b81..3ab49ae1 100644 --- a/cosmic-panel-workspaces-button/data/com.system76.CosmicPanelWorkspacesButton.desktop +++ b/cosmic-panel-workspaces-button/data/com.system76.CosmicPanelWorkspacesButton.desktop @@ -2,7 +2,7 @@ Name=Cosmic Panel Workspaces Button Comment=Write a GTK + Rust application Type=Application -Exec=cosmic-panel-button -id com.system76.CosmicWorkspaces +Exec=cosmic-panel-button com.system76.CosmicWorkspaces Terminal=false Categories=GNOME;GTK; Keywords=Gnome;GTK; diff --git a/justfile b/justfile index 7ce412dd..1ef63322 100644 --- a/justfile +++ b/justfile @@ -39,12 +39,14 @@ _install_power: (_install 'com.system76.CosmicAppletPower' 'cosmic-applet-power' _install_workspace: (_install 'com.system76.CosmicAppletWorkspaces' 'cosmic-applet-workspaces') _install_time: (_install 'com.system76.CosmicAppletTime' 'cosmic-applet-time') -# TODO: `cosmic-panel-button` no longer exists and hasn't been ported to Iced -# _install_app_button: (_install 'com.system76.CosmicPanelAppButton' 'cosmic-panel-app-button') -# _install_workspaces_button: (_install 'com.system76.CosmicPanelWorkspacesButton' 'cosmic-panel-workspaces-button') +# TODO: Turn this into one configurable applet? +_install_panel_button: (_install_bin 'cosmic-panel-button') +_install_button id name: (_install_icon name + '/data/icons/' + id + '.svg') (_install_desktop name + '/data/' + id + '.desktop') +_install_app_button: (_install_button 'com.system76.CosmicPanelAppButton' 'cosmic-panel-app-button') +_install_workspaces_button: (_install_button 'com.system76.CosmicPanelWorkspacesButton' 'cosmic-panel-workspaces-button') # Installs files into the system -install: _install_app_list _install_audio _install_battery _install_bluetooth _install_graphics _install_network _install_notifications _install_power _install_workspace _install_time +install: _install_app_list _install_audio _install_battery _install_bluetooth _install_graphics _install_network _install_notifications _install_power _install_workspace _install_time _install_panel_button _install_app_button _install_workspaces_button # Extracts vendored dependencies if vendor=1 _extract_vendor: