Bug 1722700 [Wayland] Merge WaylandDragAndDropDataOffer and DataOffer classes, r=rmader

Merge WaylandDragAndDropDataOffer and DataOffer classes to avoid potential timing issue when Drag&Drop action is set before WaylandDragAndDropDataOffer is created.

Differential Revision: https://phabricator.services.mozilla.com/D121877
This commit is contained in:
stransky 2021-08-05 14:56:08 +00:00
parent a69e3b1c8f
commit 989e6bc8fc
2 changed files with 69 additions and 123 deletions

View File

@ -70,8 +70,6 @@ static GtkWidget* get_gtk_widget_for_wl_surface(struct wl_surface* surface) {
return GTK_WIDGET(user_data);
}
NS_IMPL_ISUPPORTS(DataOffer, nsISupports);
static void data_offer_offer(void* data, struct wl_data_offer* wl_data_offer,
const char* type) {
auto* offer = static_cast<DataOffer*>(data);
@ -86,12 +84,8 @@ static void data_offer_offer(void* data, struct wl_data_offer* wl_data_offer,
static void data_offer_source_actions(void* data,
struct wl_data_offer* wl_data_offer,
uint32_t source_actions) {
auto* offer = static_cast<DataOffer*>(data);
WaylandDragAndDropDataOffer* dragContext =
offer->GetAsWaylandDragAndDropDataOffer();
if (dragContext) {
dragContext->SetAvailableDragActions(source_actions);
}
auto* dragContext = static_cast<DataOffer*>(data);
dragContext->SetAvailableDragActions(source_actions);
}
/* Advertise recently selected drag and drop action by compositor, based
@ -99,16 +93,13 @@ static void data_offer_source_actions(void* data,
*/
static void data_offer_action(void* data, struct wl_data_offer* wl_data_offer,
uint32_t dnd_action) {
auto* offer = static_cast<DataOffer*>(data);
WaylandDragAndDropDataOffer* dropContext =
offer->GetAsWaylandDragAndDropDataOffer();
if (dropContext) {
dropContext->SetSelectedDragAction(dnd_action);
auto* dropContext = static_cast<DataOffer*>(data);
dropContext->SetSelectedDragAction(dnd_action);
if (dropContext->GetWidget()) {
uint32_t time;
nscoord x, y;
dropContext->GetLastDropInfo(&time, &x, &y);
WindowDragMotionHandler(dropContext->GetWidget(), nullptr, dropContext, x,
y, time);
}
@ -131,7 +122,13 @@ DataOffer::DataOffer(wl_data_offer* aDataOffer)
mMutex("DataOffer"),
mAsyncContentLength(),
mAsyncContentData(),
mGetterFinished() {
mGetterFinished(),
mSelectedDragAction(),
mAvailableDragActions(),
mTime(),
mGtkWidget(),
mX(),
mY() {
if (mWaylandDataOffer) {
wl_data_offer_add_listener(
mWaylandDataOffer, (struct wl_data_offer_listener*)&data_offer_listener,
@ -263,7 +260,7 @@ char* DataOffer::GetDataInternal(const char* aMimeType,
if (PR_Now() - entryTime > kClipboardTimeout) {
break;
}
} else { // G_IO_STATUS_ERROR
} else { // G_IO_STATUS_ERROR
if (error) {
NS_WARNING(
nsPrintfCString("Unexpected error when reading clipboard data: %s",
@ -336,12 +333,12 @@ char* DataOffer::GetDataAsync(const char* aMimeType, uint32_t* aContentLength) {
mGetterFinished = false;
RefPtr<DataOffer> offer(this);
NS_DispatchBackgroundTask(NS_NewRunnableFunction(
"DataOffer::GetDataInternal",
[offer, aMimeType]() -> void {
offer->GetDataAsyncInternal(aMimeType);
}),
nsIEventTarget::NS_DISPATCH_NORMAL);
NS_DispatchBackgroundTask(
NS_NewRunnableFunction("DataOffer::GetDataInternal",
[offer, aMimeType]() -> void {
offer->GetDataAsyncInternal(aMimeType);
}),
nsIEventTarget::NS_DISPATCH_NORMAL);
PRTime entryTime = PR_Now();
while (!mGetterFinished) {
@ -360,18 +357,16 @@ char* DataOffer::GetDataAsync(const char* aMimeType, uint32_t* aContentLength) {
return nullptr;
}
LOGCLIP((" ineration over, got data %p len %d\n", mAsyncContentData, mAsyncContentLength));
LOGCLIP((" ineration over, got data %p len %d\n", mAsyncContentData,
mAsyncContentLength));
*aContentLength = mAsyncContentLength;
return mAsyncContentData;
}
void WaylandDragAndDropDataOffer::DragOfferAccept(const char* aMimeType) {
LOGDRAG(("WaylandDragAndDropDataOffer::DragOfferAccept MIME %s mTime %d\n",
aMimeType, mTime));
void DataOffer::DragOfferAccept(const char* aMimeType) {
LOGDRAG(("DataOffer::DragOfferAccept MIME %s mTime %d\n", aMimeType, mTime));
if (!HasTarget(aMimeType)) {
LOGCLIP(
(" WaylandDragAndDropDataOffer: DataOffer does not contain %s MIME!\n",
aMimeType));
LOGCLIP((" DataOffer: DataOffer does not contain %s MIME!\n", aMimeType));
return;
}
wl_data_offer_accept(mWaylandDataOffer, mTime, aMimeType);
@ -380,13 +375,11 @@ void WaylandDragAndDropDataOffer::DragOfferAccept(const char* aMimeType) {
/* We follow logic of gdk_wayland_drag_context_commit_status()/gdkdnd-wayland.c
* here.
*/
void WaylandDragAndDropDataOffer::SetDragStatus(
GdkDragAction aPreferredAction) {
void DataOffer::SetDragStatus(GdkDragAction aPreferredAction) {
uint32_t preferredAction = gdk_to_wl_actions(aPreferredAction);
uint32_t allActions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
LOGDRAG(("WaylandDragAndDropDataOffer::SetDragStatus aPreferredAction %d\n",
aPreferredAction));
LOGDRAG(("DataOffer::SetDragStatus aPreferredAction %d\n", aPreferredAction));
/* We only don't choose a preferred action if we don't accept any.
* If we do accept any, it is currently alway copy and move
@ -411,30 +404,18 @@ void WaylandDragAndDropDataOffer::SetDragStatus(
}
}
void WaylandDragAndDropDataOffer::SetSelectedDragAction(
uint32_t aWaylandAction) {
void DataOffer::SetSelectedDragAction(uint32_t aWaylandAction) {
mSelectedDragAction = aWaylandAction;
}
GdkDragAction WaylandDragAndDropDataOffer::GetSelectedDragAction() {
GdkDragAction DataOffer::GetSelectedDragAction() {
return wl_to_gdk_actions(mSelectedDragAction);
}
void WaylandDragAndDropDataOffer::SetAvailableDragActions(
uint32_t aWaylandActions) {
void DataOffer::SetAvailableDragActions(uint32_t aWaylandActions) {
mAvailableDragActions = aWaylandActions;
}
WaylandDragAndDropDataOffer::WaylandDragAndDropDataOffer(
wl_data_offer* aDataOffer)
: DataOffer(aDataOffer),
mSelectedDragAction(),
mAvailableDragActions(),
mTime(),
mGtkWidget(),
mX(),
mY() {}
bool PrimaryDataOffer::RequestDataTransfer(const char* aMimeType, int fd) {
if (mPrimaryDataOfferGtk) {
gtk_primary_selection_offer_receive(mPrimaryDataOfferGtk, aMimeType, fd);
@ -504,30 +485,27 @@ PrimaryDataOffer::~PrimaryDataOffer(void) {
}
}
void WaylandDragAndDropDataOffer::DropDataEnter(GtkWidget* aGtkWidget,
uint32_t aTime, nscoord aX,
nscoord aY) {
void DataOffer::DropDataEnter(GtkWidget* aGtkWidget, uint32_t aTime, nscoord aX,
nscoord aY) {
mTime = aTime;
mGtkWidget = aGtkWidget;
mX = aX;
mY = aY;
}
void WaylandDragAndDropDataOffer::DropMotion(uint32_t aTime, nscoord aX,
nscoord aY) {
void DataOffer::DropMotion(uint32_t aTime, nscoord aX, nscoord aY) {
mTime = aTime;
mX = aX;
mY = aY;
}
void WaylandDragAndDropDataOffer::GetLastDropInfo(uint32_t* aTime, nscoord* aX,
nscoord* aY) {
void DataOffer::GetLastDropInfo(uint32_t* aTime, nscoord* aX, nscoord* aY) {
*aTime = mTime;
*aX = mX;
*aY = mY;
}
GdkDragAction WaylandDragAndDropDataOffer::GetAvailableDragActions() {
GdkDragAction DataOffer::GetAvailableDragActions() {
GdkDragAction gdkAction = GetSelectedDragAction();
// We emulate gdk_drag_context_get_actions() here.
@ -538,7 +516,7 @@ GdkDragAction WaylandDragAndDropDataOffer::GetAvailableDragActions() {
return gdkAction;
}
GList* WaylandDragAndDropDataOffer::GetDragTargets() {
GList* DataOffer::GetDragTargets() {
int targetNums;
GdkAtom* atoms = GetTargets(&targetNums);
@ -550,9 +528,8 @@ GList* WaylandDragAndDropDataOffer::GetDragTargets() {
return targetList;
}
char* WaylandDragAndDropDataOffer::GetDragData(const char* aMimeType,
uint32_t* aContentLength) {
LOGDRAG(("WaylandDragAndDropDataOffer::GetData %s\n", aMimeType));
char* DataOffer::GetDragData(const char* aMimeType, uint32_t* aContentLength) {
LOGDRAG(("DataOffer::GetData %s\n", aMimeType));
if (!HasTarget(aMimeType)) {
return nullptr;
}
@ -681,7 +658,6 @@ void nsRetrievalContextWayland::AddDragAndDropDataOffer(
// Remove any existing D&D contexts.
mDragContext = nullptr;
if (aDropDataOffer) {
mDragContext = FindActiveOffer(aDropDataOffer, /* remove */ true);
}
@ -713,14 +689,12 @@ static void data_device_enter(void* data, struct wl_data_device* data_device,
uint32_t time, struct wl_surface* surface,
int32_t x_fixed, int32_t y_fixed,
struct wl_data_offer* offer) {
LOGDRAG(("nsWindow data_device_enter"));
nsRetrievalContextWayland* context =
static_cast<nsRetrievalContextWayland*>(data);
context->AddDragAndDropDataOffer(offer);
RefPtr<DataOffer> dataOffer = context->GetDragContext();
WaylandDragAndDropDataOffer* dragContext =
dataOffer->GetAsWaylandDragAndDropDataOffer();
RefPtr<DataOffer> dragContext = context->GetDragContext();
if (dragContext) {
GtkWidget* gtkWidget = get_gtk_widget_for_wl_surface(surface);
if (!gtkWidget) {
@ -736,12 +710,11 @@ static void data_device_enter(void* data, struct wl_data_device* data_device,
}
static void data_device_leave(void* data, struct wl_data_device* data_device) {
LOGDRAG(("nsWindow data_device_leave"));
nsRetrievalContextWayland* context =
static_cast<nsRetrievalContextWayland*>(data);
RefPtr<DataOffer> dataOffer = context->GetDragContext();
WaylandDragAndDropDataOffer* dropContext =
dataOffer->GetAsWaylandDragAndDropDataOffer();
RefPtr<DataOffer> dropContext = context->GetDragContext();
if (dropContext) {
WindowDragLeaveHandler(dropContext->GetWidget());
@ -754,13 +727,11 @@ static void data_device_leave(void* data, struct wl_data_device* data_device) {
static void data_device_motion(void* data, struct wl_data_device* data_device,
uint32_t time, int32_t x_fixed,
int32_t y_fixed) {
LOGDRAG(("nsWindow data_device_motion"));
nsRetrievalContextWayland* context =
static_cast<nsRetrievalContextWayland*>(data);
RefPtr<DataOffer> dataOffer = context->GetDragContext();
WaylandDragAndDropDataOffer* dropContext =
dataOffer->GetAsWaylandDragAndDropDataOffer();
RefPtr<DataOffer> dropContext = context->GetDragContext();
if (dropContext) {
nscoord x = wl_fixed_to_int(x_fixed);
nscoord y = wl_fixed_to_int(y_fixed);
@ -774,13 +745,11 @@ static void data_device_motion(void* data, struct wl_data_device* data_device,
}
static void data_device_drop(void* data, struct wl_data_device* data_device) {
LOGDRAG(("nsWindow data_device_drop"));
nsRetrievalContextWayland* context =
static_cast<nsRetrievalContextWayland*>(data);
RefPtr<DataOffer> dataOffer = context->GetDragContext();
WaylandDragAndDropDataOffer* dropContext =
dataOffer->GetAsWaylandDragAndDropDataOffer();
RefPtr<DataOffer> dropContext = context->GetDragContext();
if (dropContext) {
uint32_t time;
nscoord x, y;
@ -801,9 +770,9 @@ static void data_device_drop(void* data, struct wl_data_device* data_device) {
*
* data_device_selection - It's called when the new wl_data_offer
* is a clipboard content.
*
* data_device_enter - It's called when the new wl_data_offer is a drag & drop
* content and it's tied to actual wl_surface.
*
* data_device_leave - It's called when the wl_data_offer (drag & dop) is not
* valid any more.
* data_device_motion - It's called when the drag and drop selection moves
@ -1045,7 +1014,8 @@ const char* nsRetrievalContextWayland::GetClipboardData(
NS_ASSERTION(mClipboardData == nullptr && mClipboardDataLength == 0,
"Looks like we're leaking clipboard data here!");
LOGCLIP(("nsRetrievalContextWayland::GetClipboardData [%p] mime %s\n", this, aMimeType));
LOGCLIP(("nsRetrievalContextWayland::GetClipboardData [%p] mime %s\n", this,
aMimeType));
/* If actual clipboard data is owned by us we don't need to go
* through Wayland but we ask Gtk+ to directly call data

View File

@ -19,10 +19,9 @@
#include "nsWaylandDisplay.h"
struct FastTrackClipboard;
class WaylandDragAndDropDataOffer;
class DataOffer : public nsISupports {
NS_DECL_THREADSAFE_ISUPPORTS
class DataOffer {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataOffer)
public:
explicit DataOffer(wl_data_offer* aDataOffer);
@ -39,16 +38,23 @@ class DataOffer : public nsISupports {
char* GetData(const char* aMimeType, uint32_t* aContentLength);
char* GetDataAsync(const char* aMimeType, uint32_t* aContentLength);
virtual WaylandDragAndDropDataOffer* GetAsWaylandDragAndDropDataOffer() {
return nullptr;
}
virtual GtkWidget* GetWidget() { return nullptr; }
virtual GList* GetDragTargets() { return nullptr; }
virtual char* GetDragData(const char* aMimeType, uint32_t* aContentLength) {
return nullptr;
}
virtual void SetDragStatus(GdkDragAction aPreferredAction){};
virtual GdkDragAction GetAvailableDragActions() { return (GdkDragAction)0; };
void DragOfferAccept(const char* aMimeType);
void SetDragStatus(GdkDragAction aPreferredAction);
GdkDragAction GetSelectedDragAction();
void SetSelectedDragAction(uint32_t aWaylandAction);
void SetAvailableDragActions(uint32_t aWaylandActions);
GdkDragAction GetAvailableDragActions();
void DropDataEnter(GtkWidget* aGtkWidget, uint32_t aTime, nscoord aX,
nscoord aY);
void DropMotion(uint32_t aTime, nscoord aX, nscoord aY);
void GetLastDropInfo(uint32_t* aTime, nscoord* aX, nscoord* aY);
GtkWidget* GetWidget() { return mGtkWidget; }
GList* GetDragTargets();
char* GetDragData(const char* aMimeType, uint32_t* aContentLength);
protected:
virtual ~DataOffer();
@ -60,45 +66,15 @@ class DataOffer : public nsISupports {
void GetDataAsyncInternal(const char* aMimeType);
bool EnsureDataGetterThread();
protected:
private:
wl_data_offer* mWaylandDataOffer;
nsTArray<GdkAtom> mTargetMIMETypes;
mozilla::Mutex mMutex;
uint32_t mAsyncContentLength;
char* mAsyncContentData;
mozilla::Atomic<bool> mGetterFinished;
};
class WaylandDragAndDropDataOffer : public DataOffer {
public:
explicit WaylandDragAndDropDataOffer(
wl_data_offer* aWaylandDragAndDropDataOffer);
void DragOfferAccept(const char* aMimeType);
void SetDragStatus(GdkDragAction aPreferredAction) override;
GdkDragAction GetSelectedDragAction();
void SetSelectedDragAction(uint32_t aWaylandAction);
void SetAvailableDragActions(uint32_t aWaylandActions);
GdkDragAction GetAvailableDragActions() override;
void DropDataEnter(GtkWidget* aGtkWidget, uint32_t aTime, nscoord aX,
nscoord aY);
void DropMotion(uint32_t aTime, nscoord aX, nscoord aY);
void GetLastDropInfo(uint32_t* aTime, nscoord* aX, nscoord* aY);
GtkWidget* GetWidget() override { return mGtkWidget; }
GList* GetDragTargets() override;
char* GetDragData(const char* aMimeType, uint32_t* aContentLength) override;
WaylandDragAndDropDataOffer* GetAsWaylandDragAndDropDataOffer() override {
return this;
}
virtual ~WaylandDragAndDropDataOffer() = default;
private:
uint32_t mSelectedDragAction;
uint32_t mAvailableDragActions;
uint32_t mTime;