wayland: Avoid klipper loop with existing but empty clipboards

In default settings if the clipboard or selection is empty klipper will try to
replace it with cached data.

To avoid an occurring race condition if a client deletes and then recreates a
selection kwin will deny klipper if another mimedata is present at the time
it tried to replace an empty clipboard.

Klipper also considers the presence of a valid mime data without any offers
to be an empty clipboard, whereas kwin did not.

If a super weird client set the clipboard to a valid entry with no offers,
klipper would get into an infinite loop of trying to set it's own selection
for it to be continually denied with no other valid offer from klipper's perspective
ever received.

BUG: 469644
This commit is contained in:
David Edmundson 2024-07-22 16:13:34 +01:00 committed by Vlad Zahorodnii
parent 32b117dbd8
commit 6943fab2c1

View file

@ -202,7 +202,8 @@ void SeatInterfacePrivate::registerDataControlDevice(DataControlDeviceV1Interfac
// If the mimetype x-kde-onlyReplaceEmpty is set, and we've had another update in the meantime, do nothing
// but resend selection to mimic normal event flow upon cancel and not confuse the client
// See https://github.com/swaywm/wlr-protocols/issues/92
if (dataDevice->selection() && dataDevice->selection()->mimeTypes().contains(QLatin1String("application/x-kde-onlyReplaceEmpty")) && currentSelection) {
const bool isKlipperEmptyReplacement = dataDevice->selection() && dataDevice->selection()->mimeTypes().contains(QLatin1String("application/x-kde-onlyReplaceEmpty"));
if (isKlipperEmptyReplacement && currentSelection && !currentSelection->mimeTypes().isEmpty()) {
dataDevice->selection()->cancel();
dataDevice->sendSelection(currentSelection);
return;
@ -215,8 +216,8 @@ void SeatInterfacePrivate::registerDataControlDevice(DataControlDeviceV1Interfac
// If the mimetype x-kde-onlyReplaceEmpty is set, and we've had another update in the meantime, do nothing
// but resend selection to mimic normal event flow upon cancel and not confuse the client
// See https://github.com/swaywm/wlr-protocols/issues/92
if (dataDevice->primarySelection() && dataDevice->primarySelection()->mimeTypes().contains(QLatin1String("application/x-kde-onlyReplaceEmpty"))
&& currentPrimarySelection) {
const bool isKlipperEmptyReplacement = dataDevice->primarySelection() && dataDevice->primarySelection()->mimeTypes().contains(QLatin1String("application/x-kde-onlyReplaceEmpty"));
if (isKlipperEmptyReplacement && currentPrimarySelection && !currentPrimarySelection->mimeTypes().isEmpty()) {
dataDevice->primarySelection()->cancel();
dataDevice->sendPrimarySelection(currentPrimarySelection);
return;