Backed out 7 changesets (bug 1881229) for causing linux drag and drop crashes. a=crash

Backed out changeset f98ce3bad10b (bug 1881229)
Backed out changeset 4d5da5f79ce6 (bug 1881229)
Backed out changeset d4dfae34380d (bug 1881229)
Backed out changeset 3f9f8f388f8d (bug 1881229)
Backed out changeset 4a58c9a0cbd6 (bug 1881229)
Backed out changeset e055b85d36fc (bug 1881229)
Backed out changeset 43ab3ccffa94 (bug 1881229)
This commit is contained in:
Tamas Szentpeteri 2024-04-17 11:56:57 +03:00
parent b4df363e19
commit c7df16ffad
2 changed files with 259 additions and 254 deletions

View file

@ -139,16 +139,6 @@ static const char gTabDropType[] = "application/x-moz-tabbrowser-tab";
static const char gPortalFile[] = "application/vnd.portal.files";
static const char gPortalFileTransfer[] = "application/vnd.portal.filetransfer";
GdkAtom nsDragService::sTextMimeAtom;
GdkAtom nsDragService::sMozUrlTypeAtom;
GdkAtom nsDragService::sMimeListTypeAtom;
GdkAtom nsDragService::sTextUriListTypeAtom;
GdkAtom nsDragService::sTextPlainUTF8TypeAtom;
GdkAtom nsDragService::sXdndDirectSaveTypeAtom;
GdkAtom nsDragService::sTabDropTypeAtom;
GdkAtom nsDragService::sPortalFileAtom;
GdkAtom nsDragService::sPortalFileTransferAtom;
// See https://docs.gtk.org/gtk3/enum.DragResult.html
static const char kGtkDragResults[][100]{
"GTK_DRAG_RESULT_SUCCESS", "GTK_DRAG_RESULT_NO_TARGET",
@ -171,27 +161,6 @@ static void invisibleSourceDragDataGet(GtkWidget* aWidget,
guint aInfo, guint32 aTime,
gpointer aData);
void DragData::UpdateData(void* aData, uint32_t aDataLen, bool aCopyData) {
if (aData != mDragData) {
ReleaseData();
mDragData = aCopyData ? moz_xmemdup(aData, aDataLen) : aData;
} else {
// We changed the data in place so make sure we don't overflow.
MOZ_RELEASE_ASSERT(aDataLen <= mDragDataLen);
}
mDragDataLen = aDataLen;
}
void DragData::ReleaseData() {
if (mDragData) {
free(mDragData);
mDragData = nullptr;
}
mDragDataLen = 0;
}
DragData::~DragData() { ReleaseData(); }
nsDragService::nsDragService()
: mScheduledTask(eDragTaskNone),
mTaskSource(0),
@ -229,22 +198,12 @@ nsDragService::nsDragService()
// set up our logging module
mCanDrop = false;
mTargetDragDataReceived = false;
mTargetDragUris = nullptr;
mTargetDragData = 0;
mTargetDragDataLen = 0;
mTempFileTimerID = 0;
mEventLoopDepth = 0;
static std::once_flag onceFlag;
std::call_once(onceFlag, [] {
sTextMimeAtom = gdk_atom_intern(kTextMime, FALSE);
sMozUrlTypeAtom = gdk_atom_intern(gMozUrlType, FALSE);
sMimeListTypeAtom = gdk_atom_intern(gMimeListType, FALSE);
sTextUriListTypeAtom = gdk_atom_intern(gTextUriListType, FALSE);
sTextPlainUTF8TypeAtom = gdk_atom_intern(gTextPlainUTF8Type, FALSE);
sXdndDirectSaveTypeAtom = gdk_atom_intern(gXdndDirectSaveType, FALSE);
sTabDropTypeAtom = gdk_atom_intern(gTabDropType, FALSE);
sPortalFileAtom = gdk_atom_intern(gPortalFile, FALSE);
sPortalFileTransferAtom = gdk_atom_intern(gPortalFileTransfer, FALSE);
});
LOGDRAGSERVICE("nsDragService::nsDragService");
}
@ -735,7 +694,8 @@ nsDragService::GetNumDropItems(uint32_t* aNumItems) {
return NS_OK;
}
if (IsTargetContextList()) {
bool isList = IsTargetContextList();
if (isList) {
if (!mSourceDataItems) {
*aNumItems = 0;
return NS_OK;
@ -743,25 +703,38 @@ nsDragService::GetNumDropItems(uint32_t* aNumItems) {
mSourceDataItems->GetLength(aNumItems);
} else {
// text/uri-list
nsTArray<GdkAtom> availableDragFlavors;
GetAvailableDragFlavors(availableDragFlavors);
GdkAtom gdkFlavor = gdk_atom_intern(gTextUriListType, FALSE);
if (!gdkFlavor) {
*aNumItems = 0;
return NS_OK;
}
GetDragData(sTextUriListTypeAtom, availableDragFlavors);
nsTArray<nsCString> dragFlavors;
GetDragFlavors(dragFlavors);
GetTargetDragData(gdkFlavor, dragFlavors);
// application/vnd.portal.files
if (!mDragData->HasURIs()) {
GetDragData(sPortalFileAtom, availableDragFlavors,
false /* resetTargetData */);
if (!mTargetDragUris) {
gdkFlavor = gdk_atom_intern(gPortalFile, FALSE);
if (!gdkFlavor) {
*aNumItems = 0;
return NS_OK;
}
GetTargetDragData(gdkFlavor, dragFlavors, false /* resetTargetData */);
}
// application/vnd.portal.filetransfer
if (!mDragData->HasURIs()) {
GetDragData(sPortalFileTransferAtom, availableDragFlavors,
false /* resetTargetData */);
if (!mTargetDragUris) {
gdkFlavor = gdk_atom_intern(gPortalFileTransfer, FALSE);
if (!gdkFlavor) {
*aNumItems = 0;
return NS_OK;
}
GetTargetDragData(gdkFlavor, dragFlavors, false /* resetTargetData */);
}
if (mDragData->HasURIs()) {
*aNumItems = g_strv_length(mDragData->GetURIs());
if (mTargetDragUris) {
*aNumItems = g_strv_length(mTargetDragUris.get());
} else
*aNumItems = 1;
}
@ -769,11 +742,15 @@ nsDragService::GetNumDropItems(uint32_t* aNumItems) {
return NS_OK;
}
void nsDragService::GetAvailableDragFlavors(
nsTArray<GdkAtom>& aAvailableFlavors) {
void nsDragService::GetDragFlavors(nsTArray<nsCString>& aFlavors) {
for (GList* tmp = gdk_drag_context_list_targets(mTargetDragContext); tmp;
tmp = tmp->next) {
aAvailableFlavors.AppendElement(GDK_POINTER_TO_ATOM(tmp->data));
GdkAtom atom = GDK_POINTER_TO_ATOM(tmp->data);
GUniquePtr<gchar> name(gdk_atom_name(atom));
if (!name) {
continue;
}
aFlavors.AppendElement(nsCString(name.get()));
}
}
@ -843,7 +820,9 @@ nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex) {
}
// check to see if this is an internal list
if (IsTargetContextList()) {
bool isList = IsTargetContextList();
if (isList) {
LOGDRAGSERVICE(" Process as a list...");
// find a matching flavor
for (uint32_t i = 0; i < flavors.Length(); ++i) {
@ -875,8 +854,8 @@ nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex) {
return NS_ERROR_FAILURE;
}
nsTArray<GdkAtom> availableDragFlavors;
GetAvailableDragFlavors(availableDragFlavors);
nsTArray<nsCString> dragFlavors;
GetDragFlavors(dragFlavors);
// Now walk down the list of flavors. When we find one that is
// actually present, copy out the data into the transferable in that
@ -884,57 +863,63 @@ nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex) {
for (uint32_t i = 0; i < flavors.Length(); ++i) {
nsCString& flavorStr = flavors[i];
GdkAtom requestedFlavor;
GdkAtom gdkFlavor;
if (flavorStr.EqualsLiteral(kTextMime)) {
requestedFlavor = sTextPlainUTF8TypeAtom;
gdkFlavor = gdk_atom_intern(gTextPlainUTF8Type, FALSE);
} else {
requestedFlavor = gdk_atom_intern(flavorStr.get(), FALSE);
gdkFlavor = gdk_atom_intern(flavorStr.get(), FALSE);
}
LOGDRAGSERVICE(" we're getting data %s (gdk flavor %p)\n", flavorStr.get(),
requestedFlavor);
gdkFlavor);
bool dataFound = false;
nsCOMPtr<nsIFile> file;
if (requestedFlavor) {
GetDragData(requestedFlavor, availableDragFlavors);
GetReachableFileFromUriList(mDragData->GetURIs(), aItemIndex, file);
if (gdkFlavor) {
GetTargetDragData(gdkFlavor, dragFlavors);
GetReachableFileFromUriList(mTargetDragUris.get(), aItemIndex, file);
}
// application/vnd.portal.files
if (!file || !mDragData->HasURIs()) {
if (!file || !mTargetDragUris) {
LOGDRAGSERVICE(" file not found, proceed with %s flavor\n", gPortalFile);
GetDragData(sPortalFileAtom, availableDragFlavors,
false /* resetTargetData */);
GetReachableFileFromUriList(mDragData->GetURIs(), aItemIndex, file);
gdkFlavor = gdk_atom_intern(gPortalFile, FALSE);
if (gdkFlavor) {
GetTargetDragData(gdkFlavor, dragFlavors, false /* resetTargetData */);
GetReachableFileFromUriList(mTargetDragUris.get(), aItemIndex, file);
}
}
// application/vnd.portal.filetransfer
if (!file || !mDragData->HasURIs()) {
if (!file || !mTargetDragUris) {
LOGDRAGSERVICE(" file not found, proceed with %s flavor\n",
gPortalFileTransfer);
GetDragData(sPortalFileTransferAtom, availableDragFlavors,
false /* resetTargetData */);
GetReachableFileFromUriList(mDragData->GetURIs(), aItemIndex, file);
gdkFlavor = gdk_atom_intern(gPortalFileTransfer, FALSE);
if (gdkFlavor) {
GetTargetDragData(gdkFlavor, dragFlavors, false /* resetTargetData */);
GetReachableFileFromUriList(mTargetDragUris.get(), aItemIndex, file);
}
}
// Conversion from application/x-moz-file to text/uri-list
if ((!file || !mDragData->HasURIs()) &&
(flavorStr.EqualsLiteral(kFileMime))) {
if ((!file || !mTargetDragUris) && (flavorStr.EqualsLiteral(kFileMime))) {
LOGDRAGSERVICE(
" file not found, proceed with conversion %s => %s flavor\n",
kFileMime, gTextUriListType);
GetDragData(sTextUriListTypeAtom, availableDragFlavors,
false /* resetTargetData */);
GetReachableFileFromUriList(mDragData->GetURIs(), aItemIndex, file);
gdkFlavor = gdk_atom_intern(gTextUriListType, FALSE);
if (gdkFlavor) {
GetTargetDragData(gdkFlavor, dragFlavors, false /* resetTargetData */);
GetReachableFileFromUriList(mTargetDragUris.get(), aItemIndex, file);
}
}
if (file) {
LOGDRAGSERVICE(" from drag uris set as file %s - flavor: %s",
mDragData->GetURIs()[aItemIndex], flavorStr.get());
mTargetDragUris.get()[aItemIndex], flavorStr.get());
aTransferable->SetTransferData(flavorStr.get(), file);
return NS_OK;
}
if (mDragData) {
if (mTargetDragData) {
LOGDRAGSERVICE(" dataFound = true\n");
dataFound = true;
} else {
@ -942,8 +927,9 @@ nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex) {
// If we are looking for text/plain, try again with non utf-8 text.
if (flavorStr.EqualsLiteral(kTextMime)) {
LOGDRAGSERVICE(" conversion %s => %s", kTextMime, kTextMime);
GetDragData(sTextMimeAtom, availableDragFlavors);
if (mDragData) {
gdkFlavor = gdk_atom_intern(kTextMime, FALSE);
GetTargetDragData(gdkFlavor, dragFlavors);
if (mTargetDragData) {
dataFound = true;
} // if plain text flavor present
} // if looking for text/plain
@ -953,32 +939,39 @@ nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex) {
// _NETSCAPE_URL
if (flavorStr.EqualsLiteral(kURLMime)) {
LOGDRAGSERVICE(" conversion %s => %s", kURLMime, gTextUriListType);
GetDragData(sTextUriListTypeAtom, availableDragFlavors);
if (mDragData) {
gdkFlavor = gdk_atom_intern(gTextUriListType, FALSE);
GetTargetDragData(gdkFlavor, dragFlavors);
if (mTargetDragData) {
const char* data = reinterpret_cast<char*>(mTargetDragData);
char16_t* convertedText = nullptr;
uint32_t convertedTextLen = 0;
GetTextUriListItem(static_cast<const char*>(mDragData->GetData()),
mDragData->GetDataLen(), aItemIndex,
GetTextUriListItem(data, mTargetDragDataLen, aItemIndex,
&convertedText, &convertedTextLen);
if (convertedText) {
mDragData = new DragData(convertedText, convertedTextLen * 2,
/* aCopyData */ false);
// out with the old, in with the new
g_free(mTargetDragData);
mTargetDragData = convertedText;
mTargetDragDataLen = convertedTextLen * 2;
dataFound = true;
}
}
if (!dataFound) {
LOGDRAGSERVICE(" conversion %s => %s", kURLMime, gMozUrlType);
GetDragData(sMozUrlTypeAtom, availableDragFlavors);
if (mDragData) {
gdkFlavor = gdk_atom_intern(gMozUrlType, FALSE);
GetTargetDragData(gdkFlavor, dragFlavors);
if (mTargetDragData) {
const char* castedText = reinterpret_cast<char*>(mTargetDragData);
char16_t* convertedText = nullptr;
uint32_t convertedTextLen = 0;
UTF8ToNewUTF16(static_cast<const char*>(mDragData->GetData()),
mDragData->GetDataLen(), &convertedText,
UTF8ToNewUTF16(castedText, mTargetDragDataLen, &convertedText,
&convertedTextLen);
if (convertedText) {
mDragData = new DragData(convertedText, convertedTextLen * 2,
/* aCopyData */ false);
// out with the old, in with the new
g_free(mTargetDragData);
mTargetDragData = convertedText;
mTargetDragDataLen = convertedTextLen * 2;
dataFound = true;
}
}
@ -989,17 +982,17 @@ nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex) {
if (dataFound) {
LOGDRAGSERVICE(" actual data found %s\n",
GUniquePtr<gchar>(gdk_atom_name(requestedFlavor)).get());
GUniquePtr<gchar>(gdk_atom_name(gdkFlavor)).get());
if (flavorStr.EqualsLiteral(kTextMime)) {
// The text is in UTF-8, so convert the text into UTF-16
NS_ConvertUTF8toUTF16 ucs2string(
static_cast<const char*>(mDragData->GetData()),
mDragData->GetDataLen());
const char* text = static_cast<char*>(mTargetDragData);
NS_ConvertUTF8toUTF16 ucs2string(text, mTargetDragDataLen);
char16_t* convertedText = ToNewUnicode(ucs2string, mozilla::fallible);
if (convertedText) {
mDragData = new DragData(convertedText, ucs2string.Length() * 2,
/* aCopyData */ false);
g_free(mTargetDragData);
mTargetDragData = convertedText;
mTargetDragDataLen = ucs2string.Length() * 2;
}
}
@ -1011,7 +1004,8 @@ nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex) {
nsCOMPtr<nsIInputStream> byteStream;
NS_NewByteInputStream(getter_AddRefs(byteStream),
mDragData->GetDataSpan(), NS_ASSIGNMENT_COPY);
Span((char*)mTargetDragData, mTargetDragDataLen),
NS_ASSIGNMENT_COPY);
aTransferable->SetTransferData(flavorStr.get(), byteStream);
continue;
}
@ -1019,17 +1013,15 @@ nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex) {
if (!flavorStr.EqualsLiteral(kCustomTypesMime)) {
// the DOM only wants LF, so convert from MacOS line endings
// to DOM line endings.
void* data = mDragData->GetData();
int len = mDragData->GetDataLen();
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(
flavorStr.EqualsLiteral(kRTFMime), &data, &len);
mDragData->UpdateData(data, len);
flavorStr.EqualsLiteral(kRTFMime), &mTargetDragData,
reinterpret_cast<int*>(&mTargetDragDataLen));
}
// put it into the transferable.
nsCOMPtr<nsISupports> genericDataWrapper;
nsPrimitiveHelpers::CreatePrimitiveForData(
flavorStr, mDragData->GetData(), mDragData->GetDataLen(),
flavorStr, mTargetDragData, mTargetDragDataLen,
getter_AddRefs(genericDataWrapper));
aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper);
// we found one, get out of this loop!
@ -1060,9 +1052,10 @@ nsDragService::IsDataFlavorSupported(const char* aDataFlavor, bool* _retval) {
}
// check to see if the target context is a list.
bool isList = IsTargetContextList();
// if it is, just look in the internal data since we are the source
// for it.
if (IsTargetContextList()) {
if (isList) {
LOGDRAGSERVICE(" It's a list");
uint32_t numDragItems = 0;
// if we don't have mDataItems we didn't start this drag so it's
@ -1202,7 +1195,8 @@ void nsDragService::ReplyToDragMotion(GdkDragContext* aDragContext,
void nsDragService::EnsureCachedDataValidForContext(
GdkDragContext* aDragContext) {
if (mCachedDragContext != (uintptr_t)aDragContext) {
mCachedDragData.Clear();
mCachedUris.Clear();
mCachedData.Clear();
mCachedDragContext = (uintptr_t)aDragContext;
}
}
@ -1217,66 +1211,94 @@ void nsDragService::TargetDataReceived(GtkWidget* aWidget,
EnsureCachedDataValidForContext(aContext);
GdkAtom target = gtk_selection_data_get_target(aSelectionData);
if (gtk_targets_include_uri(&target, 1)) {
if (target == sPortalFileAtom || target == sPortalFileTransferAtom) {
const guchar* data = gtk_selection_data_get_data(aSelectionData);
if (!data || data[0] == '\0') {
LOGDRAGSERVICE(" Empty data!\n");
return;
}
mTargetDragDataReceived = true;
// A workaround for https://gitlab.gnome.org/GNOME/gtk/-/issues/6563
//
GdkAtom target = gtk_selection_data_get_target(aSelectionData);
GUniquePtr<gchar> name(gdk_atom_name(target));
nsDependentCString flavor(name.get());
if (gtk_targets_include_uri(&target, 1)) {
// For the vnd.portal.filetransfer and vnd.portal.files we receive numeric
// id when it's a local file. The numeric id is then used by
// gtk_selection_data_get_uris implementation to get the actual file
// available in the flatpak environment.
//
// However due to GTK implementation also for example the uris like https
// are also provided by the vnd.portal.filetransfer target. In this case
// the call gtk_selection_data_get_uris fails. This is a bug in the gtk.
// are also provided by the vnd.portal.filetransfer target. In this case the
// call gtk_selection_data_get_uris fails. This is a bug in the gtk.
// To workaround it we try to create the valid uri and only if we fail
// we try to use the gtk_selection_data_get_uris. We ignore the valid uris
// for the vnd.portal.file* targets.
// See: https://gitlab.gnome.org/GNOME/gtk/-/issues/6563
if (flavor.Equals(gPortalFile) || flavor.Equals(gPortalFileTransfer)) {
const guchar* data = gtk_selection_data_get_data(aSelectionData);
if (!data || data[0] == '\0') {
LOGDRAGSERVICE(" Empty data!\n");
return;
}
nsCOMPtr<nsIURI> sourceURI;
nsresult rv =
NS_NewURI(getter_AddRefs(sourceURI), (const gchar*)data, nullptr);
if (NS_SUCCEEDED(rv)) {
if (NS_FAILED(rv)) {
// We're unable to get the URI, we'll use the
// gtk_selection_data_get_uris to get the actual file location
// accessible from the Firefox runtime.
GUniquePtr<gchar*> uris(gtk_selection_data_get_uris(aSelectionData));
uris.swap(mTargetDragUris);
} else {
LOGDRAGSERVICE(
" got valid uri for MIME %s - this is bug in GTK - expected "
"numeric value for portal, got %s\n",
gdk_atom_name(target), data);
flavor.get(), data);
return;
}
}
mDragData = new DragData(gtk_selection_data_get_uris(aSelectionData));
} else {
GUniquePtr<gchar*> uris(gtk_selection_data_get_uris(aSelectionData));
uris.swap(mTargetDragUris);
}
#ifdef MOZ_LOGGING
if (MOZ_LOG_TEST(gWidgetDragLog, mozilla::LogLevel::Debug)) {
gchar** uri = mDragData->GetURIs();
gchar** uri = mTargetDragUris.get();
while (uri && *uri) {
LOGDRAGSERVICE(" got uri %s, MIME %s", *uri, gdk_atom_name(target));
LOGDRAGSERVICE(" got uri %s, MIME %s", *uri, flavor.get());
uri++;
}
}
#endif
if (mTargetDragUris) {
mCachedUris.InsertOrUpdate(
flavor, GUniquePtr<gchar*>(g_strdupv(mTargetDragUris.get())));
} else {
LOGDRAGSERVICE("Failed to get uri list\n");
mCachedUris.InsertOrUpdate(flavor, GUniquePtr<gchar*>(nullptr));
}
return;
}
const guchar* data = gtk_selection_data_get_data(aSelectionData);
gint len = gtk_selection_data_get_length(aSelectionData);
if (len > 0 && data) {
mDragData = new DragData(data, len);
LOGDRAGSERVICE(" got data, MIME %s len = %d", gdk_atom_name(target),
len);
}
}
mTargetDragDataLen = len;
mTargetDragData = g_malloc(mTargetDragDataLen);
memcpy(mTargetDragData, data, mTargetDragDataLen);
if (mDragData) {
mCachedDragData.InsertOrUpdate(target, mDragData);
} else {
LOGDRAGSERVICE(" failed to get data, MIME %s", gdk_atom_name(target));
mCachedDragData.InsertOrUpdate(target, nullptr);
LOGDRAGSERVICE(" got data, len = %d", mTargetDragDataLen);
nsTArray<uint8_t> copy;
if (!copy.SetLength(len, fallible)) {
return;
}
memcpy(copy.Elements(), data, len);
mCachedData.InsertOrUpdate(flavor, std::move(copy));
} else {
LOGDRAGSERVICE("Failed to get data. selection data len was %d\n",
mTargetDragDataLen);
mCachedData.InsertOrUpdate(flavor, nsTArray<uint8_t>());
}
LOGDRAGSERVICE(" got data, MIME %s", flavor.get());
}
bool nsDragService::IsTargetContextList(void) {
@ -1313,48 +1335,63 @@ bool nsDragService::IsTargetContextList(void) {
// Spins event loop, called from eDragTaskMotion handler by
// DispatchMotionEvents().
// Can lead to another round of drag_motion events.
void nsDragService::GetDragData(GdkAtom aRequestedFlavor,
const nsTArray<GdkAtom>& aAvailableDragFlavors,
bool aResetDragData) {
LOGDRAGSERVICE("nsDragService::GetDragData(%p) requested '%s'\n",
void nsDragService::GetTargetDragData(GdkAtom aFlavor,
nsTArray<nsCString>& aDropFlavors,
bool aResetTargetData) {
LOGDRAGSERVICE("nsDragService::GetTargetDragData(%p) '%s'\n",
mTargetDragContext.get(),
GUniquePtr<gchar>(gdk_atom_name(aRequestedFlavor)).get());
GUniquePtr<gchar>(gdk_atom_name(aFlavor)).get());
// reset our target data areas
if (aResetDragData) {
if (aResetTargetData) {
TargetResetData();
}
GUniquePtr<gchar> name(gdk_atom_name(aFlavor));
nsDependentCString flavor(name.get());
// Return early when requested MIME is not offered by D&D.
if (!aAvailableDragFlavors.Contains(aRequestedFlavor)) {
LOGDRAGSERVICE(" %s is missing", gdk_atom_name(aRequestedFlavor));
return;
}
if (!mTargetDragContext) {
LOGDRAGSERVICE(" failed, missing mTargetDragContext");
if (!aDropFlavors.Contains(flavor)) {
LOGDRAGSERVICE(" %s is missing", flavor.get());
return;
}
if (mTargetDragContext) {
// We keep a copy of the requested data with the same life-time
// as mTargetDragContext.
// Especially with multiple items the same data is requested
// very often.
EnsureCachedDataValidForContext(mTargetDragContext);
mDragData = mCachedDragData.Get(GDK_ATOM_TO_POINTER(aRequestedFlavor));
if (mDragData) {
LOGDRAGSERVICE(" %s found in cache", gdk_atom_name(aRequestedFlavor));
if (auto cached = mCachedUris.Lookup(flavor)) {
LOGDRAGSERVICE(" using cached uri list for %s", flavor.get());
mTargetDragUris = GUniquePtr<gchar*>(g_strdupv(cached->get()));
mTargetDragDataReceived = true;
LOGDRAGSERVICE(" %s found in cache", flavor.get());
return;
}
if (auto cached = mCachedData.Lookup(flavor)) {
mTargetDragDataLen = cached->Length();
LOGDRAGSERVICE(" using cached data for %s, length is %d", flavor.get(),
mTargetDragDataLen);
if (mTargetDragDataLen) {
mTargetDragData = g_malloc(mTargetDragDataLen);
memcpy(mTargetDragData, cached->Elements(), mTargetDragDataLen);
}
mTargetDragDataReceived = true;
LOGDRAGSERVICE(" %s found in cache", flavor.get());
return;
}
gtk_drag_get_data(mTargetWidget, mTargetDragContext, aRequestedFlavor,
mTargetTime);
gtk_drag_get_data(mTargetWidget, mTargetDragContext, aFlavor, mTargetTime);
LOGDRAGSERVICE(" about to start inner iteration.");
gtk_main_iteration();
PRTime entryTime = PR_Now();
while (!mDragData && mDoingDrag) {
while (!mTargetDragDataReceived && mDoingDrag) {
// check the number of iterations
LOGDRAGSERVICE(" doing iteration...\n");
PR_Sleep(PR_MillisecondsToInterval(10)); /* sleep for 10 ms/iteration */
@ -1364,18 +1401,25 @@ void nsDragService::GetDragData(GdkAtom aRequestedFlavor,
}
gtk_main_iteration();
}
}
#ifdef MOZ_LOGGING
if (mDragData) {
LOGDRAGSERVICE(" %s got from system", gdk_atom_name(aRequestedFlavor));
if (mTargetDragUris || (mTargetDragDataLen && mTargetDragData)) {
LOGDRAGSERVICE(" %s got from system", flavor.get());
} else {
LOGDRAGSERVICE(" %s failed to get from system",
gdk_atom_name(aRequestedFlavor));
LOGDRAGSERVICE(" %s failed to get from system", flavor.get());
}
#endif
}
void nsDragService::TargetResetData(void) { mDragData = nullptr; }
void nsDragService::TargetResetData(void) {
mTargetDragDataReceived = false;
// make sure to free old data if we have to
mTargetDragUris = nullptr;
g_free(mTargetDragData);
mTargetDragData = 0;
mTargetDragDataLen = 0;
}
static void TargetArrayAddTarget(nsTArray<GtkTargetEntry*>& aTargetArray,
const char* aTarget) {
@ -1539,7 +1583,7 @@ void nsDragService::SourceEndDragSession(GdkDragContext* aContext,
mSourceDataItems = nullptr;
// Remove this property, if it exists, to satisfy the Direct Save Protocol.
GdkAtom property = sXdndDirectSaveTypeAtom;
GdkAtom property = gdk_atom_intern(gXdndDirectSaveType, FALSE);
gdk_property_delete(gdk_drag_context_get_source_window(aContext), property);
if (!mDoingDrag || mScheduledTask == eDragTaskSourceEnd)
@ -1951,6 +1995,9 @@ void nsDragService::SourceDataGetXDND(nsITransferable* aItem,
GdkAtom target = gtk_selection_data_get_target(aSelectionData);
gtk_selection_data_set(aSelectionData, target, 8, (guchar*)"E", 1);
GdkAtom property = gdk_atom_intern(gXdndDirectSaveType, FALSE);
GdkAtom type = gdk_atom_intern(kTextMime, FALSE);
GdkWindow* srcWindow = gdk_drag_context_get_source_window(aContext);
if (!srcWindow) {
LOGDRAGSERVICE(" failed to get source GdkWindow!");
@ -1962,9 +2009,8 @@ void nsDragService::SourceDataGetXDND(nsITransferable* aItem,
{
GUniquePtr<guchar> gdata;
gint length = 0;
if (!gdk_property_get(srcWindow, sXdndDirectSaveTypeAtom, sTextMimeAtom, 0,
INT32_MAX, FALSE, nullptr, nullptr, &length,
getter_Transfers(gdata))) {
if (!gdk_property_get(srcWindow, property, type, 0, INT32_MAX, FALSE,
nullptr, nullptr, &length, getter_Transfers(gdata))) {
LOGDRAGSERVICE(" failed to get gXdndDirectSaveType GdkWindow property.");
return;
}
@ -2197,10 +2243,13 @@ void nsDragService::SourceBeginDrag(GdkDragContext* aContext) {
nsCString fileNameCStr;
CopyUTF16toUTF8(fileNameStr, fileNameCStr);
gdk_property_change(
gdk_drag_context_get_source_window(aContext), sXdndDirectSaveTypeAtom,
sTextMimeAtom, 8, GDK_PROP_MODE_REPLACE,
(const guchar*)fileNameCStr.get(), fileNameCStr.Length());
GdkAtom property = gdk_atom_intern(gXdndDirectSaveType, FALSE);
GdkAtom type = gdk_atom_intern(kTextMime, FALSE);
gdk_property_change(gdk_drag_context_get_source_window(aContext),
property, type, 8, GDK_PROP_MODE_REPLACE,
(const guchar*)fileNameCStr.get(),
fileNameCStr.Length());
break;
}
}
@ -2319,7 +2368,8 @@ static gboolean invisibleSourceDragFailed(GtkWidget* aWidget,
for (GList* tmp = gdk_drag_context_list_targets(aContext); tmp;
tmp = tmp->next) {
GdkAtom atom = GDK_POINTER_TO_ATOM(tmp->data);
if (atom == nsDragService::sTabDropTypeAtom) {
GUniquePtr<gchar> name(gdk_atom_name(atom));
if (name && !strcmp(name.get(), gTabDropType)) {
aResult = GTK_DRAG_RESULT_NO_TARGET;
LOGDRAGSERVICESTATIC("invisibleSourceDragFailed(%p): Wayland tab drop",
aContext);

View file

@ -24,42 +24,6 @@ class SourceSurface;
}
} // namespace mozilla
class DragData final {
public:
NS_INLINE_DECL_REFCOUNTING(DragData)
DragData(void* aData, uint32_t aDataLen, bool aCopyData) {
UpdateData(aData, aDataLen, aCopyData);
}
DragData(const void* aData, uint32_t aDataLen) {
// Always copy const data as we want to update it in-place by
// UTF8/UTF16 conversions.
UpdateData(const_cast<void*>(aData), aDataLen, /* aCopyData */ true);
}
explicit DragData(gchar** aDragUris) : mDragUris(aDragUris) {}
bool HasURIs() const { return !!mDragUris.get(); }
gchar** GetURIs() const { return mDragUris.get(); }
void UpdateData(void* aData, uint32_t aDataLen, bool aCopyData = false);
void* GetData() const { return mDragData; }
uint32_t GetDataLen() const { return mDragDataLen; }
mozilla::Span<char> GetDataSpan() const {
return mozilla::Span((char*)mDragData, mDragDataLen);
}
private:
void ReleaseData();
~DragData();
// We don't use any auto pointers here because we pass mDragData directly
// to various code which re-allocates it and releases it by malloc/free.
uint32_t mDragDataLen = 0;
void* mDragData = nullptr;
mozilla::GUniquePtr<gchar*> mDragUris;
};
/**
* Native GTK DragService wrapper
*/
@ -197,15 +161,15 @@ class nsDragService final : public nsBaseDragService, public nsIObserver {
RefPtr<GdkDragContext> mPendingDragContext;
// We cache all data for the current drag context,
// because waiting for the data in GetDragData can be very slow.
//
// because waiting for the data in GetTargetDragData can be very slow.
nsTHashMap<nsCStringHashKey, nsTArray<uint8_t>> mCachedData;
// mCachedData are tied to mCachedDragContext. mCachedDragContext is not
// ref counted and may be already deleted on Gtk side.
//
// We used it for mCachedData invalidation only and can't be used for
// any D&D operation.
uintptr_t mCachedDragContext;
nsRefPtrHashtable<nsVoidPtrHashKey, DragData> mCachedDragData;
nsTHashMap<nsCStringHashKey, mozilla::GUniquePtr<gchar*>> mCachedUris;
guint mPendingTime;
@ -233,16 +197,18 @@ class nsDragService final : public nsBaseDragService, public nsIObserver {
// is it OK to drop on us?
bool mCanDrop;
// Received drag data
RefPtr<DragData> mDragData;
// have we received our drag data?
bool mTargetDragDataReceived;
// last data received and its length
void* mTargetDragData;
uint32_t mTargetDragDataLen;
mozilla::GUniquePtr<gchar*> mTargetDragUris;
// is the current target drag context contain a list?
bool IsTargetContextList(void);
// this will get the native data from the last target given a
// specific flavor
void GetDragData(GdkAtom aRequestedFlavor,
const nsTArray<GdkAtom>& aAvailableDragFlavors,
bool aResetDragData = true);
void GetTargetDragData(GdkAtom aFlavor, nsTArray<nsCString>& aDropFlavors,
bool aResetTargetData = true);
// this will reset all of the target vars
void TargetResetData(void);
// Ensure our data cache belongs to aDragContext and clear the cache if
@ -281,7 +247,7 @@ class nsDragService final : public nsBaseDragService, public nsIObserver {
#ifdef MOZ_LOGGING
const char* GetDragServiceTaskName(nsDragService::DragTask aTask);
#endif
void GetAvailableDragFlavors(nsTArray<GdkAtom>& aAvailableFlavors);
void GetDragFlavors(nsTArray<nsCString>& aFlavors);
gboolean DispatchDropEvent();
static uint32_t GetCurrentModifiers();
@ -298,17 +264,6 @@ class nsDragService final : public nsBaseDragService, public nsIObserver {
guint mTempFileTimerID;
// How deep we're nested in event loops
int mEventLoopDepth;
public:
static GdkAtom sTextMimeAtom;
static GdkAtom sMozUrlTypeAtom;
static GdkAtom sMimeListTypeAtom;
static GdkAtom sTextUriListTypeAtom;
static GdkAtom sTextPlainUTF8TypeAtom;
static GdkAtom sXdndDirectSaveTypeAtom;
static GdkAtom sTabDropTypeAtom;
static GdkAtom sPortalFileAtom;
static GdkAtom sPortalFileTransferAtom;
};
#endif // nsDragService_h__