Skip to content

剪贴板与拖拽数据 ​

transfer 包描述了系统剪贴板与原生拖放共享的序列化 内容。一个 Data 值包含有序的项目。每个项目为同一内容提供可替代的格 式;不同的项目描述不同的值。自定义格式使用 MIME 名称和显式的编码。原生数 据从不包含 Go 指针或进程内的 Go 值。

go
const noteFormat transfer.Format = "application/vnd.example.note+json"
frozen := *note
data := transfer.New(transfer.NewItem(
    transfer.Bytes(transfer.Text, []byte(frozen.Title)),
    transfer.Bytes(transfer.HTML, []byte("<b>"+html.EscapeString(frozen.Title)+"</b>")),
    transfer.Lazy(noteFormat, func() ([]byte, error) {
        return json.Marshal(frozen)
    }),
))

err := mygo.Clipboard.Write(data, mygo.ClipboardOptions{
    OnRelease: func() { /* release resources captured by these providers */ },
})
row.DragData(data) // the same model, with an independent provider cache

Bytes 会复制其输入。Data.Items 和格式列表返回独立的切片,读取返回独立 的字节。空字节是合法的。Text、HTML、PNG、URIList 和 FileList 是 常见表示形式的名称。TextData、URLData 和 FileData 构造常见的提供。 文件是以转义 file URL 编码的绝对路径;Data.Files 只接受本地路径,忽略 远程主机和非 file URL。文件既不会被读取也不会被删除。每个路径用一个项目 (FileData 会自动这样做)。

剪贴板的探测与读取 ​

Clipboard.Formats 返回可移植的名称,而不请求具体的表示形式。 transfer.PreferredFormat 和 Offer.Preferred 按接收方的偏好顺序协商。 较早的 AvailableFormats 保留其平台惯例:macOS 上是原生 UTI,Linux 上是 GTK 目标,Windows 上是规范名称(现在也包括自定义格式和文件列表)。

只请求接收方能用的格式:

go
formats := mygo.Clipboard.Formats()
if format, ok := transfer.PreferredFormat(formats, noteFormat, transfer.HTML, transfer.Text); ok {
    bytes, err := mygo.Clipboard.ReadFormat(format)
    // 按明确商定的编码解码;处理 err。
}

// 一起读取被接受的替代格式;不请求其他提供者。
data, err := mygo.Clipboard.Read(noteFormat, transfer.HTML, transfer.Text)
if err == nil {
    if format, ok := data.Preferred(noteFormat, transfer.HTML, transfer.Text); ok {
        bytes, err := data.Read(format)
        // 使用接收方偏好的表示形式。
    }
}

不带参数的 Read() 复制所有对外声明的表示形式。空的剪贴板返回空数据。 显式请求但没有匹配的格式时返回 transfer.ErrFormat。ReadFormat 像 Data.Read 一样合并项目:文本以换行符连接,URI/文件列表以 CRLF 连接,其他 格式使用第一个匹配的项目。要读取单个项目,请使用 Data.Items()。

读取返回的是已实体化的数据,不含原生提供者。在所有者变化、窗口关闭或源 应用退出后,它仍可从任意 goroutine 使用,并可以在后续的拖放中再次提供。 原生操作在主线程上运行。观察到所有权正在变化的读取会返回 mygo.ErrClipboardChanged;Windows 在读取外部内容时持有剪贴板锁。从剪贴板 提供者内部访问剪贴板会返回 mygo.ErrClipboardReentrant,以防止递归读取和 替换。

现有的 ReadText、WriteText、ReadHTML、WriteHTML、ReadImage、 WriteImage 和 Clear 保持其签名不变。WriteHTML 在所有平台上同时提供 HTML 和文本回退,修正了 Linux 此前只提供文本的行为。WriteImage 在替换 现有数据之前校验 PNG;原生图像读取器仍接受 TIFF、GTK 图像目标和 Windows DIB。WriteFiles 和 ReadFiles 交换原生文件列表。空的 Write/WriteFiles 会清空剪贴板。失败的写入不会安装其释放钩子。

惰性提供者与所有权 ​

每次写入和每次拖放都会取一个新的 Data.Snapshot。惰性提供者针对该快照在 被请求时最多运行一次;成功、错误和已恢复的 panic(transfer.ErrProviderPanic) 都会被缓存。探测和偏好协商不请求任何字节。包括剪贴板管理器在内的原生接收 方可能在发布后立即请求字节。Read 只请求其选定的格式。提供者的错误会使 该次读取失败;其他表示形式仍然可用。

提供者在主线程上执行,并且必须尽快返回。事先在一个 goroutine 上准备开销 大的内容,并冻结各替代表示形式共享的值。切勿等待另一个主线程动作、递归 读取同一个提供者,或在剪贴板提供者内部访问剪贴板。独立使用的 Data.Read 在调用它的 goroutine 上执行其提供者。

剪贴板所有权属于应用,与任何源窗口无关。关闭一个窗口后,其复制的内容 和提供者依然可用。提供者的资源须保留到 ClipboardOptions.OnRelease,它在 原生回调之后、以及任何外层剪贴板操作展开之后(包括运行嵌套事件循环的存储 操作),在主线程上运行一次。替换、Clear、成功的 Flush 和应用退出都会 释放提供者。macOS 还可能在兑现所有 promise 之后结束它们。该钩子可以在应用 运行期间写入新的剪贴板内容;应用退出后的剪贴板调用会返回循环已停止的错误, 或便捷方法的空结果。它不得依赖某个窗口仍然存在。拖放源则使用其会话的 Done 回调。

Clipboard.Flush 在把内容交给原生存储之前,先解析所有持有的表示形式。 提供者失败不会改变所有权,失败会被返回;如果持久化至关重要,请在退出前 处理它们。应用退出时会尽力自动 flush,然后释放剩余的提供者资源。在另一个 应用拥有剪贴板时执行 flush 不会动它的内容。在 Linux 上,退出后的持久化需要 剪贴板管理器。若没有,Flush 返回 mygo.ErrClipboardPersistence,释放惰性 资源,并在应用运行期间继续提供已就绪的字节。

原生互操作 ​

平台剪贴板实现项目边界与格式
macOSNSPasteboard 项目与应用拥有的数据提供者;flush 时急切求值的项目项目边界在原生读取和持久化后保持不变。文本/HTML/PNG/file URL 使用系统 UTI;自定义 MIME 名称与拖放共用 UTType 映射。完整的 URI/文件列表拥有序列化类型,并带有单 URL 回退。读取时转换 UTF-16 文本和 TIFF 图像。
LinuxGtkClipboard 选择目标、共享的拖放格式映射、get/clear 回调、所有者变化跟踪;GTK 剪贴板管理器存储在拥有它的 MyGo 进程内,所有项目都保持不变。原生选择会合并文本和 URI/文件列表;自定义格式使用第一个匹配的项目。HTML 以 text/html 提供。持久化取决于桌面的剪贴板管理器。
Windows与拖放相同的延迟渲染 IDataObject,配合 OleSetClipboard/OleFlushClipboard;带锁的 Win32 读取在拥有它的进程内,flush 之前所有项目都保持不变。原生读取会合并文本/URI/文件列表,并使用第一个自定义项目。Unicode 文本、CF_HTML、PNG/DIB、CF_HDROP、URL 和已注册的 MIME 格式与系统应用互操作。可选的私有长度提示在 HGLOBAL 持久化后保留 MyGo 的空/二进制载荷;实际的原生格式仍是不加包装的字节。

外部剪贴板的每种表示形式限制为 64 MiB。没有字节长度约定的外部 Windows HGLOBAL 自定义数据可能包含分配器填充;与此类来源互操作时,请使用自带长度 的编码。虚拟文件和文件内容 promise 不在当前模型之内。Drag(value) 使用的 Go 值是进程内的;其临时的拖放注册令牌会被剪贴板写入拒绝,并在剪贴板探测中 省略。

剪贴板示例 演示了把一条便签以文本、HTML 和惰性 JSON 进行复制与拖放,显示提供者的 调用/释放次数,粘贴文件列表,并 flush 剪贴板数据。