|
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/. */ |
|
5 |
|
6 #include <ole2.h> |
|
7 #include <oleidl.h> |
|
8 #include <shlobj.h> |
|
9 #include <shlwapi.h> |
|
10 |
|
11 // shellapi.h is needed to build with WIN32_LEAN_AND_MEAN |
|
12 #include <shellapi.h> |
|
13 |
|
14 #include "nsDragService.h" |
|
15 #include "nsITransferable.h" |
|
16 #include "nsDataObj.h" |
|
17 |
|
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" |
|
25 |
|
26 #include "nsAutoPtr.h" |
|
27 |
|
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" |
|
45 |
|
46 using namespace mozilla; |
|
47 using namespace mozilla::gfx; |
|
48 |
|
49 //------------------------------------------------------------------------- |
|
50 // |
|
51 // DragService constructor |
|
52 // |
|
53 //------------------------------------------------------------------------- |
|
54 nsDragService::nsDragService() |
|
55 : mDataObject(nullptr), mSentLocalDropEvent(false) |
|
56 { |
|
57 } |
|
58 |
|
59 //------------------------------------------------------------------------- |
|
60 // |
|
61 // DragService destructor |
|
62 // |
|
63 //------------------------------------------------------------------------- |
|
64 nsDragService::~nsDragService() |
|
65 { |
|
66 NS_IF_RELEASE(mDataObject); |
|
67 } |
|
68 |
|
69 bool |
|
70 nsDragService::CreateDragImage(nsIDOMNode *aDOMNode, |
|
71 nsIScriptableRegion *aRegion, |
|
72 SHDRAGIMAGE *psdi) |
|
73 { |
|
74 if (!psdi) |
|
75 return false; |
|
76 |
|
77 memset(psdi, 0, sizeof(SHDRAGIMAGE)); |
|
78 if (!aDOMNode) |
|
79 return false; |
|
80 |
|
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; |
|
90 |
|
91 uint32_t bmWidth = dragRect.width, bmHeight = dragRect.height; |
|
92 |
|
93 if (bmWidth == 0 || bmHeight == 0) |
|
94 return false; |
|
95 |
|
96 psdi->crColorKey = CLR_NONE; |
|
97 |
|
98 RefPtr<DataSourceSurface> dataSurface = |
|
99 Factory::CreateDataSourceSurface(IntSize(bmWidth, bmHeight), |
|
100 SurfaceFormat::B8G8R8A8); |
|
101 NS_ENSURE_TRUE(dataSurface, false); |
|
102 |
|
103 DataSourceSurface::MappedSurface map; |
|
104 if (!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) { |
|
105 return false; |
|
106 } |
|
107 |
|
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 } |
|
118 |
|
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(); |
|
125 |
|
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; |
|
138 |
|
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 } |
|
150 |
|
151 psdi->sizeDragImage.cx = bmWidth; |
|
152 psdi->sizeDragImage.cy = bmHeight; |
|
153 |
|
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 } |
|
164 |
|
165 DeleteDC(hdcSrc); |
|
166 } |
|
167 |
|
168 dataSurface->Unmap(); |
|
169 |
|
170 return psdi->hbmpDragImage != nullptr; |
|
171 } |
|
172 |
|
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); |
|
185 |
|
186 // Try and get source URI of the items that are being dragged |
|
187 nsIURI *uri = nullptr; |
|
188 |
|
189 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mSourceDocument)); |
|
190 if (doc) { |
|
191 uri = doc->GetDocumentURI(); |
|
192 } |
|
193 |
|
194 uint32_t numItemsToDrag = 0; |
|
195 rv = anArrayTransferables->Count(&numItemsToDrag); |
|
196 if (!numItemsToDrag) |
|
197 return NS_ERROR_FAILURE; |
|
198 |
|
199 // The clipboard class contains some static utility methods that we |
|
200 // can use to create an IDataObject from the transferable |
|
201 |
|
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); |
|
224 |
|
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 |
|
240 |
|
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 } |
|
253 |
|
254 // Kick off the native drag session |
|
255 return StartInvokingDragSession(itemToDrag, aActionType); |
|
256 } |
|
257 |
|
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); |
|
267 |
|
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 } |
|
280 |
|
281 // XXX not sure why we bother to cache this, it can change during |
|
282 // the drag |
|
283 mDragAction = aActionType; |
|
284 mSentLocalDropEvent = false; |
|
285 |
|
286 // Start dragging |
|
287 StartDragSession(); |
|
288 OpenDragPopup(); |
|
289 |
|
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 } |
|
298 |
|
299 // Call the native D&D method |
|
300 HRESULT res = ::DoDragDrop(aDataObj, nativeDragSrc, effects, &winDropRes); |
|
301 |
|
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; |
|
315 |
|
316 if (mDataTransfer) { |
|
317 if (res == DRAGDROP_S_DROP) // Success |
|
318 mDataTransfer->SetDropEffectInt(dropResult); |
|
319 else |
|
320 mDataTransfer->SetDropEffectInt(DRAGDROP_ACTION_NONE); |
|
321 } |
|
322 } |
|
323 |
|
324 mUserCancelled = nativeDragSrc->UserCancelled(); |
|
325 |
|
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); |
|
337 |
|
338 mDoingDrag = false; |
|
339 |
|
340 return DRAGDROP_S_DROP == res ? NS_OK : NS_ERROR_FAILURE; |
|
341 } |
|
342 |
|
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 } |
|
357 |
|
358 return dataObjCol; |
|
359 } |
|
360 |
|
361 //------------------------------------------------------------------------- |
|
362 NS_IMETHODIMP |
|
363 nsDragService::GetNumDropItems(uint32_t * aNumItems) |
|
364 { |
|
365 if (!mDataObject) { |
|
366 *aNumItems = 0; |
|
367 return NS_OK; |
|
368 } |
|
369 |
|
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 } |
|
407 |
|
408 return NS_OK; |
|
409 } |
|
410 |
|
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; |
|
420 |
|
421 nsresult dataFound = NS_ERROR_FAILURE; |
|
422 |
|
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 } |
|
453 |
|
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); |
|
463 |
|
464 return NS_OK; |
|
465 } |
|
466 |
|
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 } |
|
476 |
|
477 //------------------------------------------------------------------------- |
|
478 NS_IMETHODIMP |
|
479 nsDragService::IsDataFlavorSupported(const char *aDataFlavor, bool *_retval) |
|
480 { |
|
481 if (!aDataFlavor || !mDataObject || !_retval) |
|
482 return NS_ERROR_FAILURE; |
|
483 |
|
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 |
|
488 |
|
489 *_retval = false; |
|
490 |
|
491 FORMATETC fe; |
|
492 UINT format = 0; |
|
493 |
|
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); |
|
499 |
|
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 } |
|
548 |
|
549 return NS_OK; |
|
550 } |
|
551 |
|
552 |
|
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; |
|
564 |
|
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 } |
|
573 |
|
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; |
|
578 |
|
579 return isCollection; |
|
580 |
|
581 } // IsCollectionObject |
|
582 |
|
583 |
|
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 } |
|
600 |
|
601 nsBaseDragService::EndDragSession(aDoneDrag); |
|
602 NS_IF_RELEASE(mDataObject); |
|
603 |
|
604 return NS_OK; |
|
605 } |