/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsDragService.h" #include "nsITransferable.h" #include "nsString.h" #include "nsClipboard.h" #include "nsIRegion.h" #include "nsISupportsPrimitives.h" #include "nsPrimitiveHelpers.h" #include "nsCOMPtr.h" #include "nsXPIDLString.h" #include "nsWidgetsCID.h" char *nsDragService::mDndEvent = NULL; int nsDragService::mDndEventLen; #define kMimeCustom "text/_moz_htmlcontext" nsDragService::nsDragService() { mDndWidget = nsnull; mDndEvent = nsnull; mNativeCtrl = nsnull; mRawData = nsnull; mFlavourStr = nsnull; mTransportFile = nsnull; } nsDragService::~nsDragService() { if( mNativeCtrl ) PtReleaseTransportCtrl( mNativeCtrl ); if( mFlavourStr ) free( mFlavourStr ); if( mTransportFile ) { unlink( mTransportFile ); free( mTransportFile ); } } NS_IMETHODIMP nsDragService::SetNativeDndData( PtWidget_t *widget, PhEvent_t *event ) { mDndWidget = widget; if( !mDndEvent ) { mDndEventLen = sizeof( PhEvent_t ) + event->num_rects * sizeof( PhRect_t ) + event->data_len; mDndEvent = ( char * ) malloc( mDndEventLen ); } memcpy( mDndEvent, (char*)event, mDndEventLen ); return NS_OK; } NS_IMETHODIMP nsDragService::SetDropData( char *data ) { if( mRawData ) free( mRawData ); /* data is the filename used for passing the data */ FILE *fp = fopen( data, "r" ); PRUint32 n; fread( &n, sizeof( PRUint32 ), 1, fp ); mRawData = ( char * ) malloc( n ); if( !mRawData ) { fclose( fp ); return NS_ERROR_FAILURE; } fseek( fp, 0, SEEK_SET ); fread( mRawData, 1, n, fp ); fclose( fp ); return NS_OK; } /* remove this function with the one from libph.so, when it becomes available */ int CancelDrag( PhRid_t rid, unsigned input_group ) { struct dragevent { PhEvent_t hdr; PhDragEvent_t drag; } ev; memset( &ev, 0, sizeof(ev) ); ev.hdr.type = Ph_EV_DRAG; ev.hdr.emitter.rid = Ph_DEV_RID; ev.hdr.flags = Ph_EVENT_INCLUSIVE | Ph_EMIT_TOWARD; ev.hdr.data_len = sizeof( ev.drag ); ev.hdr.subtype = Ph_EV_DRAG_COMPLETE; ev.hdr.input_group = input_group; ev.drag.rid = rid; return PhEmit( &ev.hdr, NULL, &ev.drag ); } //------------------------------------------------------------------------- NS_IMETHODIMP nsDragService::InvokeDragSession (nsIDOMNode *aDOMNode, nsISupportsArray * aArrayTransferables, nsIScriptableRegion * aRegion, PRUint32 aActionType) { #ifdef DEBUG printf( "nsDragService::InvokeDragSession\n" ); #endif nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode, aArrayTransferables, aRegion, aActionType); NS_ENSURE_SUCCESS(rv, rv); if(!aArrayTransferables) return NS_ERROR_INVALID_ARG; /* this will also addref the transferables since we're going to hang onto this beyond the length of this call */ mSourceDataItems = aArrayTransferables; PRUint32 numDragItems = 0; mSourceDataItems->Count(&numDragItems); if ( ! numDragItems ) return NS_ERROR_FAILURE; /* cancel a previous drag ( PhInitDrag ) if one is in place */ CancelDrag( PtWidgetRid( mDndWidget ), ((PhEvent_t*)mDndEvent)->input_group ); mActionType = aActionType; PRUint32 pDataLen = sizeof( PRUint32 ) + sizeof( PRUint32 ), totalItems = 0; char *pdata = ( char * ) malloc( pDataLen ); /* we reserve space for a total size and totalItems */ if( !pdata ) return NS_ERROR_FAILURE; for(PRUint32 itemIndex = 0; itemIndex < numDragItems; ++itemIndex) { nsCOMPtr genericItem; mSourceDataItems->GetElementAt(itemIndex, getter_AddRefs(genericItem)); nsCOMPtr currItem (do_QueryInterface(genericItem)); if(currItem) { nsCOMPtr flavorList; currItem->FlavorsTransferableCanExport(getter_AddRefs(flavorList)); if(flavorList) { PRUint32 numFlavors; flavorList->Count( &numFlavors ); for( PRUint32 flavorIndex = 0; flavorIndex < numFlavors ; ++flavorIndex ) { nsCOMPtr genericWrapper; flavorList->GetElementAt (flavorIndex, getter_AddRefs(genericWrapper)); nsCOMPtr currentFlavor; currentFlavor = do_QueryInterface(genericWrapper); if(currentFlavor) { nsXPIDLCString flavorStr; currentFlavor->ToString ( getter_Copies(flavorStr) ); const char *FlavourStr = ( const char * ) flavorStr; nsCOMPtr data; PRUint32 tmpDataLen = 0; rv = currItem->GetTransferData( FlavourStr, getter_AddRefs(data), &tmpDataLen ); if( NS_SUCCEEDED( rv ) ) { /* insert FlavourStr, data into the PtTransportCtrl_t */ int len = sizeof( PRUint32 ) + sizeof( PRUint32 ) + strlen( FlavourStr ) + 1 + tmpDataLen; /* we reserve space for itemIndex|tmpDataLen|flavorStr|data */ len = ( ( len + 3 ) / 4 ) * 4; pdata = ( char * ) realloc( pdata, len + pDataLen ); if( pdata ) { char *p = pdata + pDataLen; PRUint32 *d = ( PRUint32 * ) p; d[0] = itemIndex; /* copy itemIndex*/ d[1] = tmpDataLen; /* copy PRUint32 tmpDataLen */ strcpy( p + sizeof( PRUint32 ) + sizeof( PRUint32 ), FlavourStr ); /* copy flavorStr */ void *mem_data; nsPrimitiveHelpers::CreateDataFromPrimitive ( FlavourStr, data, &mem_data, tmpDataLen ); memcpy( p + sizeof( PRUint32 ) + sizeof( PRUint32 ) + strlen( FlavourStr ) + 1, mem_data, tmpDataLen ); /* copy the data */ pDataLen += len; totalItems++; } } } } } } } if( totalItems ) { PRUint32 *p = ( PRUint32 * ) pdata; p[0] = pDataLen; p[1] = totalItems; mNativeCtrl = PtCreateTransportCtrl( ); if( !mTransportFile ) mTransportFile = strdup( (char*) tmpnam( NULL ) ); FILE *fp = fopen( mTransportFile, "w" ); fwrite( pdata, 1, pDataLen, fp ); fclose( fp ); free( pdata ); PtTransportType( mNativeCtrl, "Mozilla", "dnddata", 1, Ph_TRANSPORT_INLINE, "string", (void*)mTransportFile, 0, 0 ); PtInitDnd( mNativeCtrl, mDndWidget, (PhEvent_t*)mDndEvent, NULL, 0 ); } return NS_OK; } //------------------------------------------------------------------------- NS_IMETHODIMP nsDragService::GetNumDropItems (PRUint32 * aNumItems) { *aNumItems = 1; return NS_OK; } //------------------------------------------------------------------------- NS_IMETHODIMP nsDragService::GetData (nsITransferable * aTransferable, PRUint32 aItemIndex ) { nsresult rv = NS_ERROR_FAILURE; nsCOMPtr genericDataWrapper; if( mRawData ) { PRUint32 *d = ( PRUint32 * ) mRawData, totalItems = d[1]; PRUint32 i, pdataLen = sizeof( PRUint32 ) + sizeof( PRUint32 ); /* search for aItemIndex */ for( i=0; iSetTransferData( flavorStr, genericDataWrapper, d[1] ); break; } pdataLen += this_len; } } return rv; } //------------------------------------------------------------------------- NS_IMETHODIMP nsDragService::IsDataFlavorSupported(const char *aDataFlavor, PRBool *_retval) { if (!aDataFlavor || !_retval) return NS_ERROR_FAILURE; // set this to no by default *_retval = PR_FALSE; const char *ask; if( !strcmp( aDataFlavor, kMimeCustom ) ) ask = kHTMLMime; else ask = aDataFlavor; if(!mSourceDataItems) return NS_OK; PRUint32 numDragItems = 0; mSourceDataItems->Count(&numDragItems); for(PRUint32 itemIndex = 0; itemIndex < numDragItems; ++itemIndex) { nsCOMPtr genericItem; mSourceDataItems->GetElementAt(itemIndex, getter_AddRefs(genericItem)); nsCOMPtr currItem (do_QueryInterface(genericItem)); if(currItem) { nsCOMPtr flavorList; currItem->FlavorsTransferableCanExport(getter_AddRefs(flavorList)); if(flavorList) { PRUint32 numFlavors; flavorList->Count( &numFlavors ); for( PRUint32 flavorIndex = 0; flavorIndex < numFlavors ; ++flavorIndex ) { nsCOMPtr genericWrapper; flavorList->GetElementAt (flavorIndex, getter_AddRefs(genericWrapper)); nsCOMPtr currentFlavor; currentFlavor = do_QueryInterface(genericWrapper); if(currentFlavor) { nsXPIDLCString flavorStr; currentFlavor->ToString ( getter_Copies(flavorStr) ); if(strcmp(flavorStr, ask) == 0) { *_retval = PR_TRUE; if( mFlavourStr ) free( mFlavourStr ); mFlavourStr = strdup( ask ); } } } } } } return NS_OK; } void nsDragService::SourceEndDrag(void) { // this just releases the list of data items that we provide mSourceDataItems = 0; }