Allows you to compose custom modules consisting of multiple modules and widgets, including popups. Labels can display dynamic content from scripts, and buttons can interact with the bar or execute commands on click. The module provides a set of utility widgets, such as containers, labels and buttons. In addition to these, you can also add any native module. Paired with the other custom modules such as Cairo, this provides a powerful declarative interface for constructing your own interfaces. If you only intend to run a single script, prefer the [script](script) module, or [label](label) if you only need a single text label. ![Custom module with a button on the bar, and the popup open. The popup contains a header, shutdown button and restart button.](https://f.jstanger.dev/github/ironbar/custom-power-menu.png?raw) ## Configuration > Type: `custom` This module can be quite fiddly to configure as you effectively have to build a tree of widgets by hand. It is well worth looking at the examples. | Name | Type | Default | Description | |---------|------------------------|------------|------------------------------------------| | `bar` | `(Module or Widget)[]` | `[]` | Modules and widgets to add to the bar. | | `popup` | `(Module or Widget)[]` | `null` | Modules and widgets to add to the popup. | ### `Widget` There are many widget types, each with their own config options. You can think of these like HTML elements and their attributes. Every widget has the following options available; `type` is mandatory. You can also add common [module-level options](https://github.com/JakeStanger/ironbar/wiki/configuration-guide#32-module-level-options) on a widget. | Name | Type | Default | Description | |---------|-------------------------------------------------------------------------------|---------|-------------------------------| | `type` | `'box'` or `'label'` or `'button'` or `'image'` or `'slider'` or `'progress'` | `null` | Type of GTK widget to create. | | `name` | `string` | `null` | Widget name. | | `class` | `string` | `null` | Widget class name. | #### Box A container to place nested widgets inside. > Type: `box` | Name | Type | Default | Description | |---------------|------------------------------------------------------------|----------------|-------------------------------------------------------------------| | `orientation` | `'horizontal'` or `'vertical'` (shorthand: `'h'` or `'v'`) | `'horizontal'` | Whether child widgets should be horizontally or vertically added. | | `widgets` | `(Module or Widget)[]` | `[]` | List of modules/widgets to add to this box. | #### Label A text label. Pango markup is supported. > Type `label` | Name | Type | Default | Description | |---------|-------------------------------------------------|---------|---------------------------------------------------------------------| | `label` | [Dynamic String](dynamic-values#dynamic-string) | `null` | Widget text label. Pango markup and embedded scripts are supported. | | `orientation` | `'horizontal'` or `'vertical'` (shorthand: `'h'` or `'v'`) | `'horizontal'` | Orientation of the label. | #### Button A clickable button, which can run a command when clicked. > Type `button` | Name | Type | Default | Description | |------------|-------------------------------------------------|---------|--------------------------------------------------------------------------------------------------| | `label` | [Dynamic String](dynamic-values#dynamic-string) | `null` | Widget text label. Pango markup and embedded scripts are supported. Ignored if `widgets` is set. | | `widgets` | `(Module or Widget)[]` | `[]` | List of modules/widgets to add to this button. | | `on_click` | `string [command]` | `null` | Command to execute. More on this [below](#commands). | | `orientation` | `'horizontal'` or `'vertical'` (shorthand: `'h'` or `'v'`) | `'horizontal'` | Orientation of the button. | #### Image An image or icon from disk or http. > Type `image` | Name | Type | Default | Description | |--------|---------------------------------------------------------------------|---------|-------------------------------------------------------| | `src` | [image](images) via [Dynamic String](dynamic-values#dynamic-string) | `null` | Image source. | | `size` | `integer` | `null` | Width/height of the image. Aspect ratio is preserved. | #### Slider A draggable slider. > Type: `slider` Note that `on_change` will provide the **floating point** value as an argument. If your input program requires an integer, you will need to round it. | Name | Type | Default | Description | |---------------|------------------------------------------------------------|----------------|---------------------------------------------------------------------------------------------------------------------------------| | `orientation` | `'horizontal'` or `'vertical'` (shorthand: `'h'` or `'v'`) | `'horizontal'` | Orientation of the slider. | | `value` | `Script` | `null` | Script to run to get the slider value. Output must be a valid number. | | `on_change` | `string [command]` | `null` | Command to execute when the slider changes. More on this [below](#commands). | | `min` | `float` | `0` | Minimum slider value. | | `max` | `float` | `100` | Maximum slider value. | | `step` | `float` | - | The increment to change when scrolling with the mouse wheel. If left blank, will use the default determined by the environment. | | `length` | `integer` | `null` | Slider length. GTK will automatically size if left unset. | | `show_label` | `boolean` | `true` | Whether to show the value label above the slider. | The example slider widget below shows a volume control for MPC, which updates the server when changed, and polls the server for volume changes to keep the slider in sync. ```corn $slider = { type = "custom" bar = [ { type = "slider" length = 100 max = 100 on_change="!mpc volume ${0%.*}" value = "200:mpc volume | cut -d ':' -f2 | cut -d '%' -f1" } ] } ``` #### Progress A progress bar. > Type: `progress` Note that `value` expects a numeric value **between 0-`max`** as output. | Name | Type | Default | Description | |---------------|------------------------------------------------------------|--------------|---------------------------------------------------------------------------------| | `orientation` | `'horizontal'` or `'vertical'` (shorthand: `'h'` or `'v'`) | `horizontal` | Orientation of the progress bar. | | `value` | `Script` | `null` | Script to run to get the progress bar value. Output must be a valid percentage. | | `max` | `float` | `100` | Maximum progress bar value. | | `length` | `integer` | `null` | Slider length. GTK will automatically size if left unset. | The example below shows progress for the current playing song in MPD, and displays the elapsed/length timestamps as a label above: ```corn $progress = { type = "custom" bar = [ { type = "progress" value = "500:mpc | sed -n 2p | awk '{ print $4 }' | grep -Eo '[0-9]+' || echo 0" label = "{{500:mpc | sed -n 2p | awk '{ print $3 }'}} elapsed" length = 200 } ] } ``` ### Label Attributes > ℹ This is different to the `label` widget, although applies to it. Any widgets with a `label` attribute support embedded scripts, meaning you can interpolate text from scripts to dynamically show content. This can be done by including scripts in `{{double braces}}` using the shorthand script syntax. For example, the following label would output your system uptime, updated every 30 seconds. ``` Uptime: {{30000:uptime -p | cut -d ' ' -f2-}} ``` Both polling and watching mode are supported. For more information on script syntax, see [here](scripts). ### Commands Buttons can execute commands that interact with the bar, as well as any arbitrary shell command. To execute shell commands, prefix them with an `!`. For example, if you want to run `~/.local/bin/my-script.sh` on click, you'd set `on_click` to `!~/.local/bin/my-script.sh`. Some widgets provide a value when they run the command, such as `slider`. This is passed as an argument and can be accessed using `$0`. The following bar commands are supported: - `popup:toggle` - `popup:open` - `popup:close` --- XML is arguably better-suited and easier to read for this sort of markup, but currently is not supported. Nonetheless, it may be worth comparing the examples to the below equivalent to help get your head around what's going on: ```xml