apprt/gtk: (clipboard) add X11 atoms, extra MIME types for text content

This adds the UTF8_STRING atom and explicit UTF-8 character set MIME
type (text/plain;charset=utf-8) to text content when being sent to the
clipboard under the new multipart support.

This fixes clipboard support under X11 particularly, which generally
looks for the UTF8_STRING atom when looking for text content. This can be
verified with xclip -out -verbose, or trying to do things like paste in
Firefox.

I've noted that there's a number of other older atoms that exist, but
I've refrained from adding them for now. Kitty only seems to set
UTF8_STRING and I've had a hard time finding consensus on what exactly
is the correct set otherwise.
pull/9456/head
Chris Marchesi 2025-11-02 10:44:40 -08:00
parent 765ee68429
commit e7c68142e3
No known key found for this signature in database
GPG Key ID: E9C6A4EBE1EB7618
1 changed files with 36 additions and 2 deletions

View File

@ -3364,8 +3364,42 @@ const Clipboard = struct {
for (contents, 0..) |content, i| {
const bytes = glib.Bytes.new(content.data.ptr, content.data.len);
defer bytes.unref();
const provider = gdk.ContentProvider.newForBytes(content.mime, bytes);
providers[i] = provider;
if (std.mem.eql(u8, content.mime, "text/plain")) {
// Add some extra MIME types (and X11 atoms) for
// text/plain. This can be expanded on if certain
// applications are expecting text in a particular type
// or atom that is not currently here; UTF8_STRING
// seems to be the most common one for modern X11, but
// there are some older ones, e.g., XA_STRING or just
// plain STRING. Kitty seems to get by with just
// UTF8_STRING, but I'm also adding the explicit utf-8
// MIME parameter for correctness; technically, for
// MIME, when the charset is missing, the default
// charset is ASCII.
const text_provider_atoms = [_][:0]const u8{
"text/plain",
"text/plain;charset=utf-8",
"UTF8_STRING",
};
// Following on the same logic as our outer union,
// looks like we only need this memory during union
// construction, so it's okay if this is just a
// static-length array and goes out of scope when we're
// done. Similarly, we don't unref these providers.
var text_providers: [text_provider_atoms.len]*gdk.ContentProvider = undefined;
for (text_provider_atoms, 0..) |atom, j| {
const provider = gdk.ContentProvider.newForBytes(atom, bytes);
text_providers[j] = provider;
}
const text_union = gdk.ContentProvider.newUnion(
&text_providers,
text_providers.len,
);
providers[i] = text_union;
} else {
const provider = gdk.ContentProvider.newForBytes(content.mime, bytes);
providers[i] = provider;
}
}
const all = gdk.ContentProvider.newUnion(providers.ptr, providers.len);