Skip to content

Work around serviceFor null under third-party bars (Islands) - #10

Closed
Hertuno wants to merge 14 commits into
WhoIsCalebBrown:mainfrom
Hertuno:fix/third-party-bar-daemon-bridge
Closed

Hertuno wants to merge 14 commits into
WhoIsCalebBrown:mainfrom
Hertuno:fix/third-party-bar-daemon-bridge

Conversation

@Hertuno

@Hertuno Hertuno commented Oct 9, 2026

Copy link
Copy Markdown

Summary

On Omarchy, a third-party bar (Islands, omarchy plugin clone omarchy.bar, …) gets a service-less entry facade. bar.shell.serviceFor("whoiscalebbrown.mic-effects") is always null, so the rack stays on STARTING even though the keepLoaded Service and mic-effects-server are running and Microphone Effects exists in PipeWire.

This is omacom/omarchy#13289 (same root cause as Islands #1). The durable fix belongs in Omarchy (inject own-service into the widget without handing raw services to the bar). Until that lands, this plugin can keep working by talking to ctl.sock directly when serviceFor is unavailable.

Approach

  • Add plugin/DaemonBridge.qml: socket client mirroring the panel-facing API of Service.qml (no install/lifecycle ownership — the keepLoaded service still owns that; the bridge only reconnects / nudges mic-effects-server run if the socket is down).
  • In plugin/Panel.qml: prefer hostedSvc = serviceFor(...), else fall back to the bridge.

Stock bar path is unchanged (hostedSvc wins, bridge stays inactive).

Panel.qml hunk (included in this PR once the second commit is pushed; also pasted here for review)

-  readonly property var svc: bar && bar.shell ? bar.shell.serviceFor("whoiscalebbrown.mic-effects") : null
+  // Stock bar: serviceFor() returns the keepLoaded Service.
+  // Third-party bars (Islands, clones): serviceFor() is null — use DaemonBridge
+  // so the rack still talks to ctl.sock. See Omarchy #13289.
+  readonly property var hostedSvc: bar && bar.shell && typeof bar.shell.serviceFor === "function"
+    ? bar.shell.serviceFor("whoiscalebbrown.mic-effects") : null
+  readonly property var svc: hostedSvc || bridge
+  DaemonBridge {
+    id: bridge
+    bridgeActive: !root.hostedSvc
+  }

Test plan

  • Omarchy + Islands + this plugin: icon opens rack (not stuck on STARTING); meters/source/effects work
  • Omarchy stock bar: still uses hosted Service (bridge inactive)
  • Daemon still starts via keepLoaded service; virtual source Microphone Effects present in PipeWire

Happy to adjust naming/structure if you would rather wait purely on Omarchy, or fold the socket client differently.

@Hertuno

Hertuno commented Oct 9, 2026

Copy link
Copy Markdown
Author

Status: plugin/DaemonBridge.qml is on the branch.

The matching plugin/Panel.qml change (prefer serviceFor, else DaemonBridge) is ready locally but not yet on the remote tip because git push from this environment has no GitHub credentials beyond the MCP Contents API used for the smaller file.

Panel hunk (same as in the PR description):

-  readonly property var svc: bar && bar.shell ? bar.shell.serviceFor("whoiscalebbrown.mic-effects") : null
+  readonly property var hostedSvc: bar && bar.shell && typeof bar.shell.serviceFor === "function"
+    ? bar.shell.serviceFor("whoiscalebbrown.mic-effects") : null
+  readonly property var svc: hostedSvc || bridge
+  DaemonBridge {
+    id: bridge
+    bridgeActive: !root.hostedSvc
+  }

I will push that commit onto fix/third-party-bar-daemon-bridge shortly (or feel free to apply the hunk while reviewing).

Third-party bars such as Islands receive a service-less shell facade, so bar.shell.serviceFor() is always null and the rack stuck on STARTING even though the keepLoaded Service and daemon are running. Prefer the hosted service when present; otherwise talk to ctl.sock through DaemonBridge.

Workaround for omacom/omarchy#13289 until the host can inject own-service into bar-entry widgets without widening the bar's security boundary.
@Hertuno

Hertuno commented Oct 9, 2026

Copy link
Copy Markdown
Author

Correction: a botched Contents API upload briefly replaced plugin/Panel.qml on this branch with the literal text PLACEHOLDER. Sorry about that.

Current intended tip (local, ready to force-push once credentials allow):

  1. e64bc9f — add plugin/DaemonBridge.qml (already on the branch, good)
  2. next commit — Panel.qml hunk below (restores full file + hostedSvc || bridge)

Until that force-push lands, do not merge — Panel.qml on the remote tip is corrupted.

-  readonly property var svc: bar && bar.shell ? bar.shell.serviceFor("whoiscalebbrown.mic-effects") : null
+  readonly property var hostedSvc: bar && bar.shell && typeof bar.shell.serviceFor === "function"
+    ? bar.shell.serviceFor("whoiscalebbrown.mic-effects") : null
+  readonly property var svc: hostedSvc || bridge
+  DaemonBridge {
+    id: bridge
+    bridgeActive: !root.hostedSvc
+  }

I will replace the bad tip shortly.

@Hertuno

Hertuno commented Oct 9, 2026

Copy link
Copy Markdown
Author

Closing this PR — the branch tip was corrupted while uploading the large Panel.qml through the Contents API (size limits / accidental placeholders). Please do not merge.

The proposal is written up cleanly in #11, with the Panel.qml hunk and a link to a good DaemonBridge.qml on the fork (e64bc9f). Sorry for the noise.

@Hertuno Hertuno closed this Oct 9, 2026
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.

1 participant