extension: align D-Bus client with the GJS guide

Route ItemAdded, ItemDeleted and HistoryCleared through proxy.connectSignal
instead of the low-level Gio.DBus.session.signal_subscribe. The wrapper is
already constructed and pre-unpacks signal args.

Strip the GDBus.Error: remote prefix from D-Bus errors before logging so the
journal shows the actual message.
This commit is contained in:
Eduard Tolosa 2026-06-25 16:09:42 -05:00
parent 43a68e7970
commit 8943136384
2 changed files with 31 additions and 56 deletions

View file

@ -396,7 +396,8 @@ export default class StrataExtension extends Extension {
OBJECT_PATH, OBJECT_PATH,
(proxy, error) => { (proxy, error) => {
if (error) { if (error) {
console.error('[Strata] D-Bus proxy error:', error); Gio.DBusError.strip_remote_error(error);
console.error('[Strata] D-Bus proxy error:', error.message);
return; return;
} }
this._connectSignals(); this._connectSignals();
@ -433,48 +434,25 @@ export default class StrataExtension extends Extension {
} }
_connectSignals() { _connectSignals() {
this._itemAddedId = Gio.DBus.session.signal_subscribe( this._itemAddedId = this._proxy.connectSignal('ItemAdded',
BUS_NAME, (_p, _sender, [id, mimeType, preview]) =>
'dev.edu4rdshl.Strata.Manager', this._onItemAdded(id, mimeType, preview));
'ItemAdded',
OBJECT_PATH,
null,
Gio.DBusSignalFlags.NONE,
this._onItemAdded.bind(this)
);
this._itemDeletedId = Gio.DBus.session.signal_subscribe( this._itemDeletedId = this._proxy.connectSignal('ItemDeleted',
BUS_NAME, (_p, _sender, [id]) => {
'dev.edu4rdshl.Strata.Manager',
'ItemDeleted',
OBJECT_PATH,
null,
Gio.DBusSignalFlags.NONE,
(_conn, _sender, _path, _iface, _signal, params) => {
const [id] = params.deepUnpack();
// Best-effort: unlink the on-disk thumbnail file (if any).
// GLib.unlink returns -1 if file doesn't exist; we ignore that.
try { try {
const cachePath = const cachePath =
`${GLib.get_user_cache_dir()}/strata/thumbnails/${id}.png`; `${GLib.get_user_cache_dir()}/strata/thumbnails/${id}.png`;
GLib.unlink(cachePath); GLib.unlink(cachePath);
} catch (_) { /* not all items have thumbnails - fine */ } } catch (_) {}
GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
this._panel?.removeItem(id); this._panel?.removeItem(id);
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;
}); });
} });
);
this._historyClearedId = Gio.DBus.session.signal_subscribe( this._historyClearedId = this._proxy.connectSignal('HistoryCleared',
BUS_NAME,
'dev.edu4rdshl.Strata.Manager',
'HistoryCleared',
OBJECT_PATH,
null,
Gio.DBusSignalFlags.NONE,
() => { () => {
// Wipe all on-disk thumbnails when daemon clears history.
try { try {
const dir = `${GLib.get_user_cache_dir()}/strata/thumbnails`; const dir = `${GLib.get_user_cache_dir()}/strata/thumbnails`;
const d = Gio.File.new_for_path(dir); const d = Gio.File.new_for_path(dir);
@ -487,26 +465,25 @@ export default class StrataExtension extends Extension {
} }
en.close(null); en.close(null);
} }
} catch (e) { console.error('[Strata] cache clear failed:', e); } } catch (e) { console.error('[Strata] cache clear failed:', e.message); }
GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
this._panel?.clearItems(); this._panel?.clearItems();
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;
}); });
} });
);
} }
_disconnectSignals() { _disconnectSignals() {
if (this._itemAddedId !== null) { if (this._itemAddedId && this._proxy) {
Gio.DBus.session.signal_unsubscribe(this._itemAddedId); this._proxy.disconnectSignal(this._itemAddedId);
this._itemAddedId = null; this._itemAddedId = null;
} }
if (this._itemDeletedId !== null) { if (this._itemDeletedId && this._proxy) {
Gio.DBus.session.signal_unsubscribe(this._itemDeletedId); this._proxy.disconnectSignal(this._itemDeletedId);
this._itemDeletedId = null; this._itemDeletedId = null;
} }
if (this._historyClearedId !== null) { if (this._historyClearedId && this._proxy) {
Gio.DBus.session.signal_unsubscribe(this._historyClearedId); this._proxy.disconnectSignal(this._historyClearedId);
this._historyClearedId = null; this._historyClearedId = null;
} }
if (this._pendingSignalId !== null) { if (this._pendingSignalId !== null) {
@ -516,7 +493,7 @@ export default class StrataExtension extends Extension {
} }
_onItemAdded(_conn, _sender, _path, _iface, _signal, params) { _onItemAdded(id, mimeType, preview) {
// Debounce: if the daemon emits a burst, coalesce into one update. // Debounce: if the daemon emits a burst, coalesce into one update.
if (this._pendingSignalId !== null) { if (this._pendingSignalId !== null) {
GLib.Source.remove(this._pendingSignalId); GLib.Source.remove(this._pendingSignalId);
@ -524,28 +501,22 @@ export default class StrataExtension extends Extension {
} }
this._pendingSignalId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 50, () => { this._pendingSignalId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 50, () => {
this._pendingSignalId = null; this._pendingSignalId = null;
this._processItemAdded(params).catch(e => console.error('[Strata] ItemAdded error:', e)); this._processItemAdded(id, mimeType, preview)
.catch(e => console.error('[Strata] ItemAdded error:', e.message));
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;
}); });
} }
async _processItemAdded(params) { async _processItemAdded(id, mimeType, preview) {
if (this._busy) return; if (this._busy) return;
this._busy = true; this._busy = true;
try { try {
const [id, mimeType, preview] = params.deepUnpack();
// Exclusion check - no clipboard I/O, just string comparison.
if (this._isExcluded(this._currentFocusedApp)) { if (this._isExcluded(this._currentFocusedApp)) {
try { try {
await this._proxy?.DeleteItemAsync(id); await this._proxy?.DeleteItemAsync(id);
} catch (e) { } catch (_) { /* item may already be gone */ }
// ignore - item may already be gone
}
return; return;
} }
// Defer UI mutation to after the current frame renders.
GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
this._panel?.prependItem(id, mimeType, preview); this._panel?.prependItem(id, mimeType, preview);
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;

View file

@ -410,7 +410,8 @@ export class StrataPanel {
} }
return items.length; return items.length;
} catch (e) { } catch (e) {
console.error('[Strata] _loadHistory failed:', e); Gio.DBusError.strip_remote_error(e);
console.error('[Strata] GetHistory failed:', e.message);
return 0; return 0;
} }
} }
@ -581,7 +582,8 @@ export class StrataPanel {
const [mimeType, content] = await this._proxy.GetItemContentAsync(id); const [mimeType, content] = await this._proxy.GetItemContentAsync(id);
this._writeToClipboard(mimeType, content); this._writeToClipboard(mimeType, content);
} catch (e) { } catch (e) {
console.error('[Strata] Paste error:', e); Gio.DBusError.strip_remote_error(e);
console.error('[Strata] GetItemContent failed:', e.message);
} }
this.close(); this.close();
} }
@ -610,7 +612,8 @@ export class StrataPanel {
try { try {
await this._proxy.ClearHistoryAsync(); await this._proxy.ClearHistoryAsync();
} catch (e) { } catch (e) {
console.error('[Strata] ClearHistory error:', e); Gio.DBusError.strip_remote_error(e);
console.error('[Strata] ClearHistory failed:', e.message);
} }
} }
@ -671,7 +674,8 @@ export class StrataPanel {
try { try {
[json] = await this._proxy.SearchHistoryAsync(query, limit); [json] = await this._proxy.SearchHistoryAsync(query, limit);
} catch (e) { } catch (e) {
console.error('[Strata] SearchHistory D-Bus error:', e); Gio.DBusError.strip_remote_error(e);
console.error('[Strata] SearchHistory failed:', e.message);
return; return;
} }
if (epoch !== this._searchEpoch || !this._overlay) return; // stale or destroyed if (epoch !== this._searchEpoch || !this._overlay) return; // stale or destroyed