forked from mirrors/gecko-dev
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)
269 lines
10 KiB
C++
269 lines
10 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=4 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef nsDragService_h__
|
|
#define nsDragService_h__
|
|
|
|
#include "mozilla/RefPtr.h"
|
|
#include "nsBaseDragService.h"
|
|
#include "nsCOMArray.h"
|
|
#include "nsIObserver.h"
|
|
#include <gtk/gtk.h>
|
|
#include "nsITimer.h"
|
|
#include "GUniquePtr.h"
|
|
|
|
class nsICookieJarSettings;
|
|
class nsWindow;
|
|
|
|
namespace mozilla {
|
|
namespace gfx {
|
|
class SourceSurface;
|
|
}
|
|
} // namespace mozilla
|
|
|
|
/**
|
|
* Native GTK DragService wrapper
|
|
*/
|
|
|
|
class nsDragService final : public nsBaseDragService, public nsIObserver {
|
|
public:
|
|
nsDragService();
|
|
|
|
NS_DECL_ISUPPORTS_INHERITED
|
|
NS_DECL_NSIOBSERVER
|
|
|
|
// nsBaseDragService
|
|
MOZ_CAN_RUN_SCRIPT virtual nsresult InvokeDragSessionImpl(
|
|
nsIArray* anArrayTransferables,
|
|
const mozilla::Maybe<mozilla::CSSIntRegion>& aRegion,
|
|
uint32_t aActionType) override;
|
|
// nsIDragService
|
|
MOZ_CAN_RUN_SCRIPT NS_IMETHOD InvokeDragSession(
|
|
nsINode* aDOMNode, nsIPrincipal* aPrincipal,
|
|
nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings,
|
|
nsIArray* anArrayTransferables, uint32_t aActionType,
|
|
nsContentPolicyType aContentPolicyType) override;
|
|
NS_IMETHOD StartDragSession() override;
|
|
MOZ_CAN_RUN_SCRIPT NS_IMETHOD EndDragSession(bool aDoneDrag,
|
|
uint32_t aKeyModifiers) override;
|
|
|
|
// nsIDragSession
|
|
NS_IMETHOD SetCanDrop(bool aCanDrop) override;
|
|
NS_IMETHOD GetCanDrop(bool* aCanDrop) override;
|
|
NS_IMETHOD GetNumDropItems(uint32_t* aNumItems) override;
|
|
NS_IMETHOD GetData(nsITransferable* aTransferable,
|
|
uint32_t aItemIndex) override;
|
|
NS_IMETHOD IsDataFlavorSupported(const char* aDataFlavor,
|
|
bool* _retval) override;
|
|
|
|
// Update Drag&Drop state according child process state.
|
|
// UpdateDragEffect() is called by IPC bridge when child process
|
|
// accepts/denies D&D operation and uses stored
|
|
// mTargetDragContextForRemote context.
|
|
NS_IMETHOD UpdateDragEffect() override;
|
|
|
|
// Methods called from nsWindow to handle responding to GTK drag
|
|
// destination signals
|
|
|
|
static already_AddRefed<nsDragService> GetInstance();
|
|
|
|
void TargetDataReceived(GtkWidget* aWidget, GdkDragContext* aContext, gint aX,
|
|
gint aY, GtkSelectionData* aSelection_data,
|
|
guint aInfo, guint32 aTime);
|
|
|
|
gboolean ScheduleMotionEvent(nsWindow* aWindow, GdkDragContext* aDragContext,
|
|
mozilla::LayoutDeviceIntPoint aWindowPoint,
|
|
guint aTime);
|
|
void ScheduleLeaveEvent();
|
|
gboolean ScheduleDropEvent(nsWindow* aWindow, GdkDragContext* aDragContext,
|
|
mozilla::LayoutDeviceIntPoint aWindowPoint,
|
|
guint aTime);
|
|
|
|
nsWindow* GetMostRecentDestWindow() {
|
|
return mScheduledTask == eDragTaskNone ? mTargetWindow : mPendingWindow;
|
|
}
|
|
|
|
// END PUBLIC API
|
|
|
|
// These methods are public only so that they can be called from functions
|
|
// with C calling conventions. They are called for drags started with the
|
|
// invisible widget.
|
|
void SourceEndDragSession(GdkDragContext* aContext, gint aResult);
|
|
void SourceDataGet(GtkWidget* widget, GdkDragContext* context,
|
|
GtkSelectionData* selection_data, guint32 aTime);
|
|
bool SourceDataGetText(nsITransferable* aItem, const nsACString& aMIMEType,
|
|
bool aNeedToDoConversionToPlainText,
|
|
GtkSelectionData* aSelectionData);
|
|
void SourceDataGetImage(nsITransferable* aItem,
|
|
GtkSelectionData* aSelectionData);
|
|
void SourceDataGetXDND(nsITransferable* aItem, GdkDragContext* aContext,
|
|
GtkSelectionData* aSelectionData);
|
|
void SourceDataGetUriList(GdkDragContext* aContext,
|
|
GtkSelectionData* aSelectionData,
|
|
uint32_t aDragItems);
|
|
bool SourceDataAppendURLFileItem(nsACString& aURI, nsITransferable* aItem);
|
|
bool SourceDataAppendURLItem(nsITransferable* aItem, bool aExternalDrop,
|
|
nsACString& aURI);
|
|
|
|
void SourceBeginDrag(GdkDragContext* aContext);
|
|
|
|
// set the drag icon during drag-begin
|
|
void SetDragIcon(GdkDragContext* aContext);
|
|
|
|
class AutoEventLoop {
|
|
RefPtr<nsDragService> mService;
|
|
|
|
public:
|
|
explicit AutoEventLoop(RefPtr<nsDragService> aService)
|
|
: mService(std::move(aService)) {
|
|
mService->mEventLoopDepth++;
|
|
}
|
|
~AutoEventLoop() { mService->mEventLoopDepth--; }
|
|
};
|
|
int GetLoopDepth() const { return mEventLoopDepth; };
|
|
|
|
protected:
|
|
virtual ~nsDragService();
|
|
|
|
private:
|
|
// mScheduledTask indicates what signal has been received from GTK and
|
|
// so what needs to be dispatched when the scheduled task is run. It is
|
|
// eDragTaskNone when there is no task scheduled (but the
|
|
// previous task may still not have finished running).
|
|
enum DragTask {
|
|
eDragTaskNone,
|
|
eDragTaskMotion,
|
|
eDragTaskLeave,
|
|
eDragTaskDrop,
|
|
eDragTaskSourceEnd
|
|
};
|
|
DragTask mScheduledTask;
|
|
// mTaskSource is the GSource id for the task that is either scheduled
|
|
// or currently running. It is 0 if no task is scheduled or running.
|
|
guint mTaskSource;
|
|
bool mScheduledTaskIsRunning;
|
|
|
|
// Where the drag begins. We need to keep it open on Wayland.
|
|
RefPtr<nsWindow> mSourceWindow;
|
|
|
|
// target/destination side vars
|
|
// These variables keep track of the state of the current drag.
|
|
|
|
// 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;
|
|
RefPtr<GdkDragContext> mPendingDragContext;
|
|
|
|
// We cache all data for the current drag context,
|
|
// 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;
|
|
|
|
nsTHashMap<nsCStringHashKey, mozilla::GUniquePtr<gchar*>> mCachedUris;
|
|
|
|
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.
|
|
RefPtr<GtkWidget> mTargetWidget;
|
|
RefPtr<GdkDragContext> mTargetDragContext;
|
|
|
|
// When we route D'n'D request to child process
|
|
// (by EventStateManager::DispatchCrossProcessEvent)
|
|
// we save GdkDragContext to mTargetDragContextForRemote.
|
|
// When we get a reply from child process we use
|
|
// the stored GdkDragContext to send reply to OS.
|
|
//
|
|
// We need to store GdkDragContext because mTargetDragContext is cleared
|
|
// after every D'n'D event.
|
|
RefPtr<GdkDragContext> mTargetDragContextForRemote;
|
|
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
|
|
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 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
|
|
// aDragContext is different than mCachedDragContext.
|
|
void EnsureCachedDataValidForContext(GdkDragContext* aDragContext);
|
|
|
|
// source side vars
|
|
|
|
// the source of our drags
|
|
GtkWidget* mHiddenWidget;
|
|
// our source data items
|
|
nsCOMPtr<nsIArray> mSourceDataItems;
|
|
|
|
// get a list of the sources in gtk's format
|
|
GtkTargetList* GetSourceList(void);
|
|
|
|
// attempts to create a semi-transparent drag image. Returns TRUE if
|
|
// successful, FALSE if not
|
|
bool SetAlphaPixmap(SourceSurface* aPixbuf, GdkDragContext* aContext,
|
|
int32_t aXOffset, int32_t aYOffset,
|
|
const mozilla::LayoutDeviceIntRect& dragRect);
|
|
|
|
gboolean Schedule(DragTask aTask, nsWindow* aWindow,
|
|
GdkDragContext* aDragContext,
|
|
mozilla::LayoutDeviceIntPoint aWindowPoint, guint aTime);
|
|
|
|
// Callback for g_idle_add_full() to run mScheduledTask.
|
|
MOZ_CAN_RUN_SCRIPT static gboolean TaskDispatchCallback(gpointer data);
|
|
MOZ_CAN_RUN_SCRIPT gboolean RunScheduledTask();
|
|
MOZ_CAN_RUN_SCRIPT void DispatchMotionEvents();
|
|
void ReplyToDragMotion(GdkDragContext* aDragContext, guint aTime);
|
|
void ReplyToDragMotion();
|
|
void UpdateDragAction(GdkDragContext* aDragContext);
|
|
void UpdateDragAction();
|
|
|
|
#ifdef MOZ_LOGGING
|
|
const char* GetDragServiceTaskName(nsDragService::DragTask aTask);
|
|
#endif
|
|
void GetDragFlavors(nsTArray<nsCString>& aFlavors);
|
|
gboolean DispatchDropEvent();
|
|
static uint32_t GetCurrentModifiers();
|
|
|
|
nsresult CreateTempFile(nsITransferable* aItem, nsACString& aURI);
|
|
bool RemoveTempFiles();
|
|
static gboolean TaskRemoveTempFiles(gpointer data);
|
|
|
|
// the url of the temporary file that has been created in the current drag
|
|
// session
|
|
nsTArray<nsCString> mTempFileUrls;
|
|
// stores all temporary files
|
|
nsCOMArray<nsIFile> mTemporaryFiles;
|
|
// timer to trigger deletion of temporary files
|
|
guint mTempFileTimerID;
|
|
// How deep we're nested in event loops
|
|
int mEventLoopDepth;
|
|
};
|
|
|
|
#endif // nsDragService_h__
|