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.

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

mercurial