1559 lines
52 KiB
Diff
1559 lines
52 KiB
Diff
|
|
||
|
# HG changeset patch
|
||
|
# User Martin Stransky <stransky@redhat.com>
|
||
|
# Date 1522937803 -7200
|
||
|
# Node ID 7e4166e13b3ec513ef3003527df601adf85f654b
|
||
|
# Parent bf4962739d38ac21ba6ba216fa61f572e7976354
|
||
|
Bug 1438131 - Implement Drop on Wayland, r=jhorak
|
||
|
|
||
|
This patch implements Drop operation on Wayland/Gtk+. That's because drop operations are part
|
||
|
of clipboard on Wayland and we use our own paste clipboard handler on Wayland (Bug 1282015).
|
||
|
|
||
|
Wayland drop data are provided by wl_data_device_listener, it provides us drag and drop callbacks
|
||
|
which we route to nsDragService module.
|
||
|
|
||
|
MozReview-Commit-ID: 9uGYPg9YF6P
|
||
|
|
||
|
diff --git a/widget/gtk/nsClipboardWayland.cpp b/widget/gtk/nsClipboardWayland.cpp
|
||
|
--- a/widget/gtk/nsClipboardWayland.cpp
|
||
|
+++ b/widget/gtk/nsClipboardWayland.cpp
|
||
|
@@ -18,16 +18,17 @@
|
||
|
#include "nsPrimitiveHelpers.h"
|
||
|
#include "nsIServiceManager.h"
|
||
|
#include "nsImageToPixbuf.h"
|
||
|
#include "nsStringStream.h"
|
||
|
#include "nsIObserverService.h"
|
||
|
#include "mozilla/Services.h"
|
||
|
#include "mozilla/RefPtr.h"
|
||
|
#include "mozilla/TimeStamp.h"
|
||
|
+#include "nsDragService.h"
|
||
|
|
||
|
#include "imgIContainer.h"
|
||
|
|
||
|
#include <gtk/gtk.h>
|
||
|
#include <poll.h>
|
||
|
#include <sys/epoll.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
@@ -41,16 +42,54 @@
|
||
|
const char*
|
||
|
nsRetrievalContextWayland::sTextMimeTypes[TEXT_MIME_TYPES_NUM] =
|
||
|
{
|
||
|
"text/plain;charset=utf-8",
|
||
|
"UTF8_STRING",
|
||
|
"COMPOUND_TEXT"
|
||
|
};
|
||
|
|
||
|
+static inline GdkDragAction
|
||
|
+wl_to_gdk_actions(uint32_t dnd_actions)
|
||
|
+{
|
||
|
+ GdkDragAction actions = GdkDragAction(0);
|
||
|
+
|
||
|
+ if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
|
||
|
+ actions = GdkDragAction(actions|GDK_ACTION_COPY);
|
||
|
+ if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
|
||
|
+ actions = GdkDragAction(actions|GDK_ACTION_MOVE);
|
||
|
+
|
||
|
+ return actions;
|
||
|
+}
|
||
|
+
|
||
|
+static inline uint32_t
|
||
|
+gdk_to_wl_actions(GdkDragAction action)
|
||
|
+{
|
||
|
+ uint32_t dnd_actions = 0;
|
||
|
+
|
||
|
+ if (action & (GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_PRIVATE))
|
||
|
+ dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
|
||
|
+ if (action & GDK_ACTION_MOVE)
|
||
|
+ dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
|
||
|
+
|
||
|
+ return dnd_actions;
|
||
|
+}
|
||
|
+
|
||
|
+static GtkWidget*
|
||
|
+get_gtk_widget_for_wl_surface(struct wl_surface *surface)
|
||
|
+{
|
||
|
+ GdkWindow *gdkParentWindow =
|
||
|
+ static_cast<GdkWindow*>(wl_surface_get_user_data(surface));
|
||
|
+
|
||
|
+ gpointer user_data = nullptr;
|
||
|
+ gdk_window_get_user_data(gdkParentWindow, &user_data);
|
||
|
+
|
||
|
+ return GTK_WIDGET(user_data);
|
||
|
+}
|
||
|
+
|
||
|
void
|
||
|
DataOffer::AddMIMEType(const char *aMimeType)
|
||
|
{
|
||
|
GdkAtom atom = gdk_atom_intern(aMimeType, FALSE);
|
||
|
mTargetMIMETypes.AppendElement(atom);
|
||
|
}
|
||
|
|
||
|
GdkAtom*
|
||
|
@@ -150,44 +189,99 @@ WaylandDataOffer::RequestDataTransfer(co
|
||
|
if (mWaylandDataOffer) {
|
||
|
wl_data_offer_receive(mWaylandDataOffer, aMimeType, fd);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
+void
|
||
|
+WaylandDataOffer::DragOfferAccept(const char* aMimeType, uint32_t aTime)
|
||
|
+{
|
||
|
+ wl_data_offer_accept(mWaylandDataOffer, aTime, aMimeType);
|
||
|
+}
|
||
|
+
|
||
|
+/* We follow logic of gdk_wayland_drag_context_commit_status()/gdkdnd-wayland.c
|
||
|
+ * here.
|
||
|
+ */
|
||
|
+void
|
||
|
+WaylandDataOffer::SetDragStatus(GdkDragAction aAction, uint32_t aTime)
|
||
|
+{
|
||
|
+ uint32_t dnd_actions = gdk_to_wl_actions(aAction);
|
||
|
+ uint32_t all_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
|
||
|
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
|
||
|
+
|
||
|
+ wl_data_offer_set_actions(mWaylandDataOffer, all_actions, dnd_actions);
|
||
|
+
|
||
|
+ /* Workaround Wayland D&D architecture here. To get the data_device_drop()
|
||
|
+ signal (which routes to nsDragService::GetData() call) we need to
|
||
|
+ accept at least one mime type before data_device_leave().
|
||
|
+
|
||
|
+ Real wl_data_offer_accept() for actualy requested data mime type is
|
||
|
+ called from nsDragService::GetData().
|
||
|
+ */
|
||
|
+ if (mTargetMIMETypes[0]) {
|
||
|
+ wl_data_offer_accept(mWaylandDataOffer, aTime,
|
||
|
+ gdk_atom_name(mTargetMIMETypes[0]));
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+WaylandDataOffer::SetSelectedDragAction(uint32_t aWaylandAction)
|
||
|
+{
|
||
|
+ mSelectedDragAction = aWaylandAction;
|
||
|
+}
|
||
|
+
|
||
|
+GdkDragAction
|
||
|
+WaylandDataOffer::GetSelectedDragAction()
|
||
|
+{
|
||
|
+ return wl_to_gdk_actions(mSelectedDragAction);
|
||
|
+}
|
||
|
+
|
||
|
static void
|
||
|
data_offer_offer (void *data,
|
||
|
struct wl_data_offer *wl_data_offer,
|
||
|
const char *type)
|
||
|
{
|
||
|
auto *offer = static_cast<DataOffer*>(data);
|
||
|
offer->AddMIMEType(type);
|
||
|
}
|
||
|
|
||
|
+/* Advertise all available drag and drop actions from source.
|
||
|
+ * We don't use that but follow gdk_wayland_drag_context_commit_status()
|
||
|
+ * from gdkdnd-wayland.c here.
|
||
|
+ */
|
||
|
static void
|
||
|
data_offer_source_actions(void *data,
|
||
|
struct wl_data_offer *wl_data_offer,
|
||
|
uint32_t source_actions)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
+/* Advertise recently selected drag and drop action by compositor, based
|
||
|
+ * on source actions and user choice (key modifiers, etc.).
|
||
|
+ */
|
||
|
static void
|
||
|
data_offer_action(void *data,
|
||
|
struct wl_data_offer *wl_data_offer,
|
||
|
uint32_t dnd_action)
|
||
|
{
|
||
|
+ auto *offer = static_cast<WaylandDataOffer*>(data);
|
||
|
+ offer->SetSelectedDragAction(dnd_action);
|
||
|
}
|
||
|
|
||
|
/* wl_data_offer callback description:
|
||
|
*
|
||
|
* data_offer_offer - Is called for each MIME type available at wl_data_offer.
|
||
|
- * data_offer_source_actions - Exposes all available D&D actions.
|
||
|
- * data_offer_action - Expose one actually selected D&D action.
|
||
|
+ * data_offer_source_actions - This event indicates the actions offered by
|
||
|
+ * the data source.
|
||
|
+ * data_offer_action - This event indicates the action selected by
|
||
|
+ * the compositor after matching the source/destination
|
||
|
+ * side actions.
|
||
|
*/
|
||
|
static const struct wl_data_offer_listener data_offer_listener = {
|
||
|
data_offer_offer,
|
||
|
data_offer_source_actions,
|
||
|
data_offer_action
|
||
|
};
|
||
|
|
||
|
WaylandDataOffer::WaylandDataOffer(wl_data_offer* aWaylandDataOffer)
|
||
|
@@ -241,92 +335,203 @@ PrimaryDataOffer::PrimaryDataOffer(gtk_p
|
||
|
|
||
|
PrimaryDataOffer::~PrimaryDataOffer(void)
|
||
|
{
|
||
|
if(mPrimaryDataOffer) {
|
||
|
gtk_primary_selection_offer_destroy(mPrimaryDataOffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+NS_IMPL_ISUPPORTS(nsWaylandDragContext, nsISupports);
|
||
|
+
|
||
|
+nsWaylandDragContext::nsWaylandDragContext(WaylandDataOffer* aDataOffer,
|
||
|
+ wl_display *aDisplay)
|
||
|
+ : mDataOffer(aDataOffer)
|
||
|
+ , mDisplay(aDisplay)
|
||
|
+ , mTime(0)
|
||
|
+ , mGtkWidget(nullptr)
|
||
|
+ , mX(0)
|
||
|
+ , mY(0)
|
||
|
+{
|
||
|
+}
|
||
|
+
|
||
|
void
|
||
|
-nsRetrievalContextWayland::RegisterDataOffer(wl_data_offer *aWaylandDataOffer)
|
||
|
+nsWaylandDragContext::DropDataEnter(GtkWidget* aGtkWidget, uint32_t aTime,
|
||
|
+ nscoord aX, nscoord aY)
|
||
|
+{
|
||
|
+ mTime = aTime;
|
||
|
+ mGtkWidget = aGtkWidget;
|
||
|
+ mX = aX;
|
||
|
+ mY = aY;
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+nsWaylandDragContext::DropMotion(uint32_t aTime, nscoord aX, nscoord aY)
|
||
|
+{
|
||
|
+ mTime = aTime;
|
||
|
+ mX = aX;
|
||
|
+ mY = aY;
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+nsWaylandDragContext::GetLastDropInfo(uint32_t *aTime, nscoord *aX, nscoord *aY)
|
||
|
+{
|
||
|
+ *aTime = mTime;
|
||
|
+ *aX = mX;
|
||
|
+ *aY = mY;
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+nsWaylandDragContext::SetDragStatus(GdkDragAction aAction)
|
||
|
+{
|
||
|
+ mDataOffer->SetDragStatus(aAction, mTime);
|
||
|
+}
|
||
|
+
|
||
|
+GdkDragAction
|
||
|
+nsWaylandDragContext::GetSelectedDragAction()
|
||
|
+{
|
||
|
+ return mDataOffer->GetSelectedDragAction();
|
||
|
+}
|
||
|
+
|
||
|
+GList*
|
||
|
+nsWaylandDragContext::GetTargets()
|
||
|
+{
|
||
|
+ int targetNums;
|
||
|
+ GdkAtom *atoms = mDataOffer->GetTargets(&targetNums);
|
||
|
+
|
||
|
+ GList* targetList = nullptr;
|
||
|
+ for (int i = 0; i < targetNums; i++) {
|
||
|
+ targetList = g_list_append(targetList, GDK_ATOM_TO_POINTER(atoms[i]));
|
||
|
+ }
|
||
|
+
|
||
|
+ return targetList;
|
||
|
+}
|
||
|
+
|
||
|
+char*
|
||
|
+nsWaylandDragContext::GetData(const char* aMimeType, uint32_t* aContentLength)
|
||
|
+{
|
||
|
+ mDataOffer->DragOfferAccept(aMimeType, mTime);
|
||
|
+ return mDataOffer->GetData(mDisplay, aMimeType, aContentLength);
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+nsRetrievalContextWayland::RegisterNewDataOffer(wl_data_offer *aWaylandDataOffer)
|
||
|
{
|
||
|
DataOffer* dataOffer =
|
||
|
static_cast<DataOffer*>(g_hash_table_lookup(mActiveOffers,
|
||
|
aWaylandDataOffer));
|
||
|
+ MOZ_ASSERT(dataOffer == nullptr,
|
||
|
+ "Registered WaylandDataOffer already exists. Wayland protocol error?");
|
||
|
+
|
||
|
if (!dataOffer) {
|
||
|
dataOffer = new WaylandDataOffer(aWaylandDataOffer);
|
||
|
g_hash_table_insert(mActiveOffers, aWaylandDataOffer, dataOffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
-nsRetrievalContextWayland::RegisterDataOffer(
|
||
|
+nsRetrievalContextWayland::RegisterNewDataOffer(
|
||
|
gtk_primary_selection_offer *aPrimaryDataOffer)
|
||
|
{
|
||
|
DataOffer* dataOffer =
|
||
|
static_cast<DataOffer*>(g_hash_table_lookup(mActiveOffers,
|
||
|
aPrimaryDataOffer));
|
||
|
+ MOZ_ASSERT(dataOffer == nullptr,
|
||
|
+ "Registered PrimaryDataOffer already exists. Wayland protocol error?");
|
||
|
+
|
||
|
if (!dataOffer) {
|
||
|
dataOffer = new PrimaryDataOffer(aPrimaryDataOffer);
|
||
|
g_hash_table_insert(mActiveOffers, aPrimaryDataOffer, dataOffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsRetrievalContextWayland::SetClipboardDataOffer(wl_data_offer *aWaylandDataOffer)
|
||
|
{
|
||
|
+ // Delete existing clipboard data offer
|
||
|
+ mClipboardOffer = nullptr;
|
||
|
+
|
||
|
DataOffer* dataOffer =
|
||
|
static_cast<DataOffer*>(g_hash_table_lookup(mActiveOffers,
|
||
|
aWaylandDataOffer));
|
||
|
NS_ASSERTION(dataOffer, "We're missing clipboard data offer!");
|
||
|
if (dataOffer) {
|
||
|
g_hash_table_remove(mActiveOffers, aWaylandDataOffer);
|
||
|
mClipboardOffer = dataOffer;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsRetrievalContextWayland::SetPrimaryDataOffer(
|
||
|
gtk_primary_selection_offer *aPrimaryDataOffer)
|
||
|
{
|
||
|
- if (aPrimaryDataOffer == nullptr) {
|
||
|
- // Release any primary offer we have.
|
||
|
- mPrimaryOffer = nullptr;
|
||
|
- } else {
|
||
|
+ // Release any primary offer we have.
|
||
|
+ mPrimaryOffer = nullptr;
|
||
|
+
|
||
|
+ // aPrimaryDataOffer can be null which means we lost
|
||
|
+ // the mouse selection.
|
||
|
+ if (aPrimaryDataOffer) {
|
||
|
DataOffer* dataOffer =
|
||
|
static_cast<DataOffer*>(g_hash_table_lookup(mActiveOffers,
|
||
|
aPrimaryDataOffer));
|
||
|
NS_ASSERTION(dataOffer, "We're missing primary data offer!");
|
||
|
if (dataOffer) {
|
||
|
g_hash_table_remove(mActiveOffers, aPrimaryDataOffer);
|
||
|
mPrimaryOffer = dataOffer;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
-nsRetrievalContextWayland::ClearDataOffers(void)
|
||
|
+nsRetrievalContextWayland::AddDragAndDropDataOffer(wl_data_offer *aDropDataOffer)
|
||
|
+{
|
||
|
+ // Remove any existing D&D contexts.
|
||
|
+ mDragContext = nullptr;
|
||
|
+
|
||
|
+ WaylandDataOffer* dataOffer =
|
||
|
+ static_cast<WaylandDataOffer*>(g_hash_table_lookup(mActiveOffers,
|
||
|
+ aDropDataOffer));
|
||
|
+ NS_ASSERTION(dataOffer, "We're missing drag and drop data offer!");
|
||
|
+ if (dataOffer) {
|
||
|
+ g_hash_table_remove(mActiveOffers, aDropDataOffer);
|
||
|
+ mDragContext = new nsWaylandDragContext(dataOffer, mDisplay);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+nsWaylandDragContext*
|
||
|
+nsRetrievalContextWayland::GetDragContext(void)
|
||
|
+{
|
||
|
+ return mDragContext;
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+nsRetrievalContextWayland::ClearClipboardDataOffers(void)
|
||
|
{
|
||
|
if (mClipboardOffer)
|
||
|
mClipboardOffer = nullptr;
|
||
|
if (mPrimaryOffer)
|
||
|
mPrimaryOffer = nullptr;
|
||
|
}
|
||
|
|
||
|
+void
|
||
|
+nsRetrievalContextWayland::ClearDragAndDropDataOffer(void)
|
||
|
+{
|
||
|
+ mDragContext = nullptr;
|
||
|
+}
|
||
|
+
|
||
|
// We have a new fresh data content.
|
||
|
// We should attach listeners to it and save for further use.
|
||
|
static void
|
||
|
data_device_data_offer (void *data,
|
||
|
struct wl_data_device *data_device,
|
||
|
struct wl_data_offer *offer)
|
||
|
{
|
||
|
nsRetrievalContextWayland *context =
|
||
|
static_cast<nsRetrievalContextWayland*>(data);
|
||
|
- context->RegisterDataOffer(offer);
|
||
|
+ context->RegisterNewDataOffer(offer);
|
||
|
}
|
||
|
|
||
|
// The new fresh data content is clipboard.
|
||
|
static void
|
||
|
data_device_selection (void *data,
|
||
|
struct wl_data_device *wl_data_device,
|
||
|
struct wl_data_offer *offer)
|
||
|
{
|
||
|
@@ -336,41 +541,88 @@ data_device_selection (void
|
||
|
}
|
||
|
|
||
|
// The new fresh wayland data content is drag and drop.
|
||
|
static void
|
||
|
data_device_enter (void *data,
|
||
|
struct wl_data_device *data_device,
|
||
|
uint32_t time,
|
||
|
struct wl_surface *surface,
|
||
|
- int32_t x,
|
||
|
- int32_t y,
|
||
|
+ int32_t x_fixed,
|
||
|
+ int32_t y_fixed,
|
||
|
struct wl_data_offer *offer)
|
||
|
{
|
||
|
+ nsRetrievalContextWayland *context =
|
||
|
+ static_cast<nsRetrievalContextWayland*>(data);
|
||
|
+ context->AddDragAndDropDataOffer(offer);
|
||
|
+
|
||
|
+ nsWaylandDragContext* dragContext = context->GetDragContext();
|
||
|
+
|
||
|
+ GtkWidget* gtkWidget = get_gtk_widget_for_wl_surface(surface);
|
||
|
+ if (!gtkWidget) {
|
||
|
+ NS_WARNING("DragAndDrop: Unable to get GtkWidget for wl_surface!");
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ LOGDRAG(("nsWindow data_device_enter for GtkWidget %p\n",
|
||
|
+ (void*)gtkWidget));
|
||
|
+
|
||
|
+ dragContext->DropDataEnter(gtkWidget, time,
|
||
|
+ wl_fixed_to_int(x_fixed),
|
||
|
+ wl_fixed_to_int(y_fixed));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
data_device_leave (void *data,
|
||
|
struct wl_data_device *data_device)
|
||
|
{
|
||
|
+ nsRetrievalContextWayland *context =
|
||
|
+ static_cast<nsRetrievalContextWayland*>(data);
|
||
|
+
|
||
|
+ nsWaylandDragContext* dropContext = context->GetDragContext();
|
||
|
+ WindowDragLeaveHandler(dropContext->GetWidget());
|
||
|
+
|
||
|
+ context->ClearDragAndDropDataOffer();
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
data_device_motion (void *data,
|
||
|
struct wl_data_device *data_device,
|
||
|
uint32_t time,
|
||
|
- int32_t x,
|
||
|
- int32_t y)
|
||
|
+ int32_t x_fixed,
|
||
|
+ int32_t y_fixed)
|
||
|
{
|
||
|
+ nsRetrievalContextWayland *context =
|
||
|
+ static_cast<nsRetrievalContextWayland*>(data);
|
||
|
+
|
||
|
+ nsWaylandDragContext* dropContext = context->GetDragContext();
|
||
|
+
|
||
|
+ nscoord x = wl_fixed_to_int(x_fixed);
|
||
|
+ nscoord y = wl_fixed_to_int(y_fixed);
|
||
|
+ dropContext->DropMotion(time, x, y);
|
||
|
+
|
||
|
+ WindowDragMotionHandler(dropContext->GetWidget(), nullptr,
|
||
|
+ dropContext, x, y, time);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
data_device_drop (void *data,
|
||
|
struct wl_data_device *data_device)
|
||
|
{
|
||
|
+ nsRetrievalContextWayland *context =
|
||
|
+ static_cast<nsRetrievalContextWayland*>(data);
|
||
|
+
|
||
|
+ nsWaylandDragContext* dropContext = context->GetDragContext();
|
||
|
+
|
||
|
+ uint32_t time;
|
||
|
+ nscoord x, y;
|
||
|
+ dropContext->GetLastDropInfo(&time, &x, &y);
|
||
|
+
|
||
|
+ WindowDragDropHandler(dropContext->GetWidget(), nullptr, dropContext,
|
||
|
+ x, y, time);
|
||
|
}
|
||
|
|
||
|
/* wl_data_device callback description:
|
||
|
*
|
||
|
* data_device_data_offer - It's called when there's a new wl_data_offer
|
||
|
* available. We need to attach wl_data_offer_listener
|
||
|
* to it to get available MIME types.
|
||
|
*
|
||
|
@@ -400,29 +652,41 @@ static const struct wl_data_device_liste
|
||
|
static void
|
||
|
primary_selection_data_offer (void *data,
|
||
|
struct gtk_primary_selection_device *gtk_primary_selection_device,
|
||
|
struct gtk_primary_selection_offer *gtk_primary_offer)
|
||
|
{
|
||
|
// create and add listener
|
||
|
nsRetrievalContextWayland *context =
|
||
|
static_cast<nsRetrievalContextWayland*>(data);
|
||
|
- context->RegisterDataOffer(gtk_primary_offer);
|
||
|
+ context->RegisterNewDataOffer(gtk_primary_offer);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
primary_selection_selection (void *data,
|
||
|
struct gtk_primary_selection_device *gtk_primary_selection_device,
|
||
|
struct gtk_primary_selection_offer *gtk_primary_offer)
|
||
|
{
|
||
|
nsRetrievalContextWayland *context =
|
||
|
static_cast<nsRetrievalContextWayland*>(data);
|
||
|
context->SetPrimaryDataOffer(gtk_primary_offer);
|
||
|
}
|
||
|
|
||
|
+/* gtk_primary_selection_device callback description:
|
||
|
+ *
|
||
|
+ * primary_selection_data_offer - It's called when there's a new
|
||
|
+ * gtk_primary_selection_offer available.
|
||
|
+ * We need to attach gtk_primary_selection_offer_listener
|
||
|
+ * to it to get available MIME types.
|
||
|
+ *
|
||
|
+ * primary_selection_selection - It's called when the new gtk_primary_selection_offer
|
||
|
+ * is a primary selection content. It can be also called with
|
||
|
+ * gtk_primary_selection_offer = null which means there's no
|
||
|
+ * primary selection.
|
||
|
+ */
|
||
|
static const struct
|
||
|
gtk_primary_selection_device_listener primary_selection_device_listener = {
|
||
|
primary_selection_data_offer,
|
||
|
primary_selection_selection,
|
||
|
};
|
||
|
|
||
|
bool
|
||
|
nsRetrievalContextWayland::HasSelectionSupport(void)
|
||
|
@@ -446,17 +710,17 @@ keyboard_handle_enter(void *data, struct
|
||
|
static void
|
||
|
keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
|
||
|
uint32_t serial, struct wl_surface *surface)
|
||
|
{
|
||
|
// We lost focus so our clipboard data are outdated
|
||
|
nsRetrievalContextWayland *context =
|
||
|
static_cast<nsRetrievalContextWayland*>(data);
|
||
|
|
||
|
- context->ClearDataOffers();
|
||
|
+ context->ClearClipboardDataOffers();
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
|
||
|
uint32_t serial, uint32_t time, uint32_t key,
|
||
|
uint32_t state)
|
||
|
{
|
||
|
}
|
||
|
@@ -568,16 +832,17 @@ nsRetrievalContextWayland::nsRetrievalCo
|
||
|
: mInitialized(false)
|
||
|
, mSeat(nullptr)
|
||
|
, mDataDeviceManager(nullptr)
|
||
|
, mPrimarySelectionDataDeviceManager(nullptr)
|
||
|
, mKeyboard(nullptr)
|
||
|
, mActiveOffers(g_hash_table_new(NULL, NULL))
|
||
|
, mClipboardOffer(nullptr)
|
||
|
, mPrimaryOffer(nullptr)
|
||
|
+ , mDragContext(nullptr)
|
||
|
, mClipboardRequestNumber(0)
|
||
|
, mClipboardData(nullptr)
|
||
|
, mClipboardDataLength(0)
|
||
|
{
|
||
|
// Available as of GTK 3.8+
|
||
|
static auto sGdkWaylandDisplayGetWlDisplay =
|
||
|
(wl_display *(*)(GdkDisplay *))
|
||
|
dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
|
||
|
@@ -611,18 +876,31 @@ nsRetrievalContextWayland::nsRetrievalCo
|
||
|
mSeat);
|
||
|
gtk_primary_selection_device_add_listener(primaryDataDevice,
|
||
|
&primary_selection_device_listener, this);
|
||
|
}
|
||
|
|
||
|
mInitialized = true;
|
||
|
}
|
||
|
|
||
|
+static gboolean
|
||
|
+offer_hash_remove(gpointer wl_offer, gpointer aDataOffer, gpointer user_data)
|
||
|
+{
|
||
|
+#ifdef DEBUG
|
||
|
+ nsPrintfCString msg("nsRetrievalContextWayland(): leaked nsDataOffer %p\n",
|
||
|
+ aDataOffer);
|
||
|
+ NS_WARNING(msg.get());
|
||
|
+#endif
|
||
|
+ delete static_cast<DataOffer*>(aDataOffer);
|
||
|
+ return true;
|
||
|
+}
|
||
|
+
|
||
|
nsRetrievalContextWayland::~nsRetrievalContextWayland(void)
|
||
|
{
|
||
|
+ g_hash_table_foreach_remove(mActiveOffers, offer_hash_remove, nullptr);
|
||
|
g_hash_table_destroy(mActiveOffers);
|
||
|
}
|
||
|
|
||
|
GdkAtom*
|
||
|
nsRetrievalContextWayland::GetTargets(int32_t aWhichClipboard,
|
||
|
int* aTargetNum)
|
||
|
{
|
||
|
if (GetSelectionAtom(aWhichClipboard) == GDK_SELECTION_CLIPBOARD) {
|
||
|
diff --git a/widget/gtk/nsClipboardWayland.h b/widget/gtk/nsClipboardWayland.h
|
||
|
--- a/widget/gtk/nsClipboardWayland.h
|
||
|
+++ b/widget/gtk/nsClipboardWayland.h
|
||
|
@@ -27,65 +27,108 @@ public:
|
||
|
|
||
|
char* GetData(wl_display* aDisplay, const char* aMimeType,
|
||
|
uint32_t* aContentLength);
|
||
|
|
||
|
virtual ~DataOffer() {};
|
||
|
private:
|
||
|
virtual bool RequestDataTransfer(const char* aMimeType, int fd) = 0;
|
||
|
|
||
|
+protected:
|
||
|
nsTArray<GdkAtom> mTargetMIMETypes;
|
||
|
};
|
||
|
|
||
|
class WaylandDataOffer : public DataOffer
|
||
|
{
|
||
|
public:
|
||
|
WaylandDataOffer(wl_data_offer* aWaylandDataOffer);
|
||
|
|
||
|
+ void DragOfferAccept(const char* aMimeType, uint32_t aTime);
|
||
|
+ void SetDragStatus(GdkDragAction aAction, uint32_t aTime);
|
||
|
+
|
||
|
+ GdkDragAction GetSelectedDragAction();
|
||
|
+ void SetSelectedDragAction(uint32_t aWaylandAction);
|
||
|
+
|
||
|
+ void SetSourceDragActions(uint32_t aWaylandActions);
|
||
|
+
|
||
|
+ virtual ~WaylandDataOffer();
|
||
|
private:
|
||
|
- virtual ~WaylandDataOffer();
|
||
|
bool RequestDataTransfer(const char* aMimeType, int fd) override;
|
||
|
|
||
|
wl_data_offer* mWaylandDataOffer;
|
||
|
+ uint32_t mSelectedDragAction;
|
||
|
};
|
||
|
|
||
|
class PrimaryDataOffer : public DataOffer
|
||
|
{
|
||
|
public:
|
||
|
PrimaryDataOffer(gtk_primary_selection_offer* aPrimaryDataOffer);
|
||
|
+ void SetAvailableDragActions(uint32_t aWaylandActions) {};
|
||
|
|
||
|
+ virtual ~PrimaryDataOffer();
|
||
|
private:
|
||
|
- virtual ~PrimaryDataOffer();
|
||
|
bool RequestDataTransfer(const char* aMimeType, int fd) override;
|
||
|
|
||
|
gtk_primary_selection_offer* mPrimaryDataOffer;
|
||
|
};
|
||
|
|
||
|
+class nsWaylandDragContext : public nsISupports
|
||
|
+{
|
||
|
+ NS_DECL_ISUPPORTS
|
||
|
+
|
||
|
+public:
|
||
|
+ nsWaylandDragContext(WaylandDataOffer* aWaylandDataOffer,
|
||
|
+ wl_display *aDisplay);
|
||
|
+
|
||
|
+ 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);
|
||
|
+
|
||
|
+ void SetDragStatus(GdkDragAction action);
|
||
|
+ GdkDragAction GetSelectedDragAction();
|
||
|
+
|
||
|
+ GtkWidget* GetWidget() { return mGtkWidget; }
|
||
|
+ GList* GetTargets();
|
||
|
+ char* GetData(const char* aMimeType, uint32_t* aContentLength);
|
||
|
+private:
|
||
|
+ virtual ~nsWaylandDragContext() {};
|
||
|
+
|
||
|
+ nsAutoPtr<WaylandDataOffer> mDataOffer;
|
||
|
+ wl_display* mDisplay;
|
||
|
+ uint32_t mTime;
|
||
|
+ GtkWidget* mGtkWidget;
|
||
|
+ nscoord mX, mY;
|
||
|
+};
|
||
|
+
|
||
|
class nsRetrievalContextWayland : public nsRetrievalContext
|
||
|
{
|
||
|
public:
|
||
|
nsRetrievalContextWayland();
|
||
|
|
||
|
virtual const char* GetClipboardData(const char* aMimeType,
|
||
|
int32_t aWhichClipboard,
|
||
|
uint32_t* aContentLength) override;
|
||
|
virtual const char* GetClipboardText(int32_t aWhichClipboard) override;
|
||
|
virtual void ReleaseClipboardData(const char* aClipboardData) override;
|
||
|
|
||
|
virtual GdkAtom* GetTargets(int32_t aWhichClipboard,
|
||
|
int* aTargetNum) override;
|
||
|
virtual bool HasSelectionSupport(void) override;
|
||
|
|
||
|
- void RegisterDataOffer(wl_data_offer *aWaylandDataOffer);
|
||
|
- void RegisterDataOffer(gtk_primary_selection_offer *aPrimaryDataOffer);
|
||
|
+ void RegisterNewDataOffer(wl_data_offer *aWaylandDataOffer);
|
||
|
+ void RegisterNewDataOffer(gtk_primary_selection_offer *aPrimaryDataOffer);
|
||
|
|
||
|
void SetClipboardDataOffer(wl_data_offer *aWaylandDataOffer);
|
||
|
void SetPrimaryDataOffer(gtk_primary_selection_offer *aPrimaryDataOffer);
|
||
|
+ void AddDragAndDropDataOffer(wl_data_offer *aWaylandDataOffer);
|
||
|
+ nsWaylandDragContext* GetDragContext();
|
||
|
|
||
|
- void ClearDataOffers();
|
||
|
+ void ClearClipboardDataOffers();
|
||
|
+ void ClearDragAndDropDataOffer();
|
||
|
|
||
|
void ConfigureKeyboard(wl_seat_capability caps);
|
||
|
void TransferFastTrackClipboard(int aClipboardRequestNumber,
|
||
|
GtkSelectionData *aSelectionData);
|
||
|
|
||
|
void InitDataDeviceManager(wl_registry *registry, uint32_t id, uint32_t version);
|
||
|
void InitPrimarySelectionDataDeviceManager(wl_registry *registry, uint32_t id);
|
||
|
void InitSeat(wl_registry *registry, uint32_t id, uint32_t version, void *data);
|
||
|
@@ -98,16 +141,17 @@ private:
|
||
|
wl_data_device_manager *mDataDeviceManager;
|
||
|
gtk_primary_selection_device_manager *mPrimarySelectionDataDeviceManager;
|
||
|
wl_keyboard *mKeyboard;
|
||
|
|
||
|
// Data offers provided by Wayland data device
|
||
|
GHashTable* mActiveOffers;
|
||
|
nsAutoPtr<DataOffer> mClipboardOffer;
|
||
|
nsAutoPtr<DataOffer> mPrimaryOffer;
|
||
|
+ RefPtr<nsWaylandDragContext> mDragContext;
|
||
|
|
||
|
int mClipboardRequestNumber;
|
||
|
char* mClipboardData;
|
||
|
uint32_t mClipboardDataLength;
|
||
|
|
||
|
// Mime types used for text data at Gtk+, see request_text_received_func()
|
||
|
// at gtkclipboard.c.
|
||
|
#define TEXT_MIME_TYPES_NUM 3
|
||
|
diff --git a/widget/gtk/nsDragService.cpp b/widget/gtk/nsDragService.cpp
|
||
|
--- a/widget/gtk/nsDragService.cpp
|
||
|
+++ b/widget/gtk/nsDragService.cpp
|
||
|
@@ -37,16 +37,19 @@
|
||
|
#include "nsViewManager.h"
|
||
|
#include "nsIFrame.h"
|
||
|
#include "nsGtkUtils.h"
|
||
|
#include "nsGtkKeyUtils.h"
|
||
|
#include "mozilla/gfx/2D.h"
|
||
|
#include "gfxPlatform.h"
|
||
|
#include "ScreenHelperGTK.h"
|
||
|
#include "nsArrayUtils.h"
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+#include "nsClipboardWayland.h"
|
||
|
+#endif
|
||
|
|
||
|
using namespace mozilla;
|
||
|
using namespace mozilla::gfx;
|
||
|
|
||
|
// This sets how opaque the drag image is
|
||
|
#define DRAG_IMAGE_ALPHA_LEVEL 0.5
|
||
|
|
||
|
// These values are copied from GtkDragResult (rather than using GtkDragResult
|
||
|
@@ -93,16 +96,20 @@ invisibleSourceDragDataGet(GtkWidget
|
||
|
GtkSelectionData *aSelectionData,
|
||
|
guint aInfo,
|
||
|
guint32 aTime,
|
||
|
gpointer aData);
|
||
|
|
||
|
nsDragService::nsDragService()
|
||
|
: mScheduledTask(eDragTaskNone)
|
||
|
, mTaskSource(0)
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+ , mPendingWaylandDragContext(nullptr)
|
||
|
+ , mTargetWaylandDragContext(nullptr)
|
||
|
+#endif
|
||
|
{
|
||
|
// We have to destroy the hidden widget before the event loop stops
|
||
|
// running.
|
||
|
nsCOMPtr<nsIObserverService> obsServ =
|
||
|
mozilla::services::GetObserverService();
|
||
|
obsServ->AddObserver(this, "quit-application", false);
|
||
|
|
||
|
// our hidden source widget
|
||
|
@@ -509,16 +516,19 @@ nsDragService::EndDragSession(bool aDone
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// unset our drag action
|
||
|
SetDragAction(DRAGDROP_ACTION_NONE);
|
||
|
|
||
|
// We're done with the drag context.
|
||
|
mTargetDragContextForRemote = nullptr;
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+ mTargetWaylandDragContextForRemote = nullptr;
|
||
|
+#endif
|
||
|
|
||
|
return nsBaseDragService::EndDragSession(aDoneDrag, aKeyModifiers);
|
||
|
}
|
||
|
|
||
|
// nsIDragSession
|
||
|
NS_IMETHODIMP
|
||
|
nsDragService::SetCanDrop(bool aCanDrop)
|
||
|
{
|
||
|
@@ -629,16 +639,24 @@ nsDragService::GetNumDropItems(uint32_t
|
||
|
if (!mTargetWidget) {
|
||
|
MOZ_LOG(sDragLm, LogLevel::Debug,
|
||
|
("*** warning: GetNumDropItems \
|
||
|
called without a valid target widget!\n"));
|
||
|
*aNumItems = 0;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+ // TODO: Wayland implementation of text/uri-list.
|
||
|
+ if (!mTargetDragContext) {
|
||
|
+ *aNumItems = 1;
|
||
|
+ return NS_OK;
|
||
|
+ }
|
||
|
+#endif
|
||
|
+
|
||
|
bool isList = IsTargetContextList();
|
||
|
if (isList)
|
||
|
mSourceDataItems->GetLength(aNumItems);
|
||
|
else {
|
||
|
GdkAtom gdkFlavor = gdk_atom_intern(gTextUriListType, FALSE);
|
||
|
GetTargetDragData(gdkFlavor);
|
||
|
if (mTargetDragData) {
|
||
|
const char *data = reinterpret_cast<char*>(mTargetDragData);
|
||
|
@@ -1020,19 +1038,28 @@ nsDragService::IsDataFlavorSupported(con
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
// check the target context vs. this flavor, one at a time
|
||
|
- GList *tmp;
|
||
|
- for (tmp = gdk_drag_context_list_targets(mTargetDragContext);
|
||
|
- tmp; tmp = tmp->next) {
|
||
|
+ GList *tmp = nullptr;
|
||
|
+ if (mTargetDragContext) {
|
||
|
+ tmp = gdk_drag_context_list_targets(mTargetDragContext);
|
||
|
+ }
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+ else {
|
||
|
+ tmp = mTargetWaylandDragContext->GetTargets();
|
||
|
+ }
|
||
|
+#endif
|
||
|
+ GList *tmp_head = tmp;
|
||
|
+
|
||
|
+ for (; tmp; tmp = tmp->next) {
|
||
|
/* Bug 331198 */
|
||
|
GdkAtom atom = GDK_POINTER_TO_ATOM(tmp->data);
|
||
|
gchar *name = nullptr;
|
||
|
name = gdk_atom_name(atom);
|
||
|
MOZ_LOG(sDragLm, LogLevel::Debug,
|
||
|
("checking %s against %s\n", name, aDataFlavor));
|
||
|
if (name && (strcmp(name, aDataFlavor) == 0)) {
|
||
|
MOZ_LOG(sDragLm, LogLevel::Debug, ("good!\n"));
|
||
|
@@ -1067,16 +1094,23 @@ nsDragService::IsDataFlavorSupported(con
|
||
|
(strcmp(aDataFlavor, kFileMime) == 0))) {
|
||
|
MOZ_LOG(sDragLm, LogLevel::Debug,
|
||
|
("good! ( it's text plain and we're checking \
|
||
|
against text/unicode or application/x-moz-file)\n"));
|
||
|
*_retval = true;
|
||
|
}
|
||
|
g_free(name);
|
||
|
}
|
||
|
+
|
||
|
+ // mTargetWaylandDragContext->GetTargets allocates the list
|
||
|
+ // so we need to free it here.
|
||
|
+ if (!mTargetDragContext) {
|
||
|
+ g_list_free(tmp_head);
|
||
|
+ }
|
||
|
+
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsDragService::ReplyToDragMotion(GdkDragContext* aDragContext)
|
||
|
{
|
||
|
MOZ_LOG(sDragLm, LogLevel::Debug,
|
||
|
("nsDragService::ReplyToDragMotion %d", mCanDrop));
|
||
|
@@ -1098,16 +1132,46 @@ nsDragService::ReplyToDragMotion(GdkDrag
|
||
|
action = GDK_ACTION_MOVE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
gdk_drag_status(aDragContext, action, mTargetTime);
|
||
|
}
|
||
|
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+void
|
||
|
+nsDragService::ReplyToDragMotion(nsWaylandDragContext* aDragContext)
|
||
|
+{
|
||
|
+ MOZ_LOG(sDragLm, LogLevel::Debug,
|
||
|
+ ("nsDragService::ReplyToDragMotion %d", mCanDrop));
|
||
|
+
|
||
|
+ GdkDragAction action = (GdkDragAction)0;
|
||
|
+ if (mCanDrop) {
|
||
|
+ // notify the dragger if we can drop
|
||
|
+ switch (mDragAction) {
|
||
|
+ case DRAGDROP_ACTION_COPY:
|
||
|
+ action = GDK_ACTION_COPY;
|
||
|
+ break;
|
||
|
+ case DRAGDROP_ACTION_LINK:
|
||
|
+ action = GDK_ACTION_LINK;
|
||
|
+ break;
|
||
|
+ case DRAGDROP_ACTION_NONE:
|
||
|
+ action = (GdkDragAction)0;
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ action = GDK_ACTION_MOVE;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ aDragContext->SetDragStatus(action);
|
||
|
+}
|
||
|
+#endif
|
||
|
+
|
||
|
void
|
||
|
nsDragService::TargetDataReceived(GtkWidget *aWidget,
|
||
|
GdkDragContext *aContext,
|
||
|
gint aX,
|
||
|
gint aY,
|
||
|
GtkSelectionData *aSelectionData,
|
||
|
guint aInfo,
|
||
|
guint32 aTime)
|
||
|
@@ -1129,16 +1193,22 @@ nsDragService::TargetDataReceived(GtkWid
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
nsDragService::IsTargetContextList(void)
|
||
|
{
|
||
|
bool retval = false;
|
||
|
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+ // TODO: We need a wayland implementation here.
|
||
|
+ if (!mTargetDragContext)
|
||
|
+ return retval;
|
||
|
+#endif
|
||
|
+
|
||
|
// gMimeListType drags only work for drags within a single process. The
|
||
|
// gtk_drag_get_source_widget() function will return nullptr if the source
|
||
|
// of the drag is another app, so we use it to check if a gMimeListType
|
||
|
// drop will work or not.
|
||
|
if (gtk_drag_get_source_widget(mTargetDragContext) == nullptr)
|
||
|
return retval;
|
||
|
|
||
|
GList *tmp;
|
||
|
@@ -1167,27 +1237,38 @@ void
|
||
|
nsDragService::GetTargetDragData(GdkAtom aFlavor)
|
||
|
{
|
||
|
MOZ_LOG(sDragLm, LogLevel::Debug, ("getting data flavor %p\n", aFlavor));
|
||
|
MOZ_LOG(sDragLm, LogLevel::Debug, ("mLastWidget is %p and mLastContext is %p\n",
|
||
|
mTargetWidget.get(),
|
||
|
mTargetDragContext.get()));
|
||
|
// reset our target data areas
|
||
|
TargetResetData();
|
||
|
- gtk_drag_get_data(mTargetWidget, mTargetDragContext, aFlavor, mTargetTime);
|
||
|
+
|
||
|
+ if (mTargetDragContext) {
|
||
|
+ gtk_drag_get_data(mTargetWidget, mTargetDragContext, aFlavor, mTargetTime);
|
||
|
|
||
|
- MOZ_LOG(sDragLm, LogLevel::Debug, ("about to start inner iteration."));
|
||
|
- PRTime entryTime = PR_Now();
|
||
|
- while (!mTargetDragDataReceived && mDoingDrag) {
|
||
|
- // check the number of iterations
|
||
|
- MOZ_LOG(sDragLm, LogLevel::Debug, ("doing iteration...\n"));
|
||
|
- PR_Sleep(20*PR_TicksPerSecond()/1000); /* sleep for 20 ms/iteration */
|
||
|
- if (PR_Now()-entryTime > NS_DND_TIMEOUT) break;
|
||
|
- gtk_main_iteration();
|
||
|
+ MOZ_LOG(sDragLm, LogLevel::Debug, ("about to start inner iteration."));
|
||
|
+ PRTime entryTime = PR_Now();
|
||
|
+ while (!mTargetDragDataReceived && mDoingDrag) {
|
||
|
+ // check the number of iterations
|
||
|
+ MOZ_LOG(sDragLm, LogLevel::Debug, ("doing iteration...\n"));
|
||
|
+ PR_Sleep(20*PR_TicksPerSecond()/1000); /* sleep for 20 ms/iteration */
|
||
|
+ if (PR_Now()-entryTime > NS_DND_TIMEOUT) break;
|
||
|
+ gtk_main_iteration();
|
||
|
+ }
|
||
|
}
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+ else {
|
||
|
+ mTargetDragData =
|
||
|
+ mTargetWaylandDragContext->GetData(gdk_atom_name(aFlavor),
|
||
|
+ &mTargetDragDataLen);
|
||
|
+ mTargetDragDataReceived = true;
|
||
|
+ }
|
||
|
+#endif
|
||
|
MOZ_LOG(sDragLm, LogLevel::Debug, ("finished inner iteration\n"));
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsDragService::TargetResetData(void)
|
||
|
{
|
||
|
mTargetDragDataReceived = false;
|
||
|
// make sure to free old data if we have to
|
||
|
@@ -1428,17 +1509,17 @@ nsDragService::SourceEndDragSession(GdkD
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (mDataTransfer) {
|
||
|
mDataTransfer->SetDropEffectInt(dropEffect);
|
||
|
}
|
||
|
|
||
|
// Schedule the appropriate drag end dom events.
|
||
|
- Schedule(eDragTaskSourceEnd, nullptr, nullptr, LayoutDeviceIntPoint(), 0);
|
||
|
+ Schedule(eDragTaskSourceEnd, nullptr, nullptr, nullptr, LayoutDeviceIntPoint(), 0);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
CreateUriList(nsIArray *items, gchar **text, gint *length)
|
||
|
{
|
||
|
uint32_t i, count;
|
||
|
GString *uriList = g_string_new(nullptr);
|
||
|
|
||
|
@@ -1778,64 +1859,68 @@ invisibleSourceDragEnd(GtkWidget
|
||
|
//
|
||
|
// No Gecko drag events are dispatched (during nested event loops) while other
|
||
|
// Gecko drag events are in flight. This helps event handlers that may not
|
||
|
// expect nested events, while accessing an event's dataTransfer for example.
|
||
|
|
||
|
gboolean
|
||
|
nsDragService::ScheduleMotionEvent(nsWindow *aWindow,
|
||
|
GdkDragContext *aDragContext,
|
||
|
+ nsWaylandDragContext *aWaylandDragContext,
|
||
|
LayoutDeviceIntPoint aWindowPoint, guint aTime)
|
||
|
{
|
||
|
- if (mScheduledTask == eDragTaskMotion) {
|
||
|
+ if (aDragContext && mScheduledTask == eDragTaskMotion) {
|
||
|
// The drag source has sent another motion message before we've
|
||
|
// replied to the previous. That shouldn't happen with Xdnd. The
|
||
|
// spec for Motif drags is less clear, but we'll just update the
|
||
|
// scheduled task with the new position reply only to the most
|
||
|
// recent message.
|
||
|
NS_WARNING("Drag Motion message received before previous reply was sent");
|
||
|
}
|
||
|
|
||
|
// Returning TRUE means we'll reply with a status message, unless we first
|
||
|
// get a leave.
|
||
|
- return Schedule(eDragTaskMotion, aWindow, aDragContext,
|
||
|
+ return Schedule(eDragTaskMotion, aWindow, aDragContext, aWaylandDragContext,
|
||
|
aWindowPoint, aTime);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsDragService::ScheduleLeaveEvent()
|
||
|
{
|
||
|
// We don't know at this stage whether a drop signal will immediately
|
||
|
// follow. If the drop signal gets sent it will happen before we return
|
||
|
// to the main loop and the scheduled leave task will be replaced.
|
||
|
- if (!Schedule(eDragTaskLeave, nullptr, nullptr, LayoutDeviceIntPoint(), 0)) {
|
||
|
+ if (!Schedule(eDragTaskLeave, nullptr, nullptr, nullptr,
|
||
|
+ LayoutDeviceIntPoint(), 0)) {
|
||
|
NS_WARNING("Drag leave after drop");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
gboolean
|
||
|
nsDragService::ScheduleDropEvent(nsWindow *aWindow,
|
||
|
GdkDragContext *aDragContext,
|
||
|
+ nsWaylandDragContext *aWaylandDragContext,
|
||
|
LayoutDeviceIntPoint aWindowPoint, guint aTime)
|
||
|
{
|
||
|
if (!Schedule(eDragTaskDrop, aWindow,
|
||
|
- aDragContext, aWindowPoint, aTime)) {
|
||
|
+ aDragContext, aWaylandDragContext, aWindowPoint, aTime)) {
|
||
|
NS_WARNING("Additional drag drop ignored");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
SetDragEndPoint(aWindowPoint + aWindow->WidgetToScreenOffset());
|
||
|
|
||
|
// We'll reply with gtk_drag_finish().
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
gboolean
|
||
|
nsDragService::Schedule(DragTask aTask, nsWindow *aWindow,
|
||
|
GdkDragContext *aDragContext,
|
||
|
+ nsWaylandDragContext *aWaylandDragContext,
|
||
|
LayoutDeviceIntPoint aWindowPoint, guint aTime)
|
||
|
{
|
||
|
// If there is an existing leave or motion task scheduled, then that
|
||
|
// will be replaced. When the new task is run, it will dispatch
|
||
|
// any necessary leave or motion events.
|
||
|
|
||
|
// If aTask is eDragTaskSourceEnd, then it will replace even a scheduled
|
||
|
// drop event (which could happen if the drop event has not been processed
|
||
|
@@ -1844,16 +1929,19 @@ nsDragService::Schedule(DragTask aTask,
|
||
|
// drop.
|
||
|
if (mScheduledTask == eDragTaskSourceEnd ||
|
||
|
(mScheduledTask == eDragTaskDrop && aTask != eDragTaskSourceEnd))
|
||
|
return FALSE;
|
||
|
|
||
|
mScheduledTask = aTask;
|
||
|
mPendingWindow = aWindow;
|
||
|
mPendingDragContext = aDragContext;
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+ mPendingWaylandDragContext = aWaylandDragContext;
|
||
|
+#endif
|
||
|
mPendingWindowPoint = aWindowPoint;
|
||
|
mPendingTime = aTime;
|
||
|
|
||
|
if (!mTaskSource) {
|
||
|
// High priority is used here because the native events involved have
|
||
|
// already waited at default priority. Perhaps a lower than default
|
||
|
// priority could be used for motion tasks because there is a chance
|
||
|
// that a leave or drop is waiting, but managing different priorities
|
||
|
@@ -1919,17 +2007,24 @@ nsDragService::RunScheduledTask()
|
||
|
// This may be the start of a destination drag session.
|
||
|
StartDragSession();
|
||
|
|
||
|
// mTargetWidget may be nullptr if the window has been destroyed.
|
||
|
// (The leave event is not scheduled if a drop task is still scheduled.)
|
||
|
// We still reply appropriately to indicate that the drop will or didn't
|
||
|
// succeeed.
|
||
|
mTargetWidget = mTargetWindow->GetMozContainerWidget();
|
||
|
- mTargetDragContext.steal(mPendingDragContext);
|
||
|
+ if (mTargetDragContext) {
|
||
|
+ mTargetDragContext.steal(mPendingDragContext);
|
||
|
+ }
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+ else {
|
||
|
+ mTargetWaylandDragContext = mPendingWaylandDragContext.forget();
|
||
|
+ }
|
||
|
+#endif
|
||
|
mTargetTime = mPendingTime;
|
||
|
|
||
|
// http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#drag-and-drop-processing-model
|
||
|
// (as at 27 December 2010) indicates that a "drop" event should only be
|
||
|
// fired (at the current target element) if the current drag operation is
|
||
|
// not none. The current drag operation will only be set to a non-none
|
||
|
// value during a "dragover" event.
|
||
|
//
|
||
|
@@ -1951,44 +2046,59 @@ nsDragService::RunScheduledTask()
|
||
|
// protocol is used.
|
||
|
if (task == eDragTaskMotion || positionHasChanged) {
|
||
|
UpdateDragAction();
|
||
|
TakeDragEventDispatchedToChildProcess(); // Clear the old value.
|
||
|
DispatchMotionEvents();
|
||
|
if (task == eDragTaskMotion) {
|
||
|
if (TakeDragEventDispatchedToChildProcess()) {
|
||
|
mTargetDragContextForRemote = mTargetDragContext;
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+ mTargetWaylandDragContextForRemote = mTargetWaylandDragContext;
|
||
|
+#endif
|
||
|
} else {
|
||
|
// Reply to tell the source whether we can drop and what
|
||
|
// action would be taken.
|
||
|
- ReplyToDragMotion(mTargetDragContext);
|
||
|
+ if (mTargetDragContext) {
|
||
|
+ ReplyToDragMotion(mTargetDragContext);
|
||
|
+ }
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+ else {
|
||
|
+ ReplyToDragMotion(mTargetWaylandDragContext);
|
||
|
+ }
|
||
|
+#endif
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (task == eDragTaskDrop) {
|
||
|
gboolean success = DispatchDropEvent();
|
||
|
|
||
|
// Perhaps we should set the del parameter to TRUE when the drag
|
||
|
// action is move, but we don't know whether the data was successfully
|
||
|
// transferred.
|
||
|
- gtk_drag_finish(mTargetDragContext, success,
|
||
|
- /* del = */ FALSE, mTargetTime);
|
||
|
+ if (mTargetDragContext) {
|
||
|
+ gtk_drag_finish(mTargetDragContext, success,
|
||
|
+ /* del = */ FALSE, mTargetTime);
|
||
|
+ }
|
||
|
|
||
|
// This drag is over, so clear out our reference to the previous
|
||
|
// window.
|
||
|
mTargetWindow = nullptr;
|
||
|
// Make sure to end the drag session. If this drag started in a
|
||
|
// different app, we won't get a drag_end signal to end it from.
|
||
|
EndDragSession(true, GetCurrentModifiers());
|
||
|
}
|
||
|
|
||
|
// We're done with the drag context.
|
||
|
mTargetWidget = nullptr;
|
||
|
mTargetDragContext = nullptr;
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+ mTargetWaylandDragContext = nullptr;
|
||
|
+#endif
|
||
|
|
||
|
// If we got another drag signal while running the sheduled task, that
|
||
|
// must have happened while running a nested event loop. Leave the task
|
||
|
// source on the event loop.
|
||
|
if (mScheduledTask != eDragTaskNone)
|
||
|
return TRUE;
|
||
|
|
||
|
// We have no task scheduled.
|
||
|
@@ -2008,17 +2118,26 @@ nsDragService::UpdateDragAction()
|
||
|
// nsContentUtils::SetDataTransferInEvent() to set the initial
|
||
|
// dataTransfer.dropEffect, so GdkDragContext::suggested_action would be
|
||
|
// more appropriate. GdkDragContext::actions should be used to set
|
||
|
// dataTransfer.effectAllowed, which doesn't currently happen with
|
||
|
// external sources.
|
||
|
|
||
|
// default is to do nothing
|
||
|
int action = nsIDragService::DRAGDROP_ACTION_NONE;
|
||
|
- GdkDragAction gdkAction = gdk_drag_context_get_actions(mTargetDragContext);
|
||
|
+ GdkDragAction gdkAction = GDK_ACTION_DEFAULT;
|
||
|
+ if (mTargetDragContext) {
|
||
|
+ gdkAction = gdk_drag_context_get_actions(mTargetDragContext);
|
||
|
+ }
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+ else {
|
||
|
+ // We got the selected D&D action from compositor on Wayland.
|
||
|
+ gdkAction = mTargetWaylandDragContext->GetSelectedDragAction();
|
||
|
+ }
|
||
|
+#endif
|
||
|
|
||
|
// set the default just in case nothing matches below
|
||
|
if (gdkAction & GDK_ACTION_DEFAULT)
|
||
|
action = nsIDragService::DRAGDROP_ACTION_MOVE;
|
||
|
|
||
|
// first check to see if move is set
|
||
|
if (gdkAction & GDK_ACTION_MOVE)
|
||
|
action = nsIDragService::DRAGDROP_ACTION_MOVE;
|
||
|
@@ -2037,16 +2156,22 @@ nsDragService::UpdateDragAction()
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsDragService::UpdateDragEffect()
|
||
|
{
|
||
|
if (mTargetDragContextForRemote) {
|
||
|
ReplyToDragMotion(mTargetDragContextForRemote);
|
||
|
mTargetDragContextForRemote = nullptr;
|
||
|
}
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+ else if (mTargetWaylandDragContextForRemote) {
|
||
|
+ ReplyToDragMotion(mTargetWaylandDragContextForRemote);
|
||
|
+ mTargetWaylandDragContextForRemote = nullptr;
|
||
|
+ }
|
||
|
+#endif
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
nsDragService::DispatchMotionEvents()
|
||
|
{
|
||
|
mCanDrop = false;
|
||
|
|
||
|
diff --git a/widget/gtk/nsDragService.h b/widget/gtk/nsDragService.h
|
||
|
--- a/widget/gtk/nsDragService.h
|
||
|
+++ b/widget/gtk/nsDragService.h
|
||
|
@@ -9,16 +9,17 @@
|
||
|
|
||
|
#include "mozilla/RefPtr.h"
|
||
|
#include "nsBaseDragService.h"
|
||
|
#include "nsIObserver.h"
|
||
|
#include "nsAutoRef.h"
|
||
|
#include <gtk/gtk.h>
|
||
|
|
||
|
class nsWindow;
|
||
|
+class nsWaylandDragContext;
|
||
|
|
||
|
namespace mozilla {
|
||
|
namespace gfx {
|
||
|
class SourceSurface;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifndef HAVE_NSGOBJECTREFTRAITS
|
||
|
@@ -93,21 +94,23 @@ public:
|
||
|
gint aX,
|
||
|
gint aY,
|
||
|
GtkSelectionData *aSelection_data,
|
||
|
guint aInfo,
|
||
|
guint32 aTime);
|
||
|
|
||
|
gboolean ScheduleMotionEvent(nsWindow *aWindow,
|
||
|
GdkDragContext *aDragContext,
|
||
|
+ nsWaylandDragContext* aPendingWaylandDragContext,
|
||
|
mozilla::LayoutDeviceIntPoint aWindowPoint,
|
||
|
guint aTime);
|
||
|
void ScheduleLeaveEvent();
|
||
|
gboolean ScheduleDropEvent(nsWindow *aWindow,
|
||
|
GdkDragContext *aDragContext,
|
||
|
+ nsWaylandDragContext* aPendingWaylandDragContext,
|
||
|
mozilla::LayoutDeviceIntPoint aWindowPoint,
|
||
|
guint aTime);
|
||
|
|
||
|
nsWindow* GetMostRecentDestWindow()
|
||
|
{
|
||
|
return mScheduledTask == eDragTaskNone ? mTargetWindow
|
||
|
: mPendingWindow;
|
||
|
}
|
||
|
@@ -153,30 +156,39 @@ private:
|
||
|
|
||
|
// mPendingWindow, mPendingWindowPoint, mPendingDragContext, and
|
||
|
// mPendingTime, carry information from the GTK signal that will be used
|
||
|
// when the scheduled task is run. mPendingWindow and mPendingDragContext
|
||
|
// will be nullptr if the scheduled task is eDragTaskLeave.
|
||
|
RefPtr<nsWindow> mPendingWindow;
|
||
|
mozilla::LayoutDeviceIntPoint mPendingWindowPoint;
|
||
|
nsCountedRef<GdkDragContext> mPendingDragContext;
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+ RefPtr<nsWaylandDragContext> mPendingWaylandDragContext;
|
||
|
+#endif
|
||
|
guint mPendingTime;
|
||
|
|
||
|
// mTargetWindow and mTargetWindowPoint record the position of the last
|
||
|
// eDragTaskMotion or eDragTaskDrop task that was run or is still running.
|
||
|
// mTargetWindow is cleared once the drag has completed or left.
|
||
|
RefPtr<nsWindow> mTargetWindow;
|
||
|
mozilla::LayoutDeviceIntPoint mTargetWindowPoint;
|
||
|
// mTargetWidget and mTargetDragContext are set only while dispatching
|
||
|
// motion or drop events. mTime records the corresponding timestamp.
|
||
|
nsCountedRef<GtkWidget> mTargetWidget;
|
||
|
nsCountedRef<GdkDragContext> mTargetDragContext;
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+ RefPtr<nsWaylandDragContext> mTargetWaylandDragContext;
|
||
|
+#endif
|
||
|
// mTargetDragContextForRemote is set while waiting for a reply from
|
||
|
// a child process.
|
||
|
nsCountedRef<GdkDragContext> mTargetDragContextForRemote;
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+ RefPtr<nsWaylandDragContext> mTargetWaylandDragContextForRemote;
|
||
|
+#endif
|
||
|
guint mTargetTime;
|
||
|
|
||
|
// is it OK to drop on us?
|
||
|
bool mCanDrop;
|
||
|
|
||
|
// have we received our drag data?
|
||
|
bool mTargetDragDataReceived;
|
||
|
// last data received and its length
|
||
|
@@ -207,22 +219,25 @@ private:
|
||
|
bool SetAlphaPixmap(SourceSurface *aPixbuf,
|
||
|
GdkDragContext *aContext,
|
||
|
int32_t aXOffset,
|
||
|
int32_t aYOffset,
|
||
|
const mozilla::LayoutDeviceIntRect &dragRect);
|
||
|
|
||
|
gboolean Schedule(DragTask aTask, nsWindow *aWindow,
|
||
|
GdkDragContext *aDragContext,
|
||
|
+ nsWaylandDragContext* aPendingWaylandDragContext,
|
||
|
mozilla::LayoutDeviceIntPoint aWindowPoint, guint aTime);
|
||
|
|
||
|
// Callback for g_idle_add_full() to run mScheduledTask.
|
||
|
static gboolean TaskDispatchCallback(gpointer data);
|
||
|
gboolean RunScheduledTask();
|
||
|
void UpdateDragAction();
|
||
|
void DispatchMotionEvents();
|
||
|
void ReplyToDragMotion(GdkDragContext* aDragContext);
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+ void ReplyToDragMotion(nsWaylandDragContext* aDragContext);
|
||
|
+#endif
|
||
|
gboolean DispatchDropEvent();
|
||
|
static uint32_t GetCurrentModifiers();
|
||
|
};
|
||
|
|
||
|
#endif // nsDragService_h__
|
||
|
-
|
||
|
diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp
|
||
|
--- a/widget/gtk/nsWindow.cpp
|
||
|
+++ b/widget/gtk/nsWindow.cpp
|
||
|
@@ -6081,23 +6081,23 @@ touch_event_cb(GtkWidget* aWidget, GdkEv
|
||
|
void
|
||
|
nsWindow::InitDragEvent(WidgetDragEvent &aEvent)
|
||
|
{
|
||
|
// set the keyboard modifiers
|
||
|
guint modifierState = KeymapWrapper::GetCurrentModifierState();
|
||
|
KeymapWrapper::InitInputEvent(aEvent, modifierState);
|
||
|
}
|
||
|
|
||
|
-static gboolean
|
||
|
-drag_motion_event_cb(GtkWidget *aWidget,
|
||
|
- GdkDragContext *aDragContext,
|
||
|
- gint aX,
|
||
|
- gint aY,
|
||
|
- guint aTime,
|
||
|
- gpointer aData)
|
||
|
+gboolean
|
||
|
+WindowDragMotionHandler(GtkWidget *aWidget,
|
||
|
+ GdkDragContext *aDragContext,
|
||
|
+ nsWaylandDragContext *aWaylandDragContext,
|
||
|
+ gint aX,
|
||
|
+ gint aY,
|
||
|
+ guint aTime)
|
||
|
{
|
||
|
RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
|
||
|
if (!window)
|
||
|
return FALSE;
|
||
|
|
||
|
// figure out which internal widget this drag motion actually happened on
|
||
|
nscoord retx = 0;
|
||
|
nscoord rety = 0;
|
||
|
@@ -6112,25 +6112,34 @@ drag_motion_event_cb(GtkWidget *aWidget,
|
||
|
}
|
||
|
|
||
|
LOGDRAG(("nsWindow drag-motion signal for %p\n", (void*)innerMostWindow));
|
||
|
|
||
|
LayoutDeviceIntPoint point = window->GdkPointToDevicePixels({ retx, rety });
|
||
|
|
||
|
RefPtr<nsDragService> dragService = nsDragService::GetInstance();
|
||
|
return dragService->
|
||
|
- ScheduleMotionEvent(innerMostWindow, aDragContext,
|
||
|
+ ScheduleMotionEvent(innerMostWindow, aDragContext, aWaylandDragContext,
|
||
|
point, aTime);
|
||
|
}
|
||
|
|
||
|
-static void
|
||
|
-drag_leave_event_cb(GtkWidget *aWidget,
|
||
|
- GdkDragContext *aDragContext,
|
||
|
- guint aTime,
|
||
|
- gpointer aData)
|
||
|
+static gboolean
|
||
|
+drag_motion_event_cb(GtkWidget *aWidget,
|
||
|
+ GdkDragContext *aDragContext,
|
||
|
+ gint aX,
|
||
|
+ gint aY,
|
||
|
+ guint aTime,
|
||
|
+ gpointer aData)
|
||
|
+{
|
||
|
+ return WindowDragMotionHandler(aWidget, aDragContext, nullptr,
|
||
|
+ aX, aY, aTime);
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+WindowDragLeaveHandler(GtkWidget *aWidget)
|
||
|
{
|
||
|
RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
|
||
|
if (!window)
|
||
|
return;
|
||
|
|
||
|
RefPtr<nsDragService> dragService = nsDragService::GetInstance();
|
||
|
|
||
|
nsWindow *mostRecentDragWindow = dragService->GetMostRecentDestWindow();
|
||
|
@@ -6153,24 +6162,32 @@ drag_leave_event_cb(GtkWidget *aWidget,
|
||
|
}
|
||
|
|
||
|
LOGDRAG(("nsWindow drag-leave signal for %p\n",
|
||
|
(void*)mostRecentDragWindow));
|
||
|
|
||
|
dragService->ScheduleLeaveEvent();
|
||
|
}
|
||
|
|
||
|
-
|
||
|
-static gboolean
|
||
|
-drag_drop_event_cb(GtkWidget *aWidget,
|
||
|
- GdkDragContext *aDragContext,
|
||
|
- gint aX,
|
||
|
- gint aY,
|
||
|
- guint aTime,
|
||
|
- gpointer aData)
|
||
|
+static void
|
||
|
+drag_leave_event_cb(GtkWidget *aWidget,
|
||
|
+ GdkDragContext *aDragContext,
|
||
|
+ guint aTime,
|
||
|
+ gpointer aData)
|
||
|
+{
|
||
|
+ WindowDragLeaveHandler(aWidget);
|
||
|
+}
|
||
|
+
|
||
|
+gboolean
|
||
|
+WindowDragDropHandler(GtkWidget *aWidget,
|
||
|
+ GdkDragContext *aDragContext,
|
||
|
+ nsWaylandDragContext *aWaylandDragContext,
|
||
|
+ gint aX,
|
||
|
+ gint aY,
|
||
|
+ guint aTime)
|
||
|
{
|
||
|
RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
|
||
|
if (!window)
|
||
|
return FALSE;
|
||
|
|
||
|
// figure out which internal widget this drag motion actually happened on
|
||
|
nscoord retx = 0;
|
||
|
nscoord rety = 0;
|
||
|
@@ -6185,20 +6202,31 @@ drag_drop_event_cb(GtkWidget *aWidget,
|
||
|
}
|
||
|
|
||
|
LOGDRAG(("nsWindow drag-drop signal for %p\n", (void*)innerMostWindow));
|
||
|
|
||
|
LayoutDeviceIntPoint point = window->GdkPointToDevicePixels({ retx, rety });
|
||
|
|
||
|
RefPtr<nsDragService> dragService = nsDragService::GetInstance();
|
||
|
return dragService->
|
||
|
- ScheduleDropEvent(innerMostWindow, aDragContext,
|
||
|
+ ScheduleDropEvent(innerMostWindow, aDragContext, aWaylandDragContext,
|
||
|
point, aTime);
|
||
|
}
|
||
|
|
||
|
+static gboolean
|
||
|
+drag_drop_event_cb(GtkWidget *aWidget,
|
||
|
+ GdkDragContext *aDragContext,
|
||
|
+ gint aX,
|
||
|
+ gint aY,
|
||
|
+ guint aTime,
|
||
|
+ gpointer aData)
|
||
|
+{
|
||
|
+ return WindowDragDropHandler(aWidget, aDragContext, nullptr, aX, aY, aTime);
|
||
|
+}
|
||
|
+
|
||
|
static void
|
||
|
drag_data_received_event_cb(GtkWidget *aWidget,
|
||
|
GdkDragContext *aDragContext,
|
||
|
gint aX,
|
||
|
gint aY,
|
||
|
GtkSelectionData *aSelectionData,
|
||
|
guint aInfo,
|
||
|
guint aTime,
|
||
|
diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h
|
||
|
--- a/widget/gtk/nsWindow.h
|
||
|
+++ b/widget/gtk/nsWindow.h
|
||
|
@@ -61,16 +61,31 @@ extern mozilla::LazyLogModule gWidgetDra
|
||
|
|
||
|
#define LOG(args)
|
||
|
#define LOGFOCUS(args)
|
||
|
#define LOGDRAG(args)
|
||
|
#define LOGDRAW(args)
|
||
|
|
||
|
#endif /* MOZ_LOGGING */
|
||
|
|
||
|
+#ifdef MOZ_WAYLAND
|
||
|
+class nsWaylandDragContext;
|
||
|
+
|
||
|
+gboolean
|
||
|
+WindowDragMotionHandler(GtkWidget *aWidget, GdkDragContext *aDragContext,
|
||
|
+ nsWaylandDragContext *aWaylandDragContext,
|
||
|
+ gint aX, gint aY, guint aTime);
|
||
|
+gboolean
|
||
|
+WindowDragDropHandler(GtkWidget *aWidget, GdkDragContext *aDragContext,
|
||
|
+ nsWaylandDragContext *aWaylandDragContext, gint aX, gint aY,
|
||
|
+ guint aTime);
|
||
|
+void
|
||
|
+WindowDragLeaveHandler(GtkWidget *aWidget);
|
||
|
+#endif
|
||
|
+
|
||
|
class gfxPattern;
|
||
|
|
||
|
namespace mozilla {
|
||
|
class TimeStamp;
|
||
|
class CurrentX11TimeGetter;
|
||
|
}
|
||
|
|
||
|
class nsWindow final : public nsBaseWidget
|
||
|
|