diff --git a/docs/modules/Launcher.md b/docs/modules/Launcher.md index 3d6dfa8..08561e6 100644 --- a/docs/modules/Launcher.md +++ b/docs/modules/Launcher.md @@ -13,23 +13,24 @@ Optionally displays a launchable set of favourites. > Type: `launcher` -| | Type | Default | Description | -|-----------------------------|---------------------------------------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------| -| `favorites` | `string[]` | `[]` | List of app IDs (or classes) to always show at the start of the launcher. | -| `show_names` | `boolean` | `false` | Whether to show app names on the button label. Names will still show on tooltips when set to false. | -| `show_icons` | `boolean` | `true` | Whether to show app icons on the button. | -| `icon_size` | `integer` | `32` | Size to render icon at (image icons only). | -| `reversed` | `boolean` | `false` | Whether to reverse the order of favorites/items | -| `minimize_focused` | `boolean` | `true` | Whether to minimize a focused window when its icon is clicked. Only minimizes single windows. | -| `truncate.mode` | `'start'` or `'middle'` or `'end'` or `off` | `end` | Location of the ellipses and where to truncate text from. Applies to application names when `show_names` is enabled. | -| `truncate.length` | `integer` | `null` | Fixed width (in chars) of the widget. Leave blank to let GTK automatically handle. | -| `truncate.max_length` | `integer` | `null` | Maximum number of characters before truncating. Leave blank to let GTK automatically handle. | -| `truncate_popup.mode` | `'start'` or `'middle'` or `'end'` or `off` | `middle` | Location of the ellipses and where to truncate text from. Applies to window names within a group popup. | -| `truncate_popup.length` | `integer` | `null` | Fixed width (in chars) of the widget. Leave blank to let GTK automatically handle. | -| `truncate_popup.max_length` | `integer` | `25` | Maximum number of characters before truncating. Leave blank to let GTK automatically handle. | -| `page_size` | `integer` | `1000` | Number of items to show on a page. When the number of items is reached, controls appear which can be used to move forward/back through the list of items. | -| `icons.page_back` | `string` or [image](images) | `󰅁` | Icon to show for page back button. | -| `icons.page_forward` | `string` or [image](images) | `󰅂` | Icon to show for page forward button. | +| | Type | Default | Description | +|-----------------------------|---------------------------------------------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------| +| `favorites` | `string[]` | `[]` | List of app IDs (or classes) to always show at the start of the launcher. | +| `show_names` | `boolean` | `false` | Whether to show app names on the button label. Names will still show on tooltips when set to false. | +| `show_icons` | `boolean` | `true` | Whether to show app icons on the button. | +| `icon_size` | `integer` | `32` | Size to render icon at (image icons only). | +| `launch_command` | `string` | `gtk-launch {app_name}` | Command used to launch applications. | +| `reversed` | `boolean` | `false` | Whether to reverse the order of favorites/items | +| `minimize_focused` | `boolean` | `true` | Whether to minimize a focused window when its icon is clicked. Only minimizes single windows. | +| `truncate.mode` | `'start'` or `'middle'` or `'end'` or `off` | `end` | Location of the ellipses and where to truncate text from. Applies to application names when `show_names` is enabled. | +| `truncate.length` | `integer` | `null` | Fixed width (in chars) of the widget. Leave blank to let GTK automatically handle. | +| `truncate.max_length` | `integer` | `null` | Maximum number of characters before truncating. Leave blank to let GTK automatically handle. | +| `truncate_popup.mode` | `'start'` or `'middle'` or `'end'` or `off` | `middle` | Location of the ellipses and where to truncate text from. Applies to window names within a group popup. | +| `truncate_popup.length` | `integer` | `null` | Fixed width (in chars) of the widget. Leave blank to let GTK automatically handle. | +| `truncate_popup.max_length` | `integer` | `25` | Maximum number of characters before truncating. Leave blank to let GTK automatically handle. | +| `page_size` | `integer` | `1000` | Number of items to show on a page. When the number of items is reached, controls appear which can be used to move forward/back through the list of items. | +| `icons.page_back` | `string` or [image](images) | `󰅁` | Icon to show for page back button. | +| `icons.page_forward` | `string` or [image](images) | `󰅂` | Icon to show for page forward button. |
JSON diff --git a/docs/modules/Menu.md b/docs/modules/Menu.md index 793f4d0..53617e1 100644 --- a/docs/modules/Menu.md +++ b/docs/modules/Menu.md @@ -10,20 +10,21 @@ It is also possible to add custom categories and actions into the menu. ## Configuration -| | Type | Default | Description | -|-----------------------|------------------------------------------------------|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `start` | `MenuEntry[]` | `[]` | Items to add to the start of the main menu. | -| `center` | `MenuEntry[]` | Default XDG menu | Items to add to the centre of the main menu. By default this shows a number of XDG entries that should cover all common applications. | -| `end` | `MenuEntry[]` | `[]` | Items to add to the end of the main menu. | -| `height` | `integer` | `null` | Height of the menu. Leave null to resize dynamically. | -| `width` | `integer` | `null` | Width of the menu. Leave null to resize dynamically. | -| `label` | `string` | `≡` | Label to show on the menu button on the bar. | -| `label_icon` | `string` | `null` | Icon to show on the menu button on the bar. | -| `label_icon_size` | `integer` | `16` | Size of the label_icon image. | -| `truncate` | `'start'` or `'middle'` or `'end'` or `off` or `Map` | `off` | Applies to popup. The location of the ellipses and where to truncate text from. Leave null to avoid truncating. Use the long-hand `Map` version if specifying a length. | -| `truncate.mode` | `'start'` or `'middle'` or `'end'` or `off` | `off` | Applies to popup. The location of the ellipses and where to truncate text from. Leave null to avoid truncating. | -| `truncate.length` | `integer` | `null` | Applies to popup. The fixed width (in chars) of the widget. Leave blank to let GTK automatically handle. | -| `truncate.max_length` | `integer` | `null` | Applies to popup. The maximum number of characters before truncating. Leave blank to let GTK automatically handle. | +| | Type | Default | Description | +|-----------------------|------------------------------------------------------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| +| `start` | `MenuEntry[]` | `[]` | Items to add to the start of the main menu. | +| `center` | `MenuEntry[]` | Default XDG menu | Items to add to the centre of the main menu. By default this shows a number of XDG entries that should cover all common applications. | +| `end` | `MenuEntry[]` | `[]` | Items to add to the end of the main menu. | +| `height` | `integer` | `null` | Height of the menu. Leave null to resize dynamically. | +| `width` | `integer` | `null` | Width of the menu. Leave null to resize dynamically. | +| `label` | `string` | `≡` | Label to show on the menu button on the bar. | +| `label_icon` | `string` | `null` | Icon to show on the menu button on the bar. | +| `label_icon_size` | `integer` | `16` | Size of the label_icon image. | +| `launch_command` | `string` | `gtk-launch {app_name}` | Command used to launch applications. | +| `truncate` | `'start'` or `'middle'` or `'end'` or `off` or `Map` | `off` | Applies to popup. The location of the ellipses and where to truncate text from. Leave null to avoid truncating. Use the long-hand `Map` version if specifying a length. | +| `truncate.mode` | `'start'` or `'middle'` or `'end'` or `off` | `off` | Applies to popup. The location of the ellipses and where to truncate text from. Leave null to avoid truncating. | +| `truncate.length` | `integer` | `null` | Applies to popup. The fixed width (in chars) of the widget. Leave blank to let GTK automatically handle. | +| `truncate.max_length` | `integer` | `null` | Applies to popup. The maximum number of characters before truncating. Leave blank to let GTK automatically handle. | ### `MenuEntry` diff --git a/src/config/mod.rs b/src/config/mod.rs index 2d32091..7c06bd9 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -481,3 +481,7 @@ pub const fn default_false() -> bool { pub const fn default_true() -> bool { true } + +pub fn default_launch_command() -> String { + String::from("gtk-launch {app_name}") +} diff --git a/src/desktop_file.rs b/src/desktop_file.rs index 3fdf346..8b0a509 100644 --- a/src/desktop_file.rs +++ b/src/desktop_file.rs @@ -1,12 +1,13 @@ use crate::spawn; -use color_eyre::Result; +use color_eyre::{Help, Report, Result}; use std::collections::HashMap; use std::env; use std::path::{Path, PathBuf}; +use std::process::{Command, Stdio}; use std::sync::Arc; use tokio::io::{AsyncBufReadExt, BufReader}; use tokio::sync::Mutex; -use tracing::debug; +use tracing::{debug, error}; use walkdir::{DirEntry, WalkDir}; #[derive(Debug, Clone)] @@ -323,6 +324,25 @@ fn files(dir: &Path) -> Vec { .collect() } +/// Starts a `.desktop` file with the provided formatted command. +pub fn open_program(file_name: &str, str: &str) { + let expanded = str.replace("{app_name}", file_name); + let launch_command_parts: Vec<&str> = expanded.split_whitespace().collect(); + if let Err(err) = Command::new(&launch_command_parts[0]) + .args(&launch_command_parts[1..]) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + { + error!( + "{:?}", + Report::new(err) + .wrap_err("Failed to run launch command.") + .suggestion("Perhaps the applications file is invalid?") + ); + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/modules/launcher/mod.rs b/src/modules/launcher/mod.rs index 0a6757f..0bdfbb2 100644 --- a/src/modules/launcher/mod.rs +++ b/src/modules/launcher/mod.rs @@ -7,17 +7,19 @@ use self::open_state::OpenState; use super::{Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, WidgetContext}; use crate::channels::{AsyncSenderExt, BroadcastReceiverExt}; use crate::clients::wayland::{self, ToplevelEvent}; -use crate::config::{CommonConfig, EllipsizeMode, LayoutConfig, TruncateMode}; +use crate::config::{ + CommonConfig, EllipsizeMode, LayoutConfig, TruncateMode, default_launch_command, +}; +use crate::desktop_file::open_program; use crate::gtk_helpers::{IronbarGtkExt, IronbarLabelExt}; use crate::modules::launcher::item::ImageTextButton; use crate::modules::launcher::pagination::{IconContext, Pagination}; use crate::{arc_mut, lock, module_impl, spawn, write_lock}; -use color_eyre::{Help, Report}; +use color_eyre::Report; use gtk::prelude::*; use gtk::{Button, Orientation}; use indexmap::IndexMap; use serde::Deserialize; -use std::process::{Command, Stdio}; use std::sync::Arc; use tokio::sync::mpsc; use tracing::{debug, error, trace, warn}; @@ -108,6 +110,12 @@ pub struct LauncherModule { #[serde(default, flatten)] layout: LayoutConfig, + /// Command used to launch applications. + /// + /// **Default**: `gtk-launch` + #[serde(default = "default_launch_command")] + launch_command: String, + /// See [common options](module-level-options#common-options). #[serde(flatten)] pub common: Option, @@ -373,25 +381,14 @@ impl Module for LauncherModule { let wl = context.client::(); let desktop_files = context.ironbar.desktop_files(); + let launch_command_str: String = self.launch_command.clone(); spawn(async move { while let Some(event) = rx.recv().await { if let ItemEvent::OpenItem(app_id) = event { match desktop_files.find(&app_id).await { Ok(Some(file)) => { - if let Err(err) = Command::new("gtk-launch") - .arg(file.file_name) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .spawn() - { - error!( - "{:?}", - Report::new(err) - .wrap_err("Failed to run gtk-launch command.") - .suggestion("Perhaps the applications file is invalid?") - ); - } + open_program(&file.file_name, &launch_command_str); } Ok(None) => warn!("Could not find applications file for {}", app_id), Err(err) => error!("Failed to find parse file for {}: {}", app_id, err), diff --git a/src/modules/menu/config.rs b/src/modules/menu/config.rs index 4575880..1d72386 100644 --- a/src/modules/menu/config.rs +++ b/src/modules/menu/config.rs @@ -1,3 +1,4 @@ +use crate::config::default_launch_command; use crate::config::{CommonConfig, TruncateMode}; use crate::modules::menu::{MenuEntry, XdgSection}; use indexmap::IndexMap; @@ -123,6 +124,12 @@ pub struct MenuModule { /// See [common options](module-level-options#common-options). #[serde(flatten)] pub common: Option, + + /// Command used to launch applications. + /// + /// **Default**: `gtk-launch` + #[serde(default = "default_launch_command")] + pub launch_command: String, } impl Default for MenuModule { @@ -139,6 +146,7 @@ impl Default for MenuModule { label_icon: None, label_icon_size: default_menu_popup_icon_size(), common: Some(CommonConfig::default()), + launch_command: default_launch_command(), } } } diff --git a/src/modules/menu/mod.rs b/src/modules/menu/mod.rs index cd46766..2c58526 100644 --- a/src/modules/menu/mod.rs +++ b/src/modules/menu/mod.rs @@ -262,8 +262,13 @@ impl Module