1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/windows/nsDragService.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,605 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include <ole2.h> 1.10 +#include <oleidl.h> 1.11 +#include <shlobj.h> 1.12 +#include <shlwapi.h> 1.13 + 1.14 +// shellapi.h is needed to build with WIN32_LEAN_AND_MEAN 1.15 +#include <shellapi.h> 1.16 + 1.17 +#include "nsDragService.h" 1.18 +#include "nsITransferable.h" 1.19 +#include "nsDataObj.h" 1.20 + 1.21 +#include "nsWidgetsCID.h" 1.22 +#include "nsNativeDragTarget.h" 1.23 +#include "nsNativeDragSource.h" 1.24 +#include "nsClipboard.h" 1.25 +#include "nsISupportsArray.h" 1.26 +#include "nsIDocument.h" 1.27 +#include "nsDataObjCollection.h" 1.28 + 1.29 +#include "nsAutoPtr.h" 1.30 + 1.31 +#include "nsString.h" 1.32 +#include "nsEscape.h" 1.33 +#include "nsISupportsPrimitives.h" 1.34 +#include "nsNetUtil.h" 1.35 +#include "nsIURL.h" 1.36 +#include "nsCWebBrowserPersist.h" 1.37 +#include "nsToolkit.h" 1.38 +#include "nsCRT.h" 1.39 +#include "nsDirectoryServiceDefs.h" 1.40 +#include "nsUnicharUtils.h" 1.41 +#include "gfxContext.h" 1.42 +#include "nsRect.h" 1.43 +#include "nsMathUtils.h" 1.44 +#include "gfxWindowsPlatform.h" 1.45 +#include "mozilla/gfx/2D.h" 1.46 +#include "mozilla/gfx/DataSurfaceHelpers.h" 1.47 +#include "mozilla/gfx/Tools.h" 1.48 + 1.49 +using namespace mozilla; 1.50 +using namespace mozilla::gfx; 1.51 + 1.52 +//------------------------------------------------------------------------- 1.53 +// 1.54 +// DragService constructor 1.55 +// 1.56 +//------------------------------------------------------------------------- 1.57 +nsDragService::nsDragService() 1.58 + : mDataObject(nullptr), mSentLocalDropEvent(false) 1.59 +{ 1.60 +} 1.61 + 1.62 +//------------------------------------------------------------------------- 1.63 +// 1.64 +// DragService destructor 1.65 +// 1.66 +//------------------------------------------------------------------------- 1.67 +nsDragService::~nsDragService() 1.68 +{ 1.69 + NS_IF_RELEASE(mDataObject); 1.70 +} 1.71 + 1.72 +bool 1.73 +nsDragService::CreateDragImage(nsIDOMNode *aDOMNode, 1.74 + nsIScriptableRegion *aRegion, 1.75 + SHDRAGIMAGE *psdi) 1.76 +{ 1.77 + if (!psdi) 1.78 + return false; 1.79 + 1.80 + memset(psdi, 0, sizeof(SHDRAGIMAGE)); 1.81 + if (!aDOMNode) 1.82 + return false; 1.83 + 1.84 + // Prepare the drag image 1.85 + nsIntRect dragRect; 1.86 + RefPtr<SourceSurface> surface; 1.87 + nsPresContext* pc; 1.88 + DrawDrag(aDOMNode, aRegion, 1.89 + mScreenX, mScreenY, 1.90 + &dragRect, &surface, &pc); 1.91 + if (!surface) 1.92 + return false; 1.93 + 1.94 + uint32_t bmWidth = dragRect.width, bmHeight = dragRect.height; 1.95 + 1.96 + if (bmWidth == 0 || bmHeight == 0) 1.97 + return false; 1.98 + 1.99 + psdi->crColorKey = CLR_NONE; 1.100 + 1.101 + RefPtr<DataSourceSurface> dataSurface = 1.102 + Factory::CreateDataSourceSurface(IntSize(bmWidth, bmHeight), 1.103 + SurfaceFormat::B8G8R8A8); 1.104 + NS_ENSURE_TRUE(dataSurface, false); 1.105 + 1.106 + DataSourceSurface::MappedSurface map; 1.107 + if (!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) { 1.108 + return false; 1.109 + } 1.110 + 1.111 + RefPtr<DrawTarget> dt = 1.112 + Factory::CreateDrawTargetForData(BackendType::CAIRO, 1.113 + map.mData, 1.114 + dataSurface->GetSize(), 1.115 + map.mStride, 1.116 + dataSurface->GetFormat()); 1.117 + if (!dt) { 1.118 + dataSurface->Unmap(); 1.119 + return false; 1.120 + } 1.121 + 1.122 + dt->DrawSurface(surface, 1.123 + Rect(0, 0, dataSurface->GetSize().width, dataSurface->GetSize().height), 1.124 + Rect(0, 0, surface->GetSize().width, surface->GetSize().height), 1.125 + DrawSurfaceOptions(), 1.126 + DrawOptions(1.0f, CompositionOp::OP_SOURCE)); 1.127 + dt->Flush(); 1.128 + 1.129 + BITMAPV5HEADER bmih; 1.130 + memset((void*)&bmih, 0, sizeof(BITMAPV5HEADER)); 1.131 + bmih.bV5Size = sizeof(BITMAPV5HEADER); 1.132 + bmih.bV5Width = bmWidth; 1.133 + bmih.bV5Height = -(int32_t)bmHeight; // flip vertical 1.134 + bmih.bV5Planes = 1; 1.135 + bmih.bV5BitCount = 32; 1.136 + bmih.bV5Compression = BI_BITFIELDS; 1.137 + bmih.bV5RedMask = 0x00FF0000; 1.138 + bmih.bV5GreenMask = 0x0000FF00; 1.139 + bmih.bV5BlueMask = 0x000000FF; 1.140 + bmih.bV5AlphaMask = 0xFF000000; 1.141 + 1.142 + HDC hdcSrc = CreateCompatibleDC(nullptr); 1.143 + void *lpBits = nullptr; 1.144 + if (hdcSrc) { 1.145 + psdi->hbmpDragImage = 1.146 + ::CreateDIBSection(hdcSrc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, 1.147 + (void**)&lpBits, nullptr, 0); 1.148 + if (psdi->hbmpDragImage && lpBits) { 1.149 + CopySurfaceDataToPackedArray(map.mData, static_cast<uint8_t*>(lpBits), 1.150 + dataSurface->GetSize(), map.mStride, 1.151 + BytesPerPixel(dataSurface->GetFormat())); 1.152 + } 1.153 + 1.154 + psdi->sizeDragImage.cx = bmWidth; 1.155 + psdi->sizeDragImage.cy = bmHeight; 1.156 + 1.157 + // Mouse position in center 1.158 + if (mScreenX == -1 || mScreenY == -1) { 1.159 + psdi->ptOffset.x = (uint32_t)((float)bmWidth/2.0f); 1.160 + psdi->ptOffset.y = (uint32_t)((float)bmHeight/2.0f); 1.161 + } else { 1.162 + int32_t sx = mScreenX, sy = mScreenY; 1.163 + ConvertToUnscaledDevPixels(pc, &sx, &sy); 1.164 + psdi->ptOffset.x = sx - dragRect.x; 1.165 + psdi->ptOffset.y = sy - dragRect.y; 1.166 + } 1.167 + 1.168 + DeleteDC(hdcSrc); 1.169 + } 1.170 + 1.171 + dataSurface->Unmap(); 1.172 + 1.173 + return psdi->hbmpDragImage != nullptr; 1.174 +} 1.175 + 1.176 +//------------------------------------------------------------------------- 1.177 +NS_IMETHODIMP 1.178 +nsDragService::InvokeDragSession(nsIDOMNode *aDOMNode, 1.179 + nsISupportsArray *anArrayTransferables, 1.180 + nsIScriptableRegion *aRegion, 1.181 + uint32_t aActionType) 1.182 +{ 1.183 + nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode, 1.184 + anArrayTransferables, 1.185 + aRegion, 1.186 + aActionType); 1.187 + NS_ENSURE_SUCCESS(rv, rv); 1.188 + 1.189 + // Try and get source URI of the items that are being dragged 1.190 + nsIURI *uri = nullptr; 1.191 + 1.192 + nsCOMPtr<nsIDocument> doc(do_QueryInterface(mSourceDocument)); 1.193 + if (doc) { 1.194 + uri = doc->GetDocumentURI(); 1.195 + } 1.196 + 1.197 + uint32_t numItemsToDrag = 0; 1.198 + rv = anArrayTransferables->Count(&numItemsToDrag); 1.199 + if (!numItemsToDrag) 1.200 + return NS_ERROR_FAILURE; 1.201 + 1.202 + // The clipboard class contains some static utility methods that we 1.203 + // can use to create an IDataObject from the transferable 1.204 + 1.205 + // if we're dragging more than one item, we need to create a 1.206 + // "collection" object to fake out the OS. This collection contains 1.207 + // one |IDataObject| for each transferable. If there is just the one 1.208 + // (most cases), only pass around the native |IDataObject|. 1.209 + nsRefPtr<IDataObject> itemToDrag; 1.210 + if (numItemsToDrag > 1) { 1.211 + nsDataObjCollection * dataObjCollection = new nsDataObjCollection(); 1.212 + if (!dataObjCollection) 1.213 + return NS_ERROR_OUT_OF_MEMORY; 1.214 + itemToDrag = dataObjCollection; 1.215 + for (uint32_t i=0; i<numItemsToDrag; ++i) { 1.216 + nsCOMPtr<nsISupports> supports; 1.217 + anArrayTransferables->GetElementAt(i, getter_AddRefs(supports)); 1.218 + nsCOMPtr<nsITransferable> trans(do_QueryInterface(supports)); 1.219 + if (trans) { 1.220 + nsRefPtr<IDataObject> dataObj; 1.221 + rv = nsClipboard::CreateNativeDataObject(trans, 1.222 + getter_AddRefs(dataObj), uri); 1.223 + NS_ENSURE_SUCCESS(rv, rv); 1.224 + // Add the flavors to the collection object too 1.225 + rv = nsClipboard::SetupNativeDataObject(trans, dataObjCollection); 1.226 + NS_ENSURE_SUCCESS(rv, rv); 1.227 + 1.228 + dataObjCollection->AddDataObject(dataObj); 1.229 + } 1.230 + } 1.231 + } // if dragging multiple items 1.232 + else { 1.233 + nsCOMPtr<nsISupports> supports; 1.234 + anArrayTransferables->GetElementAt(0, getter_AddRefs(supports)); 1.235 + nsCOMPtr<nsITransferable> trans(do_QueryInterface(supports)); 1.236 + if (trans) { 1.237 + rv = nsClipboard::CreateNativeDataObject(trans, 1.238 + getter_AddRefs(itemToDrag), 1.239 + uri); 1.240 + NS_ENSURE_SUCCESS(rv, rv); 1.241 + } 1.242 + } // else dragging a single object 1.243 + 1.244 + // Create a drag image if support is available 1.245 + IDragSourceHelper *pdsh; 1.246 + if (SUCCEEDED(CoCreateInstance(CLSID_DragDropHelper, nullptr, 1.247 + CLSCTX_INPROC_SERVER, 1.248 + IID_IDragSourceHelper, (void**)&pdsh))) { 1.249 + SHDRAGIMAGE sdi; 1.250 + if (CreateDragImage(aDOMNode, aRegion, &sdi)) { 1.251 + if (FAILED(pdsh->InitializeFromBitmap(&sdi, itemToDrag))) 1.252 + DeleteObject(sdi.hbmpDragImage); 1.253 + } 1.254 + pdsh->Release(); 1.255 + } 1.256 + 1.257 + // Kick off the native drag session 1.258 + return StartInvokingDragSession(itemToDrag, aActionType); 1.259 +} 1.260 + 1.261 +//------------------------------------------------------------------------- 1.262 +NS_IMETHODIMP 1.263 +nsDragService::StartInvokingDragSession(IDataObject * aDataObj, 1.264 + uint32_t aActionType) 1.265 +{ 1.266 + // To do the drag we need to create an object that 1.267 + // implements the IDataObject interface (for OLE) 1.268 + nsRefPtr<nsNativeDragSource> nativeDragSrc = 1.269 + new nsNativeDragSource(mDataTransfer); 1.270 + 1.271 + // Now figure out what the native drag effect should be 1.272 + DWORD winDropRes; 1.273 + DWORD effects = DROPEFFECT_SCROLL; 1.274 + if (aActionType & DRAGDROP_ACTION_COPY) { 1.275 + effects |= DROPEFFECT_COPY; 1.276 + } 1.277 + if (aActionType & DRAGDROP_ACTION_MOVE) { 1.278 + effects |= DROPEFFECT_MOVE; 1.279 + } 1.280 + if (aActionType & DRAGDROP_ACTION_LINK) { 1.281 + effects |= DROPEFFECT_LINK; 1.282 + } 1.283 + 1.284 + // XXX not sure why we bother to cache this, it can change during 1.285 + // the drag 1.286 + mDragAction = aActionType; 1.287 + mSentLocalDropEvent = false; 1.288 + 1.289 + // Start dragging 1.290 + StartDragSession(); 1.291 + OpenDragPopup(); 1.292 + 1.293 + nsRefPtr<IAsyncOperation> pAsyncOp; 1.294 + // Offer to do an async drag 1.295 + if (SUCCEEDED(aDataObj->QueryInterface(IID_IAsyncOperation, 1.296 + getter_AddRefs(pAsyncOp)))) { 1.297 + pAsyncOp->SetAsyncMode(VARIANT_TRUE); 1.298 + } else { 1.299 + NS_NOTREACHED("When did our data object stop being async"); 1.300 + } 1.301 + 1.302 + // Call the native D&D method 1.303 + HRESULT res = ::DoDragDrop(aDataObj, nativeDragSrc, effects, &winDropRes); 1.304 + 1.305 + // In cases where the drop operation completed outside the application, update 1.306 + // the source node's nsIDOMDataTransfer dropEffect value so it is up to date. 1.307 + if (!mSentLocalDropEvent) { 1.308 + uint32_t dropResult; 1.309 + // Order is important, since multiple flags can be returned. 1.310 + if (winDropRes & DROPEFFECT_COPY) 1.311 + dropResult = DRAGDROP_ACTION_COPY; 1.312 + else if (winDropRes & DROPEFFECT_LINK) 1.313 + dropResult = DRAGDROP_ACTION_LINK; 1.314 + else if (winDropRes & DROPEFFECT_MOVE) 1.315 + dropResult = DRAGDROP_ACTION_MOVE; 1.316 + else 1.317 + dropResult = DRAGDROP_ACTION_NONE; 1.318 + 1.319 + if (mDataTransfer) { 1.320 + if (res == DRAGDROP_S_DROP) // Success 1.321 + mDataTransfer->SetDropEffectInt(dropResult); 1.322 + else 1.323 + mDataTransfer->SetDropEffectInt(DRAGDROP_ACTION_NONE); 1.324 + } 1.325 + } 1.326 + 1.327 + mUserCancelled = nativeDragSrc->UserCancelled(); 1.328 + 1.329 + // We're done dragging, get the cursor position and end the drag 1.330 + // Use GetMessagePos to get the position of the mouse at the last message 1.331 + // seen by the event loop. (Bug 489729) 1.332 + // Note that we must convert this from device pixels back to Windows logical 1.333 + // pixels (bug 818927). 1.334 + DWORD pos = ::GetMessagePos(); 1.335 + FLOAT dpiScale = gfxWindowsPlatform::GetPlatform()->GetDPIScale(); 1.336 + nsIntPoint logPos(NSToIntRound(GET_X_LPARAM(pos) / dpiScale), 1.337 + NSToIntRound(GET_Y_LPARAM(pos) / dpiScale)); 1.338 + SetDragEndPoint(logPos); 1.339 + EndDragSession(true); 1.340 + 1.341 + mDoingDrag = false; 1.342 + 1.343 + return DRAGDROP_S_DROP == res ? NS_OK : NS_ERROR_FAILURE; 1.344 +} 1.345 + 1.346 +//------------------------------------------------------------------------- 1.347 +// Make Sure we have the right kind of object 1.348 +nsDataObjCollection* 1.349 +nsDragService::GetDataObjCollection(IDataObject* aDataObj) 1.350 +{ 1.351 + nsDataObjCollection * dataObjCol = nullptr; 1.352 + if (aDataObj) { 1.353 + nsIDataObjCollection* dataObj; 1.354 + if (aDataObj->QueryInterface(IID_IDataObjCollection, 1.355 + (void**)&dataObj) == S_OK) { 1.356 + dataObjCol = static_cast<nsDataObjCollection*>(aDataObj); 1.357 + dataObj->Release(); 1.358 + } 1.359 + } 1.360 + 1.361 + return dataObjCol; 1.362 +} 1.363 + 1.364 +//------------------------------------------------------------------------- 1.365 +NS_IMETHODIMP 1.366 +nsDragService::GetNumDropItems(uint32_t * aNumItems) 1.367 +{ 1.368 + if (!mDataObject) { 1.369 + *aNumItems = 0; 1.370 + return NS_OK; 1.371 + } 1.372 + 1.373 + if (IsCollectionObject(mDataObject)) { 1.374 + nsDataObjCollection * dataObjCol = GetDataObjCollection(mDataObject); 1.375 + if (dataObjCol) { 1.376 + *aNumItems = dataObjCol->GetNumDataObjects(); 1.377 + } 1.378 + else { 1.379 + // If the count cannot be determined just return 0. 1.380 + // This can happen if we have collection data of type 1.381 + // MULTI_MIME ("Mozilla/IDataObjectCollectionFormat") on the clipboard 1.382 + // from another process but we can't obtain an IID_IDataObjCollection 1.383 + // from this process. 1.384 + *aNumItems = 0; 1.385 + } 1.386 + } 1.387 + else { 1.388 + // Next check if we have a file drop. Return the number of files in 1.389 + // the file drop as the number of items we have, pretending like we 1.390 + // actually have > 1 drag item. 1.391 + FORMATETC fe2; 1.392 + SET_FORMATETC(fe2, CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL); 1.393 + if (mDataObject->QueryGetData(&fe2) == S_OK) { 1.394 + STGMEDIUM stm; 1.395 + if (mDataObject->GetData(&fe2, &stm) == S_OK) { 1.396 + HDROP hdrop = (HDROP)GlobalLock(stm.hGlobal); 1.397 + *aNumItems = ::DragQueryFileW(hdrop, 0xFFFFFFFF, nullptr, 0); 1.398 + ::GlobalUnlock(stm.hGlobal); 1.399 + ::ReleaseStgMedium(&stm); 1.400 + // Data may be provided later, so assume we have 1 item 1.401 + if (*aNumItems == 0) 1.402 + *aNumItems = 1; 1.403 + } 1.404 + else 1.405 + *aNumItems = 1; 1.406 + } 1.407 + else 1.408 + *aNumItems = 1; 1.409 + } 1.410 + 1.411 + return NS_OK; 1.412 +} 1.413 + 1.414 +//------------------------------------------------------------------------- 1.415 +NS_IMETHODIMP 1.416 +nsDragService::GetData(nsITransferable * aTransferable, uint32_t anItem) 1.417 +{ 1.418 + // This typcially happens on a drop, the target would be asking 1.419 + // for it's transferable to be filled in 1.420 + // Use a static clipboard utility method for this 1.421 + if (!mDataObject) 1.422 + return NS_ERROR_FAILURE; 1.423 + 1.424 + nsresult dataFound = NS_ERROR_FAILURE; 1.425 + 1.426 + if (IsCollectionObject(mDataObject)) { 1.427 + // multiple items, use |anItem| as an index into our collection 1.428 + nsDataObjCollection * dataObjCol = GetDataObjCollection(mDataObject); 1.429 + uint32_t cnt = dataObjCol->GetNumDataObjects(); 1.430 + if (anItem >= 0 && anItem < cnt) { 1.431 + IDataObject * dataObj = dataObjCol->GetDataObjectAt(anItem); 1.432 + dataFound = nsClipboard::GetDataFromDataObject(dataObj, 0, nullptr, 1.433 + aTransferable); 1.434 + } 1.435 + else 1.436 + NS_WARNING("Index out of range!"); 1.437 + } 1.438 + else { 1.439 + // If they are asking for item "0", we can just get it... 1.440 + if (anItem == 0) { 1.441 + dataFound = nsClipboard::GetDataFromDataObject(mDataObject, anItem, 1.442 + nullptr, aTransferable); 1.443 + } else { 1.444 + // It better be a file drop, or else non-zero indexes are invalid! 1.445 + FORMATETC fe2; 1.446 + SET_FORMATETC(fe2, CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL); 1.447 + if (mDataObject->QueryGetData(&fe2) == S_OK) 1.448 + dataFound = nsClipboard::GetDataFromDataObject(mDataObject, anItem, 1.449 + nullptr, aTransferable); 1.450 + else 1.451 + NS_WARNING("Reqesting non-zero index, but clipboard data is not a collection!"); 1.452 + } 1.453 + } 1.454 + return dataFound; 1.455 +} 1.456 + 1.457 +//--------------------------------------------------------- 1.458 +NS_IMETHODIMP 1.459 +nsDragService::SetIDataObject(IDataObject * aDataObj) 1.460 +{ 1.461 + // When the native drag starts the DragService gets 1.462 + // the IDataObject that is being dragged 1.463 + NS_IF_RELEASE(mDataObject); 1.464 + mDataObject = aDataObj; 1.465 + NS_IF_ADDREF(mDataObject); 1.466 + 1.467 + return NS_OK; 1.468 +} 1.469 + 1.470 +//--------------------------------------------------------- 1.471 +void 1.472 +nsDragService::SetDroppedLocal() 1.473 +{ 1.474 + // Sent from the native drag handler, letting us know 1.475 + // a drop occurred within the application vs. outside of it. 1.476 + mSentLocalDropEvent = true; 1.477 + return; 1.478 +} 1.479 + 1.480 +//------------------------------------------------------------------------- 1.481 +NS_IMETHODIMP 1.482 +nsDragService::IsDataFlavorSupported(const char *aDataFlavor, bool *_retval) 1.483 +{ 1.484 + if (!aDataFlavor || !mDataObject || !_retval) 1.485 + return NS_ERROR_FAILURE; 1.486 + 1.487 +#ifdef DEBUG 1.488 + if (strcmp(aDataFlavor, kTextMime) == 0) 1.489 + NS_WARNING("DO NOT USE THE text/plain DATA FLAVOR ANY MORE. USE text/unicode INSTEAD"); 1.490 +#endif 1.491 + 1.492 + *_retval = false; 1.493 + 1.494 + FORMATETC fe; 1.495 + UINT format = 0; 1.496 + 1.497 + if (IsCollectionObject(mDataObject)) { 1.498 + // We know we have one of our special collection objects. 1.499 + format = nsClipboard::GetFormat(aDataFlavor); 1.500 + SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1, 1.501 + TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI); 1.502 + 1.503 + // See if any one of the IDataObjects in the collection supports 1.504 + // this data type 1.505 + nsDataObjCollection* dataObjCol = GetDataObjCollection(mDataObject); 1.506 + if (dataObjCol) { 1.507 + uint32_t cnt = dataObjCol->GetNumDataObjects(); 1.508 + for (uint32_t i=0;i<cnt;++i) { 1.509 + IDataObject * dataObj = dataObjCol->GetDataObjectAt(i); 1.510 + if (S_OK == dataObj->QueryGetData(&fe)) 1.511 + *_retval = true; // found it! 1.512 + } 1.513 + } 1.514 + } // if special collection object 1.515 + else { 1.516 + // Ok, so we have a single object. Check to see if has the correct 1.517 + // data type. Since this can come from an outside app, we also 1.518 + // need to see if we need to perform text->unicode conversion if 1.519 + // the client asked for unicode and it wasn't available. 1.520 + format = nsClipboard::GetFormat(aDataFlavor); 1.521 + SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1, 1.522 + TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI); 1.523 + if (mDataObject->QueryGetData(&fe) == S_OK) 1.524 + *_retval = true; // found it! 1.525 + else { 1.526 + // We haven't found the exact flavor the client asked for, but 1.527 + // maybe we can still find it from something else that's on the 1.528 + // clipboard 1.529 + if (strcmp(aDataFlavor, kUnicodeMime) == 0) { 1.530 + // client asked for unicode and it wasn't present, check if we 1.531 + // have CF_TEXT. We'll handle the actual data substitution in 1.532 + // the data object. 1.533 + format = nsClipboard::GetFormat(kTextMime); 1.534 + SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1, 1.535 + TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI); 1.536 + if (mDataObject->QueryGetData(&fe) == S_OK) 1.537 + *_retval = true; // found it! 1.538 + } 1.539 + else if (strcmp(aDataFlavor, kURLMime) == 0) { 1.540 + // client asked for a url and it wasn't present, but if we 1.541 + // have a file, then we have a URL to give them (the path, or 1.542 + // the internal URL if an InternetShortcut). 1.543 + format = nsClipboard::GetFormat(kFileMime); 1.544 + SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1, 1.545 + TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI); 1.546 + if (mDataObject->QueryGetData(&fe) == S_OK) 1.547 + *_retval = true; // found it! 1.548 + } 1.549 + } // else try again 1.550 + } 1.551 + 1.552 + return NS_OK; 1.553 +} 1.554 + 1.555 + 1.556 +// 1.557 +// IsCollectionObject 1.558 +// 1.559 +// Determine if this is a single |IDataObject| or one of our private 1.560 +// collection objects. We know the difference because our collection 1.561 +// object will respond to supporting the private |MULTI_MIME| format. 1.562 +// 1.563 +bool 1.564 +nsDragService::IsCollectionObject(IDataObject* inDataObj) 1.565 +{ 1.566 + bool isCollection = false; 1.567 + 1.568 + // setup the format object to ask for the MULTI_MIME format. We only 1.569 + // need to do this once 1.570 + static UINT sFormat = 0; 1.571 + static FORMATETC sFE; 1.572 + if (!sFormat) { 1.573 + sFormat = nsClipboard::GetFormat(MULTI_MIME); 1.574 + SET_FORMATETC(sFE, sFormat, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL); 1.575 + } 1.576 + 1.577 + // ask the object if it supports it. If yes, we have a collection 1.578 + // object 1.579 + if (inDataObj->QueryGetData(&sFE) == S_OK) 1.580 + isCollection = true; 1.581 + 1.582 + return isCollection; 1.583 + 1.584 +} // IsCollectionObject 1.585 + 1.586 + 1.587 +// 1.588 +// EndDragSession 1.589 +// 1.590 +// Override the default to make sure that we release the data object 1.591 +// when the drag ends. It seems that OLE doesn't like to let apps quit 1.592 +// w/out crashing when we're still holding onto their data 1.593 +// 1.594 +NS_IMETHODIMP 1.595 +nsDragService::EndDragSession(bool aDoneDrag) 1.596 +{ 1.597 + // Bug 100180: If we've got mouse events captured, make sure we release it - 1.598 + // that way, if we happen to call EndDragSession before diving into a nested 1.599 + // event loop, we can still respond to mouse events. 1.600 + if (::GetCapture()) { 1.601 + ::ReleaseCapture(); 1.602 + } 1.603 + 1.604 + nsBaseDragService::EndDragSession(aDoneDrag); 1.605 + NS_IF_RELEASE(mDataObject); 1.606 + 1.607 + return NS_OK; 1.608 +}