mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-22 15:11:31 +00:00
[client] clipboard: preserve formats after file import failure
Retain non-file clipboard representations while asynchronous file MIME imports are validated. If an offered URI list is invalid or cannot be read, publish the retained image and text formats instead of clearing the clipboard.
This commit is contained in:
@@ -210,6 +210,17 @@ static bool hasImageMimetype(char ** mimetypes)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t getRepresentationTypes(char * const mimetypes[],
|
||||||
|
LG_ClipboardData types[])
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
for (enum LG_ClipboardData type = 0;
|
||||||
|
type < LG_CLIPBOARD_DATA_NONE; ++type)
|
||||||
|
if (type != LG_CLIPBOARD_DATA_FILES && mimetypes[type])
|
||||||
|
types[count++] = type;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
enum ClipboardInvalidateMode
|
enum ClipboardInvalidateMode
|
||||||
{
|
{
|
||||||
CLIPBOARD_INVALIDATE_CONDITIONAL,
|
CLIPBOARD_INVALIDATE_CONDITIONAL,
|
||||||
@@ -307,8 +318,10 @@ static void fileImportCleanup(void * opaque)
|
|||||||
static void fileImportCallback(uint32_t events, void * opaque)
|
static void fileImportCallback(uint32_t events, void * opaque)
|
||||||
{
|
{
|
||||||
struct ClipboardFileImport * import = opaque;
|
struct ClipboardFileImport * import = opaque;
|
||||||
bool complete = false;
|
LG_ClipboardData types[LG_CLIPBOARD_DATA_NONE];
|
||||||
bool failed = (events & EPOLLERR) != 0;
|
size_t typeCount = 0;
|
||||||
|
bool complete = false;
|
||||||
|
bool failed = (events & EPOLLERR) != 0;
|
||||||
while (!failed)
|
while (!failed)
|
||||||
{
|
{
|
||||||
if (import->size > SIZE_MAX - 4096U)
|
if (import->size > SIZE_MAX - 4096U)
|
||||||
@@ -337,6 +350,8 @@ static void fileImportCallback(uint32_t events, void * opaque)
|
|||||||
LG_LOCK(wlCb.lock);
|
LG_LOCK(wlCb.lock);
|
||||||
const bool current = wlCb.fileImport == import &&
|
const bool current = wlCb.fileImport == import &&
|
||||||
wlCb.offer == import->offer;
|
wlCb.offer == import->offer;
|
||||||
|
if (current)
|
||||||
|
typeCount = getRepresentationTypes(wlCb.mimetypes, types);
|
||||||
if (wlCb.fileImport == import)
|
if (wlCb.fileImport == import)
|
||||||
wlCb.fileImport = NULL;
|
wlCb.fileImport = NULL;
|
||||||
LG_UNLOCK(wlCb.lock);
|
LG_UNLOCK(wlCb.lock);
|
||||||
@@ -345,7 +360,7 @@ static void fileImportCallback(uint32_t events, void * opaque)
|
|||||||
import->data, import->size)))
|
import->data, import->size)))
|
||||||
{
|
{
|
||||||
clipboardFiles_clearLocal();
|
clipboardFiles_clearLocal();
|
||||||
clipboard_release();
|
clipboard_notifyTypes(types, typeCount);
|
||||||
}
|
}
|
||||||
if (current)
|
if (current)
|
||||||
waylandPollUnregister(import->fd);
|
waylandPollUnregister(import->fd);
|
||||||
@@ -516,11 +531,9 @@ static void dataDeviceHandleSelection(void * opaque,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t idx = 0;
|
|
||||||
enum LG_ClipboardData types[LG_CLIPBOARD_DATA_NONE];
|
enum LG_ClipboardData types[LG_CLIPBOARD_DATA_NONE];
|
||||||
for (enum LG_ClipboardData i = 0; i < LG_CLIPBOARD_DATA_NONE; ++i)
|
const size_t typeCount =
|
||||||
if (extra->mimetypes[i])
|
getRepresentationTypes(extra->mimetypes, types);
|
||||||
types[idx++] = i;
|
|
||||||
|
|
||||||
char * oldMimetypes[LG_CLIPBOARD_DATA_NONE];
|
char * oldMimetypes[LG_CLIPBOARD_DATA_NONE];
|
||||||
LG_LOCK(wlCb.lock);
|
LG_LOCK(wlCb.lock);
|
||||||
@@ -555,11 +568,11 @@ static void dataDeviceHandleSelection(void * opaque,
|
|||||||
if (!fileImportStart(offer, wlCb.mimetypes[LG_CLIPBOARD_DATA_FILES]))
|
if (!fileImportStart(offer, wlCb.mimetypes[LG_CLIPBOARD_DATA_FILES]))
|
||||||
{
|
{
|
||||||
clipboardFiles_clearLocal();
|
clipboardFiles_clearLocal();
|
||||||
clipboard_release();
|
clipboard_notifyTypes(types, typeCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
clipboard_notifyTypes(types, idx);
|
clipboard_notifyTypes(types, typeCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dataDeviceHandleEnter(void * data, struct wl_data_device * device,
|
static void dataDeviceHandleEnter(void * data, struct wl_data_device * device,
|
||||||
|
|||||||
@@ -76,14 +76,16 @@ struct X11ClipboardWrite
|
|||||||
|
|
||||||
struct X11ClipboardFileImport
|
struct X11ClipboardFileImport
|
||||||
{
|
{
|
||||||
Window window;
|
Window window;
|
||||||
Atom target;
|
Atom target;
|
||||||
const char * mime;
|
const char * mime;
|
||||||
long propertyOffset;
|
long propertyOffset;
|
||||||
uint8_t * data;
|
uint8_t * data;
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
bool incremental;
|
bool incremental;
|
||||||
|
LG_ClipboardData types[LG_CLIPBOARD_DATA_NONE];
|
||||||
|
size_t typeCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct X11ClipboardState
|
struct X11ClipboardState
|
||||||
@@ -858,7 +860,8 @@ static bool fileImportGrowNL(size_t wanted)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool startFileImport(Atom target)
|
static bool startFileImport(Atom target,
|
||||||
|
const LG_ClipboardData types[], size_t typeCount)
|
||||||
{
|
{
|
||||||
const char * mime = fileMimeForAtom(target);
|
const char * mime = fileMimeForAtom(target);
|
||||||
if (!mime)
|
if (!mime)
|
||||||
@@ -886,6 +889,8 @@ static bool startFileImport(Atom target)
|
|||||||
.target = target,
|
.target = target,
|
||||||
.mime = mime,
|
.mime = mime,
|
||||||
};
|
};
|
||||||
|
memcpy(x11cb.fileImport.types, types, typeCount * sizeof(*types));
|
||||||
|
x11cb.fileImport.typeCount = typeCount;
|
||||||
XSelectInput(x11.display, window, PropertyChangeMask);
|
XSelectInput(x11.display, window, PropertyChangeMask);
|
||||||
XConvertSelection(x11.display, x11cb.aCurSelection, target,
|
XConvertSelection(x11.display, x11cb.aCurSelection, target,
|
||||||
x11atoms.SEL_DATA, window, CurrentTime);
|
x11atoms.SEL_DATA, window, CurrentTime);
|
||||||
@@ -900,11 +905,18 @@ static void finishFileImport(struct X11ClipboardFileImport import,
|
|||||||
if (!clipboardFiles_setLocal(import.mime, data, size))
|
if (!clipboardFiles_setLocal(import.mime, data, size))
|
||||||
{
|
{
|
||||||
clipboardFiles_clearLocal();
|
clipboardFiles_clearLocal();
|
||||||
clipboard_release();
|
clipboard_notifyTypes(import.types, import.typeCount);
|
||||||
}
|
}
|
||||||
free(import.data);
|
free(import.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void failFileImport(struct X11ClipboardFileImport import)
|
||||||
|
{
|
||||||
|
free(import.data);
|
||||||
|
clipboardFiles_clearLocal();
|
||||||
|
clipboard_notifyTypes(import.types, import.typeCount);
|
||||||
|
}
|
||||||
|
|
||||||
static bool x11CBFileImportSelectionNotify(const XSelectionEvent e)
|
static bool x11CBFileImportSelectionNotify(const XSelectionEvent e)
|
||||||
{
|
{
|
||||||
Atom type;
|
Atom type;
|
||||||
@@ -930,8 +942,7 @@ static bool x11CBFileImportSelectionNotify(const XSelectionEvent e)
|
|||||||
LG_UNLOCK(x11cb.lock);
|
LG_UNLOCK(x11cb.lock);
|
||||||
if (data)
|
if (data)
|
||||||
XFree(data);
|
XFree(data);
|
||||||
free(failed.data);
|
failFileImport(failed);
|
||||||
clipboard_release();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -943,8 +954,7 @@ static bool x11CBFileImportSelectionNotify(const XSelectionEvent e)
|
|||||||
LG_UNLOCK(x11cb.lock);
|
LG_UNLOCK(x11cb.lock);
|
||||||
if (data)
|
if (data)
|
||||||
XFree(data);
|
XFree(data);
|
||||||
free(failed.data);
|
failFileImport(failed);
|
||||||
clipboard_release();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
x11cb.fileImport.incremental = true;
|
x11cb.fileImport.incremental = true;
|
||||||
@@ -960,10 +970,7 @@ static bool x11CBFileImportSelectionNotify(const XSelectionEvent e)
|
|||||||
if (valid)
|
if (valid)
|
||||||
finishFileImport(import, data, itemCount);
|
finishFileImport(import, data, itemCount);
|
||||||
else
|
else
|
||||||
{
|
failFileImport(import);
|
||||||
free(import.data);
|
|
||||||
clipboard_release();
|
|
||||||
}
|
|
||||||
if (data)
|
if (data)
|
||||||
XFree(data);
|
XFree(data);
|
||||||
return true;
|
return true;
|
||||||
@@ -1000,8 +1007,7 @@ readProperty:
|
|||||||
LG_UNLOCK(x11cb.lock);
|
LG_UNLOCK(x11cb.lock);
|
||||||
if (data)
|
if (data)
|
||||||
XFree(data);
|
XFree(data);
|
||||||
free(failed.data);
|
failFileImport(failed);
|
||||||
clipboard_release();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1026,8 +1032,7 @@ readProperty:
|
|||||||
{
|
{
|
||||||
const struct X11ClipboardFileImport failed = takeFileImportNL();
|
const struct X11ClipboardFileImport failed = takeFileImportNL();
|
||||||
LG_UNLOCK(x11cb.lock);
|
LG_UNLOCK(x11cb.lock);
|
||||||
free(failed.data);
|
failFileImport(failed);
|
||||||
clipboard_release();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
x11cb.fileImport.propertyOffset += (long)units;
|
x11cb.fileImport.propertyOffset += (long)units;
|
||||||
@@ -1407,11 +1412,23 @@ static void x11CBSelectionNotify(const XSelectionEvent e)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t typeCount = 0;
|
size_t typeCount = 0;
|
||||||
LG_ClipboardData types[LG_CLIPBOARD_DATA_NONE];
|
LG_ClipboardData types[LG_CLIPBOARD_DATA_NONE];
|
||||||
|
|
||||||
// see if we support any of the targets listed
|
// see if we support any of the targets listed
|
||||||
const Atom * targets = (const Atom *)data;
|
const Atom * targets = (const Atom *)data;
|
||||||
|
for(int n = 0; n < LG_CLIPBOARD_DATA_NONE; ++n)
|
||||||
|
{
|
||||||
|
if (n == LG_CLIPBOARD_DATA_FILES)
|
||||||
|
continue;
|
||||||
|
for(unsigned long i = 0; i < itemCount; ++i)
|
||||||
|
if (x11cb.aTypes[n] == targets[i])
|
||||||
|
{
|
||||||
|
types[typeCount++] = n;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Atom fileTarget = None;
|
Atom fileTarget = None;
|
||||||
for (unsigned long i = 0; i < itemCount; ++i)
|
for (unsigned long i = 0; i < itemCount; ++i)
|
||||||
{
|
{
|
||||||
@@ -1438,19 +1455,11 @@ static void x11CBSelectionNotify(const XSelectionEvent e)
|
|||||||
if (fileTarget != None)
|
if (fileTarget != None)
|
||||||
{
|
{
|
||||||
clipboardFiles_clearLocal();
|
clipboardFiles_clearLocal();
|
||||||
if (!startFileImport(fileTarget))
|
if (!startFileImport(fileTarget, types, typeCount))
|
||||||
clipboard_release();
|
clipboard_notifyTypes(types, typeCount);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int n = 0; n < LG_CLIPBOARD_DATA_NONE; ++n)
|
|
||||||
for(unsigned long i = 0; i < itemCount; ++i)
|
|
||||||
if (x11cb.aTypes[n] == targets[i])
|
|
||||||
{
|
|
||||||
types[typeCount++] = n;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
clipboard_notifyTypes(types, typeCount);
|
clipboard_notifyTypes(types, typeCount);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user