Bug 329385, r+sr=jst
authorOlli.Pettay@helsinki.fi
Tue, 18 Mar 2008 17:06:22 -0700
changeset 13279 cbddfce243af3978b525908ddeb21e01f78c16c8
parent 13278 089ef5601add3cb37e2ed0f573066e0961d6af59
child 13280 e21edc92080901681c1d3977d90df22e99e254e2
push idunknown
push userunknown
push dateunknown
bugs329385
milestone1.9b5pre
Bug 329385, r+sr=jst
dom/src/base/nsGlobalWindow.cpp
widget/public/nsIDragService.idl
widget/src/xpwidgets/nsBaseDragService.cpp
widget/src/xpwidgets/nsBaseDragService.h
--- a/dom/src/base/nsGlobalWindow.cpp
+++ b/dom/src/base/nsGlobalWindow.cpp
@@ -189,16 +189,17 @@
 #include "nsBindingManager.h"
 #include "nsIXBLService.h"
 
 // used for popup blocking, needs to be converted to something
 // belonging to the back-end like nsIContentPolicy
 #include "nsIPopupWindowManager.h"
 
 #include "nsIPermissionManager.h"
+#include "nsIDragService.h"
 
 #ifdef MOZ_LOGGING
 // so we can get logging even in release builds
 #define FORCE_PR_LOG 1
 #endif
 #include "prlog.h"
 
 #ifdef PR_LOGGING
@@ -207,16 +208,18 @@ static PRLogModuleInfo* gDOMLeakPRLog;
 
 nsIFactory *nsGlobalWindow::sComputedDOMStyleFactory   = nsnull;
 
 static nsIEntropyCollector *gEntropyCollector          = nsnull;
 static PRInt32              gRefCnt                    = 0;
 static PRInt32              gOpenPopupSpamCount        = 0;
 static PopupControlState    gPopupControlState         = openAbused;
 static PRInt32              gRunningTimeoutDepth       = 0;
+static PRBool               gMouseDown                 = PR_FALSE;
+static PRBool               gDragServiceDisabled       = PR_FALSE;
 
 #ifdef DEBUG
 static PRUint32             gSerialCounter             = 0;
 #endif
 
 #ifdef DEBUG_jst
 PRInt32 gTimeoutCnt                                    = 0;
 #endif
@@ -2176,16 +2179,30 @@ nsGlobalWindow::PreHandleEvent(nsEventCh
       myCoord[0] = aVisitor.mEvent->refPoint.x;
       myCoord[1] = aVisitor.mEvent->refPoint.y;
       gEntropyCollector->RandomUpdate((void*)myCoord, sizeof(myCoord));
       gEntropyCollector->RandomUpdate((void*)&(aVisitor.mEvent->time),
                                       sizeof(PRUint32));
     }
   } else if (msg == NS_RESIZE_EVENT) {
     mIsHandlingResizeEvent = PR_TRUE;
+  } else if (msg == NS_MOUSE_BUTTON_DOWN &&
+             NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
+    gMouseDown = PR_TRUE;
+  } else if (msg == NS_MOUSE_BUTTON_UP &&
+             NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
+    gMouseDown = PR_FALSE;
+    if (gDragServiceDisabled) {
+      nsCOMPtr<nsIDragService> ds =
+        do_GetService("@mozilla.org/widget/dragservice;1");
+      if (ds) {
+        gDragServiceDisabled = PR_FALSE;
+        ds->Unsuppress();
+      }
+    }
   }
 
   aVisitor.mParentTarget = mChromeEventHandler;
   return NS_OK;
 }
 
 nsresult
 nsGlobalWindow::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
@@ -3942,18 +3959,29 @@ nsGlobalWindow::CanMoveResizeWindows()
 
   nsCOMPtr<nsIPermissionManager> pm =
     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, PR_FALSE);
   
   PRUint32 testResult;
   rv = pm->TestPermission(uri, "moveresize", &testResult);
   NS_ENSURE_SUCCESS(rv, PR_FALSE);
-  
-  return testResult == nsIPermissionManager::ALLOW_ACTION;
+
+  if (testResult == nsIPermissionManager::ALLOW_ACTION) {
+    if (gMouseDown && !gDragServiceDisabled) {
+      nsCOMPtr<nsIDragService> ds =
+        do_GetService("@mozilla.org/widget/dragservice;1");
+      if (ds) {
+        gDragServiceDisabled = PR_TRUE;
+        ds->Suppress();
+      }
+    }
+    return PR_TRUE;
+  }
+  return PR_FALSE;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::Alert(const nsAString& aString)
 {
   FORWARD_TO_OUTER(Alert, (aString), NS_ERROR_NOT_INITIALIZED);
 
   nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
--- a/widget/public/nsIDragService.idl
+++ b/widget/public/nsIDragService.idl
@@ -42,17 +42,17 @@
 #include "nsIDragSession.idl"
 #include "nsIScriptableRegion.idl"
 
 
 interface nsIDOMNode;
 interface nsIDOMMouseEvent;
 interface nsISelection;
 
-[scriptable, uuid(E8CD74A6-8BB6-4D27-9C65-4ED1B4398F8C)]
+[scriptable, uuid(034c44a4-604b-44a2-9205-676d5135f359)]
 interface nsIDragService : nsISupports
 {
   const long DRAGDROP_ACTION_NONE = 0;
   const long DRAGDROP_ACTION_COPY = 1;
   const long DRAGDROP_ACTION_MOVE = 2;
   const long DRAGDROP_ACTION_LINK = 4;
 
   /**
@@ -129,14 +129,21 @@ interface nsIDragService : nsISupports
     * just left the window.
     */
   void endDragSession ( in PRBool aDoneDrag ) ;
 
   /**
    * Fire a drag event at the source of the drag
    */
   void fireDragEventAtSource ( in unsigned long aMsg );
+
+  /**
+   * Increase/decrease dragging suppress level by one.
+   * If level is greater than one, dragging is disabled.
+   */
+  void suppress();
+  void unsuppress();
 };
 
 
 %{ C++
 
 %}
--- a/widget/src/xpwidgets/nsBaseDragService.cpp
+++ b/widget/src/xpwidgets/nsBaseDragService.cpp
@@ -74,17 +74,17 @@
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
 
 #define DRAGIMAGES_PREF "nglayout.enable_drag_images"
 
 nsBaseDragService::nsBaseDragService()
   : mCanDrop(PR_FALSE), mDoingDrag(PR_FALSE), mHasImage(PR_FALSE),
     mDragAction(DRAGDROP_ACTION_NONE), mTargetSize(0,0),
-    mImageX(0), mImageY(0), mScreenX(-1), mScreenY(-1)
+    mImageX(0), mImageY(0), mScreenX(-1), mScreenY(-1), mSuppressLevel(0)
 {
 }
 
 nsBaseDragService::~nsBaseDragService()
 {
 }
 
 NS_IMPL_ISUPPORTS2(nsBaseDragService, nsIDragService, nsIDragSession)
@@ -198,16 +198,17 @@ nsBaseDragService::IsDataFlavorSupported
 //-------------------------------------------------------------------------
 NS_IMETHODIMP
 nsBaseDragService::InvokeDragSession(nsIDOMNode *aDOMNode,
                                      nsISupportsArray* aTransferableArray,
                                      nsIScriptableRegion* aDragRgn,
                                      PRUint32 aActionType)
 {
   NS_ENSURE_TRUE(aDOMNode, NS_ERROR_INVALID_ARG);
+  NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE);
 
   // stash the document of the dom node
   aDOMNode->GetOwnerDocument(getter_AddRefs(mSourceDocument));
   mSourceNode = aDOMNode;
 
   // When the mouse goes down, the selection code starts a mouse
   // capture. However, this gets in the way of determining drag
   // feedback for things like trees because the event coordinates
@@ -236,16 +237,17 @@ nsBaseDragService::InvokeDragSessionWith
                                               nsISupportsArray* aTransferableArray,
                                               nsIScriptableRegion* aRegion,
                                               PRUint32 aActionType,
                                               nsIDOMNode* aImage,
                                               PRInt32 aImageX, PRInt32 aImageY,
                                               nsIDOMMouseEvent* aDragEvent)
 {
   NS_ENSURE_TRUE(aDragEvent, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE);
 
   mSelection = nsnull;
   mHasImage = PR_TRUE;
   mImage = aImage;
   mImageX = aImageX;
   mImageY = aImageY;
 
   aDragEvent->GetScreenX(&mScreenX);
@@ -257,16 +259,17 @@ nsBaseDragService::InvokeDragSessionWith
 NS_IMETHODIMP
 nsBaseDragService::InvokeDragSessionWithSelection(nsISelection* aSelection,
                                                   nsISupportsArray* aTransferableArray,
                                                   PRUint32 aActionType,
                                                   nsIDOMMouseEvent* aDragEvent)
 {
   NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(aDragEvent, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE);
 
   mSelection = aSelection;
   mHasImage = PR_TRUE;
   mImage = nsnull;
   mImageX = 0;
   mImageY = 0;
 
   aDragEvent->GetScreenX(&mScreenX);
@@ -283,17 +286,17 @@ nsBaseDragService::InvokeDragSessionWith
 NS_IMETHODIMP
 nsBaseDragService::GetCurrentSession(nsIDragSession ** aSession)
 {
   if (!aSession)
     return NS_ERROR_INVALID_ARG;
 
   // "this" also implements a drag session, so say we are one but only
   // if there is currently a drag going on.
-  if (mDoingDrag) {
+  if (!mSuppressLevel && mDoingDrag) {
     *aSession = this;
     NS_ADDREF(*aSession);      // addRef because we're a "getter"
   }
   else
     *aSession = nsnull;
 
   return NS_OK;
 }
@@ -312,17 +315,17 @@ nsBaseDragService::StartDragSession()
 //-------------------------------------------------------------------------
 NS_IMETHODIMP
 nsBaseDragService::EndDragSession(PRBool aDoneDrag)
 {
   if (!mDoingDrag) {
     return NS_ERROR_FAILURE;
   }
 
-  if (aDoneDrag)
+  if (aDoneDrag && !mSuppressLevel)
     FireDragEventAtSource(NS_DRAGDROP_END);
 
   mDoingDrag = PR_FALSE;
 
   // release the source we've been holding on to.
   mSourceDocument = nsnull;
   mSourceNode = nsnull;
   mSelection = nsnull;
@@ -334,17 +337,17 @@ nsBaseDragService::EndDragSession(PRBool
   mScreenY = -1;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsBaseDragService::FireDragEventAtSource(PRUint32 aMsg)
 {
-  if (mSourceNode) {
+  if (mSourceNode && !mSuppressLevel) {
     nsCOMPtr<nsIDocument> doc = do_QueryInterface(mSourceDocument);
     if (doc) {
       nsCOMPtr<nsIPresShell> presShell = doc->GetPrimaryShell();
       if (presShell) {
         nsEventStatus status = nsEventStatus_eIgnore;
         nsMouseEvent event(PR_TRUE, aMsg, nsnull, nsMouseEvent::eReal);
 
         nsCOMPtr<nsIContent> content = do_QueryInterface(mSourceNode);
@@ -573,8 +576,22 @@ void
 nsBaseDragService::ConvertToUnscaledDevPixels(nsPresContext* aPresContext,
                                               PRInt32* aScreenX, PRInt32* aScreenY)
 {
   PRInt32 adj = aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
   *aScreenX = nsPresContext::CSSPixelsToAppUnits(*aScreenX) / adj;
   *aScreenY = nsPresContext::CSSPixelsToAppUnits(*aScreenY) / adj;
 }
 
+NS_IMETHODIMP
+nsBaseDragService::Suppress()
+{
+  EndDragSession(PR_FALSE);
+  ++mSuppressLevel;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBaseDragService::Unsuppress()
+{
+  --mSuppressLevel;
+  return NS_OK;
+}
--- a/widget/src/xpwidgets/nsBaseDragService.h
+++ b/widget/src/xpwidgets/nsBaseDragService.h
@@ -141,11 +141,13 @@ protected:
   // set if a selection is being dragged
   nsCOMPtr<nsISelection> mSelection;
 
   // the screen position where drag gesture occured, used for positioning the
   // drag image when no image is specified. If a value is -1, no event was
   // supplied so the screen position is not known
   PRInt32 mScreenX;
   PRInt32 mScreenY;
+
+  PRUint32 mSuppressLevel;
 };
 
 #endif // nsBaseDragService_h__