michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifdef MOZ_LOGGING michael@0: #define FORCE_PR_LOG michael@0: #endif michael@0: #include "prlog.h" michael@0: michael@0: #include "nsDragService.h" michael@0: #include "nsObjCExceptions.h" michael@0: #include "nsITransferable.h" michael@0: #include "nsString.h" michael@0: #include "nsClipboard.h" michael@0: #include "nsXPCOM.h" michael@0: #include "nsISupportsPrimitives.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsPrimitiveHelpers.h" michael@0: #include "nsLinebreakConverter.h" michael@0: #include "nsIMacUtils.h" michael@0: #include "nsIDOMNode.h" michael@0: #include "nsRect.h" michael@0: #include "nsPoint.h" michael@0: #include "nsIIOService.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsIContent.h" michael@0: #include "nsView.h" michael@0: #include "gfxContext.h" michael@0: #include "nsCocoaUtils.h" michael@0: #include "mozilla/gfx/2D.h" michael@0: #include "gfxPlatform.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::gfx; michael@0: michael@0: #ifdef PR_LOGGING michael@0: extern PRLogModuleInfo* sCocoaLog; michael@0: #endif michael@0: michael@0: extern void EnsureLogInitialized(); michael@0: michael@0: extern NSPasteboard* globalDragPboard; michael@0: extern NSView* gLastDragView; michael@0: extern NSEvent* gLastDragMouseDownEvent; michael@0: extern bool gUserCancelledDrag; michael@0: michael@0: // This global makes the transferable array available to Cocoa's promised michael@0: // file destination callback. michael@0: nsISupportsArray *gDraggedTransferables = nullptr; michael@0: michael@0: NSString* const kWildcardPboardType = @"MozillaWildcard"; michael@0: NSString* const kCorePboardType_url = @"CorePasteboardFlavorType 0x75726C20"; // 'url ' url michael@0: NSString* const kCorePboardType_urld = @"CorePasteboardFlavorType 0x75726C64"; // 'urld' desc michael@0: NSString* const kCorePboardType_urln = @"CorePasteboardFlavorType 0x75726C6E"; // 'urln' title michael@0: michael@0: nsDragService::nsDragService() michael@0: { michael@0: mNativeDragView = nil; michael@0: mNativeDragEvent = nil; michael@0: michael@0: EnsureLogInitialized(); michael@0: } michael@0: michael@0: nsDragService::~nsDragService() michael@0: { michael@0: } michael@0: michael@0: static nsresult SetUpDragClipboard(nsISupportsArray* aTransferableArray) michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; michael@0: michael@0: if (!aTransferableArray) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: uint32_t count = 0; michael@0: aTransferableArray->Count(&count); michael@0: michael@0: NSPasteboard* dragPBoard = [NSPasteboard pasteboardWithName:NSDragPboard]; michael@0: michael@0: for (uint32_t i = 0; i < count; i++) { michael@0: nsCOMPtr currentTransferableSupports; michael@0: aTransferableArray->GetElementAt(i, getter_AddRefs(currentTransferableSupports)); michael@0: if (!currentTransferableSupports) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsCOMPtr currentTransferable(do_QueryInterface(currentTransferableSupports)); michael@0: if (!currentTransferable) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // Transform the transferable to an NSDictionary michael@0: NSDictionary* pasteboardOutputDict = nsClipboard::PasteboardDictFromTransferable(currentTransferable); michael@0: if (!pasteboardOutputDict) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // write everything out to the general pasteboard michael@0: unsigned int typeCount = [pasteboardOutputDict count]; michael@0: NSMutableArray* types = [NSMutableArray arrayWithCapacity:typeCount + 1]; michael@0: [types addObjectsFromArray:[pasteboardOutputDict allKeys]]; michael@0: // Gecko is initiating this drag so we always want its own views to consider michael@0: // it. Add our wildcard type to the pasteboard to accomplish this. michael@0: [types addObject:kWildcardPboardType]; // we don't increase the count for the loop below on purpose michael@0: [dragPBoard declareTypes:types owner:nil]; michael@0: for (unsigned int i = 0; i < typeCount; i++) { michael@0: NSString* currentKey = [types objectAtIndex:i]; michael@0: id currentValue = [pasteboardOutputDict valueForKey:currentKey]; michael@0: if (currentKey == NSStringPboardType || michael@0: currentKey == kCorePboardType_url || michael@0: currentKey == kCorePboardType_urld || michael@0: currentKey == kCorePboardType_urln) { michael@0: [dragPBoard setString:currentValue forType:currentKey]; michael@0: } michael@0: else if (currentKey == NSHTMLPboardType) { michael@0: [dragPBoard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue)) michael@0: forType:currentKey]; michael@0: } michael@0: else if (currentKey == NSTIFFPboardType) { michael@0: [dragPBoard setData:currentValue forType:currentKey]; michael@0: } michael@0: else if (currentKey == NSFilesPromisePboardType || michael@0: currentKey == NSFilenamesPboardType) { michael@0: [dragPBoard setPropertyList:currentValue forType:currentKey]; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; michael@0: } michael@0: michael@0: NSImage* michael@0: nsDragService::ConstructDragImage(nsIDOMNode* aDOMNode, michael@0: nsIntRect* aDragRect, michael@0: nsIScriptableRegion* aRegion) michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; michael@0: michael@0: NSPoint screenPoint = michael@0: [[gLastDragView window] convertBaseToScreen: michael@0: [gLastDragMouseDownEvent locationInWindow]]; michael@0: // Y coordinates are bottom to top, so reverse this michael@0: screenPoint.y = nsCocoaUtils::FlippedScreenY(screenPoint.y); michael@0: michael@0: CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(gLastDragView); michael@0: michael@0: RefPtr surface; michael@0: nsPresContext* pc; michael@0: nsresult rv = DrawDrag(aDOMNode, aRegion, michael@0: NSToIntRound(screenPoint.x), michael@0: NSToIntRound(screenPoint.y), michael@0: aDragRect, &surface, &pc); michael@0: if (!aDragRect->width || !aDragRect->height) { michael@0: // just use some suitable defaults michael@0: int32_t size = nsCocoaUtils::CocoaPointsToDevPixels(20, scaleFactor); michael@0: aDragRect->SetRect(nsCocoaUtils::CocoaPointsToDevPixels(screenPoint.x, scaleFactor), michael@0: nsCocoaUtils::CocoaPointsToDevPixels(screenPoint.y, scaleFactor), michael@0: size, size); michael@0: } michael@0: michael@0: if (NS_FAILED(rv) || !surface) michael@0: return nil; michael@0: michael@0: uint32_t width = aDragRect->width; michael@0: uint32_t height = aDragRect->height; michael@0: michael@0: nsRefPtr imgSurface = new gfxImageSurface( michael@0: gfxIntSize(width, height), gfxImageFormat::ARGB32); michael@0: if (!imgSurface) michael@0: return nil; michael@0: michael@0: RefPtr dt = michael@0: gfxPlatform::GetPlatform()-> michael@0: CreateDrawTargetForSurface(imgSurface, IntSize(width, height)); michael@0: if (!dt) michael@0: return nil; michael@0: michael@0: dt->FillRect(gfx::Rect(0, 0, width, height), michael@0: SurfacePattern(surface, ExtendMode::CLAMP), michael@0: DrawOptions(1.0f, CompositionOp::OP_SOURCE)); michael@0: michael@0: uint32_t* imageData = (uint32_t*)imgSurface->Data(); michael@0: int32_t stride = imgSurface->Stride(); michael@0: michael@0: NSBitmapImageRep* imageRep = michael@0: [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL michael@0: pixelsWide:width michael@0: pixelsHigh:height michael@0: bitsPerSample:8 michael@0: samplesPerPixel:4 michael@0: hasAlpha:YES michael@0: isPlanar:NO michael@0: colorSpaceName:NSDeviceRGBColorSpace michael@0: bytesPerRow:width * 4 michael@0: bitsPerPixel:32]; michael@0: michael@0: uint8_t* dest = [imageRep bitmapData]; michael@0: for (uint32_t i = 0; i < height; ++i) { michael@0: uint8_t* src = (uint8_t *)imageData + i * stride; michael@0: for (uint32_t j = 0; j < width; ++j) { michael@0: // Reduce transparency overall by multipying by a factor. Remember, Alpha michael@0: // is premultipled here. Also, Quartz likes RGBA, so do that translation as well. michael@0: #ifdef IS_BIG_ENDIAN michael@0: dest[0] = uint8_t(src[1] * DRAG_TRANSLUCENCY); michael@0: dest[1] = uint8_t(src[2] * DRAG_TRANSLUCENCY); michael@0: dest[2] = uint8_t(src[3] * DRAG_TRANSLUCENCY); michael@0: dest[3] = uint8_t(src[0] * DRAG_TRANSLUCENCY); michael@0: #else michael@0: dest[0] = uint8_t(src[2] * DRAG_TRANSLUCENCY); michael@0: dest[1] = uint8_t(src[1] * DRAG_TRANSLUCENCY); michael@0: dest[2] = uint8_t(src[0] * DRAG_TRANSLUCENCY); michael@0: dest[3] = uint8_t(src[3] * DRAG_TRANSLUCENCY); michael@0: #endif michael@0: src += 4; michael@0: dest += 4; michael@0: } michael@0: } michael@0: michael@0: NSImage* image = michael@0: [[NSImage alloc] initWithSize:NSMakeSize(width / scaleFactor, michael@0: height / scaleFactor)]; michael@0: [image addRepresentation:imageRep]; michael@0: [imageRep release]; michael@0: michael@0: return [image autorelease]; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK_NIL; michael@0: } michael@0: michael@0: // We can only invoke NSView's 'dragImage:at:offset:event:pasteboard:source:slideBack:' from michael@0: // within NSView's 'mouseDown:' or 'mouseDragged:'. Luckily 'mouseDragged' is always on the michael@0: // stack when InvokeDragSession gets called. michael@0: NS_IMETHODIMP michael@0: nsDragService::InvokeDragSession(nsIDOMNode* aDOMNode, nsISupportsArray* aTransferableArray, michael@0: nsIScriptableRegion* aDragRgn, uint32_t aActionType) michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; michael@0: michael@0: nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode, michael@0: aTransferableArray, michael@0: aDragRgn, aActionType); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mDataItems = aTransferableArray; michael@0: michael@0: // put data on the clipboard michael@0: if (NS_FAILED(SetUpDragClipboard(aTransferableArray))) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsIntRect dragRect(0, 0, 20, 20); michael@0: NSImage* image = ConstructDragImage(aDOMNode, &dragRect, aDragRgn); michael@0: if (!image) { michael@0: // if no image was returned, just draw a rectangle michael@0: NSSize size; michael@0: size.width = dragRect.width; michael@0: size.height = dragRect.height; michael@0: image = [[NSImage alloc] initWithSize:size]; michael@0: [image lockFocus]; michael@0: [[NSColor grayColor] set]; michael@0: NSBezierPath* path = [NSBezierPath bezierPath]; michael@0: [path setLineWidth:2.0]; michael@0: [path moveToPoint:NSMakePoint(0, 0)]; michael@0: [path lineToPoint:NSMakePoint(0, size.height)]; michael@0: [path lineToPoint:NSMakePoint(size.width, size.height)]; michael@0: [path lineToPoint:NSMakePoint(size.width, 0)]; michael@0: [path lineToPoint:NSMakePoint(0, 0)]; michael@0: [path stroke]; michael@0: [image unlockFocus]; michael@0: } michael@0: michael@0: nsIntPoint pt(dragRect.x, dragRect.YMost()); michael@0: CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(gLastDragView); michael@0: NSPoint point = nsCocoaUtils::DevPixelsToCocoaPoints(pt, scaleFactor); michael@0: point.y = nsCocoaUtils::FlippedScreenY(point.y); michael@0: michael@0: point = [[gLastDragView window] convertScreenToBase: point]; michael@0: NSPoint localPoint = [gLastDragView convertPoint:point fromView:nil]; michael@0: michael@0: // Save the transferables away in case a promised file callback is invoked. michael@0: gDraggedTransferables = aTransferableArray; michael@0: michael@0: nsBaseDragService::StartDragSession(); michael@0: nsBaseDragService::OpenDragPopup(); michael@0: michael@0: // We need to retain the view and the event during the drag in case either gets destroyed. michael@0: mNativeDragView = [gLastDragView retain]; michael@0: mNativeDragEvent = [gLastDragMouseDownEvent retain]; michael@0: michael@0: gUserCancelledDrag = false; michael@0: [mNativeDragView dragImage:image michael@0: at:localPoint michael@0: offset:NSZeroSize michael@0: event:mNativeDragEvent michael@0: pasteboard:[NSPasteboard pasteboardWithName:NSDragPboard] michael@0: source:mNativeDragView michael@0: slideBack:YES]; michael@0: gUserCancelledDrag = false; michael@0: michael@0: if (mDoingDrag) michael@0: nsBaseDragService::EndDragSession(false); michael@0: michael@0: return NS_OK; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex) michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; michael@0: michael@0: if (!aTransferable) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // get flavor list that includes all acceptable flavors (including ones obtained through conversion) michael@0: nsCOMPtr flavorList; michael@0: nsresult rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList)); michael@0: if (NS_FAILED(rv)) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: uint32_t acceptableFlavorCount; michael@0: flavorList->Count(&acceptableFlavorCount); michael@0: michael@0: // if this drag originated within Mozilla we should just use the cached data from michael@0: // when the drag started if possible michael@0: if (mDataItems) { michael@0: nsCOMPtr currentTransferableSupports; michael@0: mDataItems->GetElementAt(aItemIndex, getter_AddRefs(currentTransferableSupports)); michael@0: if (currentTransferableSupports) { michael@0: nsCOMPtr currentTransferable(do_QueryInterface(currentTransferableSupports)); michael@0: if (currentTransferable) { michael@0: for (uint32_t i = 0; i < acceptableFlavorCount; i++) { michael@0: nsCOMPtr genericFlavor; michael@0: flavorList->GetElementAt(i, getter_AddRefs(genericFlavor)); michael@0: nsCOMPtr currentFlavor(do_QueryInterface(genericFlavor)); michael@0: if (!currentFlavor) michael@0: continue; michael@0: nsXPIDLCString flavorStr; michael@0: currentFlavor->ToString(getter_Copies(flavorStr)); michael@0: michael@0: nsCOMPtr dataSupports; michael@0: uint32_t dataSize = 0; michael@0: rv = currentTransferable->GetTransferData(flavorStr, getter_AddRefs(dataSupports), &dataSize); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: aTransferable->SetTransferData(flavorStr, dataSupports, dataSize); michael@0: return NS_OK; // maybe try to fill in more types? Is there a point? michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: // now check the actual clipboard for data michael@0: for (uint32_t i = 0; i < acceptableFlavorCount; i++) { michael@0: nsCOMPtr genericFlavor; michael@0: flavorList->GetElementAt(i, getter_AddRefs(genericFlavor)); michael@0: nsCOMPtr currentFlavor(do_QueryInterface(genericFlavor)); michael@0: michael@0: if (!currentFlavor) michael@0: continue; michael@0: michael@0: nsXPIDLCString flavorStr; michael@0: currentFlavor->ToString(getter_Copies(flavorStr)); michael@0: michael@0: PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("nsDragService::GetData: looking for clipboard data of type %s\n", flavorStr.get())); michael@0: michael@0: if (flavorStr.EqualsLiteral(kFileMime)) { michael@0: NSArray* pFiles = [globalDragPboard propertyListForType:NSFilenamesPboardType]; michael@0: if (!pFiles || [pFiles count] < (aItemIndex + 1)) michael@0: continue; michael@0: michael@0: NSString* filePath = [pFiles objectAtIndex:aItemIndex]; michael@0: if (!filePath) michael@0: continue; michael@0: michael@0: unsigned int stringLength = [filePath length]; michael@0: unsigned int dataLength = (stringLength + 1) * sizeof(char16_t); // in bytes michael@0: char16_t* clipboardDataPtr = (char16_t*)malloc(dataLength); michael@0: if (!clipboardDataPtr) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: [filePath getCharacters:reinterpret_cast(clipboardDataPtr)]; michael@0: clipboardDataPtr[stringLength] = 0; // null terminate michael@0: michael@0: nsCOMPtr file; michael@0: nsresult rv = NS_NewLocalFile(nsDependentString(clipboardDataPtr), true, getter_AddRefs(file)); michael@0: free(clipboardDataPtr); michael@0: if (NS_FAILED(rv)) michael@0: continue; michael@0: michael@0: aTransferable->SetTransferData(flavorStr, file, dataLength); michael@0: michael@0: break; michael@0: } michael@0: michael@0: NSString *pboardType = NSStringPboardType; michael@0: michael@0: if (nsClipboard::IsStringType(flavorStr, &pboardType) || michael@0: flavorStr.EqualsLiteral(kURLMime) || michael@0: flavorStr.EqualsLiteral(kURLDataMime) || michael@0: flavorStr.EqualsLiteral(kURLDescriptionMime)) { michael@0: NSString* pString = [globalDragPboard stringForType:pboardType]; michael@0: if (!pString) michael@0: continue; michael@0: michael@0: NSData* stringData = [pString dataUsingEncoding:NSUnicodeStringEncoding]; michael@0: unsigned int dataLength = [stringData length]; michael@0: void* clipboardDataPtr = malloc(dataLength); michael@0: if (!clipboardDataPtr) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: [stringData getBytes:clipboardDataPtr]; michael@0: michael@0: // The DOM only wants LF, so convert from MacOS line endings to DOM line endings. michael@0: int32_t signedDataLength = dataLength; michael@0: nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(flavorStr, &clipboardDataPtr, &signedDataLength); michael@0: dataLength = signedDataLength; michael@0: michael@0: // skip BOM (Byte Order Mark to distinguish little or big endian) michael@0: char16_t* clipboardDataPtrNoBOM = (char16_t*)clipboardDataPtr; michael@0: if ((dataLength > 2) && michael@0: ((clipboardDataPtrNoBOM[0] == 0xFEFF) || michael@0: (clipboardDataPtrNoBOM[0] == 0xFFFE))) { michael@0: dataLength -= sizeof(char16_t); michael@0: clipboardDataPtrNoBOM += 1; michael@0: } michael@0: michael@0: nsCOMPtr genericDataWrapper; michael@0: nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtrNoBOM, dataLength, michael@0: getter_AddRefs(genericDataWrapper)); michael@0: aTransferable->SetTransferData(flavorStr, genericDataWrapper, dataLength); michael@0: free(clipboardDataPtr); michael@0: break; michael@0: } michael@0: michael@0: // We have never supported this on Mac OS X, we should someday. Normally dragging images michael@0: // in is accomplished with a file path drag instead of the image data itself. michael@0: /* michael@0: if (flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kJPEGImageMime) || michael@0: flavorStr.EqualsLiteral(kJPGImageMime) || flavorStr.EqualsLiteral(kGIFImageMime)) { michael@0: michael@0: } michael@0: */ michael@0: } michael@0: return NS_OK; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDragService::IsDataFlavorSupported(const char *aDataFlavor, bool *_retval) michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; michael@0: michael@0: *_retval = false; michael@0: michael@0: if (!globalDragPboard) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsDependentCString dataFlavor(aDataFlavor); michael@0: michael@0: // first see if we have data for this in our cached transferable michael@0: if (mDataItems) { michael@0: uint32_t dataItemsCount; michael@0: mDataItems->Count(&dataItemsCount); michael@0: for (unsigned int i = 0; i < dataItemsCount; i++) { michael@0: nsCOMPtr currentTransferableSupports; michael@0: mDataItems->GetElementAt(i, getter_AddRefs(currentTransferableSupports)); michael@0: if (!currentTransferableSupports) michael@0: continue; michael@0: michael@0: nsCOMPtr currentTransferable(do_QueryInterface(currentTransferableSupports)); michael@0: if (!currentTransferable) michael@0: continue; michael@0: michael@0: nsCOMPtr flavorList; michael@0: nsresult rv = currentTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList)); michael@0: if (NS_FAILED(rv)) michael@0: continue; michael@0: michael@0: uint32_t flavorCount; michael@0: flavorList->Count(&flavorCount); michael@0: for (uint32_t j = 0; j < flavorCount; j++) { michael@0: nsCOMPtr genericFlavor; michael@0: flavorList->GetElementAt(j, getter_AddRefs(genericFlavor)); michael@0: nsCOMPtr currentFlavor(do_QueryInterface(genericFlavor)); michael@0: if (!currentFlavor) michael@0: continue; michael@0: nsXPIDLCString flavorStr; michael@0: currentFlavor->ToString(getter_Copies(flavorStr)); michael@0: if (dataFlavor.Equals(flavorStr)) { michael@0: *_retval = true; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: NSString *pboardType = nil; michael@0: michael@0: if (dataFlavor.EqualsLiteral(kFileMime)) { michael@0: NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObject:NSFilenamesPboardType]]; michael@0: if (availableType && [availableType isEqualToString:NSFilenamesPboardType]) michael@0: *_retval = true; michael@0: } michael@0: else if (dataFlavor.EqualsLiteral(kURLMime)) { michael@0: NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObject:kCorePboardType_url]]; michael@0: if (availableType && [availableType isEqualToString:kCorePboardType_url]) michael@0: *_retval = true; michael@0: } michael@0: else if (nsClipboard::IsStringType(dataFlavor, &pboardType)) { michael@0: NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObject:pboardType]]; michael@0: if (availableType && [availableType isEqualToString:pboardType]) michael@0: *_retval = true; michael@0: } michael@0: michael@0: return NS_OK; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDragService::GetNumDropItems(uint32_t* aNumItems) michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; michael@0: michael@0: *aNumItems = 0; michael@0: michael@0: // first check to see if we have a number of items cached michael@0: if (mDataItems) { michael@0: mDataItems->Count(aNumItems); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // if there is a clipboard and there is something on it, then there is at least 1 item michael@0: NSArray* clipboardTypes = [globalDragPboard types]; michael@0: if (globalDragPboard && [clipboardTypes count] > 0) michael@0: *aNumItems = 1; michael@0: else michael@0: return NS_OK; michael@0: michael@0: // if there is a list of files, send the number of files in that list michael@0: NSArray* fileNames = [globalDragPboard propertyListForType:NSFilenamesPboardType]; michael@0: if (fileNames) michael@0: *aNumItems = [fileNames count]; michael@0: michael@0: return NS_OK; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDragService::EndDragSession(bool aDoneDrag) michael@0: { michael@0: NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; michael@0: michael@0: if (mNativeDragView) { michael@0: [mNativeDragView release]; michael@0: mNativeDragView = nil; michael@0: } michael@0: if (mNativeDragEvent) { michael@0: [mNativeDragEvent release]; michael@0: mNativeDragEvent = nil; michael@0: } michael@0: michael@0: mUserCancelled = gUserCancelledDrag; michael@0: michael@0: nsresult rv = nsBaseDragService::EndDragSession(aDoneDrag); michael@0: mDataItems = nullptr; michael@0: return rv; michael@0: michael@0: NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; michael@0: }