Merge pull request #3247 from benjamin-voisin/menu

Adding the ability to have dropdown menu for modules
This commit is contained in:
Alexis Rouillard 2024-07-01 09:18:13 +02:00 committed by GitHub
commit 9c7a275cd6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
35 changed files with 611 additions and 2 deletions

View File

@ -27,6 +27,10 @@ class ALabel : public AModule {
bool handleToggle(GdkEventButton *const &e) override; bool handleToggle(GdkEventButton *const &e) override;
virtual std::string getState(uint8_t value, bool lesser = false); virtual std::string getState(uint8_t value, bool lesser = false);
std::map<std::string, GtkMenuItem *> submenus_;
std::map<std::string, std::string> menuActionsMap_;
static void handleGtkMenuEvent(GtkMenuItem *menuitem, gpointer data);
}; };
} // namespace waybar } // namespace waybar

View File

@ -2,6 +2,7 @@
#include <glibmm/dispatcher.h> #include <glibmm/dispatcher.h>
#include <glibmm/markup.h> #include <glibmm/markup.h>
#include <gtkmm.h>
#include <gtkmm/eventbox.h> #include <gtkmm/eventbox.h>
#include <json/json.h> #include <json/json.h>
@ -44,6 +45,7 @@ class AModule : public IModule {
virtual bool handleMouseLeave(GdkEventCrossing *const &ev); virtual bool handleMouseLeave(GdkEventCrossing *const &ev);
virtual bool handleScroll(GdkEventScroll *); virtual bool handleScroll(GdkEventScroll *);
virtual bool handleRelease(GdkEventButton *const &ev); virtual bool handleRelease(GdkEventButton *const &ev);
GObject *menu_;
private: private:
bool handleUserEvent(GdkEventButton *const &ev); bool handleUserEvent(GdkEventButton *const &ev);

View File

@ -81,6 +81,19 @@ The *backlight* module displays the current backlight level.
default: 1.0 ++ default: 1.0 ++
The speed at which to change the brightness when scrolling. The speed at which to change the brightness when scrolling.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# EXAMPLE: # EXAMPLE:
``` ```

View File

@ -109,6 +109,19 @@ The *battery* module displays the current capacity and state (eg. charging) of y
default: false ++ default: false ++
Option to enable battery compatibility if not detected. Option to enable battery compatibility if not detected.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{capacity}*: Capacity in percentage *{capacity}*: Capacity in percentage

View File

@ -129,6 +129,19 @@ Addressed by *bluetooth*
typeof: string ++ typeof: string ++
This format is used to define how each connected device should be displayed within the *device_enumerate* format replacement in the tooltip menu. This format is used to define how each connected device should be displayed within the *device_enumerate* format replacement in the tooltip menu.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{status}*: Status of the bluetooth device. *{status}*: Status of the bluetooth device.

View File

@ -120,6 +120,18 @@ libcava lives in:
:[ string :[ string
:[ /dev/stdout :[ /dev/stdout
:[ It's impossible to set it. Waybar sets it to = /dev/stdout for internal needs :[ It's impossible to set it. Waybar sets it to = /dev/stdout for internal needs
|[ *menu*
:[ string
:[
:[ Action that popups the menu.
|[ *menu-file*
:[ string
:[
:[ Location of the menu descriptor file. There need to be an element of type GtkMenu with id *menu*
|[ *menu-actions*
:[ array
:[
:[ The actions corresponding to the buttons of the menu.
Configuration can be provided as: Configuration can be provided as:
- The only cava configuration file which is provided through *cava_config*. The rest configuration can be skipped - The only cava configuration file which is provided through *cava_config*. The rest configuration can be skipped

View File

@ -84,6 +84,18 @@ $XDG_CONFIG_HOME/waybar/config ++
:[ string :[ string
:[ same as format :[ same as format
:[ Tooltip on hover :[ Tooltip on hover
|[ *menu*
:[ string
:[
:[ Action that popups the menu.
|[ *menu-file*
:[ string
:[
:[ Location of the menu descriptor file. There need to be an element of type GtkMenu with id *menu*
|[ *menu-actions*
:[ array
:[
:[ The actions corresponding to the buttons of the menu.
View all valid format options in *strftime(3)* or have a look https://en.cppreference.com/w/cpp/chrono/duration/formatter View all valid format options in *strftime(3)* or have a look https://en.cppreference.com/w/cpp/chrono/duration/formatter

View File

@ -121,6 +121,19 @@ Addressed by *custom/<name>*
default: false ++ default: false ++
Option to enable escaping of script output. Option to enable escaping of script output.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# RETURN-TYPE # RETURN-TYPE
When *return-type* is set to *json*, Waybar expects the *exec*-script to output its data in JSON format. When *return-type* is set to *json*, Waybar expects the *exec*-script to output its data in JSON format.

View File

@ -93,6 +93,19 @@ Addressed by *disk*
typeof: string ++ typeof: string ++
Use with specific_free, specific_used, and specific_total to force calculation to always be in a certain unit. Accepts kB, kiB, MB, Mib, GB, GiB, TB, TiB. Use with specific_free, specific_used, and specific_total to force calculation to always be in a certain unit. Accepts kB, kiB, MB, Mib, GB, GiB, TB, TiB.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{percentage_used}*: Percentage of disk in use. *{percentage_used}*: Percentage of disk in use.

View File

@ -25,6 +25,19 @@ Addressed by *hyprland/language*
typeof: string ++ typeof: string ++
Specifies which keyboard to use from hyprctl devices output. Using the option that begins with "at-translated-set..." is recommended. Specifies which keyboard to use from hyprctl devices output. Using the option that begins with "at-translated-set..." is recommended.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS

View File

@ -80,6 +80,19 @@ Addressed by *hyprland/submap*
default: Default ++ default: Default ++
Option to set the submap name to display when not in an active submap. Option to set the submap name to display when not in an active submap.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# EXAMPLES # EXAMPLES

View File

@ -89,6 +89,19 @@ screensaver, also known as "presentation mode".
typeof: string ++ typeof: string ++
This format is used when the inhibit is deactivated. This format is used when the inhibit is deactivated.
*menu*: ++
typeof: string ++
Action that popups the menu. Cannot be "on-click".
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{status}*: status (*activated* or *deactivated*) *{status}*: status (*activated* or *deactivated*)

View File

@ -76,6 +76,19 @@ See *systemd-inhibit*(1) for more information.
default: true ++ default: true ++
Option to disable tooltip on hover. Option to disable tooltip on hover.
*menu*: ++
typeof: string ++
Action that popups the menu. Cannot be "on-click".
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{status}*: status (*activated* or *deactivated*) *{status}*: status (*activated* or *deactivated*)

View File

@ -85,6 +85,19 @@ Addressed by *jack*
typeof: string ++ typeof: string ++
Command to execute when the module is updated. Command to execute when the module is updated.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{load}*: The current CPU load estimated by JACK. *{load}*: The current CPU load estimated by JACK.

View File

@ -84,6 +84,19 @@ Addressed by *memory*
default: true ++ default: true ++
Option to disable tooltip on hover. Option to disable tooltip on hover.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{percentage}*: Percentage of memory in use. *{percentage}*: Percentage of memory in use.

153
man/waybar-menu.5.scd Normal file
View File

@ -0,0 +1,153 @@
waybar-menu(5)
# NAME
waybar - menu property
# OVERVIEW
Some modules support a 'menu', which allows to have a popup menu whan a defined
click is done over the module.
# PROPERTIES
A module that implements a 'menu' needs 3 properties defined in its config :
*menu*: ++
typeof: string ++
Action that popups the menu. The possibles actions are :
[- *Option*
:- *Description*
|[ *on-click*
:< When you left-click on the module
|[ *on-click-release*
:< When you release left button on the module
|[ *on-double-click*
:< When you double left click on the module
|[ *on-triple-click*
:< When you triple left click on the module
|[ *on-click-middle*
:< When you middle click on the module using mousewheel
|[ *on-click-middle-release*
:< When you release mousewheel button on the module
|[ *on-double-click-middle*
:< When you double middle click on the module
|[ *on-triple-click-middle*
:< When you triple middle click on the module
|[ *on-click-right*
:< When you right click on the module using
|[ *on-click-right-release*
:< When you release right button on the module
|[ *on-double-click-right*
:< When you double right click on the module
|[ *on-triple-click-right*
:< When you triple middle click on the module
|[ *on-click-backward*
:< When you click on the module using mouse backward button
|[ *on-click-backward-release*
:< When you release mouse backward button on the module
|[ *on-double-click-backward*
:< When you double click on the module using mouse backward button
|[ *on-triple-click-backward*
:< When you triple click on the module using mouse backawrd button
|[ *on-click-forward*
:< When you click on the module using mouse forward button
|[ *on-click-forward-release*
:< When you release mouse forward button on the module
|[ *on-double-click-forward*
:< When you double click on the module using mouse forward button
|[ *on-triple-click-forward*
:< When you triple click on the module using mouse forward button
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*.
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu. The identifiers of
each actions needs to exists as an id in the 'menu-file' for it to be linked
properly.
# MENU-FILE
The menu-file is an `.xml` file representing a GtkBuilder. Documentation for it
can be found here : https://docs.gtk.org/gtk4/class.Builder.html
Here, it needs to have an element of type GtkMenu with id "menu". Eeach actions
in *menu-actions* are linked to elements in the *menu-file* file by the id of
the elements.
# EXAMPLE
Module config :
```
"custom/power": {
"format" : "⏻ ",
"tooltip": false,
"menu": "on-click",
"menu-file": "~/.config/waybar/power_menu.xml",
"menu-actions": {
"shutdown": "shutdown",
"reboot": "reboot",
"suspend": "systemctl suspend",
"hibernate": "systemctl hibernate",
},
},
```
~/.config/waybar/power_menu.xml :
```
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkMenu" id="menu">
<child>
<object class="GtkMenuItem" id="suspend">
<property name="label">Suspend</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="hibernat">
<property name="label">Hibernate</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="shutdown">
<property name="label">Shutdown</property>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="delimiter1"/>
</child>
<child>
<object class="GtkMenuItem" id="reboot">
<property name="label">Reboot</property>
</object>
</child>
</object>
</interface>
```
# STYLING MENUS
- *menu*
Style for the menu
- *menuitem*
Style for items in the menu
# EXAMPLE:
```
menu {
border-radius: 15px;
background: #161320;
color: #B5E8E0;
}
menuitem {
border-radius: 15px;
}
```

View File

@ -162,6 +162,19 @@ Addressed by *mpd*
default: {} ++ default: {} ++
Icon to show depending on the "single" option (*{ "on": "...", "off": "..." }*) Icon to show depending on the "single" option (*{ "on": "...", "off": "..." }*)
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
## WHEN PLAYING/PAUSED ## WHEN PLAYING/PAUSED

View File

@ -129,6 +129,19 @@ Addressed by *network*
typeof: string ++ typeof: string ++
This format is used when the displayed interface is disabled. This format is used when the displayed interface is disabled.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{ifname}*: Name of the network interface. *{ifname}*: Name of the network interface.

View File

@ -113,6 +113,19 @@ Additionally, you can control the volume by scrolling *up* or *down* while the c
typeof: array ++ typeof: array ++
Sinks in this list will not be shown as active sink by Waybar. Entries should be the sink's description field. Sinks in this list will not be shown as active sink by Waybar. Entries should be the sink's description field.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{desc}*: Pulseaudio port's description, for bluetooth it'll be the device name. *{desc}*: Pulseaudio port's description, for bluetooth it'll be the device name.

View File

@ -51,6 +51,19 @@ Addressed by *river/layout*
typeof: string ++ typeof: string ++
Command to execute when you right-click on the module. Command to execute when you right-click on the module.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# EXAMPLE # EXAMPLE
``` ```

View File

@ -65,6 +65,19 @@ Addressed by *river/mode*
typeof: double ++ typeof: double ++
Threshold to be used when scrolling. Threshold to be used when scrolling.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# EXAMPLES # EXAMPLES
``` ```

View File

@ -49,6 +49,19 @@ Addressed by *river/window*
typeof: string ++ typeof: string ++
Command to execute when you right-click on the module. Command to execute when you right-click on the module.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# EXAMPLES # EXAMPLES
``` ```

View File

@ -74,6 +74,19 @@ cursor is over the module, and clicking on the module toggles mute.
typeof: double ++ typeof: double ++
Threshold to be used when scrolling. Threshold to be used when scrolling.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{volume}*: Volume in percentage. *{volume}*: Volume in percentage.

View File

@ -32,6 +32,19 @@ Addressed by *sway/language*
default: true ++ default: true ++
Option to disable tooltip on hover. Option to disable tooltip on hover.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{short}*: Short name of layout (e.g. "us"). Equals to {}. *{short}*: Short name of layout (e.g. "us"). Equals to {}.

View File

@ -70,6 +70,19 @@ Addressed by *sway/mode*
default: true ++ default: true ++
Option to disable tooltip on hover. Option to disable tooltip on hover.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# EXAMPLES # EXAMPLES
``` ```

View File

@ -36,6 +36,19 @@ Addressed by *sway/scratchpad*
default: {app}: {title} ++ default: {app}: {title} ++
The format, how information in the tooltip should be displayed. The format, how information in the tooltip should be displayed.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{icon}*: Icon, as defined in *format-icons*. *{icon}*: Icon, as defined in *format-icons*.

View File

@ -36,6 +36,19 @@ Addressed by *systemd-failed-units*
default: *true* ++ default: *true* ++
Option to hide this module when there is no failing units. Option to hide this module when there is no failing units.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{nr_failed_system}*: Number of failed units from systemwide (PID=1) systemd. *{nr_failed_system}*: Number of failed units from systemwide (PID=1) systemd.

View File

@ -111,6 +111,19 @@ Addressed by *temperature*
default: true ++ default: true ++
Option to disable tooltip on hover. Option to disable tooltip on hover.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{temperatureC}*: Temperature in Celsius. *{temperatureC}*: Temperature in Celsius.

View File

@ -62,6 +62,19 @@ compatible devices in the tooltip.
default: true ++ default: true ++
Option to disable battery icon. Option to disable battery icon.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{percentage}*: The battery capacity in percentage *{percentage}*: The battery capacity in percentage

View File

@ -87,6 +87,19 @@ The *wireplumber* module displays the current volume reported by WirePlumber.
default: 100 ++ default: 100 ++
The maximum volume that can be set, in percentage. The maximum volume that can be set, in percentage.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{volume}*: Volume in percentage. *{volume}*: Volume in percentage.

View File

@ -192,6 +192,7 @@ man_files = files(
'man/waybar-idle-inhibitor.5.scd', 'man/waybar-idle-inhibitor.5.scd',
'man/waybar-image.5.scd', 'man/waybar-image.5.scd',
'man/waybar-states.5.scd', 'man/waybar-states.5.scd',
'man/waybar-menu.5.scd',
'man/waybar-temperature.5.scd', 'man/waybar-temperature.5.scd',
) )

View File

@ -30,7 +30,8 @@
"battery", "battery",
"battery#bat2", "battery#bat2",
"clock", "clock",
"tray" "tray",
"custom/power"
], ],
// Modules configuration // Modules configuration
// "sway/workspaces": { // "sway/workspaces": {
@ -198,5 +199,17 @@
"escape": true, "escape": true,
"exec": "$HOME/.config/waybar/mediaplayer.py 2> /dev/null" // Script in resources folder "exec": "$HOME/.config/waybar/mediaplayer.py 2> /dev/null" // Script in resources folder
// "exec": "$HOME/.config/waybar/mediaplayer.py --player spotify 2> /dev/null" // Filter player based on name // "exec": "$HOME/.config/waybar/mediaplayer.py --player spotify 2> /dev/null" // Filter player based on name
},
"custom/power": {
"format" : "⏻ ",
"tooltip": false,
"menu": "on-click",
"menu-file": "$HOME/.config/waybar/power_menu.xml", // Menu file in resources folder
"menu-actions": {
"shutdown": "shutdown",
"reboot": "reboot",
"suspend": "systemctl suspend",
"hibernate": "systemctl hibernate"
}
} }
} }

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkMenu" id="menu">
<child>
<object class="GtkMenuItem" id="suspend">
<property name="label">Suspend</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="hibernate">
<property name="label">Hibernate</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="shutdown">
<property name="label">Shutdown</property>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="delimiter1"/>
</child>
<child>
<object class="GtkMenuItem" id="reboot">
<property name="label">Reboot</property>
</object>
</child>
</object>
</interface>

View File

@ -2,6 +2,8 @@
#include <fmt/format.h> #include <fmt/format.h>
#include <fstream>
#include <iostream>
#include <util/command.hpp> #include <util/command.hpp>
namespace waybar { namespace waybar {
@ -9,7 +11,9 @@ namespace waybar {
ALabel::ALabel(const Json::Value& config, const std::string& name, const std::string& id, ALabel::ALabel(const Json::Value& config, const std::string& name, const std::string& id,
const std::string& format, uint16_t interval, bool ellipsize, bool enable_click, const std::string& format, uint16_t interval, bool ellipsize, bool enable_click,
bool enable_scroll) bool enable_scroll)
: AModule(config, name, id, config["format-alt"].isString() || enable_click, enable_scroll), : AModule(config, name, id,
config["format-alt"].isString() || config["menu"].isString() || enable_click,
enable_scroll),
format_(config_["format"].isString() ? config_["format"].asString() : format), format_(config_["format"].isString() ? config_["format"].asString() : format),
interval_(config_["interval"] == "once" interval_(config_["interval"] == "once"
? std::chrono::seconds::max() ? std::chrono::seconds::max()
@ -51,6 +55,47 @@ ALabel::ALabel(const Json::Value& config, const std::string& name, const std::st
} }
} }
// If a GTKMenu is requested in the config
if (config_["menu"].isString()) {
// Create the GTKMenu widget
try {
// Check that the file exists
std::string menuFile = config_["menu-file"].asString();
// Read the menu descriptor file
std::ifstream file(menuFile);
if (!file.is_open()) {
throw std::runtime_error("Failed to open file: " + menuFile);
}
std::stringstream fileContent;
fileContent << file.rdbuf();
GtkBuilder* builder = gtk_builder_new();
// Make the GtkBuilder and check for errors in his parsing
if (!gtk_builder_add_from_string(builder, fileContent.str().c_str(), -1, nullptr)) {
throw std::runtime_error("Error found in the file " + menuFile);
}
menu_ = gtk_builder_get_object(builder, "menu");
if (!menu_) {
throw std::runtime_error("Failed to get 'menu' object from GtkBuilder");
}
submenus_ = std::map<std::string, GtkMenuItem*>();
menuActionsMap_ = std::map<std::string, std::string>();
// Linking actions to the GTKMenu based on
for (Json::Value::const_iterator it = config_["menu-actions"].begin();
it != config_["menu-actions"].end(); ++it) {
std::string key = it.key().asString();
submenus_[key] = GTK_MENU_ITEM(gtk_builder_get_object(builder, key.c_str()));
menuActionsMap_[key] = it->asString();
g_signal_connect(submenus_[key], "activate", G_CALLBACK(handleGtkMenuEvent),
(gpointer)menuActionsMap_[key].c_str());
}
} catch (std::runtime_error& e) {
spdlog::warn("Error while creating the menu : {}. Menu popup not activated.", e.what());
}
}
if (config_["justify"].isString()) { if (config_["justify"].isString()) {
auto justify_str = config_["justify"].asString(); auto justify_str = config_["justify"].asString();
if (justify_str == "left") { if (justify_str == "left") {
@ -125,6 +170,10 @@ bool waybar::ALabel::handleToggle(GdkEventButton* const& e) {
return AModule::handleToggle(e); return AModule::handleToggle(e);
} }
void ALabel::handleGtkMenuEvent(GtkMenuItem* menuitem, gpointer data) {
waybar::util::command::res res = waybar::util::command::exec((char*)data, "GtkMenu");
}
std::string ALabel::getState(uint8_t value, bool lesser) { std::string ALabel::getState(uint8_t value, bool lesser) {
if (!config_["states"].isObject()) { if (!config_["states"].isObject()) {
return ""; return "";

View File

@ -133,6 +133,16 @@ bool AModule::handleUserEvent(GdkEventButton* const& e) {
format = rec->second; format = rec->second;
} }
// Check that a menu has been configured
if (config_["menu"].isString()) {
// Check if the event is the one specified for the "menu" option
if (rec->second == config_["menu"].asString()) {
// Popup the menu
gtk_widget_show_all(GTK_WIDGET(menu_));
gtk_menu_popup_at_pointer(GTK_MENU(menu_), reinterpret_cast<GdkEvent*>(e));
}
}
// Second call user scripts // Second call user scripts
if (!format.empty()) { if (!format.empty()) {
if (config_[format].isString()) if (config_[format].isString())