argos icon indicating copy to clipboard operation
argos copied to clipboard

Fix collapsing submenus on refresh (Issues #143, #29, #40) + optional reopen/minwidth support

Open mHinz-hub opened this issue 3 months ago โ€ข 2 comments

Summary

This PR addresses a long-standing usability issue in Argos: collapsing submenus after each refresh.
Currently, whenever the menu rebuilds (e.g., due to updateInterval), all open submenus are lost and collapse.
This is tracked in multiple open issues: #143, #29, #40.

The result is a frustrating user experience whenever scripts display structured information across submenus โ€” users constantly need to reopen the submenu they were working with.

This PR introduces backward-compatible, optional extensions to improve daily usability while leaving existing BitBar/Argos scripts untouched.


Changes

1. Preserve Submenu State

  • Problem: Open submenus collapse on every refresh (see #143 / #29 / #40).
  • Solution:
    • Submenu state is captured before removeAll() and restored afterwards.
    • Requires scripts to assign a stable id to submenu headers:
      -- Connections | id=net
      ---- Item A
      ---- Item B
      
    • If id is not set, the submenu behaves as before (collapses on refresh).
  • Implementation: A new helper class submenu_state.js manages capture/restore. Uses GLib.idle_add to avoid race conditions during menu rebuild.

2. Reopen Menu After Action

  • Problem: After executing a menu command, the dropdown always closes, even when the user wants to toggle multiple options quickly.
  • Solution:
    • Scripts can add reopen=true to an item.
    • After the action finishes, the menu automatically reopens, preserving state.
  • Implementation: Handled in submenu_state.js with requestReopen() and finalizeUpdate().

3. Minimum Width for Submenus

  • Problem: When submenu content changes length between refreshes, the menu width jumps, causing visual flicker.
  • Solution:
    • Submenu headers may specify minwidth in pixels:
      -- Status | id=status minwidth=360
      ---- Connected
      ---- Last handshake: 2m ago
      
    • Applied as a min-width style to the corresponding PopupSubMenuMenuItem.
  • Implementation: Applied directly in button.js when building submenus.

Backward Compatibility

  • Scripts without id, reopen, or minwidth properties behave exactly as before.
  • All new features are strictly optional and ignored unless specified in the script output.
  • BitBar/xbar scripts continue to run without modification.

Impact

  • Directly addresses the top UX complaint in Argos (collapsing submenus, see #143 / #29 / #40).
  • Improves workflow for scripts that act as dashboards or toggles (e.g., VPN clients, system controls).
  • Minimal code changes, isolated to new utility class and property checks.

Screenshots / Demo

(optional: add screenshots or a short screencast here to illustrate submenu state being preserved and menu reopening)


Conclusion

This PR makes Argos more robust and convenient in daily use without breaking compatibility.
Users frustrated by collapsing submenus (#143 / #29 / #40) finally get relief, while all existing scripts continue to function as before.

Example

The new features can be seen in the attached demo script:

#!/usr/bin/env bash
# example.5s.sh
# Demonstrates submenu state restore (id=...), reopen=true, and minwidth.

echo "๐Ÿงช Demo"
echo "---"

# Submenu with stable id and fixed minimum width
echo "โš™๏ธ Settings | id=demo-settings minwidth=360"
FLAG="/tmp/argos-demo-flag"
if [[ -f "$FLAG" ]]; then
  echo "--โœ… Enabled  | bash='rm -f \"$FLAG\"' terminal=false refresh=true reopen=true"
else
  echo "--โŒ Disabled | bash='touch \"$FLAG\"' terminal=false refresh=true reopen=true"
fi

# Another submenu โ€“ open state will be preserved
echo "---"
echo "๐Ÿ“Š Status | id=demo-status minwidth=360"
NOW="$(date '+%H:%M:%S')"
echo "--Time: $NOW"
echo "--Flag file present: $( [[ -f \"$FLAG\" ]] && echo yes || echo no )"

# Top-level refresh action
echo "---"
echo "โ™ป๏ธ Force Refresh | refresh=true"

mHinz-hub avatar Sep 22 '25 07:09 mHinz-hub

@vaab, could you give this a try, as you've had similar issues in #173? If your testing is successful, I'll merge this.

mwilck avatar Sep 30 '25 07:09 mwilck

Awesome, a few notes:

  • There is a visible flicker because the menu is actually closing, then argos re-launch the shell script, and then a redisplay of the menu is done with the correct submenu opened.

    The flicker time will be bigger depending on the execution time of the shell script. But it is quite noticeable already with the example script. With my case, I'm already using extensive caching, so it stays usable

  • The reopen=True is plagued by the same flickering.

    And this one, with my case, it is unusable : it stays more than 1 to 2 seconds of screen and come back to the screen.

  • your demo script vanishes at some point (a few minutes after letting it alone):

    it hits an exception (i'm on gnome 46):

Oct 03 05:22:10 wen gnome-shell[42575]: Source ID 157777 was not found when attempting to remove it
Oct 03 05:22:10 wen gnome-shell[42575]: JS ERROR: TypeError: appIndicator is undefined
                                        #handleAppIndicatorItem@file:///home/vaab/.local/share/gnome-shell/extensions/[email protected]/extensionModules/BoxOrderManager.js:80:27
                                        addNewItemSettingsIdsToBoxOrder@file:///home/vaab/.local/share/gnome-shell/extensions/[email protected]/extensionModules/BoxOrderManager.js:295:70
                                        saveNewTopBarItems@file:///home/vaab/.local/share/gnome-shell/extensions/[email protected]/extensionModules/BoxOrderManager.js:333:40
                                        #handleNewItemsAndOrderTopBar@file:///home/vaab/.local/share/gnome-shell/extensions/[email protected]/extension.js:158:31
                                        handleNewItemsAndOrderTopBar@file:///home/vaab/.local/share/gnome-shell/extensions/[email protected]/extension.js:68:47
                                        #overwritePanelAddToPanelBox/Panel.Panel.prototype._addToPanelBox@file:///home/vaab/.local/share/gnome-shell/extensions/[email protected]/extension.js:76:13
                                        addButtons@file:///home/vaab/.local/share/gnome-shell/extensions/[email protected]/extension.js:105:16
                                        enable/this.directoryChangedId</this.debounceTimeout<@file:///home/vaab/.local/share/gnome-shell/extensions/[email protected]/extension.js:64:14

I didn't really check the code, but wouldn't it be possible to load the old menu while the command is being run ? That would reduce flicker. Or best, avoid closing it in the first place ;-)

Well, I feel this is incrementally better, but a little quirky feeling. I'm unsure of what to think about if this is better than just avoiding refreshes while a submenu is open for people only minding about the submenu closing upon refresh.

Screencast from 2025-10-03 05-36-25.webm

Also, this PR is not ready for merge as-is strictly speaking : there is no doc, and it contains other unrelated stuff.

vaab avatar Oct 03 '25 03:10 vaab