//-------------------------------------------------------------------------
NS_IMETHODIMP
nsDragService::StartInvokingDragSession(IDataObject * aDataObj,
                                        PRUint32 aActionType)
{
  // To do the drag we need to create an object that
  // implements the IDataObject interface (for OLE)
  nsNativeDragSource* nativeDragSource = new nsNativeDragSource(mDataTransfer);
  if (!nativeDragSource)
    return NS_ERROR_OUT_OF_MEMORY;

  NS_IF_RELEASE(mNativeDragSrc);
  mNativeDragSrc = (IDropSource *)nativeDragSource;
  mNativeDragSrc->AddRef();

  // Now figure out what the native drag effect should be
  DWORD winDropRes;
  DWORD effects = DROPEFFECT_SCROLL;
  if (aActionType & DRAGDROP_ACTION_COPY) {
    effects |= DROPEFFECT_COPY;
  }
  if (aActionType & DRAGDROP_ACTION_MOVE) {
    effects |= DROPEFFECT_MOVE;
  }
  if (aActionType & DRAGDROP_ACTION_LINK) {
    effects |= DROPEFFECT_LINK;
  }

  // XXX not sure why we bother to cache this, it can change during
  // the drag
  mDragAction = aActionType;
  mSentLocalDropEvent = PR_FALSE;

  // Start dragging
  StartDragSession();
  OpenDragPopup();

  nsRefPtr<IAsyncOperation> pAsyncOp;
  // Offer to do an async drag
  if (SUCCEEDED(aDataObj->QueryInterface(IID_IAsyncOperation,
                                         getter_AddRefs(pAsyncOp)))) {
    pAsyncOp->SetAsyncMode(VARIANT_TRUE);
  } else {
    NS_NOTREACHED("When did our data object stop being async");
  }

  // Call the native D&D method
  HRESULT res = ::DoDragDrop(aDataObj, mNativeDragSrc, effects, &winDropRes);

  // In  cases where the drop operation completed outside the application, update
  // the source node's nsIDOMNSDataTransfer dropEffect value so it is up to date.  
  if (!mSentLocalDropEvent) {
    PRUint32 dropResult;
    // Order is important, since multiple flags can be returned.
    if (winDropRes & DROPEFFECT_COPY)
        dropResult = DRAGDROP_ACTION_COPY;
    else if (winDropRes & DROPEFFECT_LINK)
        dropResult = DRAGDROP_ACTION_LINK;
    else if (winDropRes & DROPEFFECT_MOVE)
        dropResult = DRAGDROP_ACTION_MOVE;
    else
        dropResult = DRAGDROP_ACTION_NONE;
    
    nsCOMPtr<nsIDOMNSDataTransfer> dataTransfer =
      do_QueryInterface(mDataTransfer);

    if (dataTransfer) {
      if (res == DRAGDROP_S_DROP) // Success 
        dataTransfer->SetDropEffectInt(dropResult);
      else
        dataTransfer->SetDropEffectInt(DRAGDROP_ACTION_NONE);
    }
  }

  mUserCancelled = nativeDragSource->UserCancelled();

  // We're done dragging, get the cursor position and end the drag
  // Use GetMessagePos to get the position of the mouse at the last message
  // seen by the event loop. (Bug 489729)
  DWORD pos = ::GetMessagePos();
  POINT cpos;
  cpos.x = GET_X_LPARAM(pos);
  cpos.y = GET_Y_LPARAM(pos);
  SetDragEndPoint(nsIntPoint(cpos.x, cpos.y));
  EndDragSession(PR_TRUE);

  mDoingDrag = PR_FALSE;

  return DRAGDROP_S_DROP == res ? NS_OK : NS_ERROR_FAILURE;
}
示例#2
0
//
// InvokeDragSession
//
// Do all the work to kick it off.
//
NS_IMETHODIMP
nsDragService::InvokeDragSession (nsIDOMNode *aDOMNode, nsISupportsArray * aTransferableArray, nsIScriptableRegion * aDragRgn, PRUint32 aActionType)
{
#ifdef MOZ_WIDGET_COCOA
  nsGraphicsUtils::SetPortToKnownGoodPort();
  GrafPtr port;
  GDHandle handle;
  ::GetGWorld(&port, &handle);
  if (!IsValidPort(port))
  return NS_ERROR_FAILURE;
#endif

  ::InitCursor();
  nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode,
                                                     aTransferableArray,
                                                     aDragRgn, aActionType);
  NS_ENSURE_SUCCESS(rv, rv);
  
  DragReference theDragRef;
  OSErr result = ::NewDrag(&theDragRef);
  if ( result != noErr )
    return NS_ERROR_FAILURE;
  mDragRef = theDragRef;
#if DEBUG_DD
  printf("**** created drag ref %ld\n", theDragRef);
#endif
  
  Rect frameRect = { 0, 0, 0, 0 };
  RgnHandle theDragRgn = ::NewRgn();
  ::RectRgn(theDragRgn, &frameRect);

  if ( mImageDraggingSupported ) {
    Point	imgOffsetPt;
    imgOffsetPt.v = imgOffsetPt.h = 0;

    PRBool canUseRect = BuildDragRegion ( aDragRgn, aDOMNode, theDragRgn );
    if ( canUseRect ) {
      // passing in null for image's PixMapHandle to SetDragImage() means use bits on screen
      ::SetDragImage (theDragRef, nsnull, theDragRgn, imgOffsetPt, kDragDarkerTranslucency);
    }
  }
  else
    BuildDragRegion ( aDragRgn, aDOMNode, theDragRgn );

  // add the flavors from the transferables. Cache this array for the send data proc
  mDataItems = aTransferableArray;
  RegisterDragItemsAndFlavors(aTransferableArray, theDragRgn);

  // we have to synthesize the native event because we may be called from JavaScript
  // through XPConnect. In that case, we only have a DOM event and no way to
  // get to the native event. As a consequence, we just always fake it.
  EventRecord theEvent;
  theEvent.what = mouseDown;
  theEvent.message = 0L;
  theEvent.when = TickCount();
  theEvent.modifiers = 0L;

  // since we don't have the original mouseDown location, just assume the drag
  // started in the middle of the frame. This prevents us from having the mouse
  // and the region we're dragging separated by a big gap (which could happen if
  // we used the current mouse position). I know this isn't exactly right, and you can
  // see it if you're paying attention, but who pays such close attention?
  Rect dragRect;
  ::GetRegionBounds(theDragRgn, &dragRect);
  theEvent.where.v = dragRect.top + ((dragRect.bottom - dragRect.top) / 2);
  theEvent.where.h = dragRect.left + ((dragRect.right - dragRect.left) / 2);

  // register drag send proc which will call us back when asked for the actual
  // flavor data (instead of placing it all into the drag manager)
  ::SetDragSendProc ( theDragRef, mDragSendDataUPP, this );

  // start the drag. Be careful, mDragRef will be invalid AFTER this call (it is
  // reset by the dragTrackingHandler).
  StartDragSession();
  ::TrackDrag ( theDragRef, &theEvent, theDragRgn );
#ifndef MOZ_WIDGET_COCOA
  EndDragSession();
#else  // MOZ_WIDGET_COCOA
  if (mDoingDrag) {
    // An action proc inside of TrackDrag may have already ended the drag.
    EndDragSession();
  }
#endif  // MOZ_WIDGET_COCOA
  
  // clean up after ourselves 
  ::DisposeRgn ( theDragRgn );
  result = ::DisposeDrag ( theDragRef );
#if DEBUG_DD
  printf("**** disposing drag ref %ld\n", theDragRef);
#endif
  NS_ASSERTION ( result == noErr, "Error disposing drag" );
  mDragRef = 0L;
  mDataItems = nsnull;

  return NS_OK; 

} // InvokeDragSession