commit d648a9a26195 Author: Martin Stransky Date: Tue Mar 27 15:51:07 2018 +0200 Bug 1447925 - Add GetClipboardText() to get text data from clipboard, r=jhorak GetClipboardText() calls gtk_clipboard_request_text() to request text clipboard data from Gtk+ and leave Gtk+ to do clipboard text format conversions. Also unify data getting code for text/data/targets. MozReview-Commit-ID: 9DGSdOACho1 --HG-- extra : rebase_source : f1d95609f8a7587a4abc11739db9d17ec5446a7b --- widget/gtk/nsClipboard.h | 1 + widget/gtk/nsClipboardX11.cpp | 177 +++++++++++++++++++++++++++++------------- widget/gtk/nsClipboardX11.h | 39 +++++++--- 3 files changed, 152 insertions(+), 65 deletions(-) diff --git widget/gtk/nsClipboard.h widget/gtk/nsClipboard.h index 2be635bca10d..fa3b9b6ff087 100644 --- widget/gtk/nsClipboard.h +++ widget/gtk/nsClipboard.h @@ -21,6 +21,7 @@ public: virtual const char* GetClipboardData(const char* aMimeType, int32_t aWhichClipboard, uint32_t* aContentLength) = 0; + virtual const char* GetClipboardText(int32_t aWhichClipboard) = 0; virtual void ReleaseClipboardData(const char* aClipboardData) = 0; virtual GdkAtom* GetTargets(int32_t aWhichClipboard, diff --git widget/gtk/nsClipboardX11.cpp widget/gtk/nsClipboardX11.cpp index 6a574069dcc4..e8d8522651c2 100644 --- widget/gtk/nsClipboardX11.cpp +++ widget/gtk/nsClipboardX11.cpp @@ -62,8 +62,10 @@ selection_request_filter(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) nsRetrievalContextX11::nsRetrievalContextX11() : mState(INITIAL) - , mData(nullptr) , mClipboardRequestNumber(0) + , mClipboardData(nullptr) + , mClipboardDataLength(0) + , mTargetMIMEType(gdk_atom_intern("TARGETS", FALSE)) { // A custom event filter to workaround attempting to dereference a null // selection requestor in GTK3 versions before 3.11.3. See bug 1178799. @@ -139,13 +141,11 @@ checkEventProc(Display *display, XEvent *event, XPointer arg) return False; } -void * -nsRetrievalContextX11::Wait() +bool +nsRetrievalContextX11::WaitForX11Content() { if (mState == COMPLETED) { // the request completed synchronously - void *data = mData; - mData = nullptr; - return data; + return true; } GdkDisplay *gdkDisplay = gdk_display_get_default(); @@ -181,9 +181,7 @@ nsRetrievalContextX11::Wait() DispatchPropertyNotifyEvent(context.cbWidget, &xevent); if (mState == COMPLETED) { - void *data = mData; - mData = nullptr; - return data; + return true; } } @@ -200,11 +198,12 @@ nsRetrievalContextX11::Wait() printf("exceeded clipboard timeout\n"); #endif mState = TIMED_OUT; - return nullptr; + return false; } // Call this when data has been retrieved. -void nsRetrievalContextX11::Complete(GtkSelectionData* aData, +void nsRetrievalContextX11::Complete(ClipboardDataType aDataType, + const void* aData, int aDataRequestNumber) { if (mClipboardRequestNumber != aDataRequestNumber) { @@ -214,8 +213,54 @@ void nsRetrievalContextX11::Complete(GtkSelectionData* aData, if (mState == INITIAL) { mState = COMPLETED; - mData = gtk_selection_data_get_length(aData) >= 0 ? - gtk_selection_data_copy(aData) : nullptr; + + MOZ_ASSERT(mClipboardData == nullptr && + mClipboardDataLength == 0, + "We're leaking clipboard data!"); + + switch (aDataType) { + case CLIPBOARD_TEXT: + { + const char* text = static_cast(aData); + if (text) { + mClipboardDataLength = sizeof(char) * (strlen(text) + 1); + mClipboardData = moz_xmalloc(mClipboardDataLength); + memcpy(mClipboardData, text, mClipboardDataLength); + } + } + break; + case CLIPBOARD_TARGETS: + { + const GtkSelectionData *selection = + static_cast(aData); + + gint n_targets = 0; + GdkAtom *targets = nullptr; + + if (!gtk_selection_data_get_targets(selection, &targets, &n_targets) || + !n_targets) { + return; + } + + mClipboardData = targets; + mClipboardDataLength = n_targets; + } + break; + case CLIPBOARD_DATA: + { + const GtkSelectionData *selection = + static_cast(aData); + + gint dataLength = gtk_selection_data_get_length(selection); + if (dataLength > 0) { + mClipboardDataLength = dataLength; + mClipboardData = moz_xmalloc(dataLength); + memcpy(mClipboardData, gtk_selection_data_get_data(selection), + dataLength); + } + } + break; + } } else { // Already timed out MOZ_ASSERT(mState == TIMED_OUT); @@ -233,12 +278,24 @@ clipboard_contents_received(GtkClipboard *clipboard, delete handler; } -GtkSelectionData* -nsRetrievalContextX11::WaitForContents(GtkClipboard *clipboard, - const char *aMimeType) +static void +clipboard_text_received(GtkClipboard *clipboard, + const gchar *text, + gpointer data) +{ + ClipboardRequestHandler *handler = + static_cast(data); + handler->Complete(text); + delete handler; +} + +bool +nsRetrievalContextX11::WaitForClipboardData(ClipboardDataType aDataType, + GtkClipboard *clipboard, + const char *aMimeType) { mState = INITIAL; - NS_ASSERTION(!mData, "Leaking clipboard content!"); + NS_ASSERTION(!mClipboardData, "Leaking clipboard content!"); // Call ClipboardRequestHandler() with unique clipboard request number. // The request number pairs gtk_clipboard_request_contents() data request @@ -246,39 +303,45 @@ nsRetrievalContextX11::WaitForContents(GtkClipboard *clipboard, // is provided by Gtk. mClipboardRequestNumber++; ClipboardRequestHandler* handler = - new ClipboardRequestHandler(this, mClipboardRequestNumber); + new ClipboardRequestHandler(this, aDataType, mClipboardRequestNumber); + + switch (aDataType) { + case CLIPBOARD_DATA: + gtk_clipboard_request_contents(clipboard, + gdk_atom_intern(aMimeType, FALSE), clipboard_contents_received, + handler); + break; + case CLIPBOARD_TEXT: + gtk_clipboard_request_text(clipboard, clipboard_text_received, + handler); + break; + case CLIPBOARD_TARGETS: + gtk_clipboard_request_contents(clipboard, + mTargetMIMEType, clipboard_contents_received, + handler); + break; + } - gtk_clipboard_request_contents(clipboard, - gdk_atom_intern(aMimeType, FALSE), - clipboard_contents_received, - handler); - return static_cast(Wait()); + return WaitForX11Content(); } GdkAtom* nsRetrievalContextX11::GetTargets(int32_t aWhichClipboard, int* aTargetNums) { - *aTargetNums = 0; + GtkClipboard *clipboard = + gtk_clipboard_get(GetSelectionAtom(aWhichClipboard)); - GtkClipboard *clipboard = - gtk_clipboard_get(GetSelectionAtom(aWhichClipboard)); - - GtkSelectionData *selection_data = WaitForContents(clipboard, "TARGETS"); - if (!selection_data) - return nullptr; + if (!WaitForClipboardData(CLIPBOARD_TARGETS, clipboard)) + return nullptr; - gint n_targets = 0; - GdkAtom *targets = nullptr; + *aTargetNums = mClipboardDataLength; + GdkAtom* targets = static_cast(mClipboardData); - if (!gtk_selection_data_get_targets(selection_data, &targets, &n_targets) || - !n_targets) { - return nullptr; - } + // We don't hold the target list internally but we transfer the ownership. + mClipboardData = nullptr; + mClipboardDataLength = 0; - gtk_selection_data_free(selection_data); - - *aTargetNums = n_targets; - return targets; + return targets; } const char* @@ -289,25 +352,31 @@ nsRetrievalContextX11::GetClipboardData(const char* aMimeType, GtkClipboard *clipboard; clipboard = gtk_clipboard_get(GetSelectionAtom(aWhichClipboard)); - GtkSelectionData *selectionData = WaitForContents(clipboard, aMimeType); - if (!selectionData) + if (!WaitForClipboardData(CLIPBOARD_DATA, clipboard, aMimeType)) return nullptr; - char* clipboardData = nullptr; - int contentLength = gtk_selection_data_get_length(selectionData); - if (contentLength > 0) { - clipboardData = reinterpret_cast( - moz_xmalloc(sizeof(char)*contentLength)); - memcpy(clipboardData, gtk_selection_data_get_data(selectionData), - sizeof(char)*contentLength); - } - gtk_selection_data_free(selectionData); + *aContentLength = mClipboardDataLength; + return static_cast(mClipboardData); +} - *aContentLength = contentLength; - return (const char*)clipboardData; +const char* +nsRetrievalContextX11::GetClipboardText(int32_t aWhichClipboard) +{ + GtkClipboard *clipboard; + clipboard = gtk_clipboard_get(GetSelectionAtom(aWhichClipboard)); + + if (!WaitForClipboardData(CLIPBOARD_TEXT, clipboard)) + return nullptr; + + return static_cast(mClipboardData); } void nsRetrievalContextX11::ReleaseClipboardData(const char* aClipboardData) { - free((void *)aClipboardData); + NS_ASSERTION(aClipboardData == mClipboardData, + "Releasing unknown clipboard data!"); + free((void*)aClipboardData); + + mClipboardData = nullptr; + mClipboardDataLength = 0; } diff --git widget/gtk/nsClipboardX11.h widget/gtk/nsClipboardX11.h index 210f6b1fdbd4..9e89e08445dd 100644 --- widget/gtk/nsClipboardX11.h +++ widget/gtk/nsClipboardX11.h @@ -11,6 +11,12 @@ #include "nsIClipboard.h" #include +enum ClipboardDataType { + CLIPBOARD_DATA, + CLIPBOARD_TEXT, + CLIPBOARD_TARGETS +}; + class nsRetrievalContextX11 : public nsRetrievalContext { public: @@ -19,48 +25,59 @@ public: virtual const char* GetClipboardData(const char* aMimeType, int32_t aWhichClipboard, uint32_t* aContentLength) override; + virtual const char* GetClipboardText(int32_t aWhichClipboard) override; virtual void ReleaseClipboardData(const char* aClipboardData) override; virtual GdkAtom* GetTargets(int32_t aWhichClipboard, int* aTargetNums) override; - // Call this when data has been retrieved. - void Complete(GtkSelectionData* aData, int aDataRequestNumber); + // Call this when data or text has been retrieved. + void Complete(ClipboardDataType aDataType, + const void* aData, + int aDataRequestNumber); nsRetrievalContextX11(); virtual ~nsRetrievalContextX11() override; private: - GtkSelectionData* WaitForContents(GtkClipboard *clipboard, - const char *aMimeType); + bool WaitForClipboardData(ClipboardDataType aDataType, + GtkClipboard *clipboard, + const char *aMimeType = nullptr); + /** * Spins X event loop until timing out or being completed. Returns * null if we time out, otherwise returns the completed data (passing * ownership to caller). */ - void *Wait(); + bool WaitForX11Content(); - State mState; - void* mData; - int mClipboardRequestNumber; + State mState; + int mClipboardRequestNumber; + void* mClipboardData; + uint32_t mClipboardDataLength; + GdkAtom mTargetMIMEType; }; class ClipboardRequestHandler { public: - ClipboardRequestHandler(nsRetrievalContextX11 *aContext, int aDataRequestNumber) + ClipboardRequestHandler(nsRetrievalContextX11 *aContext, + ClipboardDataType aDataType, + int aDataRequestNumber) : mContext(aContext) , mDataRequestNumber(aDataRequestNumber) + , mDataType(aDataType) {} - void Complete(GtkSelectionData* aData) + void Complete(const void *aData) { - mContext->Complete(aData, mDataRequestNumber); + mContext->Complete(mDataType, aData, mDataRequestNumber); } private: nsRetrievalContextX11 *mContext; int mDataRequestNumber; + ClipboardDataType mDataType; }; #endif /* __nsClipboardX11_h_ */ commit 3a5fb9d15546 Author: Martin Stransky Date: Tue Apr 3 10:30:37 2018 +0200 Bug 1447925 - Use GetClipboardText() to get text data at nsClipboard::GetData(), r=jhorak MozReview-Commit-ID: 3JnLLyk0BOF --HG-- extra : rebase_source : 7bd5faff15d805d19628bdbd9fcd194c89c283a4 --- widget/gtk/nsClipboard.cpp | 7 ++----- widget/gtk/nsClipboard.h | 7 ++++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git widget/gtk/nsClipboard.cpp widget/gtk/nsClipboard.cpp index 5e8105987842..36e8d6ad5cee 100644 --- widget/gtk/nsClipboard.cpp +++ widget/gtk/nsClipboard.cpp @@ -301,11 +301,8 @@ nsClipboard::GetData(nsITransferable *aTransferable, int32_t aWhichClipboard) // Special case text/unicode since we can convert any // string into text/unicode if (flavorStr.EqualsLiteral(kUnicodeMime)) { - uint32_t clipboardDataLength; const char* clipboardData = - mContext->GetClipboardData(GTK_DEFAULT_MIME_TEXT, - aWhichClipboard, - &clipboardDataLength); + mContext->GetClipboardText(aWhichClipboard); if (!clipboardData) { // If the type was text/unicode and we couldn't get // text off the clipboard, run the next loop @@ -314,7 +311,7 @@ nsClipboard::GetData(nsITransferable *aTransferable, int32_t aWhichClipboard) } // Convert utf-8 into our unicode format. - NS_ConvertUTF8toUTF16 ucs2string(clipboardData, clipboardDataLength); + NS_ConvertUTF8toUTF16 ucs2string(clipboardData); const char* unicodeData = (const char *)ToNewUnicode(ucs2string); uint32_t unicodeDataLength = ucs2string.Length() * 2; SetTransferableData(aTransferable, flavorStr, diff --git widget/gtk/nsClipboard.h widget/gtk/nsClipboard.h index fa3b9b6ff087..9b59bf8176f6 100644 --- widget/gtk/nsClipboard.h +++ widget/gtk/nsClipboard.h @@ -13,17 +13,18 @@ #include "nsIBinaryOutputStream.h" #include -// Default Gtk MIME for text -#define GTK_DEFAULT_MIME_TEXT "UTF8_STRING" - class nsRetrievalContext { public: + // Get actual clipboard content (GetClipboardData/GetClipboardText) + // which has to be released by ReleaseClipboardData(). virtual const char* GetClipboardData(const char* aMimeType, int32_t aWhichClipboard, uint32_t* aContentLength) = 0; virtual const char* GetClipboardText(int32_t aWhichClipboard) = 0; virtual void ReleaseClipboardData(const char* aClipboardData) = 0; + // Get data mime types which can be obtained from clipboard. + // The returned array has to be released by g_free(). virtual GdkAtom* GetTargets(int32_t aWhichClipboard, int* aTargetNum) = 0;