mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
Bug 1753067 - Cleanup handling of clipboard data lifetime. r=stransky
This is a bit harder to mess up, and a bit simpler to read too. Differential Revision: https://phabricator.services.mozilla.com/D137549
This commit is contained in:
parent
e9c325b945
commit
85f8575823
26
widget/gtk/GUniquePtr.h
Normal file
26
widget/gtk/GUniquePtr.h
Normal file
@ -0,0 +1,26 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GUniquePtr_h_
|
||||
#define GUniquePtr_h_
|
||||
|
||||
// Provides GUniquePtr to g_free a given pointer.
|
||||
|
||||
#include <glib.h>
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
struct GFreeDeleter {
|
||||
constexpr GFreeDeleter() = default;
|
||||
void operator()(void* aPtr) const { g_free(aPtr); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using GUniquePtr = UniquePtr<T, GFreeDeleter>;
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:expandtab:shiftwidth=2:tabstop=2:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -66,12 +66,42 @@ void clipboard_get_cb(GtkClipboard* aGtkClipboard,
|
||||
// Callback when someone asks us to clear a clipboard
|
||||
void clipboard_clear_cb(GtkClipboard* aGtkClipboard, gpointer user_data);
|
||||
|
||||
static bool ConvertHTMLtoUCS2(const char* data, int32_t dataLength,
|
||||
static bool ConvertHTMLtoUCS2(Span<const char> aData,
|
||||
nsCString& charset, char16_t** unicodeData,
|
||||
int32_t& outUnicodeLen);
|
||||
|
||||
static bool GetHTMLCharset(const char* data, int32_t dataLength,
|
||||
nsCString& str);
|
||||
static bool GetHTMLCharset(Span<const char> aData, nsCString& str);
|
||||
|
||||
void ClipboardData::SetData(Span<const uint8_t> aData) {
|
||||
mData = nullptr;
|
||||
mLength = aData.Length();
|
||||
if (mLength) {
|
||||
mData.reset(reinterpret_cast<char*>(g_malloc(sizeof(char) * mLength)));
|
||||
memcpy(mData.get(), aData.data(), sizeof(char) * mLength);
|
||||
}
|
||||
}
|
||||
|
||||
void ClipboardData::SetText(Span<const char> aData) {
|
||||
mData = nullptr;
|
||||
mLength = aData.Length();
|
||||
if (mLength) {
|
||||
mData.reset(
|
||||
reinterpret_cast<char*>(g_malloc(sizeof(char) * (mLength + 1))));
|
||||
memcpy(mData.get(), aData.data(), sizeof(char) * mLength);
|
||||
mData.get()[mLength] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void ClipboardData::SetTargets(ClipboardTargets aTargets) {
|
||||
mLength = aTargets.mCount;
|
||||
mData.reset(reinterpret_cast<char*>(aTargets.mTargets.release()));
|
||||
}
|
||||
|
||||
ClipboardTargets ClipboardData::ExtractTargets() {
|
||||
GUniquePtr<GdkAtom> targets(reinterpret_cast<GdkAtom*>(mData.release()));
|
||||
uint32_t length = std::exchange(mLength, 0);
|
||||
return ClipboardTargets{std::move(targets), length};
|
||||
}
|
||||
|
||||
GdkAtom GetSelectionAtom(int32_t aWhichClipboard) {
|
||||
if (aWhichClipboard == nsIClipboard::kGlobalClipboard)
|
||||
@ -269,17 +299,14 @@ bool nsClipboard::FilterImportedFlavors(int32_t aWhichClipboard,
|
||||
nsTArray<nsCString>& aFlavors) {
|
||||
LOGCLIP("nsClipboard::FilterImportedFlavors");
|
||||
|
||||
int targetNums;
|
||||
GdkAtom* targets = mContext->GetTargets(aWhichClipboard, &targetNums);
|
||||
auto releaseTargets = MakeScopeExit([&] { g_free(targets); });
|
||||
|
||||
if (!targets) {
|
||||
auto targets = mContext->GetTargets(aWhichClipboard);
|
||||
if (!targets.mTargets) {
|
||||
LOGCLIP(" X11: no targes at clipboard (null), quit.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < targetNums; i++) {
|
||||
gchar* atom_name = gdk_atom_name(targets[i]);
|
||||
for (const auto& atom : targets.AsSpan()) {
|
||||
gchar* atom_name = gdk_atom_name(atom);
|
||||
if (!atom_name) {
|
||||
continue;
|
||||
}
|
||||
@ -305,8 +332,8 @@ bool nsClipboard::FilterImportedFlavors(int32_t aWhichClipboard,
|
||||
|
||||
// So make sure we offer only types we have at clipboard.
|
||||
nsTArray<nsCString> clipboardFlavors;
|
||||
for (int i = 0; i < targetNums; i++) {
|
||||
gchar* atom_name = gdk_atom_name(targets[i]);
|
||||
for (const auto& atom : targets.AsSpan()) {
|
||||
gchar* atom_name = gdk_atom_name(atom);
|
||||
if (!atom_name) {
|
||||
continue;
|
||||
}
|
||||
@ -370,22 +397,18 @@ nsClipboard::GetData(nsITransferable* aTransferable, int32_t aWhichClipboard) {
|
||||
|
||||
LOGCLIP(" Getting image %s MIME clipboard data\n", flavorStr.get());
|
||||
|
||||
uint32_t clipboardDataLength;
|
||||
const char* clipboardData = mContext->GetClipboardData(
|
||||
flavorStr.get(), aWhichClipboard, &clipboardDataLength);
|
||||
auto clipboardData =
|
||||
mContext->GetClipboardData(flavorStr.get(), aWhichClipboard);
|
||||
if (!clipboardData) {
|
||||
LOGCLIP(" %s type is missing\n", flavorStr.get());
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> byteStream;
|
||||
NS_NewByteInputStream(getter_AddRefs(byteStream),
|
||||
Span(clipboardData, clipboardDataLength),
|
||||
NS_NewByteInputStream(getter_AddRefs(byteStream), clipboardData.AsSpan(),
|
||||
NS_ASSIGNMENT_COPY);
|
||||
aTransferable->SetTransferData(flavorStr.get(), byteStream);
|
||||
LOGCLIP(" got %s MIME data\n", flavorStr.get());
|
||||
|
||||
mContext->ReleaseClipboardData(&clipboardData);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -394,7 +417,7 @@ nsClipboard::GetData(nsITransferable* aTransferable, int32_t aWhichClipboard) {
|
||||
if (flavorStr.EqualsLiteral(kUnicodeMime)) {
|
||||
LOGCLIP(" Getting unicode %s MIME clipboard data\n", flavorStr.get());
|
||||
|
||||
const char* clipboardData = mContext->GetClipboardText(aWhichClipboard);
|
||||
auto clipboardData = mContext->GetClipboardText(aWhichClipboard);
|
||||
if (!clipboardData) {
|
||||
LOGCLIP(" failed to get unicode data\n");
|
||||
// If the type was text/unicode and we couldn't get
|
||||
@ -404,31 +427,26 @@ nsClipboard::GetData(nsITransferable* aTransferable, int32_t aWhichClipboard) {
|
||||
}
|
||||
|
||||
// Convert utf-8 into our unicode format.
|
||||
NS_ConvertUTF8toUTF16 ucs2string(clipboardData);
|
||||
const char* unicodeData = (const char*)ToNewUnicode(ucs2string);
|
||||
uint32_t unicodeDataLength = ucs2string.Length() * 2;
|
||||
SetTransferableData(aTransferable, flavorStr, unicodeData,
|
||||
unicodeDataLength);
|
||||
free((void*)unicodeData);
|
||||
NS_ConvertUTF8toUTF16 ucs2string(clipboardData.get());
|
||||
SetTransferableData(aTransferable, flavorStr,
|
||||
(const char*)ucs2string.BeginReading(),
|
||||
ucs2string.Length() * 2);
|
||||
|
||||
LOGCLIP(" got unicode data, length %zd\n", ucs2string.Length());
|
||||
|
||||
mContext->ReleaseClipboardData(&clipboardData);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (flavorStr.EqualsLiteral(kFileMime)) {
|
||||
LOGCLIP(" Getting %s file clipboard data\n", flavorStr.get());
|
||||
|
||||
uint32_t clipboardDataLength;
|
||||
const char* clipboardData = mContext->GetClipboardData(
|
||||
kURIListMime, aWhichClipboard, &clipboardDataLength);
|
||||
auto clipboardData =
|
||||
mContext->GetClipboardData(kURIListMime, aWhichClipboard);
|
||||
if (!clipboardData) {
|
||||
LOGCLIP(" text/uri-list type is missing\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
nsDependentCSubstring data(clipboardData, clipboardDataLength);
|
||||
nsDependentCSubstring data(clipboardData.AsSpan());
|
||||
nsTArray<nsCString> uris = mozilla::widget::ParseTextURIList(data);
|
||||
if (!uris.IsEmpty()) {
|
||||
nsCOMPtr<nsIURI> fileURI;
|
||||
@ -442,16 +460,13 @@ nsClipboard::GetData(nsITransferable* aTransferable, int32_t aWhichClipboard) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mContext->ReleaseClipboardData(&clipboardData);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
LOGCLIP(" Getting %s MIME clipboard data\n", flavorStr.get());
|
||||
|
||||
uint32_t clipboardDataLength;
|
||||
const char* clipboardData = mContext->GetClipboardData(
|
||||
flavorStr.get(), aWhichClipboard, &clipboardDataLength);
|
||||
auto clipboardData =
|
||||
mContext->GetClipboardData(flavorStr.get(), aWhichClipboard);
|
||||
|
||||
#ifdef MOZ_LOGGING
|
||||
if (!clipboardData) {
|
||||
@ -468,15 +483,14 @@ nsClipboard::GetData(nsITransferable* aTransferable, int32_t aWhichClipboard) {
|
||||
int32_t htmlBodyLen = 0;
|
||||
// Convert text/html into our unicode format
|
||||
nsAutoCString charset;
|
||||
if (!GetHTMLCharset(clipboardData, clipboardDataLength, charset)) {
|
||||
if (!GetHTMLCharset(clipboardData.AsSpan(), charset)) {
|
||||
// Fall back to utf-8 in case html/data is missing kHTMLMarkupPrefix.
|
||||
LOGCLIP("Failed to get html/text encoding, fall back to utf-8.\n");
|
||||
charset.AssignLiteral("utf-8");
|
||||
}
|
||||
if (!ConvertHTMLtoUCS2(clipboardData, clipboardDataLength, charset,
|
||||
if (!ConvertHTMLtoUCS2(clipboardData.AsSpan(), charset,
|
||||
&htmlBody, htmlBodyLen)) {
|
||||
LOGCLIP(" failed to convert text/html to UCS2.\n");
|
||||
mContext->ReleaseClipboardData(&clipboardData);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -484,11 +498,9 @@ nsClipboard::GetData(nsITransferable* aTransferable, int32_t aWhichClipboard) {
|
||||
htmlBodyLen * 2);
|
||||
free(htmlBody);
|
||||
} else {
|
||||
SetTransferableData(aTransferable, flavorStr, clipboardData,
|
||||
clipboardDataLength);
|
||||
SetTransferableData(aTransferable, flavorStr, clipboardData.mData.get(),
|
||||
clipboardData.mLength);
|
||||
}
|
||||
|
||||
mContext->ReleaseClipboardData(&clipboardData);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
@ -548,9 +560,7 @@ nsClipboard::HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
int targetNums;
|
||||
GdkAtom* targets = mContext->GetTargets(aWhichClipboard, &targetNums);
|
||||
auto releaseTargets = MakeScopeExit([&] { g_free(targets); });
|
||||
auto targets = mContext->GetTargets(aWhichClipboard);
|
||||
|
||||
if (!targets) {
|
||||
LOGCLIP(" no targes at clipboard (null)\n");
|
||||
@ -558,9 +568,10 @@ nsClipboard::HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList,
|
||||
}
|
||||
|
||||
#ifdef MOZ_LOGGING
|
||||
LOGCLIP(" Clipboard content (target nums %d):\n", targetNums);
|
||||
for (int32_t j = 0; j < targetNums; j++) {
|
||||
gchar* atom_name = gdk_atom_name(targets[j]);
|
||||
if (LOGCLIP_ENABLED()) {
|
||||
LOGCLIP(" Clipboard content (target nums %d):\n", targets.mCount);
|
||||
for (const auto& target : targets.AsSpan()) {
|
||||
gchar* atom_name = gdk_atom_name(target);
|
||||
if (!atom_name) {
|
||||
LOGCLIP(" failed to get MIME\n");
|
||||
continue;
|
||||
@ -571,6 +582,7 @@ nsClipboard::HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList,
|
||||
for (auto& flavor : aFlavorList) {
|
||||
LOGCLIP(" MIME %s\n", flavor.get());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Walk through the provided types and try to match it to a
|
||||
@ -578,15 +590,17 @@ nsClipboard::HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList,
|
||||
for (auto& flavor : aFlavorList) {
|
||||
// We special case text/unicode here.
|
||||
if (flavor.EqualsLiteral(kUnicodeMime) &&
|
||||
gtk_targets_include_text(targets, targetNums)) {
|
||||
gtk_targets_include_text(targets.mTargets.get(), targets.mCount)) {
|
||||
*_retval = true;
|
||||
LOGCLIP(" has kUnicodeMime\n");
|
||||
break;
|
||||
}
|
||||
|
||||
for (int32_t j = 0; j < targetNums; j++) {
|
||||
gchar* atom_name = gdk_atom_name(targets[j]);
|
||||
if (!atom_name) continue;
|
||||
for (const auto& target : targets.AsSpan()) {
|
||||
gchar* atom_name = gdk_atom_name(target);
|
||||
if (!atom_name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flavor.Equals(atom_name)) {
|
||||
*_retval = true;
|
||||
@ -870,13 +884,13 @@ void clipboard_clear_cb(GtkClipboard* aGtkClipboard, gpointer user_data) {
|
||||
* body : pass to Mozilla
|
||||
* bodyLength: pass to Mozilla
|
||||
*/
|
||||
bool ConvertHTMLtoUCS2(const char* data, int32_t dataLength, nsCString& charset,
|
||||
bool ConvertHTMLtoUCS2(Span<const char> aData, nsCString& charset,
|
||||
char16_t** unicodeData, int32_t& outUnicodeLen) {
|
||||
if (charset.EqualsLiteral("UTF-16")) { // current mozilla
|
||||
outUnicodeLen = (dataLength / 2) - 1;
|
||||
outUnicodeLen = (aData.Length() / 2) - 1;
|
||||
*unicodeData = reinterpret_cast<char16_t*>(
|
||||
moz_xmalloc((outUnicodeLen + sizeof('\0')) * sizeof(char16_t)));
|
||||
memcpy(*unicodeData, data + sizeof(char16_t),
|
||||
memcpy(*unicodeData, aData.data() + sizeof(char16_t),
|
||||
outUnicodeLen * sizeof(char16_t));
|
||||
(*unicodeData)[outUnicodeLen] = '\0';
|
||||
return true;
|
||||
@ -894,17 +908,16 @@ bool ConvertHTMLtoUCS2(const char* data, int32_t dataLength, nsCString& charset,
|
||||
return false;
|
||||
}
|
||||
|
||||
auto dataSpan = Span(data, dataLength);
|
||||
// Remove kHTMLMarkupPrefix again, it won't necessarily cause any
|
||||
// issues, but might confuse other users.
|
||||
const size_t prefixLen = ArrayLength(kHTMLMarkupPrefix) - 1;
|
||||
if (dataSpan.Length() >= prefixLen &&
|
||||
Substring(data, prefixLen).EqualsLiteral(kHTMLMarkupPrefix)) {
|
||||
dataSpan = dataSpan.From(prefixLen);
|
||||
if (aData.Length() >= prefixLen && nsDependentCSubstring(aData.To(prefixLen))
|
||||
.EqualsLiteral(kHTMLMarkupPrefix)) {
|
||||
aData = aData.From(prefixLen);
|
||||
}
|
||||
|
||||
auto decoder = encoding->NewDecoder();
|
||||
CheckedInt<size_t> needed = decoder->MaxUTF16BufferLength(dataSpan.Length());
|
||||
CheckedInt<size_t> needed = decoder->MaxUTF16BufferLength(aData.Length());
|
||||
if (!needed.isValid() || needed.value() > INT32_MAX) {
|
||||
outUnicodeLen = 0;
|
||||
return false;
|
||||
@ -918,9 +931,9 @@ bool ConvertHTMLtoUCS2(const char* data, int32_t dataLength, nsCString& charset,
|
||||
size_t read;
|
||||
size_t written;
|
||||
std::tie(result, read, written, std::ignore) = decoder->DecodeToUTF16(
|
||||
AsBytes(dataSpan), Span(*unicodeData, needed.value()), true);
|
||||
AsBytes(aData), Span(*unicodeData, needed.value()), true);
|
||||
MOZ_ASSERT(result == kInputEmpty);
|
||||
MOZ_ASSERT(read == size_t(dataSpan.Length()));
|
||||
MOZ_ASSERT(read == size_t(aData.Length()));
|
||||
MOZ_ASSERT(written <= needed.value());
|
||||
outUnicodeLen = written;
|
||||
// null terminate.
|
||||
@ -937,16 +950,19 @@ bool ConvertHTMLtoUCS2(const char* data, int32_t dataLength, nsCString& charset,
|
||||
* 2. "UNKNOWN": mozilla can't detect what encode it use
|
||||
* 3. other: "text/html" with other charset than utf-16
|
||||
*/
|
||||
bool GetHTMLCharset(const char* data, int32_t dataLength, nsCString& str) {
|
||||
bool GetHTMLCharset(Span<const char> aData, nsCString& str) {
|
||||
// if detect "FFFE" or "FEFF", assume UTF-16
|
||||
char16_t* beginChar = (char16_t*)data;
|
||||
{
|
||||
char16_t* beginChar = (char16_t*)aData.data();
|
||||
if ((beginChar[0] == 0xFFFE) || (beginChar[0] == 0xFEFF)) {
|
||||
str.AssignLiteral("UTF-16");
|
||||
LOGCLIP("GetHTMLCharset: Charset of HTML is UTF-16\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// no "FFFE" and "FEFF", assume ASCII first to find "charset" info
|
||||
const nsDependentCSubstring htmlStr(data, dataLength);
|
||||
const nsDependentCSubstring htmlStr(aData);
|
||||
nsACString::const_iterator start, end;
|
||||
htmlStr.BeginReading(start);
|
||||
htmlStr.EndReading(end);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:expandtab:shiftwidth=2:tabstop=2:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -9,8 +9,11 @@
|
||||
#define __nsClipboard_h_
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Span.h"
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "GUniquePtr.h"
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#ifdef MOZ_LOGGING
|
||||
@ -20,11 +23,36 @@
|
||||
extern mozilla::LazyLogModule gClipboardLog;
|
||||
# define LOGCLIP(...) \
|
||||
MOZ_LOG(gClipboardLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
|
||||
# define LOGCLIP_ENABLED() \
|
||||
MOZ_LOG_TEST(gClipboardLog, mozilla::LogLevel::Debug)
|
||||
#else
|
||||
# define LOGCLIP(...)
|
||||
# define LOGCLIP_ENABLED() false
|
||||
#endif /* MOZ_LOGGING */
|
||||
|
||||
enum ClipboardDataType { CLIPBOARD_DATA, CLIPBOARD_TEXT, CLIPBOARD_TARGETS };
|
||||
struct ClipboardTargets {
|
||||
mozilla::GUniquePtr<GdkAtom> mTargets;
|
||||
uint32_t mCount = 0;
|
||||
|
||||
mozilla::Span<GdkAtom> AsSpan() const { return {mTargets.get(), mCount}; }
|
||||
explicit operator bool() const { return bool(mTargets); }
|
||||
};
|
||||
|
||||
struct ClipboardData {
|
||||
mozilla::GUniquePtr<char> mData;
|
||||
uint32_t mLength = 0;
|
||||
|
||||
void SetData(mozilla::Span<const uint8_t>);
|
||||
void SetText(mozilla::Span<const char>);
|
||||
void SetTargets(ClipboardTargets);
|
||||
|
||||
ClipboardTargets ExtractTargets();
|
||||
|
||||
mozilla::Span<char> AsSpan() const { return {mData.get(), mLength}; }
|
||||
explicit operator bool() const { return bool(mData); }
|
||||
};
|
||||
|
||||
enum class ClipboardDataType { Data, Text, Targets };
|
||||
|
||||
class nsRetrievalContext {
|
||||
public:
|
||||
@ -32,17 +60,15 @@ class nsRetrievalContext {
|
||||
// main thread only.
|
||||
NS_INLINE_DECL_REFCOUNTING(nsRetrievalContext)
|
||||
|
||||
// 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 actual clipboard content (GetClipboardData/GetClipboardText).
|
||||
virtual ClipboardData GetClipboardData(const char* aMimeType,
|
||||
int32_t aWhichClipboard) = 0;
|
||||
virtual mozilla::GUniquePtr<char> GetClipboardText(
|
||||
int32_t aWhichClipboard) = 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;
|
||||
// Get data mime types which can be obtained from clipboard. The returned
|
||||
// array has to be released by g_free().
|
||||
virtual ClipboardTargets GetTargets(int32_t aWhichClipboard) = 0;
|
||||
|
||||
virtual bool HasSelectionSupport(void) = 0;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:expandtab:shiftwidth=2:tabstop=2:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -28,12 +28,8 @@
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::widget;
|
||||
|
||||
nsRetrievalContextWayland::nsRetrievalContextWayland(void)
|
||||
: mClipboardRequestNumber(0),
|
||||
mClipboardDataReceived(),
|
||||
mClipboardData(nullptr),
|
||||
mClipboardDataLength(0),
|
||||
mMutex("nsRetrievalContextWayland") {}
|
||||
nsRetrievalContextWayland::nsRetrievalContextWayland()
|
||||
: mMutex("nsRetrievalContextWayland") {}
|
||||
|
||||
struct AsyncClipboardData {
|
||||
AsyncClipboardData(ClipboardDataType aDataType, int aClipboardRequestNumber,
|
||||
@ -50,7 +46,7 @@ static void wayland_clipboard_contents_received_async(
|
||||
GtkClipboard* clipboard, GtkSelectionData* selection_data, gpointer data) {
|
||||
LOGCLIP("wayland_clipboard_contents_received_async() selection_data = %p\n",
|
||||
selection_data);
|
||||
AsyncClipboardData* fastTrack = static_cast<AsyncClipboardData*>(data);
|
||||
auto* fastTrack = static_cast<AsyncClipboardData*>(data);
|
||||
fastTrack->mRetrievalContex->TransferClipboardData(
|
||||
fastTrack->mDataType, fastTrack->mClipboardRequestNumber, selection_data);
|
||||
delete fastTrack;
|
||||
@ -59,7 +55,7 @@ static void wayland_clipboard_contents_received_async(
|
||||
static void wayland_clipboard_text_received(GtkClipboard* clipboard,
|
||||
const gchar* text, gpointer data) {
|
||||
LOGCLIP("wayland_clipboard_text_received() text = %p\n", text);
|
||||
AsyncClipboardData* fastTrack = static_cast<AsyncClipboardData*>(data);
|
||||
auto* fastTrack = static_cast<AsyncClipboardData*>(data);
|
||||
fastTrack->mRetrievalContex->TransferClipboardData(
|
||||
fastTrack->mDataType, fastTrack->mClipboardRequestNumber, (void*)text);
|
||||
delete fastTrack;
|
||||
@ -79,17 +75,18 @@ void nsRetrievalContextWayland::TransferClipboardData(
|
||||
}
|
||||
LOGCLIP(" request number matches\n");
|
||||
|
||||
MOZ_RELEASE_ASSERT(mClipboardData == nullptr && mClipboardDataLength == 0,
|
||||
MOZ_RELEASE_ASSERT(mClipboardData.isNothing(),
|
||||
"Clipboard contains old data?");
|
||||
|
||||
int dataLength = 0;
|
||||
if (aDataType == CLIPBOARD_TARGETS || aDataType == CLIPBOARD_DATA) {
|
||||
gint dataLength = 0;
|
||||
if (aDataType == ClipboardDataType::Targets ||
|
||||
aDataType == ClipboardDataType::Data) {
|
||||
dataLength = gtk_selection_data_get_length((GtkSelectionData*)aData);
|
||||
} else {
|
||||
dataLength = aData ? strlen((const char*)aData) : 0;
|
||||
}
|
||||
|
||||
mClipboardDataReceived = true;
|
||||
mClipboardData = Some(ClipboardData());
|
||||
|
||||
// Negative size means no data or data error.
|
||||
if (dataLength <= 0) {
|
||||
@ -98,119 +95,81 @@ void nsRetrievalContextWayland::TransferClipboardData(
|
||||
}
|
||||
|
||||
switch (aDataType) {
|
||||
case CLIPBOARD_TARGETS: {
|
||||
case ClipboardDataType::Targets: {
|
||||
LOGCLIP(" getting %d bytes of clipboard targets.\n", dataLength);
|
||||
gint n_targets = 0;
|
||||
GdkAtom* targets = nullptr;
|
||||
if (!gtk_selection_data_get_targets((GtkSelectionData*)aData, &targets,
|
||||
&n_targets) ||
|
||||
!n_targets) {
|
||||
// We failed to get targes
|
||||
// We failed to get targets
|
||||
return;
|
||||
}
|
||||
mClipboardData = reinterpret_cast<char*>(targets);
|
||||
mClipboardDataLength = n_targets;
|
||||
mClipboardData->SetTargets(
|
||||
ClipboardTargets{GUniquePtr<GdkAtom>(targets), uint32_t(n_targets)});
|
||||
break;
|
||||
}
|
||||
case CLIPBOARD_TEXT: {
|
||||
case ClipboardDataType::Text: {
|
||||
LOGCLIP(" getting %d bytes of text.\n", dataLength);
|
||||
mClipboardDataLength = dataLength;
|
||||
mClipboardData = reinterpret_cast<char*>(
|
||||
g_malloc(sizeof(char) * (mClipboardDataLength + 1)));
|
||||
memcpy(mClipboardData, aData, sizeof(char) * mClipboardDataLength);
|
||||
mClipboardData[mClipboardDataLength] = '\0';
|
||||
LOGCLIP(" done, mClipboardData = %p\n", mClipboardData);
|
||||
mClipboardData->SetText(
|
||||
Span(static_cast<const char*>(aData), dataLength));
|
||||
LOGCLIP(" done, mClipboardData = %p\n", mClipboardData->mData.get());
|
||||
break;
|
||||
}
|
||||
case CLIPBOARD_DATA: {
|
||||
case ClipboardDataType::Data: {
|
||||
LOGCLIP(" getting %d bytes of data.\n", dataLength);
|
||||
mClipboardDataLength = dataLength;
|
||||
mClipboardData = reinterpret_cast<char*>(
|
||||
g_malloc(sizeof(char) * mClipboardDataLength));
|
||||
memcpy(mClipboardData,
|
||||
gtk_selection_data_get_data((GtkSelectionData*)aData),
|
||||
sizeof(char) * mClipboardDataLength);
|
||||
LOGCLIP(" done, mClipboardData = %p\n", mClipboardData);
|
||||
mClipboardData->SetData(Span(
|
||||
gtk_selection_data_get_data((GtkSelectionData*)aData), dataLength));
|
||||
LOGCLIP(" done, mClipboardData = %p\n", mClipboardData->mData.get());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GdkAtom* nsRetrievalContextWayland::GetTargets(int32_t aWhichClipboard,
|
||||
int* aTargetNum) {
|
||||
ClipboardTargets nsRetrievalContextWayland::GetTargets(
|
||||
int32_t aWhichClipboard) {
|
||||
LOGCLIP("nsRetrievalContextWayland::GetTargets()\n");
|
||||
|
||||
if (!mMutex.TryLock()) {
|
||||
LOGCLIP(" nsRetrievalContextWayland is already used!\n");
|
||||
*aTargetNum = 0;
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
auto releaseLock = MakeScopeExit([&] { mMutex.Unlock(); });
|
||||
|
||||
MOZ_RELEASE_ASSERT(mClipboardData == nullptr && mClipboardDataLength == 0,
|
||||
"Clipboard contains old data?");
|
||||
int clipboardRequest = PrepareNewClipboardRequest();
|
||||
|
||||
GdkAtom selection = GetSelectionAtom(aWhichClipboard);
|
||||
mClipboardDataReceived = false;
|
||||
mClipboardRequestNumber++;
|
||||
gtk_clipboard_request_contents(
|
||||
gtk_clipboard_get(selection), gdk_atom_intern("TARGETS", FALSE),
|
||||
wayland_clipboard_contents_received_async,
|
||||
new AsyncClipboardData(CLIPBOARD_TARGETS, mClipboardRequestNumber, this));
|
||||
new AsyncClipboardData(ClipboardDataType::Targets, clipboardRequest,
|
||||
this));
|
||||
|
||||
if (!WaitForClipboardContent()) {
|
||||
*aTargetNum = 0;
|
||||
return nullptr;
|
||||
return WaitForClipboardContent().ExtractTargets();
|
||||
}
|
||||
|
||||
// mClipboardDataLength is only signed integer, see
|
||||
// nsRetrievalContextWayland::TransferClipboardData()
|
||||
*aTargetNum = (int)mClipboardDataLength;
|
||||
GdkAtom* targets = static_cast<GdkAtom*>((void*)mClipboardData);
|
||||
|
||||
mClipboardDataLength = 0;
|
||||
mClipboardData = nullptr;
|
||||
|
||||
return targets;
|
||||
}
|
||||
|
||||
const char* nsRetrievalContextWayland::GetClipboardData(
|
||||
const char* aMimeType, int32_t aWhichClipboard, uint32_t* aContentLength) {
|
||||
ClipboardData nsRetrievalContextWayland::GetClipboardData(
|
||||
const char* aMimeType, int32_t aWhichClipboard) {
|
||||
LOGCLIP("nsRetrievalContextWayland::GetClipboardData() mime %s\n", aMimeType);
|
||||
|
||||
if (!mMutex.TryLock()) {
|
||||
LOGCLIP(" nsRetrievalContextWayland is already used!\n");
|
||||
*aContentLength = 0;
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
auto releaseLock = MakeScopeExit([&] { mMutex.Unlock(); });
|
||||
|
||||
MOZ_RELEASE_ASSERT(mClipboardData == nullptr && mClipboardDataLength == 0,
|
||||
"Clipboard contains old data?");
|
||||
int clipboardRequest = PrepareNewClipboardRequest();
|
||||
|
||||
GdkAtom selection = GetSelectionAtom(aWhichClipboard);
|
||||
mClipboardDataReceived = false;
|
||||
mClipboardRequestNumber++;
|
||||
gtk_clipboard_request_contents(
|
||||
gtk_clipboard_get(selection), gdk_atom_intern(aMimeType, FALSE),
|
||||
wayland_clipboard_contents_received_async,
|
||||
new AsyncClipboardData(CLIPBOARD_DATA, mClipboardRequestNumber, this));
|
||||
new AsyncClipboardData(ClipboardDataType::Data, clipboardRequest, this));
|
||||
|
||||
if (!WaitForClipboardContent()) {
|
||||
*aContentLength = 0;
|
||||
return nullptr;
|
||||
return WaitForClipboardContent();
|
||||
}
|
||||
|
||||
*aContentLength = mClipboardDataLength;
|
||||
const char* data = mClipboardData;
|
||||
|
||||
mClipboardDataLength = 0;
|
||||
mClipboardData = nullptr;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
const char* nsRetrievalContextWayland::GetClipboardText(
|
||||
GUniquePtr<char> nsRetrievalContextWayland::GetClipboardText(
|
||||
int32_t aWhichClipboard) {
|
||||
GdkAtom selection = GetSelectionAtom(aWhichClipboard);
|
||||
|
||||
@ -223,32 +182,26 @@ const char* nsRetrievalContextWayland::GetClipboardText(
|
||||
}
|
||||
auto releaseLock = MakeScopeExit([&] { mMutex.Unlock(); });
|
||||
|
||||
MOZ_RELEASE_ASSERT(mClipboardData == nullptr && mClipboardDataLength == 0,
|
||||
"Clipboard contains old data?");
|
||||
|
||||
mClipboardDataReceived = false;
|
||||
mClipboardRequestNumber++;
|
||||
int clipboardRequest = PrepareNewClipboardRequest();
|
||||
gtk_clipboard_request_text(
|
||||
gtk_clipboard_get(selection), wayland_clipboard_text_received,
|
||||
new AsyncClipboardData(CLIPBOARD_TEXT, mClipboardRequestNumber, this));
|
||||
new AsyncClipboardData(ClipboardDataType::Text, clipboardRequest, this));
|
||||
|
||||
if (!WaitForClipboardContent()) {
|
||||
return nullptr;
|
||||
return WaitForClipboardContent().mData;
|
||||
}
|
||||
|
||||
const char* data = mClipboardData;
|
||||
|
||||
mClipboardDataLength = 0;
|
||||
mClipboardData = nullptr;
|
||||
|
||||
return data;
|
||||
int nsRetrievalContextWayland::PrepareNewClipboardRequest() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mClipboardData.isNothing(),
|
||||
"Clipboard contains old data?");
|
||||
mClipboardData.reset();
|
||||
return ++mClipboardRequestNumber;
|
||||
}
|
||||
|
||||
bool nsRetrievalContextWayland::WaitForClipboardContent() {
|
||||
ClipboardData nsRetrievalContextWayland::WaitForClipboardContent() {
|
||||
int iteration = 1;
|
||||
|
||||
PRTime entryTime = PR_Now();
|
||||
while (!mClipboardDataReceived) {
|
||||
while (mClipboardData.isNothing()) {
|
||||
if (iteration++ > kClipboardFastIterationNum) {
|
||||
/* sleep for 10 ms/iteration */
|
||||
PR_Sleep(PR_MillisecondsToInterval(10));
|
||||
@ -262,15 +215,8 @@ bool nsRetrievalContextWayland::WaitForClipboardContent() {
|
||||
gtk_main_iteration();
|
||||
}
|
||||
|
||||
if (!mClipboardDataReceived) {
|
||||
mClipboardDataLength = 0;
|
||||
mClipboardData = nullptr;
|
||||
if (mClipboardData.isNothing()) {
|
||||
return {};
|
||||
}
|
||||
return mClipboardDataReceived;
|
||||
}
|
||||
|
||||
void nsRetrievalContextWayland::ReleaseClipboardData(
|
||||
const char** aClipboardData) {
|
||||
g_free((void*)*aClipboardData);
|
||||
*aClipboardData = nullptr;
|
||||
return mClipboardData.extract();
|
||||
}
|
||||
|
@ -13,27 +13,24 @@
|
||||
#include <nsTArray.h>
|
||||
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "nsIThread.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsClipboard.h"
|
||||
#include "nsWaylandDisplay.h"
|
||||
|
||||
class nsRetrievalContextWayland : public nsRetrievalContext {
|
||||
class nsRetrievalContextWayland final : public nsRetrievalContext {
|
||||
public:
|
||||
nsRetrievalContextWayland();
|
||||
|
||||
// Successful call of GetClipboardData()/GetClipboardText() needs to be paired
|
||||
// with ReleaseClipboardData().
|
||||
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;
|
||||
ClipboardData GetClipboardData(const char* aMimeType,
|
||||
int32_t aWhichClipboard) override;
|
||||
mozilla::GUniquePtr<char> GetClipboardText(int32_t aWhichClipboard) override;
|
||||
|
||||
// GetTargets() uses clipboard data internally so it can't be used between
|
||||
// GetClipboardData()/GetClipboardText() and ReleaseClipboardData() calls.
|
||||
virtual GdkAtom* GetTargets(int32_t aWhichClipboard,
|
||||
int* aTargetNum) override;
|
||||
ClipboardTargets GetTargets(int32_t aWhichClipboard) override;
|
||||
|
||||
void TransferClipboardData(ClipboardDataType aDataType,
|
||||
int aClipboardRequestNumber, const void* aData);
|
||||
@ -41,13 +38,11 @@ class nsRetrievalContextWayland : public nsRetrievalContext {
|
||||
bool HasSelectionSupport(void) override { return true; }
|
||||
|
||||
private:
|
||||
bool WaitForClipboardContent();
|
||||
ClipboardData WaitForClipboardContent();
|
||||
int PrepareNewClipboardRequest();
|
||||
|
||||
private:
|
||||
int mClipboardRequestNumber;
|
||||
bool mClipboardDataReceived;
|
||||
char* mClipboardData;
|
||||
uint32_t mClipboardDataLength;
|
||||
int mClipboardRequestNumber = 0;
|
||||
mozilla::Maybe<ClipboardData> mClipboardData;
|
||||
mozilla::Mutex mMutex;
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:expandtab:shiftwidth=2:tabstop=2:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -40,11 +40,7 @@ bool nsRetrievalContextX11::HasSelectionSupport(void) {
|
||||
}
|
||||
|
||||
nsRetrievalContextX11::nsRetrievalContextX11()
|
||||
: mState(INITIAL),
|
||||
mClipboardRequestNumber(0),
|
||||
mClipboardData(nullptr),
|
||||
mClipboardDataLength(0),
|
||||
mTargetMIMEType(gdk_atom_intern("TARGETS", FALSE)) {}
|
||||
: mTargetMIMEType(gdk_atom_intern("TARGETS", FALSE)) {}
|
||||
|
||||
static void DispatchSelectionNotifyEvent(GtkWidget* widget, XEvent* xevent) {
|
||||
GdkEvent event = {};
|
||||
@ -99,9 +95,9 @@ static Bool checkEventProc(Display* display, XEvent* event, XPointer arg) {
|
||||
return X11False;
|
||||
}
|
||||
|
||||
bool nsRetrievalContextX11::WaitForX11Content() {
|
||||
if (mState == COMPLETED) { // the request completed synchronously
|
||||
return true;
|
||||
ClipboardData nsRetrievalContextX11::WaitForX11Content() {
|
||||
if (mState == State::Completed) { // the request completed synchronously
|
||||
return mClipboardData.extract();
|
||||
}
|
||||
|
||||
GdkDisplay* gdkDisplay = gdk_display_get_default();
|
||||
@ -134,8 +130,8 @@ bool nsRetrievalContextX11::WaitForX11Content() {
|
||||
else
|
||||
DispatchPropertyNotifyEvent(context.cbWidget, &xevent);
|
||||
|
||||
if (mState == COMPLETED) {
|
||||
return true;
|
||||
if (mState == State::Completed) {
|
||||
return mClipboardData.extract();
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,8 +145,8 @@ bool nsRetrievalContextX11::WaitForX11Content() {
|
||||
#ifdef DEBUG_CLIPBOARD
|
||||
printf("exceeded clipboard timeout\n");
|
||||
#endif
|
||||
mState = TIMED_OUT;
|
||||
return false;
|
||||
mState = State::TimedOut;
|
||||
return {};
|
||||
}
|
||||
|
||||
// Call this when data has been retrieved.
|
||||
@ -165,25 +161,26 @@ void nsRetrievalContextX11::Complete(ClipboardDataType aDataType,
|
||||
return;
|
||||
}
|
||||
|
||||
if (mState == INITIAL) {
|
||||
mState = COMPLETED;
|
||||
if (mState != State::Initial) {
|
||||
// Already timed out
|
||||
MOZ_ASSERT(mState == State::TimedOut);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mClipboardData == nullptr && mClipboardDataLength == 0,
|
||||
"We're leaking clipboard data!");
|
||||
mState = State::Completed;
|
||||
|
||||
MOZ_ASSERT(!mClipboardData, "We're leaking clipboard data!");
|
||||
mClipboardData = Some(ClipboardData());
|
||||
|
||||
switch (aDataType) {
|
||||
case CLIPBOARD_TEXT: {
|
||||
case ClipboardDataType::Text: {
|
||||
LOGCLIP(" got text data %p\n", aData);
|
||||
const char* text = static_cast<const char*>(aData);
|
||||
if (text) {
|
||||
mClipboardDataLength = sizeof(char) * (strlen(text) + 1);
|
||||
mClipboardData = g_malloc(mClipboardDataLength);
|
||||
memcpy(mClipboardData, text, mClipboardDataLength);
|
||||
if (auto* data = static_cast<const char*>(aData)) {
|
||||
mClipboardData->SetText(Span(data, strlen(data)));
|
||||
}
|
||||
} break;
|
||||
case CLIPBOARD_TARGETS: {
|
||||
const GtkSelectionData* selection =
|
||||
static_cast<const GtkSelectionData*>(aData);
|
||||
case ClipboardDataType::Targets: {
|
||||
auto* selection = static_cast<const GtkSelectionData*>(aData);
|
||||
|
||||
gint n_targets = 0;
|
||||
GdkAtom* targets = nullptr;
|
||||
@ -195,31 +192,27 @@ void nsRetrievalContextX11::Complete(ClipboardDataType aDataType,
|
||||
|
||||
LOGCLIP(" got %d targets\n", n_targets);
|
||||
|
||||
mClipboardData = targets;
|
||||
mClipboardDataLength = n_targets;
|
||||
mClipboardData->SetTargets(
|
||||
ClipboardTargets{GUniquePtr<GdkAtom>(targets), uint32_t(n_targets)});
|
||||
} break;
|
||||
case CLIPBOARD_DATA: {
|
||||
const GtkSelectionData* selection =
|
||||
static_cast<const GtkSelectionData*>(aData);
|
||||
|
||||
gint dataLength = gtk_selection_data_get_length(selection);
|
||||
const guchar* data = gtk_selection_data_get_data(selection);
|
||||
case ClipboardDataType::Data: {
|
||||
auto* selection = static_cast<const GtkSelectionData*>(aData);
|
||||
gint len = gtk_selection_data_get_length(selection);
|
||||
if (len > 0) {
|
||||
mClipboardData->SetData(
|
||||
Span(gtk_selection_data_get_data(selection), len));
|
||||
}
|
||||
#ifdef MOZ_LOGGING
|
||||
if (LOGCLIP_ENABLED()) {
|
||||
GdkAtom target = gtk_selection_data_get_target(selection);
|
||||
LOGCLIP(" got data %p len %d MIME %s\n", data, dataLength,
|
||||
gdk_atom_name(target));
|
||||
LOGCLIP(" got data %p len %lu MIME %s\n",
|
||||
mClipboardData->AsSpan().data(),
|
||||
mClipboardData->AsSpan().Length(),
|
||||
GUniquePtr<gchar>(gdk_atom_name(target)).get());
|
||||
}
|
||||
#endif
|
||||
if (dataLength > 0) {
|
||||
mClipboardDataLength = dataLength;
|
||||
mClipboardData = g_malloc(dataLength);
|
||||
memcpy(mClipboardData, data, dataLength);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
} else {
|
||||
// Already timed out
|
||||
MOZ_ASSERT(mState == TIMED_OUT);
|
||||
}
|
||||
}
|
||||
|
||||
static void clipboard_contents_received(GtkClipboard* clipboard,
|
||||
@ -243,40 +236,41 @@ static void clipboard_text_received(GtkClipboard* clipboard, const gchar* text,
|
||||
whichClipboard == nsClipboard::kSelectionClipboard ? "primary"
|
||||
: "clipboard");
|
||||
|
||||
ClipboardRequestHandler* handler =
|
||||
static_cast<ClipboardRequestHandler*>(data);
|
||||
auto* handler = static_cast<ClipboardRequestHandler*>(data);
|
||||
handler->Complete(text);
|
||||
delete handler;
|
||||
}
|
||||
|
||||
bool nsRetrievalContextX11::WaitForClipboardData(ClipboardDataType aDataType,
|
||||
GtkClipboard* clipboard,
|
||||
ClipboardData nsRetrievalContextX11::WaitForClipboardData(
|
||||
ClipboardDataType aDataType, GtkClipboard* clipboard,
|
||||
const char* aMimeType) {
|
||||
LOGCLIP("nsRetrievalContextX11::WaitForClipboardData, MIME %s\n", aMimeType);
|
||||
|
||||
mState = INITIAL;
|
||||
NS_ASSERTION(!mClipboardData, "Leaking clipboard content!");
|
||||
mState = State::Initial;
|
||||
|
||||
NS_ASSERTION(!mClipboardData, "Leaking clipboard content!");
|
||||
mClipboardData.reset();
|
||||
// Call ClipboardRequestHandler() with unique clipboard request number.
|
||||
// The request number pairs gtk_clipboard_request_contents() data request
|
||||
// with clipboard_contents_received() callback where the data
|
||||
// is provided by Gtk.
|
||||
mClipboardRequestNumber++;
|
||||
|
||||
ClipboardRequestHandler* handler =
|
||||
new ClipboardRequestHandler(this, aDataType, mClipboardRequestNumber);
|
||||
|
||||
switch (aDataType) {
|
||||
case CLIPBOARD_DATA:
|
||||
case ClipboardDataType::Data:
|
||||
LOGCLIP(" getting DATA MIME %s\n", aMimeType);
|
||||
gtk_clipboard_request_contents(clipboard,
|
||||
gdk_atom_intern(aMimeType, FALSE),
|
||||
clipboard_contents_received, handler);
|
||||
break;
|
||||
case CLIPBOARD_TEXT:
|
||||
case ClipboardDataType::Text:
|
||||
LOGCLIP(" getting TEXT\n");
|
||||
gtk_clipboard_request_text(clipboard, clipboard_text_received, handler);
|
||||
break;
|
||||
case CLIPBOARD_TARGETS:
|
||||
case ClipboardDataType::Targets:
|
||||
LOGCLIP(" getting TARGETS\n");
|
||||
gtk_clipboard_request_contents(clipboard, mTargetMIMEType,
|
||||
clipboard_contents_received, handler);
|
||||
@ -286,8 +280,7 @@ bool nsRetrievalContextX11::WaitForClipboardData(ClipboardDataType aDataType,
|
||||
return WaitForX11Content();
|
||||
}
|
||||
|
||||
GdkAtom* nsRetrievalContextX11::GetTargets(int32_t aWhichClipboard,
|
||||
int* aTargetNums) {
|
||||
ClipboardTargets nsRetrievalContextX11::GetTargets(int32_t aWhichClipboard) {
|
||||
LOGCLIP("nsRetrievalContextX11::GetTargets(%s)\n",
|
||||
aWhichClipboard == nsClipboard::kSelectionClipboard ? "primary"
|
||||
: "clipboard");
|
||||
@ -295,61 +288,31 @@ GdkAtom* nsRetrievalContextX11::GetTargets(int32_t aWhichClipboard,
|
||||
GtkClipboard* clipboard =
|
||||
gtk_clipboard_get(GetSelectionAtom(aWhichClipboard));
|
||||
|
||||
if (!WaitForClipboardData(CLIPBOARD_TARGETS, clipboard)) {
|
||||
LOGCLIP(" WaitForClipboardData() failed!\n");
|
||||
return nullptr;
|
||||
return WaitForClipboardData(ClipboardDataType::Targets, clipboard)
|
||||
.ExtractTargets();
|
||||
}
|
||||
|
||||
*aTargetNums = mClipboardDataLength;
|
||||
GdkAtom* targets = static_cast<GdkAtom*>(mClipboardData);
|
||||
|
||||
mClipboardData = nullptr;
|
||||
mClipboardDataLength = 0;
|
||||
|
||||
LOGCLIP(" returned %d targets\n", *aTargetNums);
|
||||
return targets;
|
||||
}
|
||||
|
||||
const char* nsRetrievalContextX11::GetClipboardData(const char* aMimeType,
|
||||
int32_t aWhichClipboard,
|
||||
uint32_t* aContentLength) {
|
||||
ClipboardData nsRetrievalContextX11::GetClipboardData(const char* aMimeType,
|
||||
int32_t aWhichClipboard) {
|
||||
LOGCLIP("nsRetrievalContextX11::GetClipboardData(%s) MIME %s\n",
|
||||
aWhichClipboard == nsClipboard::kSelectionClipboard ? "primary"
|
||||
: "clipboard",
|
||||
aMimeType);
|
||||
GtkClipboard* clipboard;
|
||||
clipboard = gtk_clipboard_get(GetSelectionAtom(aWhichClipboard));
|
||||
|
||||
if (!WaitForClipboardData(CLIPBOARD_DATA, clipboard, aMimeType))
|
||||
return nullptr;
|
||||
GtkClipboard* clipboard =
|
||||
gtk_clipboard_get(GetSelectionAtom(aWhichClipboard));
|
||||
|
||||
const char* data = (const char*)mClipboardData;
|
||||
*aContentLength = mClipboardDataLength;
|
||||
|
||||
mClipboardDataLength = 0;
|
||||
mClipboardData = nullptr;
|
||||
|
||||
return data;
|
||||
return WaitForClipboardData(ClipboardDataType::Data, clipboard, aMimeType);
|
||||
}
|
||||
|
||||
const char* nsRetrievalContextX11::GetClipboardText(int32_t aWhichClipboard) {
|
||||
GUniquePtr<char> nsRetrievalContextX11::GetClipboardText(
|
||||
int32_t aWhichClipboard) {
|
||||
LOGCLIP("nsRetrievalContextX11::GetClipboardText(%s)\n",
|
||||
aWhichClipboard == nsClipboard::kSelectionClipboard ? "primary"
|
||||
: "clipboard");
|
||||
GtkClipboard* clipboard;
|
||||
clipboard = gtk_clipboard_get(GetSelectionAtom(aWhichClipboard));
|
||||
|
||||
if (!WaitForClipboardData(CLIPBOARD_TEXT, clipboard)) return nullptr;
|
||||
GtkClipboard* clipboard =
|
||||
gtk_clipboard_get(GetSelectionAtom(aWhichClipboard));
|
||||
|
||||
const char* data = (const char*)mClipboardData;
|
||||
|
||||
mClipboardData = nullptr;
|
||||
mClipboardDataLength = 0;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void nsRetrievalContextX11::ReleaseClipboardData(const char** aClipboardData) {
|
||||
g_free((void*)*aClipboardData);
|
||||
*aClipboardData = nullptr;
|
||||
return WaitForClipboardData(ClipboardDataType::Text, clipboard).mData;
|
||||
}
|
||||
|
@ -10,20 +10,20 @@
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "nsClipboard.h"
|
||||
|
||||
class nsRetrievalContextX11 : public nsRetrievalContext {
|
||||
public:
|
||||
enum State { INITIAL, COMPLETED, TIMED_OUT };
|
||||
enum class State { Initial, Completed, TimedOut };
|
||||
|
||||
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;
|
||||
ClipboardData GetClipboardData(const char* aMimeType,
|
||||
int32_t aWhichClipboard) override;
|
||||
mozilla::GUniquePtr<char> GetClipboardText(int32_t aWhichClipboard) override;
|
||||
|
||||
virtual GdkAtom* GetTargets(int32_t aWhichClipboard,
|
||||
int* aTargetNums) override;
|
||||
ClipboardTargets GetTargets(int32_t aWhichClipboard) override;
|
||||
|
||||
virtual bool HasSelectionSupport(void) override;
|
||||
bool HasSelectionSupport(void) override;
|
||||
|
||||
// Call this when data or text has been retrieved.
|
||||
void Complete(ClipboardDataType aDataType, const void* aData,
|
||||
@ -32,7 +32,7 @@ class nsRetrievalContextX11 : public nsRetrievalContext {
|
||||
nsRetrievalContextX11();
|
||||
|
||||
private:
|
||||
bool WaitForClipboardData(ClipboardDataType aDataType,
|
||||
ClipboardData WaitForClipboardData(ClipboardDataType aDataType,
|
||||
GtkClipboard* clipboard,
|
||||
const char* aMimeType = nullptr);
|
||||
|
||||
@ -41,12 +41,11 @@ class nsRetrievalContextX11 : public nsRetrievalContext {
|
||||
* null if we time out, otherwise returns the completed data (passing
|
||||
* ownership to caller).
|
||||
*/
|
||||
bool WaitForX11Content();
|
||||
ClipboardData WaitForX11Content();
|
||||
|
||||
State mState;
|
||||
int mClipboardRequestNumber;
|
||||
void* mClipboardData;
|
||||
uint32_t mClipboardDataLength;
|
||||
State mState = State::Initial;
|
||||
int mClipboardRequestNumber = 0;
|
||||
mozilla::Maybe<ClipboardData> mClipboardData;
|
||||
GdkAtom mTargetMIMEType;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user