forked from mirrors/gecko-dev
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:
parent
b4df363e19
commit
c7df16ffad
2 changed files with 259 additions and 254 deletions
|
|
@ -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);
|
||||
|
||||
mTargetDragDataReceived = true;
|
||||
|
||||
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)) {
|
||||
if (target == sPortalFileAtom || target == sPortalFileTransferAtom) {
|
||||
// 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.
|
||||
// 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;
|
||||
}
|
||||
|
||||
// A workaround for https://gitlab.gnome.org/GNOME/gtk/-/issues/6563
|
||||
//
|
||||
// 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.
|
||||
// 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.
|
||||
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
|
||||
} else {
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (mDragData) {
|
||||
mCachedDragData.InsertOrUpdate(target, mDragData);
|
||||
const guchar* data = gtk_selection_data_get_data(aSelectionData);
|
||||
gint len = gtk_selection_data_get_length(aSelectionData);
|
||||
if (len > 0 && data) {
|
||||
mTargetDragDataLen = len;
|
||||
mTargetDragData = g_malloc(mTargetDragDataLen);
|
||||
memcpy(mTargetDragData, data, mTargetDragDataLen);
|
||||
|
||||
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, MIME %s", gdk_atom_name(target));
|
||||
mCachedDragData.InsertOrUpdate(target, nullptr);
|
||||
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,69 +1335,91 @@ 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));
|
||||
if (!aDropFlavors.Contains(flavor)) {
|
||||
LOGDRAGSERVICE(" %s is missing", flavor.get());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mTargetDragContext) {
|
||||
LOGDRAGSERVICE(" failed, missing mTargetDragContext");
|
||||
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);
|
||||
if (auto cached = mCachedUris.Lookup(flavor)) {
|
||||
LOGDRAGSERVICE(" using cached uri list for %s", flavor.get());
|
||||
|
||||
// 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));
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_drag_get_data(mTargetWidget, mTargetDragContext, aRequestedFlavor,
|
||||
mTargetTime);
|
||||
|
||||
LOGDRAGSERVICE(" about to start inner iteration.");
|
||||
gtk_main_iteration();
|
||||
|
||||
PRTime entryTime = PR_Now();
|
||||
while (!mDragData && mDoingDrag) {
|
||||
// check the number of iterations
|
||||
LOGDRAGSERVICE(" doing iteration...\n");
|
||||
PR_Sleep(PR_MillisecondsToInterval(10)); /* sleep for 10 ms/iteration */
|
||||
if (PR_Now() - entryTime > NS_DND_TIMEOUT) {
|
||||
LOGDRAGSERVICE(" failed to get D&D data in time!\n");
|
||||
break;
|
||||
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, aFlavor, mTargetTime);
|
||||
|
||||
LOGDRAGSERVICE(" about to start inner iteration.");
|
||||
gtk_main_iteration();
|
||||
|
||||
PRTime entryTime = PR_Now();
|
||||
while (!mTargetDragDataReceived && mDoingDrag) {
|
||||
// check the number of iterations
|
||||
LOGDRAGSERVICE(" doing iteration...\n");
|
||||
PR_Sleep(PR_MillisecondsToInterval(10)); /* sleep for 10 ms/iteration */
|
||||
if (PR_Now() - entryTime > NS_DND_TIMEOUT) {
|
||||
LOGDRAGSERVICE(" failed to get D&D data in time!\n");
|
||||
break;
|
||||
}
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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__
|
||||
|
|
|
|||
Loading…
Reference in a new issue