feat: P4 — DBus bridge + page round-trip + system theme tracking

Three new wires from page to shell and back, proving the bridge end to
end. The dashboard placeholder now follows the system color-scheme via
the full chain: page-side dashShell.call('getTheme') → WebKit script
message handler → DBus method on the shell-owned service → gsettings
read → return value back up. ThemeChanged proves the reverse direction:
the shell watches color-scheme and emits a DBus signal that the
container forwards to the page as a CustomEvent.

extension/src/dbus-service.ts
  Owns top.hangmanlab.Dashward.Shell on the session bus; exports
  GetTheme (reads org.gnome.desktop.interface::color-scheme, maps
  prefer-dark→dark / else→light); emits ThemeChanged on the gsettings
  changed signal. Bus acquisition is async, so the constructor takes an
  onReady callback that fires from the bus_acquired handler.

extension/src/extension.ts
  Sequencing: warden → guard → dbus, and only after dbus_acquired
  callback fires do we spawn ContainerSupervisor. Disable order is
  reversed (container first so its DBus proxy stops calling the service
  before we unown the bus name).

container/src/dbus-client.ts
  Thin GJS proxy wrapper around the Shell interface; exposes a typed
  getTheme() / onThemeChange(cb) API.

container/src/bridge.ts
  Registers a `shellCall` UCM script-message handler; parses
  {id, method, args} JSON from the page, dispatches to invoke(), and
  feeds the result back via evaluate_javascript. Shell signals are
  forwarded to the page via window.__dashShell__._onSignal.

container/runtime/runtime.ts
  Installs window.__dashShell__ at script start, calls getTheme() on
  load and applies the result to <html data-theme>, listens for the
  ThemeChanged CustomEvent.

container/runtime/dashboard.html + esbuild.config.js
  Switched the runtime bundle from `format: 'esm'` to IIFE so it loads
  as a classic <script> -- WebKitGTK silently refuses `<script
  type="module">` over file:// for ES module resolution. Added an
  inline error catcher that surfaces JS errors in the visible boot
  diagnostic div instead of failing silently.

container/src/main.ts
  Construct ShellClient + Bridge before load_uri so the very first
  page-side dashShell.call() has a handler waiting. Added load-changed
  / load-failed signal logging for future diagnosis.

Verified on ubuntu2504-test VM: enable produces clean log chain through
"container window arrived", page renders with "P4 — shell bridge
online" placeholder and the correct system theme on first paint, manual
`gsettings set ... color-scheme prefer-dark` flips the placeholder
background live.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
h z
2026-05-23 00:54:19 +01:00
parent e1ae88948e
commit 5ed4170e69
9 changed files with 419 additions and 45 deletions

View File

@@ -6,7 +6,28 @@
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<!-- Visible without JS. runtime.js removes it on mount; the error
handler below replaces its content if JS throws. -->
<div id="boot">dashboard.html loaded — waiting for runtime.js</div>
<main id="grid"></main>
<script type="module" src="runtime.js"></script>
<script>
// Tiny inline diagnostic so a runtime.js syntax/runtime error is
// visible on screen (and forwarded to the host) instead of failing
// silently.
window.addEventListener('error', function (e) {
var b = document.getElementById('boot');
if (b) b.textContent = 'JS ERROR: ' + (e.message || '?') +
(e.filename ? ' @ ' + e.filename + ':' + e.lineno : '');
});
window.addEventListener('unhandledrejection', function (e) {
var b = document.getElementById('boot');
if (b) b.textContent = 'PROMISE REJECT: ' + String(e.reason);
});
</script>
<!-- bundle is self-contained; classic script avoids file:// module
loader quirks in WebKitGTK. -->
<script src="runtime.js"></script>
</body>
</html>