b=479995 handle drag-failed signal when available. r=enndeakin sr=roc

This commit is contained in:
Karl Tomlinson 2009-06-20 13:38:27 +12:00
Родитель 3199b6a2ae
Коммит 2d4728db9e
3 изменённых файлов: 97 добавлений и 36 удалений

Просмотреть файл

@ -252,8 +252,9 @@ interface nsIDOMNSDataTransfer : nsISupports
nsIVariant mozGetDataAt(in DOMString format, in unsigned long index);
/**
* Will be true if the user cancelled the drag (typically by pressing Escape).
* This will be false otherwise, including if a drag failed for any other reason.
* Will be true when the user has cancelled the drag (typically by pressing
* Escape) and when the drag has been cancelled unexpectedly. This will be
* false otherwise, including when the drop has been rejected by its target.
* This property is only relevant for the dragend event.
*/
readonly attribute boolean mozUserCancelled;

Просмотреть файл

@ -72,6 +72,15 @@
// 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
// directly) so that this code can be compiled against versions of GTK+ that
// do not have GtkDragResult.
// GtkDragResult is available from GTK+ version 2.12.
enum {
MOZ_GTK_DRAG_RESULT_SUCCESS,
MOZ_GTK_DRAG_RESULT_NO_TARGET
};
static PRLogModuleInfo *sDragLm = NULL;
static const char gMimeListType[] = "application/x-moz-internal-item-list";
@ -83,6 +92,12 @@ invisibleSourceDragEnd(GtkWidget *aWidget,
GdkDragContext *aContext,
gpointer aData);
static gboolean
invisibleSourceDragFailed(GtkWidget *aWidget,
GdkDragContext *aContext,
gint aResult,
gpointer aData);
static void
invisibleSourceDragDataGet(GtkWidget *aWidget,
GdkDragContext *aContext,
@ -110,10 +125,19 @@ nsDragService::nsDragService()
G_CALLBACK(invisibleSourceDragDataGet), this);
g_signal_connect(GTK_OBJECT(mHiddenWidget), "drag_end",
G_CALLBACK(invisibleSourceDragEnd), this);
// drag-failed is available from GTK+ version 2.12
guint dragFailedID = g_signal_lookup("drag-failed",
G_TYPE_FROM_INSTANCE(mHiddenWidget));
if (dragFailedID) {
g_signal_connect_closure_by_id(mHiddenWidget, dragFailedID, 0,
g_cclosure_new(G_CALLBACK(invisibleSourceDragFailed),
this, NULL),
FALSE);
}
// set up our logging module
if (!sDragLm)
sDragLm = PR_NewLogModule("nsDragService");
sDragLm = PR_NewLogModule("nsDragService");
PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::nsDragService"));
mTargetWidget = 0;
mTargetDragContext = 0;
@ -1155,36 +1179,58 @@ nsDragService::GetSourceList(void)
}
void
nsDragService::SourceEndDrag(GdkDragContext *aContext)
nsDragService::SourceEndDragSession(GdkDragContext *aContext,
gint aResult)
{
// this just releases the list of data items that we provide
mSourceDataItems = nsnull;
if (!mDoingDrag)
return; // EndDragSession() was called on drop
return; // EndDragSession() was already called on drop or drag-failed
gint x, y;
GdkDisplay* display = gdk_display_get_default();
if (display) {
gdk_display_get_pointer(display, NULL, &x, &y, NULL);
SetDragEndPoint(nsIntPoint(x, y));
}
// Either the drag was aborted or the drop occurred outside the app.
// The dropEffect of mDataTransfer is not updated for motion outside the
// app, but is needed for the dragend event, so set it now.
// aContext->dest_window will be non-NULL only if the drop succeeded .
GdkDragAction action =
aContext->dest_window ? aContext->action : (GdkDragAction)0;
// Only one bit of action should be set, but, just in case someone does
// something funny, erring away from MOVE, and not recording unusual
// action combinations as NONE.
PRUint32 dropEffect;
if (!action)
if (aResult == MOZ_GTK_DRAG_RESULT_SUCCESS) {
// With GTK+ versions 2.10.x and prior the drag may have been
// cancelled (but no drag-failed signal would have been sent).
// aContext->dest_window will be non-NULL only if the drop was sent.
GdkDragAction action =
aContext->dest_window ? aContext->action : (GdkDragAction)0;
// Only one bit of action should be set, but, just in case someone
// does something funny, erring away from MOVE, and not recording
// unusual action combinations as NONE.
if (!action)
dropEffect = DRAGDROP_ACTION_NONE;
else if (action & GDK_ACTION_COPY)
dropEffect = DRAGDROP_ACTION_COPY;
else if (action & GDK_ACTION_LINK)
dropEffect = DRAGDROP_ACTION_LINK;
else if (action & GDK_ACTION_MOVE)
dropEffect = DRAGDROP_ACTION_MOVE;
else
dropEffect = DRAGDROP_ACTION_COPY;
} else {
dropEffect = DRAGDROP_ACTION_NONE;
else if (action & GDK_ACTION_COPY)
dropEffect = DRAGDROP_ACTION_COPY;
else if (action & GDK_ACTION_LINK)
dropEffect = DRAGDROP_ACTION_LINK;
else if (action & GDK_ACTION_MOVE)
dropEffect = DRAGDROP_ACTION_MOVE;
else
dropEffect = DRAGDROP_ACTION_COPY;
if (aResult != MOZ_GTK_DRAG_RESULT_NO_TARGET) {
mUserCancelled = PR_TRUE;
}
}
nsCOMPtr<nsIDOMNSDataTransfer> dataTransfer =
do_QueryInterface(mDataTransfer);
@ -1386,6 +1432,26 @@ invisibleSourceDragDataGet(GtkWidget *aWidget,
aSelectionData, aInfo, aTime);
}
/* static */
gboolean
invisibleSourceDragFailed(GtkWidget *aWidget,
GdkDragContext *aContext,
gint aResult,
gpointer aData)
{
PR_LOG(sDragLm, PR_LOG_DEBUG, ("invisibleSourceDragFailed %i", aResult));
nsDragService *dragService = (nsDragService *)aData;
// End the drag session now (rather than waiting for the drag-end signal)
// so that operations performed on dropEffect == none can start immediately
// rather than waiting for the drag-failed animation to finish.
dragService->SourceEndDragSession(aContext, aResult);
// We should return TRUE to disable the drag-failed animation iff the
// source performed an operation when dropEffect was none, but the handler
// of the dragend DOM event doesn't provide this information.
return FALSE;
}
/* static */
void
invisibleSourceDragEnd(GtkWidget *aWidget,
@ -1395,14 +1461,7 @@ invisibleSourceDragEnd(GtkWidget *aWidget,
PR_LOG(sDragLm, PR_LOG_DEBUG, ("invisibleSourceDragEnd"));
nsDragService *dragService = (nsDragService *)aData;
gint x, y;
GdkDisplay* display = gdk_display_get_default();
if (display) {
gdk_display_get_pointer(display, NULL, &x, &y, NULL);
dragService->SetDragEndPoint(nsIntPoint(x, y));
}
// The drag has ended. Release the hostages!
dragService->SourceEndDrag(aContext);
dragService->SourceEndDragSession(aContext, MOZ_GTK_DRAG_RESULT_SUCCESS);
}

Просмотреть файл

@ -98,18 +98,19 @@ public:
NS_IMETHOD TargetSetTimeCallback (nsIDragSessionGTKTimeCB aCallback);
// This is called when the drag started with the invisible widget
// finishes. It's called from within the drag service code but from
// a callback - it needs to be public.
void SourceEndDrag(GdkDragContext *aContext);
// 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,
guint info,
guint32 aTime);
// END PUBLIC API
private:
// target side vars