diff --git a/widget/src/cocoa/nsChildView.mm b/widget/src/cocoa/nsChildView.mm index a7bbb7b24456..87fb1d7e014f 100644 --- a/widget/src/cocoa/nsChildView.mm +++ b/widget/src/cocoa/nsChildView.mm @@ -2564,16 +2564,31 @@ const PRInt32 kNumLines = 4; nsMouseScrollEvent geckoEvent; geckoEvent.eventStructType = NS_MOUSE_SCROLL_EVENT; geckoEvent.nativeMsg = nsnull; + geckoEvent.scrollFlags = 0; + [self convert:theEvent message:NS_MOUSE_SCROLL toGeckoEvent:&geckoEvent]; + PRInt32 incomingDeltaX = (PRInt32)[theEvent deltaX]; PRInt32 incomingDeltaY = (PRInt32)[theEvent deltaY]; + + PRInt32 scrollDelta = 0; + if (incomingDeltaY != 0) + { + geckoEvent.scrollFlags |= nsMouseScrollEvent::kIsVertical; + scrollDelta = incomingDeltaY; + } + else if (incomingDeltaX != 0) + { + geckoEvent.scrollFlags |= nsMouseScrollEvent::kIsHorizontal; + scrollDelta = incomingDeltaX; + } + // Use hasJaguarAppKit to determine if we're on 10.2 where the user has control // over the deltaY from a scrollwheel event via the Mouse panel in System Preferences if (hasJaguarAppKit()) - geckoEvent.delta = -incomingDeltaY; + geckoEvent.delta = -scrollDelta; else - geckoEvent.delta = incomingDeltaY * -kNumLines; - geckoEvent.scrollFlags |= nsMouseScrollEvent::kIsVertical; - + geckoEvent.delta = scrollDelta * -kNumLines; + // send event into Gecko by going directly to the // the widget. mGeckoChild->DispatchWindowEvent(geckoEvent); diff --git a/widget/src/cocoa/nsClipboard.cpp b/widget/src/cocoa/nsClipboard.cpp index b0707b33d157..ccc176a270ca 100644 --- a/widget/src/cocoa/nsClipboard.cpp +++ b/widget/src/cocoa/nsClipboard.cpp @@ -172,13 +172,19 @@ nsClipboard :: SetNativeClipboardData ( PRInt32 aWhichClipboard ) } } // if unicode else if ( strcmp(flavorStr, kPNGImageMime) == 0 || strcmp(flavorStr, kJPEGImageMime) == 0 || - strcmp(flavorStr, kGIFImageMime) == 0 ) { + strcmp(flavorStr, kGIFImageMime) == 0 || strcmp(flavorStr, kNativeImageMime) == 0 ) { // we have an image, which is in the transferable as an nsIImage. Convert it // to PICT (PicHandle) and put those bits on the clipboard. The actual size // of the picture is the size of the handle, not sizeof(Picture). - nsCOMPtr imageSupports; - errCode = mTransferable->GetTransferData ( flavorStr, getter_AddRefs(imageSupports), &dataSize ); - nsCOMPtr image ( do_QueryInterface(imageSupports) ); + nsCOMPtr transferSupports; + errCode = mTransferable->GetTransferData ( flavorStr, getter_AddRefs(transferSupports), &dataSize ); + nsCOMPtr ptrPrimitive(do_QueryInterface(transferSupports)); + nsCOMPtr image; + if (ptrPrimitive) { + nsCOMPtr primitiveData; + ptrPrimitive->GetData(getter_AddRefs(primitiveData)); + image = do_QueryInterface(primitiveData); + } if ( image ) { PicHandle picture = nsnull; image->ConvertToPICT ( &picture ); @@ -230,8 +236,11 @@ nsClipboard :: PutOnClipboard ( ResType inFlavor, const void* inData, PRInt32 in #if TARGET_CARBON ScrapRef scrap; - ::GetCurrentScrap(&scrap); - ::PutScrapFlavor( scrap, inFlavor, kScrapFlavorMaskNone, inLen, inData ); + OSStatus err; + err = ::GetCurrentScrap(&scrap); + NS_ASSERTION(err == noErr, "GetCurrentScrap returned error"); + err =::PutScrapFlavor( scrap, inFlavor, kScrapFlavorMaskNone, inLen, inData ); + NS_ASSERTION(err == noErr, "PutScrapFlavor returned error"); #else long numBytes = ::PutScrap ( inLen, inFlavor, inData ); if ( numBytes != noErr ) diff --git a/widget/src/cocoa/nsDragService.cpp b/widget/src/cocoa/nsDragService.cpp index 0db4da03c2b0..92c5d52a4c09 100644 --- a/widget/src/cocoa/nsDragService.cpp +++ b/widget/src/cocoa/nsDragService.cpp @@ -74,6 +74,12 @@ #include "nsCarbonHelpers.h" #include "nsGfxUtils.h" +// file save stuff +#include "nsNetUtil.h" +#include "nsIURL.h" +#include "nsILocalFileMac.h" +#include "nsIImageMac.h" + #include "nsIXULContent.h" #include "nsIDOMElement.h" #include "nsLinebreakConverter.h" @@ -89,7 +95,10 @@ NS_IMPL_QUERY_INTERFACE3(nsDragService, nsIDragService, nsIDragSession, nsIDragS // DragService constructor // nsDragService::nsDragService() - : mDragRef(0), mDataItems(nsnull), mImageDraggingSupported(PR_FALSE), mDragSendDataUPP(nsnull) + : mDragSendDataUPP(nsnull) + , mDragRef(0) + , mDataItems(nsnull) + , mImageDraggingSupported(PR_FALSE) { #if USE_TRANSLUCENT_DRAGS // check if the Drag Manager supports image dragging @@ -161,7 +170,6 @@ nsDragService :: ComputeGlobalRectFromFrame ( nsIDOMNode* aDOMNode, Rect & outSc // nsRect aRect(0,0,0,0); - nsIView *parentView = nsnull; aFrame->GetRect(aRect); // Find offset from our view @@ -445,13 +453,27 @@ nsDragService :: RegisterDragItemsAndFlavors ( nsISupportsArray * inArray, RgnHa nsXPIDLCString flavorStr; currentFlavor->ToString ( getter_Copies(flavorStr) ); FlavorType macOSFlavor = theMapper.MapMimeTypeToMacOSType(flavorStr); - ::AddDragItemFlavor ( mDragRef, itemIndex, macOSFlavor, NULL, 0, flags ); + + if (macOSFlavor == kDragFlavorTypePromiseHFS) { + // we got kFilePromiseMime + // kDragFlavorTypePromiseHFS is special. See http://developer.apple.com/technotes/tn/tn1085.html + PromiseHFSFlavor promiseData; + promiseData.fileType = 0; // let the file extension prevail! + promiseData.fileCreator = 0; + promiseData.fdFlags = 0; + promiseData.promisedFlavor = kDragPromisedFlavor; + + ::AddDragItemFlavor(mDragRef, itemIndex, flavorTypePromiseHFS, &promiseData, sizeof(promiseData), flavorNotSaved); + ::AddDragItemFlavor(mDragRef, itemIndex, kDragPromisedFlavor, NULL, 0, flavorNotSaved); + } + else + ::AddDragItemFlavor(mDragRef, itemIndex, macOSFlavor, NULL, 0, flags); // If we advertise text/unicode, then make sure we add 'TEXT' to the list // of flavors supported since we will do the conversion ourselves in GetDataForFlavor() if ( strcmp(flavorStr, kUnicodeMime) == 0 ) { theMapper.MapMimeTypeToMacOSType(kTextMime); - ::AddDragItemFlavor ( mDragRef, itemIndex, 'TEXT', NULL, 0, flags ); + ::AddDragItemFlavor(mDragRef, itemIndex, 'TEXT', NULL, 0, flags); } } @@ -470,7 +492,7 @@ nsDragService :: RegisterDragItemsAndFlavors ( nsISupportsArray * inArray, RgnHa mapping, mappingLen, flags ); nsCRT::free ( mapping ); - SetDragItemBounds(mDragRef, itemIndex, &dragRgnBounds); + ::SetDragItemBounds(mDragRef, itemIndex, &dragRgnBounds); } } // foreach drag item @@ -763,8 +785,12 @@ nsDragService :: GetDataForFlavor ( nsISupportsArray* inDragItems, DragReference { if ( !inDragItems || !inDragRef ) return paramErr; - + + *outData = nsnull; + *outDataSize = 0; + OSErr retVal = noErr; + nsresult rv; // (assumes that the items were placed into the transferable as nsITranferable*'s, not nsISupports*'s.) nsCOMPtr genericItem; @@ -786,8 +812,61 @@ nsDragService :: GetDataForFlavor ( nsISupportsArray* inDragItems, DragReference actualFlavor = kUnicodeMime; needToDoConversionToPlainText = PR_TRUE; } + else if ( strcmp(actualFlavor, kFilePromiseMime) == 0 ) { + nsCOMPtr imageURLPrimitive; + PRUint32 dataSize = 0; + rv = item->GetTransferData(kFilePromiseURLMime, getter_AddRefs(imageURLPrimitive), &dataSize); + if (NS_FAILED(rv)) return cantGetFlavorErr; + + nsCOMPtr doubleByteText = do_QueryInterface(imageURLPrimitive); + if (!doubleByteText) return cantGetFlavorErr; + + nsAutoString imageURLString; + PRUnichar* imageURL = nsnull; + doubleByteText->ToString(&imageURL); + if (imageURL) { + imageURLString.Assign(imageURL); + nsMemory::Free(imageURL); + } + + if (imageURLString.IsEmpty()) + return cantGetFlavorErr; + + return HandleHFSPromiseDrop(inDragRef, inItemIndex, inFlavor, imageURLString, outData, outDataSize); + } + else if ( strcmp(actualFlavor, kNativeImageMime) == 0 ) { + PRUint32 dataSize = 0; + nsCOMPtr transferSupports; + rv = item->GetTransferData(actualFlavor, getter_AddRefs(transferSupports), &dataSize); + if (NS_FAILED(rv)) return cantGetFlavorErr; + + nsCOMPtr ptrPrimitive(do_QueryInterface(transferSupports)); + if (!ptrPrimitive) return cantGetFlavorErr; + + nsCOMPtr primitiveData; + ptrPrimitive->GetData(getter_AddRefs(primitiveData)); + nsCOMPtr image = do_QueryInterface(primitiveData); + if (!image) return cantGetFlavorErr; + + PicHandle picture = nsnull; + image->ConvertToPICT(&picture); + if (!picture) return cantGetFlavorErr; + + PRInt32 pictSize = ::GetHandleSize((Handle)picture); + char* pictData = (char*)nsMemory::Alloc(pictSize); + if (pictData) { + ::BlockMoveData(*picture, pictData, pictSize); // doesn't move memory + *outData = (void*)pictData; + *outDataSize = pictSize; + retVal = noErr; + } + else + retVal = cantGetFlavorErr; + ::KillPicture(picture); + + return retVal; + } - *outDataSize = 0; nsCOMPtr data; if ( NS_SUCCEEDED(item->GetTransferData(actualFlavor, getter_AddRefs(data), outDataSize)) ) { nsPrimitiveHelpers::CreateDataFromPrimitive ( actualFlavor, data, outData, *outDataSize ); @@ -800,7 +879,7 @@ nsDragService :: GetDataForFlavor ( nsISupportsArray* inDragItems, DragReference nsLinebreakConverter::ConvertUnicharLineBreaksInSitu(&castedUnicode, nsLinebreakConverter::eLinebreakUnix, nsLinebreakConverter::eLinebreakMac, - *outDataSize, nsnull); + *outDataSize / sizeof(PRUnichar), nsnull); // if required, do the extra work to convert unicode to plain text and replace the output // values with the plain text. @@ -967,3 +1046,125 @@ nsDragService :: SetDragAction ( PRUint32 anAction ) return nsBaseDragService::SetDragAction(anAction); } + +#pragma mark - +// Utility routines for dragging files to the Finder + +static OSErr GetDropDirectory(DragReference dragRef, FSSpecPtr fssOut) +{ + OSErr err; + + AEDesc dropLocAlias = { typeNull, nil }; + err = ::GetDropLocation(dragRef, &dropLocAlias); + if (err != noErr) return err; + + if (dropLocAlias.descriptorType != typeAlias) + return paramErr; + + AEDesc dropLocFSS = { typeNull, nil }; + if ((err = ::AECoerceDesc(&dropLocAlias, typeFSS, &dropLocFSS)) == noErr) + { + err = ::AEGetDescData(&dropLocFSS, fssOut, sizeof(FSSpec)); + (void)::AEDisposeDesc(&dropLocFSS); + } + + if (dropLocAlias.dataHandle) + (void)::AEDisposeDesc(&dropLocAlias); + + return err; +} + +static OSErr CreatePromisedFile(const PromiseHFSFlavor *phfs, const FSSpec *fss, ScriptCode scriptTag) +{ + OSErr err; + + err = ::FSpCreate(fss, phfs->fileCreator, phfs->fileType, scriptTag); + if (err != noErr) return err; + + if (phfs->fdFlags) + { + FInfo finderInfo; + if (::FSpGetFInfo(fss, &finderInfo) == noErr) + { + finderInfo.fdFlags = phfs->fdFlags; + err = ::FSpSetFInfo(fss, &finderInfo); + } + } + + return err; +} + +// will return -43 if the file does not exist, which is OK +static OSErr GetFolderFileSpec(const FSSpec *inFolderSpec, ConstStr255Param inFileName, FSSpec* outFSSpec) +{ + CInfoPBRec cipbp = {0}; + OSErr err = noErr; + + cipbp.dirInfo.ioVRefNum = inFolderSpec->vRefNum; + cipbp.dirInfo.ioDrDirID = inFolderSpec->parID; + cipbp.dirInfo.ioNamePtr = (StringPtr)inFolderSpec->name; + + err = ::PBGetCatInfoSync(&cipbp); + if (err != noErr) return err; + + if ((cipbp.dirInfo.ioFlAttrib & ioDirMask) == 0) + return dirNFErr; + + return ::FSMakeFSSpec(inFolderSpec->vRefNum, cipbp.dirInfo.ioDrDirID, inFileName, outFSSpec); +} + + +OSErr +nsDragService::HandleHFSPromiseDrop(DragReference inDragRef, unsigned int inItemIndex, + FlavorType inFlavor, const nsAString& inSourceURL, void** outData, unsigned int* outDataSize) +{ + *outData = NULL; + *outDataSize = 0; + + OSErr err; + nsresult rv; + + nsCOMPtr sourceURI; + rv = NS_NewURI(getter_AddRefs(sourceURI), inSourceURL); + if (NS_FAILED(rv)) return paramErr; + + // get the promise data + PromiseHFSFlavor promiseData; + Size dataSize = sizeof(promiseData); + err = ::GetFlavorData(inDragRef, inItemIndex, kDragFlavorTypePromiseHFS, &promiseData, &dataSize, 0); + if (err != noErr) return err; + + FSSpec dropLocation; + err = GetDropDirectory(inDragRef, &dropLocation); + if (err != noErr) return err; + + nsCOMPtr dropFolderSpec; + rv = NS_NewLocalFileWithFSSpec(&dropLocation, PR_FALSE, getter_AddRefs(dropFolderSpec)); + if (NS_FAILED(rv)) return paramErr; + + // call the base class to create the file + nsCOMPtr droppedFileSpec; + rv = CreateFileInDirectory(sourceURI, dropFolderSpec, getter_AddRefs(droppedFileSpec)); + if (NS_FAILED(rv)) return paramErr; + + // now fire off a download of the item into the file. + // we rely on the fact that the WPB is refcounted by the channel etc, + // so we don't keep a ref to it. It will die when finished. + rv = SaveURIToFile(sourceURI, droppedFileSpec); + if (NS_FAILED(rv)) return paramErr; + + nsCOMPtr targetFileMac = do_QueryInterface(droppedFileSpec); + if (!targetFileMac) return paramErr; + + FSSpec targetFileSpec; + rv = targetFileMac->GetFSSpec(&targetFileSpec); + if (NS_FAILED(rv)) return paramErr; + + // now we know that everything is working, put the promised data back in the drag + err = ::SetDragItemFlavorData(inDragRef, inItemIndex, inFlavor, &targetFileSpec, sizeof(FSSpec), 0); + if (err != noErr) return err; + + return err; +} + + diff --git a/widget/src/cocoa/nsDragService.h b/widget/src/cocoa/nsDragService.h index 74bec07b51d8..4e26c9144c1e 100644 --- a/widget/src/cocoa/nsDragService.h +++ b/widget/src/cocoa/nsDragService.h @@ -95,16 +95,19 @@ private: // compute a screen rect from the frame associated with the given dom node PRBool ComputeGlobalRectFromFrame ( nsIDOMNode* aDOMNode, Rect & outScreenRect ) ; + OSErr HandleHFSPromiseDrop(DragReference inDragRef, unsigned int inItemIndex, + FlavorType inFlavor, const nsAString& inSourceURL, void** outData, unsigned int* outDataSize); + // callback for the MacOS DragManager when a drop site asks for data static pascal OSErr DragSendDataProc ( FlavorType inFlavor, void* inRefCon, ItemReference theItemRef, DragReference inDragRef ) ; - PRBool mImageDraggingSupported; DragSendDataUPP mDragSendDataUPP; DragReference mDragRef; // reference to _the_ drag. There can be only one. nsISupportsArray* mDataItems; // cached here for when we start the drag so the // DragSendDataProc has access to them. // ONLY VALID DURING A DRAG STARTED WITHIN THIS APP. + PRBool mImageDraggingSupported; }; // class nsDragService diff --git a/widget/src/cocoa/nsMimeMapper.cpp b/widget/src/cocoa/nsMimeMapper.cpp index 5c7ffe5560a2..88a181b5a9f5 100644 --- a/widget/src/cocoa/nsMimeMapper.cpp +++ b/widget/src/cocoa/nsMimeMapper.cpp @@ -99,13 +99,17 @@ nsMimeMapperMac :: MapMimeTypeToMacOSType ( const char* aMimeStr, PRBool inAddIf if ( PL_strcmp(aMimeStr, kTextMime) == 0 ) format = kScrapFlavorTypeText; else if ( PL_strcmp(aMimeStr, kFileMime) == 0 ) - format = flavorTypeHFS; + format = kDragFlavorTypeHFS; + else if ( PL_strcmp(aMimeStr, kFilePromiseMime) == 0 ) + format = kDragFlavorTypePromiseHFS; else if ( PL_strcmp(aMimeStr, kPNGImageMime) == 0 ) format = kScrapFlavorTypePicture; else if ( PL_strcmp(aMimeStr, kJPEGImageMime) == 0 ) format = kScrapFlavorTypePicture; else if ( PL_strcmp(aMimeStr, kGIFImageMime) == 0 ) format = kScrapFlavorTypePicture; + else if ( PL_strcmp(aMimeStr, kNativeImageMime) == 0 ) + format = kScrapFlavorTypePicture; else if ( PL_strcmp(aMimeStr, kUnicodeMime) == 0 ) format = kScrapFlavorTypeUnicode; /* @@ -125,7 +129,8 @@ nsMimeMapperMac :: MapMimeTypeToMacOSType ( const char* aMimeStr, PRBool inAddIf } if ( inAddIfNotPresent ) - NS_ASSERTION ( format, "Didn't map mimeType to a macOS type for some reason" ); + NS_ASSERTION ( format, "Didn't map mimeType to a macOS type for some reason" ); + return format; } // MapMimeTypeToMacOSType @@ -143,9 +148,12 @@ nsMimeMapperMac :: MapMacOSTypeToMimeType ( ResType inMacType, nsCAutoString & o { switch ( inMacType ) { - case kScrapFlavorTypeText: outMimeStr = kTextMime; break; - case kScrapFlavorTypeUnicode: outMimeStr = kUnicodeMime; break; - case flavorTypeHFS: outMimeStr = kFileMime; break; + case kScrapFlavorTypeText: outMimeStr = kTextMime; break; + case kScrapFlavorTypeUnicode: outMimeStr = kUnicodeMime; break; + case kScrapFlavorTypePicture: outMimeStr = kNativeImageMime; break; + case kDragFlavorTypeHFS: outMimeStr = kFileMime; break; + case kDragFlavorTypePromiseHFS: outMimeStr = kFilePromiseMime; break; + case kDragPromisedFlavor: outMimeStr = kFilePromiseMime; break; // This flavor is the old 4.x Composer flavor for HTML. The actual data is a binary // data structure which we do NOT want to deal with in any way shape or form. I am