v0.8.0 — a community milestone 🎉
This is by far the largest release in the project's history — and it exists because of you. Every feature below started as a community issue, a prototype, a design discussion, or a bug report. Thank you to everyone who reported, proposed, prototyped, reviewed, and pushed for these — your input directly shaped this release. 🙏
Heads up — one breaking change:
Watchnow returns<-chan Datainstead of<-chan []byte. Migration is one line: readdata.Bytes(and you can now inspectdata.Format).
✨ Highlights
- Cgo-free on every desktop platform. macOS (purego/Obj-C), Linux/X11, and the BSDs now talk to the OS clipboard with no C toolchain at build time and no
libX11/libwaylandat runtime (Windows was already Cgo-free). Cross-compiling to desktop "just works." (#69, #25, #55) - Native Wayland support. A pure-Go data-control backend (
ext-data-control-v1/zwlr_data_control_manager_v1), event-drivenWatch, auto-selected over X11 when available, with XWayland fallback. (#6) - Custom, MIME-typed formats.
Register(mime) Format+ReadAs[T]give raw, passthrough read/write/watch for any MIME type — no conversion, no new mandatory dependency, no platform detail leaking into your code. (#17, subsumes #40) - Clipboard enumeration.
Formats() []Formatreports what's on the clipboard right now (auto-registering MIME types it discovers), andFormat.MIME()tells you what a token is. (#89) - Variadic, format-tagged
Watch.Watch(ctx, ...Format) <-chan Datawatches several formats at once and tags each change with its format (no args watches the built-ins). (#89) - Flexible image input.
Write(FmtImage, …)now accepts JPEG/GIF/WebP/… (when you blank-import the decoder) and normalizes to canonical PNG;Read(FmtImage)always returns PNG. (#155)
🐛 Fixes
- Windows: transparent images no longer paste too dark — images are stored/read with straight (non-premultiplied) alpha to match
CF_DIBV5. Verified end-to-end via a real Windows consumer in CI. (#105) - Windows: 24-bit (and other non-32-bit) DIB images now decode instead of returning nil. (#65)
- Windows:
OpenClipboardno longer busy-waits forever — bounded backoff + timeout when another app holds the clipboard. (#144) Watchno longer leaks — tickers are stopped and the send honors context cancellation. (#153)
📦 Dependencies
- Adds the first-party, pure-Go X11 codec
golang.design/x/x11v0.2.0 (extracted from this repo; reusable elsewhere). - iOS/Android continue to use
gomobile(Cgo); mobile keeps text-only support.
🙏 Thanks
This release is the work of many hands. With gratitude to:
- Wayland: @trading-peter (#6), @ajayd-san (#61)
- Dropping Cgo: @TotallyGamerJet (the purego prototype, #83), @gen2brain (#25), @sarumaj (#69), @arturbrzoz (#55), @microo8 (#20)
- Custom formats & raw access: @dmzlingyin, @HuakunShen, @MarvinJWendt (#17), @rams3sh (#40)
- Watch-all & enumeration: @xiebruce (#89)
- Images on Windows / image formats: @allanpk716 (#65), @matwachich (#48), @AlejandroSuero (#58), @jmmemo (#38), @c17abab (#45)
- Bug reports & feature requests that shaped the roadmap: @fanybook (#59), @dongziyudongziyu (#37), @Esword618 (#50), @jinmao88 (#31), @gucio321 (#67), @ValorZard (#64), @qjerome (#22)
…and everyone who joined the discussions, tested pre-release behavior, and filed clear, actionable issues. Thank you all. ❤️
Migration
// Before (v0.7.x):
for data := range clipboard.Watch(ctx, clipboard.FmtText) {
use(data) // data was []byte
}
// After (v0.8.0):
for data := range clipboard.Watch(ctx, clipboard.FmtText) {
use(data.Bytes) // data is clipboard.Data{Format, Bytes}
}Full changelog: v0.7.1...v0.8.0