widget/windows/nsDragService.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include <ole2.h>
     7 #include <oleidl.h>
     8 #include <shlobj.h>
     9 #include <shlwapi.h>
    11 // shellapi.h is needed to build with WIN32_LEAN_AND_MEAN
    12 #include <shellapi.h>
    14 #include "nsDragService.h"
    15 #include "nsITransferable.h"
    16 #include "nsDataObj.h"
    18 #include "nsWidgetsCID.h"
    19 #include "nsNativeDragTarget.h"
    20 #include "nsNativeDragSource.h"
    21 #include "nsClipboard.h"
    22 #include "nsISupportsArray.h"
    23 #include "nsIDocument.h"
    24 #include "nsDataObjCollection.h"
    26 #include "nsAutoPtr.h"
    28 #include "nsString.h"
    29 #include "nsEscape.h"
    30 #include "nsISupportsPrimitives.h"
    31 #include "nsNetUtil.h"
    32 #include "nsIURL.h"
    33 #include "nsCWebBrowserPersist.h"
    34 #include "nsToolkit.h"
    35 #include "nsCRT.h"
    36 #include "nsDirectoryServiceDefs.h"
    37 #include "nsUnicharUtils.h"
    38 #include "gfxContext.h"
    39 #include "nsRect.h"
    40 #include "nsMathUtils.h"
    41 #include "gfxWindowsPlatform.h"
    42 #include "mozilla/gfx/2D.h"
    43 #include "mozilla/gfx/DataSurfaceHelpers.h"
    44 #include "mozilla/gfx/Tools.h"
    46 using namespace mozilla;
    47 using namespace mozilla::gfx;
    49 //-------------------------------------------------------------------------
    50 //
    51 // DragService constructor
    52 //
    53 //-------------------------------------------------------------------------
    54 nsDragService::nsDragService()
    55   : mDataObject(nullptr), mSentLocalDropEvent(false)
    56 {
    57 }
    59 //-------------------------------------------------------------------------
    60 //
    61 // DragService destructor
    62 //
    63 //-------------------------------------------------------------------------
    64 nsDragService::~nsDragService()
    65 {
    66   NS_IF_RELEASE(mDataObject);
    67 }
    69 bool
    70 nsDragService::CreateDragImage(nsIDOMNode *aDOMNode,
    71                                nsIScriptableRegion *aRegion,
    72                                SHDRAGIMAGE *psdi)
    73 {
    74   if (!psdi)
    75     return false;
    77   memset(psdi, 0, sizeof(SHDRAGIMAGE));
    78   if (!aDOMNode) 
    79     return false;
    81   // Prepare the drag image
    82   nsIntRect dragRect;
    83   RefPtr<SourceSurface> surface;
    84   nsPresContext* pc;
    85   DrawDrag(aDOMNode, aRegion,
    86            mScreenX, mScreenY,
    87            &dragRect, &surface, &pc);
    88   if (!surface)
    89     return false;
    91   uint32_t bmWidth = dragRect.width, bmHeight = dragRect.height;
    93   if (bmWidth == 0 || bmHeight == 0)
    94     return false;
    96   psdi->crColorKey = CLR_NONE;
    98   RefPtr<DataSourceSurface> dataSurface =
    99     Factory::CreateDataSourceSurface(IntSize(bmWidth, bmHeight),
   100                                      SurfaceFormat::B8G8R8A8);
   101   NS_ENSURE_TRUE(dataSurface, false);
   103   DataSourceSurface::MappedSurface map;
   104   if (!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) {
   105     return false;
   106   }
   108   RefPtr<DrawTarget> dt =
   109     Factory::CreateDrawTargetForData(BackendType::CAIRO,
   110                                      map.mData,
   111                                      dataSurface->GetSize(),
   112                                      map.mStride,
   113                                      dataSurface->GetFormat());
   114   if (!dt) {
   115     dataSurface->Unmap();
   116     return false;
   117   }
   119   dt->DrawSurface(surface,
   120                   Rect(0, 0, dataSurface->GetSize().width, dataSurface->GetSize().height),
   121                   Rect(0, 0, surface->GetSize().width, surface->GetSize().height),
   122                   DrawSurfaceOptions(),
   123                   DrawOptions(1.0f, CompositionOp::OP_SOURCE));
   124   dt->Flush();
   126   BITMAPV5HEADER bmih;
   127   memset((void*)&bmih, 0, sizeof(BITMAPV5HEADER));
   128   bmih.bV5Size        = sizeof(BITMAPV5HEADER);
   129   bmih.bV5Width       = bmWidth;
   130   bmih.bV5Height      = -(int32_t)bmHeight; // flip vertical
   131   bmih.bV5Planes      = 1;
   132   bmih.bV5BitCount    = 32;
   133   bmih.bV5Compression = BI_BITFIELDS;
   134   bmih.bV5RedMask     = 0x00FF0000;
   135   bmih.bV5GreenMask   = 0x0000FF00;
   136   bmih.bV5BlueMask    = 0x000000FF;
   137   bmih.bV5AlphaMask   = 0xFF000000;
   139   HDC hdcSrc = CreateCompatibleDC(nullptr);
   140   void *lpBits = nullptr;
   141   if (hdcSrc) {
   142     psdi->hbmpDragImage = 
   143     ::CreateDIBSection(hdcSrc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS,
   144                        (void**)&lpBits, nullptr, 0);
   145     if (psdi->hbmpDragImage && lpBits) {
   146       CopySurfaceDataToPackedArray(map.mData, static_cast<uint8_t*>(lpBits),
   147                                    dataSurface->GetSize(), map.mStride,
   148                                    BytesPerPixel(dataSurface->GetFormat()));
   149     }
   151     psdi->sizeDragImage.cx = bmWidth;
   152     psdi->sizeDragImage.cy = bmHeight;
   154     // Mouse position in center
   155     if (mScreenX == -1 || mScreenY == -1) {
   156       psdi->ptOffset.x = (uint32_t)((float)bmWidth/2.0f);
   157       psdi->ptOffset.y = (uint32_t)((float)bmHeight/2.0f);
   158     } else {
   159       int32_t sx = mScreenX, sy = mScreenY;
   160       ConvertToUnscaledDevPixels(pc, &sx, &sy);
   161       psdi->ptOffset.x = sx - dragRect.x;
   162       psdi->ptOffset.y = sy - dragRect.y;
   163     }
   165     DeleteDC(hdcSrc);
   166   }
   168   dataSurface->Unmap();
   170   return psdi->hbmpDragImage != nullptr;
   171 }
   173 //-------------------------------------------------------------------------
   174 NS_IMETHODIMP
   175 nsDragService::InvokeDragSession(nsIDOMNode *aDOMNode,
   176                                  nsISupportsArray *anArrayTransferables,
   177                                  nsIScriptableRegion *aRegion,
   178                                  uint32_t aActionType)
   179 {
   180   nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode,
   181                                                      anArrayTransferables,
   182                                                      aRegion,
   183                                                      aActionType);
   184   NS_ENSURE_SUCCESS(rv, rv);
   186   // Try and get source URI of the items that are being dragged
   187   nsIURI *uri = nullptr;
   189   nsCOMPtr<nsIDocument> doc(do_QueryInterface(mSourceDocument));
   190   if (doc) {
   191     uri = doc->GetDocumentURI();
   192   }
   194   uint32_t numItemsToDrag = 0;
   195   rv = anArrayTransferables->Count(&numItemsToDrag);
   196   if (!numItemsToDrag)
   197     return NS_ERROR_FAILURE;
   199   // The clipboard class contains some static utility methods that we
   200   // can use to create an IDataObject from the transferable
   202   // if we're dragging more than one item, we need to create a
   203   // "collection" object to fake out the OS. This collection contains
   204   // one |IDataObject| for each transferable. If there is just the one
   205   // (most cases), only pass around the native |IDataObject|.
   206   nsRefPtr<IDataObject> itemToDrag;
   207   if (numItemsToDrag > 1) {
   208     nsDataObjCollection * dataObjCollection = new nsDataObjCollection();
   209     if (!dataObjCollection)
   210       return NS_ERROR_OUT_OF_MEMORY;
   211     itemToDrag = dataObjCollection;
   212     for (uint32_t i=0; i<numItemsToDrag; ++i) {
   213       nsCOMPtr<nsISupports> supports;
   214       anArrayTransferables->GetElementAt(i, getter_AddRefs(supports));
   215       nsCOMPtr<nsITransferable> trans(do_QueryInterface(supports));
   216       if (trans) {
   217         nsRefPtr<IDataObject> dataObj;
   218         rv = nsClipboard::CreateNativeDataObject(trans,
   219                                                  getter_AddRefs(dataObj), uri);
   220         NS_ENSURE_SUCCESS(rv, rv);
   221         // Add the flavors to the collection object too
   222         rv = nsClipboard::SetupNativeDataObject(trans, dataObjCollection);
   223         NS_ENSURE_SUCCESS(rv, rv);
   225         dataObjCollection->AddDataObject(dataObj);
   226       }
   227     }
   228   } // if dragging multiple items
   229   else {
   230     nsCOMPtr<nsISupports> supports;
   231     anArrayTransferables->GetElementAt(0, getter_AddRefs(supports));
   232     nsCOMPtr<nsITransferable> trans(do_QueryInterface(supports));
   233     if (trans) {
   234       rv = nsClipboard::CreateNativeDataObject(trans,
   235                                                getter_AddRefs(itemToDrag),
   236                                                uri);
   237       NS_ENSURE_SUCCESS(rv, rv);
   238     }
   239   } // else dragging a single object
   241   // Create a drag image if support is available
   242   IDragSourceHelper *pdsh;
   243   if (SUCCEEDED(CoCreateInstance(CLSID_DragDropHelper, nullptr,
   244                                  CLSCTX_INPROC_SERVER,
   245                                  IID_IDragSourceHelper, (void**)&pdsh))) {
   246     SHDRAGIMAGE sdi;
   247     if (CreateDragImage(aDOMNode, aRegion, &sdi)) {
   248       if (FAILED(pdsh->InitializeFromBitmap(&sdi, itemToDrag)))
   249         DeleteObject(sdi.hbmpDragImage);
   250     }
   251     pdsh->Release();
   252   }
   254   // Kick off the native drag session
   255   return StartInvokingDragSession(itemToDrag, aActionType);
   256 }
   258 //-------------------------------------------------------------------------
   259 NS_IMETHODIMP
   260 nsDragService::StartInvokingDragSession(IDataObject * aDataObj,
   261                                         uint32_t aActionType)
   262 {
   263   // To do the drag we need to create an object that
   264   // implements the IDataObject interface (for OLE)
   265   nsRefPtr<nsNativeDragSource> nativeDragSrc =
   266     new nsNativeDragSource(mDataTransfer);
   268   // Now figure out what the native drag effect should be
   269   DWORD winDropRes;
   270   DWORD effects = DROPEFFECT_SCROLL;
   271   if (aActionType & DRAGDROP_ACTION_COPY) {
   272     effects |= DROPEFFECT_COPY;
   273   }
   274   if (aActionType & DRAGDROP_ACTION_MOVE) {
   275     effects |= DROPEFFECT_MOVE;
   276   }
   277   if (aActionType & DRAGDROP_ACTION_LINK) {
   278     effects |= DROPEFFECT_LINK;
   279   }
   281   // XXX not sure why we bother to cache this, it can change during
   282   // the drag
   283   mDragAction = aActionType;
   284   mSentLocalDropEvent = false;
   286   // Start dragging
   287   StartDragSession();
   288   OpenDragPopup();
   290   nsRefPtr<IAsyncOperation> pAsyncOp;
   291   // Offer to do an async drag
   292   if (SUCCEEDED(aDataObj->QueryInterface(IID_IAsyncOperation,
   293                                          getter_AddRefs(pAsyncOp)))) {
   294     pAsyncOp->SetAsyncMode(VARIANT_TRUE);
   295   } else {
   296     NS_NOTREACHED("When did our data object stop being async");
   297   }
   299   // Call the native D&D method
   300   HRESULT res = ::DoDragDrop(aDataObj, nativeDragSrc, effects, &winDropRes);
   302   // In  cases where the drop operation completed outside the application, update
   303   // the source node's nsIDOMDataTransfer dropEffect value so it is up to date.  
   304   if (!mSentLocalDropEvent) {
   305     uint32_t dropResult;
   306     // Order is important, since multiple flags can be returned.
   307     if (winDropRes & DROPEFFECT_COPY)
   308         dropResult = DRAGDROP_ACTION_COPY;
   309     else if (winDropRes & DROPEFFECT_LINK)
   310         dropResult = DRAGDROP_ACTION_LINK;
   311     else if (winDropRes & DROPEFFECT_MOVE)
   312         dropResult = DRAGDROP_ACTION_MOVE;
   313     else
   314         dropResult = DRAGDROP_ACTION_NONE;
   316     if (mDataTransfer) {
   317       if (res == DRAGDROP_S_DROP) // Success 
   318         mDataTransfer->SetDropEffectInt(dropResult);
   319       else
   320         mDataTransfer->SetDropEffectInt(DRAGDROP_ACTION_NONE);
   321     }
   322   }
   324   mUserCancelled = nativeDragSrc->UserCancelled();
   326   // We're done dragging, get the cursor position and end the drag
   327   // Use GetMessagePos to get the position of the mouse at the last message
   328   // seen by the event loop. (Bug 489729)
   329   // Note that we must convert this from device pixels back to Windows logical
   330   // pixels (bug 818927).
   331   DWORD pos = ::GetMessagePos();
   332   FLOAT dpiScale = gfxWindowsPlatform::GetPlatform()->GetDPIScale();
   333   nsIntPoint logPos(NSToIntRound(GET_X_LPARAM(pos) / dpiScale),
   334                     NSToIntRound(GET_Y_LPARAM(pos) / dpiScale));
   335   SetDragEndPoint(logPos);
   336   EndDragSession(true);
   338   mDoingDrag = false;
   340   return DRAGDROP_S_DROP == res ? NS_OK : NS_ERROR_FAILURE;
   341 }
   343 //-------------------------------------------------------------------------
   344 // Make Sure we have the right kind of object
   345 nsDataObjCollection*
   346 nsDragService::GetDataObjCollection(IDataObject* aDataObj)
   347 {
   348   nsDataObjCollection * dataObjCol = nullptr;
   349   if (aDataObj) {
   350     nsIDataObjCollection* dataObj;
   351     if (aDataObj->QueryInterface(IID_IDataObjCollection,
   352                                  (void**)&dataObj) == S_OK) {
   353       dataObjCol = static_cast<nsDataObjCollection*>(aDataObj);
   354       dataObj->Release();
   355     }
   356   }
   358   return dataObjCol;
   359 }
   361 //-------------------------------------------------------------------------
   362 NS_IMETHODIMP
   363 nsDragService::GetNumDropItems(uint32_t * aNumItems)
   364 {
   365   if (!mDataObject) {
   366     *aNumItems = 0;
   367     return NS_OK;
   368   }
   370   if (IsCollectionObject(mDataObject)) {
   371     nsDataObjCollection * dataObjCol = GetDataObjCollection(mDataObject);
   372     if (dataObjCol) {
   373       *aNumItems = dataObjCol->GetNumDataObjects();
   374     }
   375     else {
   376       // If the count cannot be determined just return 0.
   377       // This can happen if we have collection data of type 
   378       // MULTI_MIME ("Mozilla/IDataObjectCollectionFormat") on the clipboard
   379       // from another process but we can't obtain an IID_IDataObjCollection
   380       // from this process.
   381       *aNumItems = 0;
   382     }
   383   }
   384   else {
   385     // Next check if we have a file drop. Return the number of files in
   386     // the file drop as the number of items we have, pretending like we
   387     // actually have > 1 drag item.
   388     FORMATETC fe2;
   389     SET_FORMATETC(fe2, CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
   390     if (mDataObject->QueryGetData(&fe2) == S_OK) {
   391       STGMEDIUM stm;
   392       if (mDataObject->GetData(&fe2, &stm) == S_OK) {
   393         HDROP hdrop = (HDROP)GlobalLock(stm.hGlobal);
   394         *aNumItems = ::DragQueryFileW(hdrop, 0xFFFFFFFF, nullptr, 0);
   395         ::GlobalUnlock(stm.hGlobal);
   396         ::ReleaseStgMedium(&stm);
   397         // Data may be provided later, so assume we have 1 item
   398         if (*aNumItems == 0)
   399           *aNumItems = 1;
   400       }
   401       else
   402         *aNumItems = 1;
   403     }
   404     else
   405       *aNumItems = 1;
   406   }
   408   return NS_OK;
   409 }
   411 //-------------------------------------------------------------------------
   412 NS_IMETHODIMP
   413 nsDragService::GetData(nsITransferable * aTransferable, uint32_t anItem)
   414 {
   415   // This typcially happens on a drop, the target would be asking
   416   // for it's transferable to be filled in
   417   // Use a static clipboard utility method for this
   418   if (!mDataObject)
   419     return NS_ERROR_FAILURE;
   421   nsresult dataFound = NS_ERROR_FAILURE;
   423   if (IsCollectionObject(mDataObject)) {
   424     // multiple items, use |anItem| as an index into our collection
   425     nsDataObjCollection * dataObjCol = GetDataObjCollection(mDataObject);
   426     uint32_t cnt = dataObjCol->GetNumDataObjects();
   427     if (anItem >= 0 && anItem < cnt) {
   428       IDataObject * dataObj = dataObjCol->GetDataObjectAt(anItem);
   429       dataFound = nsClipboard::GetDataFromDataObject(dataObj, 0, nullptr,
   430                                                      aTransferable);
   431     }
   432     else
   433       NS_WARNING("Index out of range!");
   434   }
   435   else {
   436     // If they are asking for item "0", we can just get it...
   437     if (anItem == 0) {
   438        dataFound = nsClipboard::GetDataFromDataObject(mDataObject, anItem,
   439                                                       nullptr, aTransferable);
   440     } else {
   441       // It better be a file drop, or else non-zero indexes are invalid!
   442       FORMATETC fe2;
   443       SET_FORMATETC(fe2, CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
   444       if (mDataObject->QueryGetData(&fe2) == S_OK)
   445         dataFound = nsClipboard::GetDataFromDataObject(mDataObject, anItem,
   446                                                        nullptr, aTransferable);
   447       else
   448         NS_WARNING("Reqesting non-zero index, but clipboard data is not a collection!");
   449     }
   450   }
   451   return dataFound;
   452 }
   454 //---------------------------------------------------------
   455 NS_IMETHODIMP
   456 nsDragService::SetIDataObject(IDataObject * aDataObj)
   457 {
   458   // When the native drag starts the DragService gets
   459   // the IDataObject that is being dragged
   460   NS_IF_RELEASE(mDataObject);
   461   mDataObject = aDataObj;
   462   NS_IF_ADDREF(mDataObject);
   464   return NS_OK;
   465 }
   467 //---------------------------------------------------------
   468 void
   469 nsDragService::SetDroppedLocal()
   470 {
   471   // Sent from the native drag handler, letting us know
   472   // a drop occurred within the application vs. outside of it.
   473   mSentLocalDropEvent = true;
   474   return;
   475 }
   477 //-------------------------------------------------------------------------
   478 NS_IMETHODIMP
   479 nsDragService::IsDataFlavorSupported(const char *aDataFlavor, bool *_retval)
   480 {
   481   if (!aDataFlavor || !mDataObject || !_retval)
   482     return NS_ERROR_FAILURE;
   484 #ifdef DEBUG
   485   if (strcmp(aDataFlavor, kTextMime) == 0)
   486     NS_WARNING("DO NOT USE THE text/plain DATA FLAVOR ANY MORE. USE text/unicode INSTEAD");
   487 #endif
   489   *_retval = false;
   491   FORMATETC fe;
   492   UINT format = 0;
   494   if (IsCollectionObject(mDataObject)) {
   495     // We know we have one of our special collection objects.
   496     format = nsClipboard::GetFormat(aDataFlavor);
   497     SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1,
   498                   TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI);
   500     // See if any one of the IDataObjects in the collection supports
   501     // this data type
   502     nsDataObjCollection* dataObjCol = GetDataObjCollection(mDataObject);
   503     if (dataObjCol) {
   504       uint32_t cnt = dataObjCol->GetNumDataObjects();
   505       for (uint32_t i=0;i<cnt;++i) {
   506         IDataObject * dataObj = dataObjCol->GetDataObjectAt(i);
   507         if (S_OK == dataObj->QueryGetData(&fe))
   508           *_retval = true;             // found it!
   509       }
   510     }
   511   } // if special collection object
   512   else {
   513     // Ok, so we have a single object. Check to see if has the correct
   514     // data type. Since this can come from an outside app, we also
   515     // need to see if we need to perform text->unicode conversion if
   516     // the client asked for unicode and it wasn't available.
   517     format = nsClipboard::GetFormat(aDataFlavor);
   518     SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1,
   519                   TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI);
   520     if (mDataObject->QueryGetData(&fe) == S_OK)
   521       *_retval = true;                 // found it!
   522     else {
   523       // We haven't found the exact flavor the client asked for, but
   524       // maybe we can still find it from something else that's on the
   525       // clipboard
   526       if (strcmp(aDataFlavor, kUnicodeMime) == 0) {
   527         // client asked for unicode and it wasn't present, check if we
   528         // have CF_TEXT.  We'll handle the actual data substitution in
   529         // the data object.
   530         format = nsClipboard::GetFormat(kTextMime);
   531         SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1,
   532                       TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI);
   533         if (mDataObject->QueryGetData(&fe) == S_OK)
   534           *_retval = true;                 // found it!
   535       }
   536       else if (strcmp(aDataFlavor, kURLMime) == 0) {
   537         // client asked for a url and it wasn't present, but if we
   538         // have a file, then we have a URL to give them (the path, or
   539         // the internal URL if an InternetShortcut).
   540         format = nsClipboard::GetFormat(kFileMime);
   541         SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1,
   542                       TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI);
   543         if (mDataObject->QueryGetData(&fe) == S_OK)
   544           *_retval = true;                 // found it!
   545       }
   546     } // else try again
   547   }
   549   return NS_OK;
   550 }
   553 //
   554 // IsCollectionObject
   555 //
   556 // Determine if this is a single |IDataObject| or one of our private
   557 // collection objects. We know the difference because our collection
   558 // object will respond to supporting the private |MULTI_MIME| format.
   559 //
   560 bool
   561 nsDragService::IsCollectionObject(IDataObject* inDataObj)
   562 {
   563   bool isCollection = false;
   565   // setup the format object to ask for the MULTI_MIME format. We only
   566   // need to do this once
   567   static UINT sFormat = 0;
   568   static FORMATETC sFE;
   569   if (!sFormat) {
   570     sFormat = nsClipboard::GetFormat(MULTI_MIME);
   571     SET_FORMATETC(sFE, sFormat, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
   572   }
   574   // ask the object if it supports it. If yes, we have a collection
   575   // object
   576   if (inDataObj->QueryGetData(&sFE) == S_OK)
   577     isCollection = true;
   579   return isCollection;
   581 } // IsCollectionObject
   584 //
   585 // EndDragSession
   586 //
   587 // Override the default to make sure that we release the data object
   588 // when the drag ends. It seems that OLE doesn't like to let apps quit
   589 // w/out crashing when we're still holding onto their data
   590 //
   591 NS_IMETHODIMP
   592 nsDragService::EndDragSession(bool aDoneDrag)
   593 {
   594   // Bug 100180: If we've got mouse events captured, make sure we release it -
   595   // that way, if we happen to call EndDragSession before diving into a nested
   596   // event loop, we can still respond to mouse events.
   597   if (::GetCapture()) {
   598     ::ReleaseCapture();
   599   }
   601   nsBaseDragService::EndDragSession(aDoneDrag);
   602   NS_IF_RELEASE(mDataObject);
   604   return NS_OK;
   605 }

mercurial