Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add Menu module #609

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ default = [
"http",
"ipc",
"launcher",
"menu",
"music+all",
"notifications",
"sys_info",
Expand Down Expand Up @@ -56,6 +57,8 @@ focused = []

launcher = []

menu = ["dep:freedesktop_entry_parser", "dep:unicode-segmentation"]

music = ["regex"]
"music+all" = ["music", "music+mpris", "music+mpd"]
"music+mpris" = ["music", "mpris"]
Expand Down Expand Up @@ -130,6 +133,10 @@ nix = { version = "0.27.1", optional = true, features = ["event"] }
# clock
chrono = { version = "0.4.38", optional = true, default_features = false, features = ["clock", "unstable-locales"] }

# menu
freedesktop_entry_parser = { version = "1.3.0", optional = true }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

freedesktop_entry_parser is needed to parse .desktop entries which it doesn't seem ironbar was doing until now. There's one other rust library that can do that but this one seemed lighter-weight and more stable.

unicode-segmentation is needed for truncating menu entries which is really needed because some common .desktop files (like the JDK) have really long names. As far as I can tell there's no actually safe way to truncate unicode strings in the Rust stdlib.

Copy link
Owner

@JakeStanger JakeStanger May 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is .desktop file parsing happening in the desktop_file module already. Did you not spot that, or does that not do what is necessary here?

In some other modules (music, focused) these are already using a (partially) common truncate option that hooks into GTK's in-built truncation/elipsize system. I'd prefer to use that here, although I'm open to integrating unicode-segmentation and having a words mode there.

unicode-segmentation = { version = "1.11.0", optional = true }

# music
mpd-utils = { version = "0.2.1", optional = true }
mpris = { version = "2.0.1", optional = true }
Expand Down
133 changes: 133 additions & 0 deletions docs/modules/Menu.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
Application menu that shows installed programs and optionally custom entries. Clicking the menu button will open the main menu, clicking on any application category will open a sub-menu with any installed applications that match.

Copy link
Owner

@JakeStanger JakeStanger May 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reminder for myself to add an image

(no need to action anything)

## Configuration

> Type: `menu`

| | Type | Default | Description |
|--------------|------------|---------|-----------------------------------------------------------------------------------------------------|
| `start` | `MenuEntry[]` | `[]` | List of menu entries |
| `center` | `MenuEntry[]` | default XDG menu | List of menu entries. By default this shows a number of XDG entries that should cover all common applications |
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you set this, does it append to or replace the XDG entries?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will replace the default entries. It might be worthwhile to list the default entries in the documentation in case you want some of them but not others.

| `end` | `MenuEntry[]` | `[]` | List of menu entries |
| `height` | `integer | null` | `null` | The height of the menu, leave null for it to resize dynamically |
| `width` | `integer | null` | `null` | The width of the menu, leave null for it to resize dynamically |
| `max_label_length` | `integer` | `25` | Maximum length for the label of an XDG entry |
| `label` | `string | null` | `≡` | The label of the button that opens the menu |
| `label_icon` | `string | null` | `null` | An icon (from icon theme) to display on the button which opens the application menu |
| `label_icon_size` | `integer` | `16` | Size of the label_icon if one is supplied |


> Type: `MenuEntry`

| | Type | Default | Description |
|--------------|------------|---------|-----------------------------------------------------------------------------------------------------|
| `type` | `xdg_entry | xdg_other | custom` | | Type of the entry |
| `label` | `string` | | Label of the entry's button |
| `icon` | `string | null` | `null` | Icon for the entry's button |
| `categories` | `string[]` | | If `xdg_entry` this is is the list of freedesktop.org categories to include in this entry's sub menu |
| `on_click` | `string` | | If `custom` this is a shell command to execute when the entry's button is clicked |

<details>

<summary>JSON</summary>

```json
{
"start": [
{
"type": "menu",
"start": [
{
"type": "custom",
"label": "Terminal",
"on_click": "xterm",
}
],
"height": 440,
"width": 200,
"icon": "archlinux",
"label": null
}
]
}


```

</details>

<details>
<summary>TOML</summary>

```toml
[[start.menu]]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not actually sure this is correct, the way ironbar handles TOML is a bit confusing to me.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ironbar is just using the standard toml crate, it's TOML that's confusing - there's two syntaxes for objects, and two for arrays.

Generally I write the corn config and then use its CLI to generate the other three formats, which isn't necessarily the most readable but at least ensures they're valid.

I think here, you actually want something like (shortened and untested):

[[start]]
type = "menu"

[[start.start]]
type = "custom"

height = 400
width = 200
icon = "archlinux"
label = null

[[start.menu.start]]
type = "custom"
label = "Terminal"
on_click = "xterm"
```

</details>

<details>
<summary>YAML</summary>

```yaml
start:
- type: "menu"
start:
- type: custom
label: Terminal
on_click: xterm
height: 440
width: 200
icon: archlinux
label: null
```

</details>

<details>
<summary>Corn</summary>

```corn
{
start = [
{
type = "menu"
start = [
{
type = "custom"
label = "Terminal"
on_click = "xterm"
}
]
height = 440
width = 200
icon = "archlinux"
label = null
}
]
}
```

</details>

## Styling

| Selector | Description |
|-------------------------------|--------------------------------|
| `.menu` | Menu button |
| `.menu-popup` | Main container of the popup |
| `.menu-popup_main` | Main menu of the menu |
| `.menu-popup_main_start` | Container for `start` entries |
| `.menu-popup_main_center` | Container for `center` entries |
| `.menu-popup_main_end` | Container for `end` entries |
| `.menu-popup_sub-menu` | All sub-menues |

For more information on styling, please see the [styling guide](styling-guide).
6 changes: 6 additions & 0 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use crate::modules::focused::FocusedModule;
use crate::modules::label::LabelModule;
#[cfg(feature = "launcher")]
use crate::modules::launcher::LauncherModule;
#[cfg(feature = "menu")]
use crate::modules::menu::MenuModule;
#[cfg(feature = "music")]
use crate::modules::music::MusicModule;
#[cfg(feature = "notifications")]
Expand Down Expand Up @@ -54,6 +56,8 @@ pub enum ModuleConfig {
Label(Box<LabelModule>),
#[cfg(feature = "launcher")]
Launcher(Box<LauncherModule>),
#[cfg(feature = "menu")]
Menu(Box<MenuModule>),
#[cfg(feature = "music")]
Music(Box<MusicModule>),
#[cfg(feature = "notifications")]
Expand Down Expand Up @@ -97,6 +101,8 @@ impl ModuleConfig {
Self::Label(module) => create!(module),
#[cfg(feature = "launcher")]
Self::Launcher(module) => create!(module),
#[cfg(feature = "menu")]
Self::Menu(module) => create!(module),
#[cfg(feature = "music")]
Self::Music(module) => create!(module),
#[cfg(feature = "notifications")]
Expand Down
2 changes: 1 addition & 1 deletion src/desktop_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ fn find_application_dirs() -> Vec<PathBuf> {
}

/// Finds all the desktop files
fn find_desktop_files() -> Vec<PathBuf> {
pub fn find_desktop_files() -> Vec<PathBuf> {
let dirs = find_application_dirs();
dirs.into_iter()
.flat_map(|dir| {
Expand Down
Loading
Loading