diff --git a/widget/cocoa/nsClipboard.h b/widget/cocoa/nsClipboard.h index c838f531d098..dfda7130f984 100644 --- a/widget/cocoa/nsClipboard.h +++ b/widget/cocoa/nsClipboard.h @@ -32,6 +32,7 @@ class nsClipboard : public nsBaseClipboard { // in the parent process. This is needed for the services menu which // requires synchronous access to the current selection. static mozilla::StaticRefPtr sSelectionCache; + static int32_t sSelectionCacheChangeCount; // Helper methods, used also by nsDragService static NSDictionary* PasteboardDictFromTransferable(nsITransferable* aTransferable); @@ -47,6 +48,9 @@ class nsClipboard : public nsBaseClipboard { int32_t aWhichClipboard) override; NS_IMETHOD GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhichClipboard) override; + mozilla::Result GetNativeClipboardSequenceNumber( + int32_t aWhichClipboard) override; + void ClearSelectionCache(); void SetSelectionCache(nsITransferable* aTransferable); diff --git a/widget/cocoa/nsClipboard.mm b/widget/cocoa/nsClipboard.mm index 0d1c7c688b03..f3183b533086 100644 --- a/widget/cocoa/nsClipboard.mm +++ b/widget/cocoa/nsClipboard.mm @@ -29,6 +29,7 @@ using mozilla::gfx::DataSourceSurface; using mozilla::gfx::SourceSurface; mozilla::StaticRefPtr nsClipboard::sSelectionCache; +int32_t nsClipboard::sSelectionCacheChangeCount = 0; nsClipboard::nsClipboard() : nsBaseClipboard(mozilla::dom::ClipboardCapabilities(false /* supportsSelectionClipboard */, @@ -75,10 +76,11 @@ static NSPasteboard* GetPasteboard(int32_t aWhichClipboard) { } // namespace void nsClipboard::SetSelectionCache(nsITransferable* aTransferable) { + sSelectionCacheChangeCount++; sSelectionCache = aTransferable; } -void nsClipboard::ClearSelectionCache() { sSelectionCache = nullptr; } +void nsClipboard::ClearSelectionCache() { SetSelectionCache(nullptr); } NS_IMETHODIMP nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, nsIClipboardOwner* aOwner, @@ -774,3 +776,23 @@ nsClipboard::EmptyClipboard(int32_t aWhichClipboard) { NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE); } + +mozilla::Result nsClipboard::GetNativeClipboardSequenceNumber( + int32_t aWhichClipboard) { + NS_OBJC_BEGIN_TRY_BLOCK_RETURN; + + MOZ_DIAGNOSTIC_ASSERT(nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)); + + if (kSelectionCache == aWhichClipboard) { + return sSelectionCacheChangeCount; + } + + NSPasteboard* cocoaPasteboard = GetPasteboard(aWhichClipboard); + if (!cocoaPasteboard) { + return mozilla::Err(NS_ERROR_FAILURE); + } + + return [cocoaPasteboard changeCount]; + + NS_OBJC_END_TRY_BLOCK_RETURN(mozilla::Err(NS_ERROR_FAILURE)); +} diff --git a/widget/nsBaseClipboard.cpp b/widget/nsBaseClipboard.cpp index 1af81819ada5..b36b584371c8 100644 --- a/widget/nsBaseClipboard.cpp +++ b/widget/nsBaseClipboard.cpp @@ -158,9 +158,11 @@ NS_IMETHODIMP nsBaseClipboard::SetData(nsITransferable* aTransferable, int32_t aWhichClipboard) { NS_ASSERTION(aTransferable, "clipboard given a null transferable"); - CLIPBOARD_LOG("%s", __FUNCTION__); + CLIPBOARD_LOG("%s: clipboard=%d", __FUNCTION__, aWhichClipboard); if (!nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)) { + CLIPBOARD_LOG("%s: clipboard %d is not supported.", __FUNCTION__, + aWhichClipboard); return NS_ERROR_FAILURE; } @@ -178,8 +180,6 @@ NS_IMETHODIMP nsBaseClipboard::SetData(nsITransferable* aTransferable, } mEmptyingForSetData = false; - clipboardCache->Update(aTransferable, anOwner); - nsresult rv = NS_ERROR_FAILURE; if (aTransferable) { mIgnoreEmptyNotification = true; @@ -189,9 +189,18 @@ NS_IMETHODIMP nsBaseClipboard::SetData(nsITransferable* aTransferable, } if (NS_FAILED(rv)) { CLIPBOARD_LOG("%s: setting native clipboard data failed.", __FUNCTION__); + return rv; } - return rv; + auto result = GetNativeClipboardSequenceNumber(aWhichClipboard); + if (result.isErr()) { + CLIPBOARD_LOG("%s: getting native clipboard change count failed.", + __FUNCTION__); + return result.unwrapErr(); + } + + clipboardCache->Update(aTransferable, anOwner, result.unwrap()); + return NS_OK; } /** @@ -298,4 +307,5 @@ void nsBaseClipboard::ClipboardCache::Clear() { mClipboardOwner = nullptr; } mTransferable = nullptr; + mSequenceNumber = -1; } diff --git a/widget/nsBaseClipboard.h b/widget/nsBaseClipboard.h index 6d9c064b76fc..a7e2501ca48e 100644 --- a/widget/nsBaseClipboard.h +++ b/widget/nsBaseClipboard.h @@ -8,7 +8,7 @@ #include "mozilla/dom/PContent.h" #include "mozilla/Logging.h" -#include "mozilla/UniquePtr.h" +#include "mozilla/Result.h" #include "nsIClipboard.h" #include "nsITransferable.h" #include "nsCOMPtr.h" @@ -124,6 +124,8 @@ class nsBaseClipboard : public ClipboardSetDataHelper { // Implement the native clipboard behavior. NS_IMETHOD GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhichClipboard) = 0; + virtual mozilla::Result GetNativeClipboardSequenceNumber( + int32_t aWhichClipboard) = 0; class ClipboardCache final { public: @@ -138,11 +140,12 @@ class nsBaseClipboard : public ClipboardSetDataHelper { */ void Clear(); void Update(nsITransferable* aTransferable, - nsIClipboardOwner* aClipboardOwner) { + nsIClipboardOwner* aClipboardOwner, int32_t aSequenceNumber) { // Clear first to notify the old clipboard owner. Clear(); mTransferable = aTransferable; mClipboardOwner = aClipboardOwner; + mSequenceNumber = aSequenceNumber; } nsITransferable* GetTransferable() const { return mTransferable; } nsIClipboardOwner* GetClipboardOwner() const { return mClipboardOwner; } @@ -150,6 +153,7 @@ class nsBaseClipboard : public ClipboardSetDataHelper { private: nsCOMPtr mTransferable; nsCOMPtr mClipboardOwner; + int32_t mSequenceNumber = -1; }; mozilla::UniquePtr mCaches[nsIClipboard::kClipboardTypeCount]; diff --git a/widget/windows/nsClipboard.cpp b/widget/windows/nsClipboard.cpp index f2c16343ee74..e89c2dde4a93 100644 --- a/widget/windows/nsClipboard.cpp +++ b/widget/windows/nsClipboard.cpp @@ -1356,6 +1356,12 @@ nsClipboard::EmptyClipboard(int32_t aWhichClipboard) { return nsBaseClipboard::EmptyClipboard(aWhichClipboard); } +Result nsClipboard::GetNativeClipboardSequenceNumber( + int32_t aWhichClipboard) { + MOZ_DIAGNOSTIC_ASSERT(kGlobalClipboard == aWhichClipboard); + return (int32_t)::GetClipboardSequenceNumber(); +} + //------------------------------------------------------------------------- NS_IMETHODIMP nsClipboard::HasDataMatchingFlavors( const nsTArray& aFlavorList, int32_t aWhichClipboard, diff --git a/widget/windows/nsClipboard.h b/widget/windows/nsClipboard.h index 2f0ed4aa3b26..74e87ea2929f 100644 --- a/widget/windows/nsClipboard.h +++ b/widget/windows/nsClipboard.h @@ -82,6 +82,8 @@ class nsClipboard : public nsBaseClipboard, public nsIObserver { int32_t aWhichClipboard) override; NS_IMETHOD GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhichClipboard) override; + mozilla::Result GetNativeClipboardSequenceNumber( + int32_t aWhichClipboard) override; static bool IsInternetShortcut(const nsAString& inFileName); static bool FindURLFromLocalFile(IDataObject* inDataObject, UINT inIndex,