[client] clipboard: advertise standard text formats

This commit is contained in:
Geoffrey McRae
2026-08-25 22:22:21 +10:00
parent 057073924a
commit b888be0ec3
2 changed files with 49 additions and 16 deletions

View File

@@ -41,8 +41,13 @@ struct DataOffer {
static const char * textMimetypes[] = static const char * textMimetypes[] =
{ {
"text/plain",
"text/plain;charset=utf-8", "text/plain;charset=utf-8",
"text/plain",
NULL,
};
static const char * textMimetypeAliases[] =
{
"TEXT", "TEXT",
"STRING", "STRING",
"UTF8_STRING", "UTF8_STRING",
@@ -128,9 +133,15 @@ static bool mimetypeEndswith(const char * mimetype, const char * what)
return !strcmp(mimetype + mimetypeLen - whatLen, what); return !strcmp(mimetype + mimetypeLen - whatLen, what);
} }
static bool isPlainTextMimetype(const char * mimetype)
{
return containsMimetype(textMimetypes, mimetype) ||
containsMimetype(textMimetypeAliases, mimetype);
}
static bool isTextMimetype(const char * mimetype) static bool isTextMimetype(const char * mimetype)
{ {
if (containsMimetype(textMimetypes, mimetype)) if (isPlainTextMimetype(mimetype))
return true; return true;
if (!strcmp(mimetype, "text/ico")) if (!strcmp(mimetype, "text/ico"))
@@ -437,7 +448,7 @@ static void dataOfferHandleOffer(void * opaque, struct wl_data_offer * offer,
// text/html represents rich text format, which is almost never desirable when // text/html represents rich text format, which is almost never desirable when
// and should not be used when a plain text or image format is available. // and should not be used when a plain text or image format is available.
if ((isImageCbtype(type) || containsMimetype(textMimetypes, mimetype)) && if ((isImageCbtype(type) || isPlainTextMimetype(mimetype)) &&
data->mimetypes[LG_CLIPBOARD_DATA_TEXT] && data->mimetypes[LG_CLIPBOARD_DATA_TEXT] &&
strstr(data->mimetypes[LG_CLIPBOARD_DATA_TEXT], "html")) strstr(data->mimetypes[LG_CLIPBOARD_DATA_TEXT], "html"))
{ {

View File

@@ -93,6 +93,8 @@ struct X11ClipboardState
LG_Lock lock; LG_Lock lock;
Atom aCurSelection; Atom aCurSelection;
Atom aTypes[LG_CLIPBOARD_DATA_NONE]; Atom aTypes[LG_CLIPBOARD_DATA_NONE];
Atom aTextPlain;
Atom aTextPlainUtf8;
Atom aFileGnome; Atom aFileGnome;
Atom aFileMate; Atom aFileMate;
Atom aFileKde; Atom aFileKde;
@@ -116,7 +118,9 @@ static const char * atomTypes[] =
"text/uri-list", "text/uri-list",
}; };
static const char fileGnomeMime[] = "x-special/gnome-copied-files"; static const char textPlainMime [] = "text/plain";
static const char textPlainUtf8Mime[] = "text/plain;charset=utf-8";
static const char fileGnomeMime [] = "x-special/gnome-copied-files";
static const char fileMateMime [] = "x-special/mate-copied-files"; static const char fileMateMime [] = "x-special/mate-copied-files";
static const char fileKdeMime [] = "application/x-kde-cutselection"; static const char fileKdeMime [] = "application/x-kde-cutselection";
static const char fileUriMime [] = "text/uri-list"; static const char fileUriMime [] = "text/uri-list";
@@ -154,6 +158,15 @@ static const char * fileMimeForAtom(Atom atom)
return NULL; return NULL;
} }
static bool typeMatchesAtom(LG_ClipboardData type, Atom atom)
{
if (type != LG_CLIPBOARD_DATA_TEXT)
return atom == x11cb.aTypes[type];
return atom == x11cb.aTypes[type] ||
atom == x11cb.aTextPlain || atom == x11cb.aTextPlainUtf8;
}
bool x11CBEventThread(const XEvent * xe) bool x11CBEventThread(const XEvent * xe)
{ {
switch(xe->type) switch(xe->type)
@@ -290,15 +303,19 @@ bool x11CBInit(void)
} }
} }
x11cb.aFileGnome = XInternAtom(x11.display, fileGnomeMime, False); x11cb.aTextPlain = XInternAtom(x11.display, textPlainMime , False);
x11cb.aTextPlainUtf8 = XInternAtom(x11.display, textPlainUtf8Mime, False);
x11cb.aFileGnome = XInternAtom(x11.display, fileGnomeMime , False);
x11cb.aFileMate = XInternAtom(x11.display, fileMateMime , False); x11cb.aFileMate = XInternAtom(x11.display, fileMateMime , False);
x11cb.aFileKde = XInternAtom(x11.display, fileKdeMime , False); x11cb.aFileKde = XInternAtom(x11.display, fileKdeMime , False);
if ( if (
x11cb.aTextPlain == BadAlloc || x11cb.aTextPlain == BadValue ||
x11cb.aTextPlainUtf8 == BadAlloc || x11cb.aTextPlainUtf8 == BadValue ||
x11cb.aFileGnome == BadAlloc || x11cb.aFileGnome == BadValue || x11cb.aFileGnome == BadAlloc || x11cb.aFileGnome == BadValue ||
x11cb.aFileMate == BadAlloc || x11cb.aFileMate == BadValue || x11cb.aFileMate == BadAlloc || x11cb.aFileMate == BadValue ||
x11cb.aFileKde == BadAlloc || x11cb.aFileKde == BadValue) x11cb.aFileKde == BadAlloc || x11cb.aFileKde == BadValue)
{ {
DEBUG_ERROR("failed to get clipboard file atoms"); DEBUG_ERROR("failed to get clipboard atoms");
return false; return false;
} }
@@ -493,7 +510,12 @@ static void x11CBSelectionRequest(const XSelectionRequestEvent e)
targets[0] = x11atoms.TARGETS; targets[0] = x11atoms.TARGETS;
targets[1] = x11cb.aTypes[requestType]; targets[1] = x11cb.aTypes[requestType];
int count = 2; int count = 2;
if (requestType == LG_CLIPBOARD_DATA_FILES) if (requestType == LG_CLIPBOARD_DATA_TEXT)
{
targets[count++] = x11cb.aTextPlain;
targets[count++] = x11cb.aTextPlainUtf8;
}
else if (requestType == LG_CLIPBOARD_DATA_FILES)
{ {
targets[count++] = x11cb.aFileGnome; targets[count++] = x11cb.aFileGnome;
targets[count++] = x11cb.aFileMate; targets[count++] = x11cb.aFileMate;
@@ -602,7 +624,7 @@ static void x11CBSelectionRequest(const XSelectionRequestEvent e)
// look to see if we can satisfy the data type // look to see if we can satisfy the data type
for(int i = 0; i < LG_CLIPBOARD_DATA_NONE; ++i) for(int i = 0; i < LG_CLIPBOARD_DATA_NONE; ++i)
if (x11cb.aTypes[i] == e.target && requestType == i) if (typeMatchesAtom(i, e.target) && requestType == i)
{ {
struct X11ClipboardWrite * write = calloc(1, sizeof(*write)); struct X11ClipboardWrite * write = calloc(1, sizeof(*write));
if (!write) if (!write)