From 6943fab2c1c46eb15e0018ae3419c0d43eb3c8d7 Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Mon, 22 Jul 2024 16:13:34 +0100 Subject: [PATCH] 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 --- src/wayland/seat.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/wayland/seat.cpp b/src/wayland/seat.cpp index 6a15964bd3..3b1728d985 100644 --- a/src/wayland/seat.cpp +++ b/src/wayland/seat.cpp @@ -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;