Skip to content

Keep a panel plugin enabled when its bar icon is removed - #6510

Open
28allday wants to merge 1 commit into
basecamp:quattrofrom
28allday:plugin-enable-panel-ref
Open

Keep a panel plugin enabled when its bar icon is removed#6510
28allday wants to merge 1 commit into
basecamp:quattrofrom
28allday:plugin-enable-panel-ref

Conversation

@28allday

@28allday 28allday commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

A plugin whose kinds include both bar-widget and a panel, overlay or menu kind is enabled by its bar entry alone. setEnabled picks the bar branch of an if/else chain, so the config.plugins.push(entry) below it is unreachable for that shape:

if (!location.found && isBarWidget) {
  ...                                    // bar entry written here
} else if (!location.found && !isFirstParty) {
  config.plugins.push(entry)             // never reached for a panel widget
}

isEnabled() then falls through to findEntryLocation(), which only finds the bar entry. Take such a plugin's icon out of the bar and it counts as disabled: the panel delegate is never instantiated and omarchy-shell shell toggle <id> becomes a silent no-op — exit 0, nothing on screen, and the reason only in /run/user/$UID/quickshell/by-pid/*/log.log:

WARN qml: summon: plugin not enabled, not summoning: <id>

Users hit this by binding a key to a panel plugin and then not wanting a second icon in their bar, or by running with the bar hidden. It reads as a broken keybinding, which is a long way from where the cause is.

Changes

  • setEnabled writes both references on enable: the bar entry for the widget, and a plugins[] entry for the kind that outlives it. Widget-only plugins are unaffected — they still get the bar entry alone, and first-party plugins still get neither.
  • Disable clears every reference in one call rather than the first one found, so off still means off. This also means omarchy plugin remove's single setPluginEnabled <id> false can no longer leave an orphan entry pointing at a directory that has been deleted.
  • restoreCloneSource drops a clone's plugins[] entry whichever way it was referenced — without this the enable change would orphan one on every hybrid clone.
  • listPlugins reports a widget-only plugin by its place in the bar as before; anything with another kind reports whether it is actually enabled.
  • New findPluginLocation, plus a note on findEntryLocation that it returns the first reference now that two can coexist.

Testing

plugin-registry-contract-test.sh runs real headless quickshell against the registry, so these are behavioural checks rather than source assertions. Added a third.hybrid ["panel","bar-widget"] fixture covering:

  • both references written on enable
  • still enabled after the bar entry is removed
  • one-call disable clearing both
  • re-enabling twice adding one of each
  • no orphan left behind when a clone's source is restored

Reverting only PluginRegistry.qml fails on exactly the new assertions (expected=[{"id":"third.hybrid"}] actual=[]), so the test pins the fix rather than merely passing alongside it. ./test/shell is otherwise green — 603 passing.

🤖 Generated with Claude Code

A plugin whose kinds include both a bar-widget and a panel, overlay or
menu was enabled by its bar entry alone: setEnabled picked the bar branch
of an if/else chain, so the plugins[] push below it was unreachable. Take
such a plugin's icon out of the bar and isEnabled() went false, the panel
delegate was never instantiated, and `omarchy-shell shell toggle <id>`
became a silent no-op — exit 0, nothing on screen, and the reason only in
the shell log. Users hit this by binding a key to a panel and then not
wanting a second icon in their bar.

Enable now writes both references: the bar entry for the widget, and a
plugins[] entry for the kind that outlives it. Disable clears every
reference in one call rather than the first one found, so off still means
off, and restoring a clone's source drops the clone's plugins[] entry
whichever way it was referenced.

listPlugins reports a plugin that is only a widget by its place in the
bar as before, and anything with another kind by whether it is enabled.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 2, 2026 10:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Updates plugin enablement so hybrid panel/bar plugins remain active without their bar icon.

Changes:

  • Stores independent bar and plugin references for hybrid plugins.
  • Removes references when disabling or restoring clones.
  • Adds behavioral coverage for hybrid plugin lifecycle.

Tip

If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
shell/services/PluginRegistry.qml Manages hybrid plugin references and clone restoration.
shell/shell.qml Reports hybrid plugin enablement state.
test/shell.d/fixtures/plugin-registry/shell.qml Adds hybrid lifecycle contract tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +518 to +521
var barEntry = findBarLocation(config, key, "")
if (barEntry.found) config.bar.layout[barEntry.section].splice(barEntry.index, 1)
var pluginEntry = findPluginLocation(config, key)
if (pluginEntry.found) config.plugins.splice(pluginEntry.index, 1)
Comment thread shell/shell.qml
Comment on lines 961 to +962
enabled: isBarOption ? active
: (isBarWidget ? shell.pluginRegistry.inBar(id) : shell.pluginRegistry.isEnabled(id)),
: (isWidgetOnly ? shell.pluginRegistry.inBar(id) : shell.pluginRegistry.isEnabled(id)),
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants