From b41c9662cb7063d7d8e259a4481b32d256b4af84 Mon Sep 17 00:00:00 2001 From: Eduard Tolosa Date: Tue, 26 May 2026 19:20:12 -0500 Subject: [PATCH] fix: rename D-Bus name to dev.edu4rdshl.Strata; drop recursive theme reload Two changes for 0.7.0: BREAKING (D-Bus): the service is renamed from org.gnome.Strata to dev.edu4rdshl.Strata. The org.gnome.* namespace is reserved for official GNOME software; Strata is third-party, so it now uses the reverse-DNS of its own domain (matching the strata@edu4rdshl.dev UUID). Bus name, object path (/dev/edu4rdshl/Strata), and interface (dev.edu4rdshl.Strata.Manager) all change. Daemon and extension are updated together; only external busctl scripts / non-GNOME front-ends that hard-coded the old name need updating. The GSettings schema (org.gnome.shell.extensions.strata) is unchanged - that namespace is correct for GNOME Shell extension settings. Fix recursion: the theme-context 'changed' handler reloaded light.css, but load_stylesheet itself emits 'changed', so it fed back into itself and hit "too much recursion" - flooding the journal and spinning the CPU on screen unlock (which restyles widgets and fires 'changed'). The subscription is removed; light.css is loaded once. Dark/light switching is unaffected (it is the panel's class toggle, not this load). A GNOME Shell theme switch no longer auto-re-applies the sheet, which is recoverable by re-enabling. Co-Authored-By: Claude Opus 4.7 --- AGENTS.md | 2 +- ARCHITECTURE.md | 6 ++--- README.md | 2 +- strata-daemon/README.md | 16 ++++++------- strata-daemon/src/dbus_service.rs | 2 +- strata-daemon/src/main.rs | 10 ++++---- strata@edu4rdshl.dev/dbus.js | 6 ++--- strata@edu4rdshl.dev/extension.js | 40 ++++++++++++++----------------- 8 files changed, 40 insertions(+), 44 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f74d2f0..0272b9f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -72,7 +72,7 @@ ssh fedoradev 'glib-compile-schemas ~/.local/share/gnome-shell/extensions/strata ## D-Bus interface summary -Service `org.gnome.Strata`, object `/org/gnome/Strata`, interface `org.gnome.Strata.Manager`. +Service `dev.edu4rdshl.Strata`, object `/dev/edu4rdshl/Strata`, interface `dev.edu4rdshl.Strata.Manager`. Methods: `GetHistory(offset u32, limit u32) -> json s`, `SearchHistory(query s, limit u32) -> json s`, diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index ab3a9fa..e93d38d 100755 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -24,7 +24,7 @@ together and the trade-offs at each layer. | | ItemAdded / ItemDeleted / HistoryCleared | +--------+-------------------------------------------------------------------------+ | - | session D-Bus (org.gnome.Strata) + | session D-Bus (dev.edu4rdshl.Strata) v +----------------------- strata-daemon (Rust process) --------------------------+ | | @@ -68,7 +68,7 @@ hot ingest path (it fires `SubmitItem` and returns immediately). ### Startup The extension listens for `notify::g-name-owner` on the D-Bus proxy. When -the daemon's `org.gnome.Strata` name becomes owned, the panel triggers +the daemon's `dev.edu4rdshl.Strata` name becomes owned, the panel triggers its initial fetch. No polling, no fixed delays. ## Ingest path @@ -313,7 +313,7 @@ and it is small and isolated. | App to history | Password leak | `x-kde-passwordManagerHint` opt-out | | User to search | SQL injection | rusqlite `params![]`, FTS5 input bound as value | | Daemon to FS | Path traversal via id | Ids are server-generated UUID v4 | -| Daemon to extension | Signal spoofing | D-Bus enforces single owner of `org.gnome.Strata` | +| Daemon to extension | Signal spoofing | D-Bus enforces single owner of `dev.edu4rdshl.Strata` | | Stored item to paste | Command execution | No spawn, no launch_uri, no markup parsing | ## Non-GNOME front-end diff --git a/README.md b/README.md index 5ece76e..30efef9 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Strata is **two components**, and you need **both** for it to work: | Component | Language | Role | |---|---|---| -| [`strata-daemon/`](strata-daemon/) | Rust + tokio + zbus | Storage (SQLite + FTS5), dedup, thumbnails, D-Bus service `org.gnome.Strata` | +| [`strata-daemon/`](strata-daemon/) | Rust + tokio + zbus | Storage (SQLite + FTS5), dedup, thumbnails, D-Bus service `dev.edu4rdshl.Strata` | | [`strata@edu4rdshl.dev/`](strata@edu4rdshl.dev/) | GJS (GNOME Shell extension) | Top-bar panel, search UI, paste-back, clipboard ingest | The extension auto-connects to the daemon on enable. If the daemon is managed diff --git a/strata-daemon/README.md b/strata-daemon/README.md index 0520de0..465e35b 100644 --- a/strata-daemon/README.md +++ b/strata-daemon/README.md @@ -24,9 +24,9 @@ manually if you're using a non-GNOME front-end. ## D-Bus interface -- **Bus name:** `org.gnome.Strata` -- **Object path:** `/org/gnome/Strata` -- **Interface:** `org.gnome.Strata.Manager` +- **Bus name:** `dev.edu4rdshl.Strata` +- **Object path:** `/dev/edu4rdshl/Strata` +- **Interface:** `dev.edu4rdshl.Strata.Manager` | Member | Signature | Notes | |---|---|---| @@ -51,15 +51,15 @@ manually if you're using a non-GNOME front-end. ./target/release/strata-daemon # In another terminal: -busctl --user call org.gnome.Strata /org/gnome/Strata \ - org.gnome.Strata.Manager GetHistory uu 0 10 +busctl --user call dev.edu4rdshl.Strata /dev/edu4rdshl/Strata \ + dev.edu4rdshl.Strata.Manager GetHistory uu 0 10 # Submit text: -busctl --user call org.gnome.Strata /org/gnome/Strata \ - org.gnome.Strata.Manager SubmitItem say "text/plain;charset=utf-8" 5 104 101 108 108 111 +busctl --user call dev.edu4rdshl.Strata /dev/edu4rdshl/Strata \ + dev.edu4rdshl.Strata.Manager SubmitItem say "text/plain;charset=utf-8" 5 104 101 108 108 111 # Listen for new items: -busctl --user monitor org.gnome.Strata +busctl --user monitor dev.edu4rdshl.Strata ``` ## Supported clipboard payloads diff --git a/strata-daemon/src/dbus_service.rs b/strata-daemon/src/dbus_service.rs index 2675729..68d3553 100644 --- a/strata-daemon/src/dbus_service.rs +++ b/strata-daemon/src/dbus_service.rs @@ -57,7 +57,7 @@ pub struct StrataManager { pub shutdown_tx: tokio::sync::mpsc::UnboundedSender<()>, } -#[interface(name = "org.gnome.Strata.Manager")] +#[interface(name = "dev.edu4rdshl.Strata.Manager")] impl StrataManager { /// Called by the GJS extension when it detects a clipboard change via Meta.Selection. /// `content` is the raw bytes of the clipboard payload (D-Bus `ay`). diff --git a/strata-daemon/src/main.rs b/strata-daemon/src/main.rs index 8c53b1e..07fa32b 100644 --- a/strata-daemon/src/main.rs +++ b/strata-daemon/src/main.rs @@ -49,7 +49,7 @@ async fn main() -> Result<()> { }; let dbus_conn = zbus::connection::Builder::session()? - .serve_at("/org/gnome/Strata", manager)? + .serve_at("/dev/edu4rdshl/Strata", manager)? .build() .await .context("Building D-Bus connection")?; @@ -61,14 +61,14 @@ async fn main() -> Result<()> { // would be refused. dbus_conn .request_name_with_flags( - "org.gnome.Strata", + "dev.edu4rdshl.Strata", zbus::fdo::RequestNameFlags::ReplaceExisting | zbus::fdo::RequestNameFlags::AllowReplacement, ) .await - .context("Acquiring D-Bus name org.gnome.Strata")?; + .context("Acquiring D-Bus name dev.edu4rdshl.Strata")?; - tracing::info!("D-Bus service registered as org.gnome.Strata"); + tracing::info!("D-Bus service registered as dev.edu4rdshl.Strata"); // ----------------------------------------------------------------------- // Clipboard monitor (Wayland protocols - optional, soft-fail on GNOME). @@ -312,7 +312,7 @@ async fn process_bytes( if is_new { let iface = conn .object_server() - .interface::<_, StrataManager>("/org/gnome/Strata") + .interface::<_, StrataManager>("/dev/edu4rdshl/Strata") .await .context("Getting StrataManager interface ref")?; diff --git a/strata@edu4rdshl.dev/dbus.js b/strata@edu4rdshl.dev/dbus.js index 794e3de..9ff577b 100644 --- a/strata@edu4rdshl.dev/dbus.js +++ b/strata@edu4rdshl.dev/dbus.js @@ -10,7 +10,7 @@ import Gio from 'gi://Gio'; const STRATA_IFACE_XML = ` - + @@ -75,5 +75,5 @@ const STRATA_IFACE_XML = ` export const StrataProxy = Gio.DBusProxy.makeProxyWrapper(STRATA_IFACE_XML); -export const BUS_NAME = 'org.gnome.Strata'; -export const OBJECT_PATH = '/org/gnome/Strata'; +export const BUS_NAME = 'dev.edu4rdshl.Strata'; +export const OBJECT_PATH = '/dev/edu4rdshl/Strata'; diff --git a/strata@edu4rdshl.dev/extension.js b/strata@edu4rdshl.dev/extension.js index d675c97..f6cb37e 100644 --- a/strata@edu4rdshl.dev/extension.js +++ b/strata@edu4rdshl.dev/extension.js @@ -440,7 +440,7 @@ export default class StrataExtension extends Extension { _connectSignals() { this._itemAddedId = Gio.DBus.session.signal_subscribe( BUS_NAME, - 'org.gnome.Strata.Manager', + 'dev.edu4rdshl.Strata.Manager', 'ItemAdded', OBJECT_PATH, null, @@ -450,7 +450,7 @@ export default class StrataExtension extends Extension { this._itemDeletedId = Gio.DBus.session.signal_subscribe( BUS_NAME, - 'org.gnome.Strata.Manager', + 'dev.edu4rdshl.Strata.Manager', 'ItemDeleted', OBJECT_PATH, null, @@ -473,7 +473,7 @@ export default class StrataExtension extends Extension { this._historyClearedId = Gio.DBus.session.signal_subscribe( BUS_NAME, - 'org.gnome.Strata.Manager', + 'dev.edu4rdshl.Strata.Manager', 'HistoryCleared', OBJECT_PATH, null, @@ -600,22 +600,23 @@ export default class StrataExtension extends Extension { } - /** Load light.css into the global St theme context. Scoped under - * `.strata-theme-light`, so it does nothing until the panel adds that - * class. Reloaded on theme-context changes (a Shell-theme switch drops - * dynamically loaded stylesheets). */ + /** Load light.css into the global St theme context ONCE. It is scoped under + * `.strata-theme-light`, so it stays inert until the panel adds that class + * (dark/light switching is the panel's class toggle, independent of this). + * + * We deliberately do NOT subscribe to the theme context's 'changed' + * signal: load_stylesheet itself emits 'changed', so reloading on it feeds + * back into itself and hits "too much recursion" (it fired on screen + * unlock, which restyles widgets). The only thing a one-time load gives up + * is re-applying after a GNOME Shell *theme* switch (which replaces the + * St.Theme and drops this sheet) - a rare action, recoverable by toggling + * the extension. That trade is worth never touching the signal. */ _loadThemeStylesheet() { try { const themeContext = St.ThemeContext.get_for_stage(global.stage); this._lightCssFile = this.dir.get_child('light.css'); - themeContext.get_theme().load_stylesheet(this._lightCssFile); - this._stThemeChangedId = themeContext.connect('changed', () => { - try { - themeContext.get_theme().load_stylesheet(this._lightCssFile); - } catch (e) { - console.error('[Strata] light.css reload failed:', e); - } - }); + this._stTheme = themeContext.get_theme(); + this._stTheme.load_stylesheet(this._lightCssFile); } catch (e) { console.error('[Strata] Failed to load light.css:', e); } @@ -623,16 +624,11 @@ export default class StrataExtension extends Extension { _unloadThemeStylesheet() { try { - const themeContext = St.ThemeContext.get_for_stage(global.stage); - if (this._stThemeChangedId) { - themeContext.disconnect(this._stThemeChangedId); - this._stThemeChangedId = null; - } - if (this._lightCssFile) - themeContext.get_theme().unload_stylesheet(this._lightCssFile); + this._stTheme?.unload_stylesheet(this._lightCssFile); } catch (e) { console.error('[Strata] Failed to unload light.css:', e); } + this._stTheme = null; this._lightCssFile = null; } }