Cut the 0.4.0 release: daemon Cargo.toml/Cargo.lock to 0.4.0, extension
metadata.json version to 4, and promote the CHANGELOG [Unreleased] entry
to [0.4.0] - 2026-05-26.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The D-Bus interface previously returned content as a base64-encoded
string (type 's'), requiring the daemon to encode and GJS to decode
on every paste. D-Bus natively supports byte arrays (type 'ay'),
eliminating both encode and decode steps entirely.
Changes:
- dbus_service.rs: return (String, Vec<u8>); drop base64 calls
- dbus.js: content_b64 arg changed from type 's' to type 'ay'
- panel.js: remove GLib.base64_decode(); pass ay bytes directly
- Cargo.toml/Cargo.lock: remove base64 dependency (no longer used)
For a 1 MB text paste this avoids allocating a 1.33 MB intermediate
string and decoding it on the compositor main thread.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The daemon stored the focused app ID but never read it. App exclusion
runs entirely in the extension before SubmitItem is called, so the
D-Bus round-trip on every window focus change was pure overhead.
Removed from: extension.js call site, dbus.js XML interface,
dbus_service.rs method + struct field, main.rs Arc allocation.
Focus tracking in _connectFocusTracking is kept since _currentFocusedApp
is still used for the JS-side exclusion check.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The previous implementation iterated all visible widgets on every
mouse-move event, calling get_transformed_position/size on each to
find which one was under the cursor. With a full page of items this
fires dozens of times per second on the compositor thread.
Use event.get_source() to let Clutter do its own hit-test (already
computed), then walk up the parent chain to find the owning
ClipboardItem. The walk is O(tree-depth), typically 3-4 steps,
regardless of history size.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Each ClipboardItem widget is a direct child of _itemList.
destroy_all_children() already destroys all of them. Calling
widget.destroy() on each one beforehand triggered destruction twice on
the same actor, causing spurious warnings. Drop the forEach loop and
rely solely on destroy_all_children().
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The extension uses ESM modules (GNOME 45+). The old imports.* global
does not exist in that context, causing a silent ReferenceError when
the strata-daemon binary is not found -- the user never saw the
notification. Replace with a proper import statement.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>