Code to get the available mime types in the clipboard

This commit is contained in:
Kovid Goyal 2022-09-08 11:05:00 +05:30
parent d17a6cd3a3
commit 96160b52b6
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 73 additions and 11 deletions

67
glfw/x11_window.c vendored
View File

@ -929,6 +929,13 @@ getSelectionString(Atom selection, const char *mime_type, Atom *targets, size_t
if (XGetSelectionOwner(_glfw.x11.display, selection) ==
_glfw.x11.helperWindowHandle)
{
if (mime_type == NULL) {
AtomArray *aa = selection == _glfw.x11.PRIMARY ? &_glfw.x11.primary_atoms : &_glfw.x11.clipboard_atoms;
for (size_t i = 0; i < aa->sz; i++) {
if (!write_data(object, (char*)&aa->array[i].atom, sizeof(Atom))) break;
}
return;
}
// Instead of doing a large number of X round-trips just to put this
// string into a window property and then read it back, just return it
_GLFWClipboardData *cd = selection == _glfw.x11.PRIMARY ? &_glfw.primary : &_glfw.clipboard;
@ -1038,6 +1045,10 @@ getSelectionString(Atom selection, const char *mime_type, Atom *targets, size_t
} else write_data(object, data, itemCount);
found = true;
}
else if (actualType == XA_ATOM && targets[i] == _glfw.x11.TARGETS) {
found = true;
write_data(object, data, itemCount);
}
XFREE(data);
@ -2889,20 +2900,60 @@ void _glfwPlatformSetClipboard(GLFWClipboardType t) {
aa->sz = 0;
for (size_t i = 0; i < cd->num_mime_types; i++) {
MimeAtom *a = aa->array + aa->sz++;
if (strcmp(cd->mime_types[i], "text/plain") == 0) {
a->atom = XA_ATOM; a->mime = "text/plain";
a = aa->array + aa->sz++;
a->atom = _glfw.x11.UTF8_STRING; a->mime = "text/plain";
} else {
*a = atom_for_mime(cd->mime_types[i]);
}
*a = atom_for_mime(cd->mime_types[i]);
}
}
typedef struct chunked_writer {
char *buf; size_t sz, cap;
} chunked_writer;
static bool
write_chunk(void *object, const char *data, size_t sz) {
chunked_writer *cw = object;
if (cw->cap < cw->sz + sz) {
cw->cap = MAX(cw->cap * 2, cw->sz + 8*sz);
cw->buf = realloc(cw->buf, cw->cap);
}
memcpy(cw->buf + cw->sz, data, sz);
cw->sz += sz;
return true;
}
static void
get_available_mime_types(Atom which_clipboard, GLFWclipboardwritedatafun write_data, void *object) {
chunked_writer cw = {0};
getSelectionString(which_clipboard, NULL, &_glfw.x11.TARGETS, 1, write_chunk, &cw);
size_t count = 0;
bool ok = true;
if (cw.buf) {
Atom *atoms = (Atom*)cw.buf;
count = cw.sz / sizeof(Atom);
char **names = calloc(count, sizeof(char*));
get_atom_names(atoms, count, names);
for (size_t i = 0; i < count; i++) {
if (atoms[i] != _glfw.x11.UTF8_STRING && atoms[i] != XA_STRING) {
if (ok) ok = write_data(object, names[i], strlen(names[i]));
}
XFree(names[i]);
}
free(cw.buf);
free(names);
}
if (!count && ok) {
// if no atoms then we assume text/plain is available, for compatibility with broken clients
ok = write_data(object, "text/plain", strlen("text/plain"));
}
}
void
_glfwPlatformGetClipboard(GLFWClipboardType clipboard_type, const char* mime_type, GLFWclipboardwritedatafun write_data, void *object) {
// TODO: Handle NULL mime_type
Atom atoms[2], which = clipboard_type == GLFW_PRIMARY_SELECTION ? _glfw.x11.PRIMARY : _glfw.x11.CLIPBOARD;
if (mime_type == NULL) {
get_available_mime_types(which, write_data, object);
return;
}
size_t count = 1;
if (strcmp(mime_type, "text/plain") == 0) {
atoms[0] = _glfw.x11.UTF8_STRING;

View File

@ -2,10 +2,13 @@
# License: GPLv3 Copyright: 2022, Kovid Goyal <kovid at kovidgoyal.net>
import io
from typing import IO, Callable, Dict, Union, List
from typing import IO, Callable, Dict, List, Tuple, Union
from .conf.utils import uniq
from .constants import supports_primary_selection
from .fast_data_types import GLFW_CLIPBOARD, get_boss, set_clipboard_data_types, get_clipboard_mime
from .fast_data_types import (
GLFW_CLIPBOARD, get_boss, get_clipboard_mime, set_clipboard_data_types
)
DataType = Union[bytes, 'IO[bytes]']
@ -31,7 +34,15 @@ class Clipboard:
return b''.join(parts).decode('utf-8', 'replace')
def get_mime(self, mime: str, output: Callable[[bytes], None]) -> None:
get_clipboard_mime(self.clipboard_type, mime, output)
if self.enabled:
get_clipboard_mime(self.clipboard_type, mime, output)
def get_available_mime_types_for_paste(self) -> Tuple[str, ...]:
if self.enabled:
parts: List[bytes] = []
get_clipboard_mime(self.clipboard_type, None, parts.append)
return tuple(x.decode('utf-8', 'replace') for x in uniq(parts))
return ()
def __call__(self, mime: str) -> Callable[[], bytes]:
data = self.data.get(mime, b'')