commit ceb53ef162316194ea1e4b0cd52d6aa696ee7950
parent 2b637764b38661a01e479f264631a208fe43704c
Author: stransky <stransky@redhat.com>
Date: Tue, 14 Oct 2025 09:59:16 +0000
Bug 1935188 [Wayland] Don't change clipboard sequence number if the clipboard data is set by us r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D266170
Diffstat:
2 files changed, 53 insertions(+), 30 deletions(-)
diff --git a/widget/gtk/nsClipboard.cpp b/widget/gtk/nsClipboard.cpp
@@ -343,31 +343,34 @@ nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable,
ClearCachedTargets(aWhichClipboard);
+ // On Wayland, track when we're setting clipboard data to avoid double
+ // sequence number increment in OwnerChangedEvent
+ MarkNextOwnerClipboardChange(aWhichClipboard, /* aOurChange */ true);
+
// Set getcallback and request to store data after an application exit
if (gtk_clipboard_set_with_data(gtkClipboard, gtkTargets, numTargets,
clipboard_get_cb, clipboard_clear_cb, this)) {
+ IncrementSequenceNumber(aWhichClipboard);
// We managed to set-up the clipboard so update internal state
// We have to set it now because gtk_clipboard_set_with_data() calls
// clipboard_clear_cb() which reset our internal state
if (aWhichClipboard == kSelectionClipboard) {
- mSelectionSequenceNumber++;
mSelectionTransferable = aTransferable;
} else {
- mGlobalSequenceNumber++;
mGlobalTransferable = aTransferable;
gtk_clipboard_set_can_store(gtkClipboard, gtkTargets, numTargets);
}
-
+ MOZ_CLIPBOARD_LOG(" sequence %d", GetSequenceNumber(aWhichClipboard));
rv = NS_OK;
} else {
- MOZ_CLIPBOARD_LOG(" gtk_clipboard_set_with_data() failed!\n");
+ MOZ_CLIPBOARD_LOG(" gtk_clipboard_set_with_data() failed!\n");
EmptyNativeClipboardData(aWhichClipboard);
+ MOZ_CLIPBOARD_LOG(" sequence %d", GetSequenceNumber(aWhichClipboard));
rv = NS_ERROR_FAILURE;
}
gtk_target_table_free(gtkTargets, numTargets);
gtk_target_list_unref(list);
-
return rv;
}
@@ -515,9 +518,9 @@ nsClipboard::GetNativeClipboardData(const nsACString& aFlavor,
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
MOZ_CLIPBOARD_LOG(
- "nsClipboard::GetNativeClipboardData (%s) for %s\n",
+ "nsClipboard::GetNativeClipboardData (%s) for %s sequence num %d",
aWhichClipboard == kSelectionClipboard ? "primary" : "clipboard",
- PromiseFlatCString(aFlavor).get());
+ PromiseFlatCString(aFlavor).get(), GetSequenceNumber(aWhichClipboard));
// TODO: Ensure we don't re-enter here.
if (!mContext) {
@@ -866,11 +869,13 @@ nsresult nsClipboard::EmptyNativeClipboardData(ClipboardType aWhichClipboard) {
if (mSelectionTransferable) {
gtk_clipboard_clear(gtk_clipboard_get(GDK_SELECTION_PRIMARY));
MOZ_ASSERT(!mSelectionTransferable);
+ MarkNextOwnerClipboardChange(aWhichClipboard, /* aOurChange */ true);
}
} else {
if (mGlobalTransferable) {
gtk_clipboard_clear(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD));
MOZ_ASSERT(!mGlobalTransferable);
+ MarkNextOwnerClipboardChange(aWhichClipboard, /* aOurChange */ true);
}
}
ClearCachedTargets(aWhichClipboard);
@@ -878,11 +883,10 @@ nsresult nsClipboard::EmptyNativeClipboardData(ClipboardType aWhichClipboard) {
}
void nsClipboard::ClearTransferable(int32_t aWhichClipboard) {
+ IncrementSequenceNumber(aWhichClipboard);
if (aWhichClipboard == kSelectionClipboard) {
- mSelectionSequenceNumber++;
mSelectionTransferable = nullptr;
} else {
- mGlobalSequenceNumber++;
mGlobalTransferable = nullptr;
}
}
@@ -1101,7 +1105,6 @@ void nsClipboard::SelectionGetEvent(GtkClipboard* aClipboard,
// that we want to do is see if that something includes text. If
// it does, try to give it text/plain after converting it to
// utf-8.
-
int32_t whichClipboard;
// which clipboard?
@@ -1357,28 +1360,21 @@ void nsClipboard::OwnerChangedEvent(GtkClipboard* aGtkClipboard,
if (whichClipboard.isNothing()) {
return;
}
- MOZ_CLIPBOARD_LOG(
- "nsClipboard::OwnerChangedEvent (%s)\n",
- *whichClipboard == kSelectionClipboard ? "primary" : "clipboard");
- GtkWidget* gtkWidget = [aEvent]() -> GtkWidget* {
- if (!aEvent->owner) {
- return nullptr;
- }
- gpointer user_data = nullptr;
- gdk_window_get_user_data(aEvent->owner, &user_data);
- return GTK_WIDGET(user_data);
- }();
- // If we can get GtkWidget from the current clipboard owner, this
- // owner-changed event must be triggered by ourself via calling
- // gtk_clipboard_set_with_data, the sequence number should already be handled.
- if (!gtkWidget) {
- if (*whichClipboard == kSelectionClipboard) {
- mSelectionSequenceNumber++;
- } else {
- mGlobalSequenceNumber++;
- }
+
+ bool shouldIncrementSequence = !IsOurOwnerClipboardChange(*whichClipboard);
+ MarkNextOwnerClipboardChange(*whichClipboard, /* aOurChange */ false);
+
+ if (shouldIncrementSequence) {
+ IncrementSequenceNumber(*whichClipboard);
}
+ MOZ_CLIPBOARD_LOG(
+ "nsClipboard::OwnerChangedEvent (%s) %s sequence %d\n",
+ *whichClipboard == kSelectionClipboard ? "primary" : "clipboard",
+ shouldIncrementSequence ? "external change" : "internal change",
+ *whichClipboard == kSelectionClipboard ? mSelectionSequenceNumber
+ : mGlobalSequenceNumber);
+
ClearCachedTargets(*whichClipboard);
}
diff --git a/widget/gtk/nsClipboard.h b/widget/gtk/nsClipboard.h
@@ -151,9 +151,36 @@ class nsClipboard final : public nsBaseClipboard, public nsIObserver {
nsCOMPtr<nsITransferable> mGlobalTransferable;
RefPtr<nsRetrievalContext> mContext;
+ void IncrementSequenceNumber(int32_t aWhichClipboard) {
+ if (aWhichClipboard == kSelectionClipboard) {
+ mSelectionSequenceNumber++;
+ } else {
+ mGlobalSequenceNumber++;
+ }
+ }
+ int32_t GetSequenceNumber(int32_t aWhichClipboard) {
+ return (aWhichClipboard == kSelectionClipboard) ? mSelectionSequenceNumber
+ : mGlobalSequenceNumber;
+ }
+
// Sequence number of the system clipboard data.
int32_t mSelectionSequenceNumber = 0;
int32_t mGlobalSequenceNumber = 0;
+
+ void MarkNextOwnerClipboardChange(int32_t aWhichClipboard, bool aOurChange) {
+ if (aWhichClipboard == kSelectionClipboard) {
+ mWeSetSelectionData = aOurChange;
+ } else {
+ mWeSetGlobalData = aOurChange;
+ }
+ }
+ bool IsOurOwnerClipboardChange(int32_t aWhichClipboard) {
+ return (aWhichClipboard == kSelectionClipboard) ? mWeSetSelectionData
+ : mWeSetGlobalData;
+ }
+
+ bool mWeSetSelectionData = false;
+ bool mWeSetGlobalData = false;
};
extern const int kClipboardTimeout;