v1cont / yad

Yet Another Dialog
GNU General Public License v3.0
685 stars 57 forks source link

[Enhancement Request] Expand `--command` Parameter Functionality in `yad` Notifications #275

Open KernelGhost opened 3 months ago

KernelGhost commented 3 months ago

Thank you for your continued development of this amazing package!

I am currently working on a simple application that uses a yad notification. As discussed in this issue, I am trying to programmatically update the yad notification menu entries (options) immediately before displaying the menu to the user following a left-click on the yad notification icon. I understand that the code to be executed when the user left-clicks the yad notification icon can be specified using the --command argument.

According to the relevant yad documentation:

"There are two special commands - 'menu' for popup user defined menu and 'quit' for exit the program."

I have tried various combinations of commands to execute an initial command (e.g., --command="bash -c 'generate_menu_entries' && menu"), but these attempts have been unsuccessful.

The current bash code I am using to generate the yad notification is as follows:

yad --notification \
    --listen \
    --no-middle \
    --text="WinApps Launcher" \
    --image="AppIcon.svg" \
    --command="menu" <&3

The actual menu entries are determined at runtime, and are communicated to the yad notification using a pipe (e.g., echo "menu:Resume!bash -c resume_windows!${ICONS_PATH}/Resume.svg" >&3).

Upon reviewing the yad source code, particularly lines 155 to 172 of src/notification.c, it seems that the popup_menu_cb function can only be executed if --command exactly specifies "menu" (via a case-insensitive string comparison).

static gboolean
activate_cb (GtkWidget * widget, YadData * data)
{
  if ((action == NULL && !options.common_data.listen) || (action && g_ascii_strcasecmp (action, "quit") == 0))
    {
      exit_code = YAD_RESPONSE_OK;
      gtk_main_quit ();
    }
  else if (action)
    {
      if (g_ascii_strcasecmp (action, "menu") == 0)
        popup_menu_cb (GTK_STATUS_ICON (widget), 1, GDK_CURRENT_TIME, data);
      else
        run_command_async (action);
    }

  return TRUE;
}

It would be extremely helpful if the functionality of the --command parameter could be expanded to allow expressions such as --command="bash -c 'update_yad_notification_menu' && menu" (or similar syntax to achieve the desired effect). This would enable running additional functions before and/or after requesting the notification menu to be displayed.

Thank you!

KernelGhost commented 3 months ago

Please note that I have also tried the following:

export PIPE=$(mktemp -u --tmpdir "${0##*/}".XXXXXXXX)
mkfifo "$PIPE"

yad --notification \
    --listen \
    --no-middle \
    --text="WinApps Launcher" \
    --image="AppIcon.svg" \
    --command="bash -c '\
menu_entries=\"menu:\$(generate_menu_entries)\"; \
exec 3<> \$PIPE; \
echo \"\$menu_entries\" >&3; \
echo \"action:\"menu\"\" >&3'" <&3

Where generate_menu_entries is an example function defined as follows:

function generate_menu_entries() {
    echo "Resume!bash -c resume_windows!${ICONS_PATH}/Resume.svg|\
Hibernate!bash -c hibernate_windows!${ICONS_PATH}/Hibernate.svg"
}
export -f generate_menu_entries

Unfortunately, this approach causes the menu to update but does not display the menu the first time the user left-clicks the icon. Additionally, all subsequent left-clicks open the menu without updating the menu entries beforehand. This is because echo "action:\"menu\"" >&3 modifies the action stored in --command without executing it. The desired behaviour, however, was to run the special "menu" command without changing the action stored in --command so as to not affect the action run upon subsequent left-clicks.

KernelGhost commented 3 months ago

I would like to propose a solution to extend the functionality of yad notifications while preserving backward compatibility. The idea is to introduce support for multiple --command arguments. This approach offers a clean and elegant way to handle multiple sequential commands by leveraging the existing command-line argument structure. It also avoids the complexity of parsing special delimiters or data formats.

Key advantages of this approach include:

  1. Backward Compatibility: Existing use cases featuring a single --command argument remain unaffected. Users who rely on the current behaviour will not experience any disruption.

  2. Ease of Implementation: This solution involves minimal changes to the existing command syntax, and therefore will require minimal modifications to the existing input parsing logic. The key functions requiring changes are handle_stdin and activate_cb in src/notification.c.

  3. Simplicity: This solution avoids requiring users to specify multiple sequential commands using complex data structures such as XML and JSON. In addition, the use of arbitrary or special delimiters to split sequential commands within a single string is avoided.

Example:

yad --notification \
    --listen \
    --no-middle \
    --text="Example YAD Notification" \
    --image="Example.svg" \
    --menu='Option 1!bash -c fnOption1!Option1.svg|Option 2!bash -c fnOption2!Option2|Option 3!bash -c fnOption3!Option3' \
    --command="bash -c 'fnExample1'"
    --command="menu"
    --command="bash -c 'fnExample2'"  <&3