Commit graph

65 commits

Author SHA1 Message Date
ab230856a4 chore: bump versions to 0.3.0
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-25 04:06:05 -05:00
5d23254c8e refactor: remove stale thumbnail_blob migration
The column is defined in the initial CREATE TABLE statement, so the
ALTER TABLE migration was redundant from day one -- it always failed
silently via .ok(). No existing user databases lack this column.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-25 04:03:53 -05:00
375f50e962 docs: update CHANGELOG, ARCHITECTURE and AGENTS for post-0.2.0 fixes
- CHANGELOG: add [Unreleased] section with all fixes and perf improvements
  since the 0.2.0 tag
- ARCHITECTURE: note that GetItemContent also returns ay (no base64)
- AGENTS: update D-Bus method summary -- GetItemContent returns (s, ay),
  SetFocusedApp removed

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-25 04:02:07 -05:00
f9826c63a8 perf: return raw bytes from GetItemContent instead of base64
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>
2026-05-25 04:00:06 -05:00
40a9a3bbd5 style: apply cargo fmt
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-25 03:56:29 -05:00
4a6a5fc4e3 fix: remove dead SetFocusedApp D-Bus call
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>
2026-05-25 03:55:46 -05:00
575e216658 perf: replace O(n) hover loop with Clutter hit-test in motion-event
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>
2026-05-25 03:51:50 -05:00
8d681a16fd fix: panic with clear message if XDG data dir is unavailable
The previous fallback to PathBuf::from(".") silently placed the
database in whatever the current working directory was, making it
impossible to find later. Since the daemon cannot function without a
persistent database, failing fast with an actionable message is the
correct behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-25 03:43:52 -05:00
eb64476a2a perf: eliminate unnecessary clones in write_to_clipboard
write_to_clipboard took ownership of WriteRequest but immediately
cloned both fields into locals, then cloned bytes again for the text
path -- three heap allocations on a potentially large byte buffer.

Destructure the owned request directly and move the fields. The text
path still needs one clone (bytes goes into two MimeSources), but the
extra upfront clones are gone.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-25 03:43:33 -05:00
64d5bbfdc3 fix: avoid double-destroy in clearItems()
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>
2026-05-25 03:43:09 -05:00
87e7e9f774 perf: don't load thumbnail_blob in get_raw_item
get_raw_item is used by GetItemContent (paste-back) and SetClipboard.
Neither caller needs the thumbnail -- they only need the original
payload. Excluding thumbnail_blob from the SELECT avoids loading up to
~40 KB of PNG data per paste operation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-25 03:42:56 -05:00
e2f7aa7a7c perf: run ORDER BY subquery only once in prune()
Previously prune() ran two identical NOT IN (SELECT ... ORDER BY
created_at DESC LIMIT n) subqueries: one to collect IDs for signals,
one to delete. SQLite executed the ORDER BY pass twice.

Now we collect the IDs first with a single subquery, then delete by
those exact IDs using params_from_iter. The ORDER BY scan runs once
regardless of how many items are pruned.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-25 03:42:29 -05:00
805b14a0bd perf: drop unused base64 return value from make_thumbnail
make_thumbnail was computing a base64 string of the thumbnail on every
image clipboard capture. The caller only ever used the raw bytes and
immediately discarded the String. Remove the base64 encode, simplify
the return type to Result<Vec<u8>>, and drop the now-unused
'use base64::Engine' import from main.rs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-25 03:41:30 -05:00
86351cb22c fix: use ESM import for MessageTray in _notifyDaemonMissing
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>
2026-05-25 03:40:54 -05:00
350d647953 Initial commit
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-25 03:02:34 -05:00