Files
Mozilla/mozilla/widget/src/os2/nsDragService.cpp
mkaply%us.ibm.com f6a75be6c1 # 25555
r= jdunn@netscape.com
OS/2 changes for Mozilla


git-svn-id: svn://10.0.0.236/trunk@60739 18797224-902f-48f8-a5cc-f745e15eee43
2000-02-14 15:57:53 +00:00

977 lines
30 KiB
C++

/*
* 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 the Mozilla OS/2 libraries.
*
* The Initial Developer of the Original Code is John Fairhurst,
* <john_fairhurst@iname.com>. Portions created by John Fairhurst are
* Copyright (C) 1999 John Fairhurst. All Rights Reserved.
*
* Contributor(s):
*
*/
// Drag'n'drop manager
#include "nsWidgetDefs.h"
#include "nsDragService.h"
#include "nsITransferable.h"
#include "nsVoidArray.h"
#include "nsFileSpec.h"
#include "nsFileStream.h"
#include "nsSpecialSystemDirectory.h"
#include "resid.h"
#include <stdio.h> // for sscanf
#include <stdlib.h> // realloc/free
//
// There are three major cases to consider:
//
// 1. Drag from xptoolkit to non-xptoolkit
//
// Use DRM_OS2FILE. Source render to get right rf used.
//
// 2. Drag from xptoolkit to xptoolkit
//
// Use a custom shared-memory RM; special-case same process
//
// 3. Drag from non-xptoolkit to xptoolkit
//
// Use DRM_OS2FILE and create nsFileListTransferable's
// Problem: we need to copy the file because we have no way of knowing
// when client has done with it & we can DM_ENDCONVERSATION
//
// Plus: xptoolkit will eventually acquire text/URL (or text/URI or something)
// which we can handle.
//
// Apart from this, the major thing not implemented is the initiation of
// post-drop conversations for DRM_OS2FILE. This is because of various reasons,
// see comment in nsDragService::DoPushedOS2FILE() below.
//
// Quick utility class to clean up files we create at some later point...
class nsGCFileSpec : public nsFileSpec
{
public:
nsGCFileSpec(nsFileSpec &fs) : nsFileSpec(fs) {}
~nsGCFileSpec()
{
Delete( FALSE);
}
};
static char *DecodeStrHandle( HSTR hstr);
static const char *MimeTypeToRF( const char *pcsz);
static const char *RFToMimeType( const char *pcsz);
static BOOL FindFile( PDRAGITEM pItem, nsFileSpec &aFileSpec);
static void GetTempFile( nsFileSpec &tempfile);
// convert between pm & xptoolkit drag operation types
#define DragOperation(at) \
(at == nsIDragService::DRAGDROP_ACTION_NONE ? DO_DEFAULT : \
(at == nsIDragService::DRAGDROP_ACTION_COPY ? DO_COPY : \
(at == nsIDragService::DRAGDROP_ACTION_MOVE ? DO_MOVE : DO_LINK)))
#define DragDropAction(do) \
(do == DO_LINK ? nsIDragService::DRAGDROP_ACTION_LINK : \
(do == DO_COPY ? nsIDragService::DRAGDROP_ACTION_COPY : \
nsIDragService::DRAGDROP_ACTION_MOVE))
nsDragService::nsDragService() : mDragInfo(0), mDragItems(0)
{
// XXX temporary icon until xptoolkit realises it needs to give us one
mIcon = WinLoadPointer( HWND_DESKTOP, gModuleData.hModResources,
ID_ICO_DRAGITEM);
// Window for doing things
mDragWnd = WinCreateWindow( HWND_DESKTOP, WC_STATIC, 0, 0, 0, 0, 0, 0,
HWND_DESKTOP, HWND_BOTTOM, 0, 0, 0);
mWndProc = WinSubclassWindow( mDragWnd, fnwpDragSource);
}
nsDragService::~nsDragService()
{
WinDestroyPointer( mIcon);
WinDestroyWindow( mDragWnd);
}
nsresult nsDragService::InvokeDragSession( nsISupportsArray *aTransArray,
nsIRegion *aRegion,
PRUint32 aActionType)
{
// This is horribly multidimensional -- we have an array of dragitems, fine.
// But -- each dragitem may be a file list, which itself is several dragitems.
PDRAGITEM pDragItems = 0;
ULONG cDragItems = 0;
PRUint32 cItems;
aTransArray->Count( &cItems);
for( PRUint32 i = 0; i < cItems; i++)
{
nsCOMPtr<nsISupports> pThing;
pThing = dont_AddRef( aTransArray->ElementAt(i)); // XXX check this doesn't leak
if( pThing)
{
// Get dragitems for this array element
nsCOMPtr<nsITransferable> pXfer = do_QueryInterface(pThing);
PDRAGITEM pDItems = 0;
ULONG cDItems = 0;
CreateDragItems( &cDItems, &pDItems, pXfer);
// Now extend & copy up into the local array
pDragItems = (PDRAGITEM)
realloc( pDragItems, cDragItems + cDItems * sizeof(DRAGITEM));
memcpy( pDragItems + cDragItems, pDItems, cDItems * sizeof(DRAGITEM));
cDragItems += cDItems;
// free local data
delete [] pDItems;
}
}
nsresult rc = NS_ERROR_FAILURE;
if( cDragItems)
{
rc = InvokeDrag( pDragItems, cDragItems, aActionType);
free( pDragItems);
}
return rc;
}
nsresult nsDragService::GetData( nsITransferable *aTransferable,
PRUint32 aItemIndex)
{
// Fill the transferable with data from the given dragitem.
if( !aTransferable || aItemIndex >= mDragInfo->cditem)
return NS_ERROR_FAILURE;
PDRAGITEM pItem = DrgQueryDragitemPtr( mDragInfo, aItemIndex);
// Problem here. Unless we're xptoolkit<->xptoolkit we can only
// get data in *one* flavour.
//
// Oh well; do our best.
nsVoidArray *pFormats = nsnull;
aTransferable->FlavorsTransferableCanImport( &pFormats);
PRUint32 cFormats = pFormats->Count();
for( PRUint32 i = 0; i < cFormats; i++)
{
nsString *pFlavour = (nsString*) pFormats->ElementAt( i);
char buff[40];
gModuleData.ConvertFromUcs( *pFlavour, buff, 40);
const char *rf = MimeTypeToRF( buff);
if( rf && DrgVerifyRMF( pItem, 0, rf))
{
// Okay, have something to do. Now pick a rendering mechanism:
void *pData = 0;
PRUint32 cData = 0;
BOOL source_dry_p = FALSE; // can only get single flavour
// 1. Some xptoolkit - use DRM_MOZILLA
if( DrgVerifyRMF( pItem, "DRM_MOZILLA", 0))
{
DoMozillaXfer( pItem, buff, &pData, &cData);
}
// 2. Some random process - use DRM_OS2FILE
else if( DrgVerifyRMF( pItem, "DRM_OS2FILE", 0))
{
// 2a. `normal' rendering - load it, break out
if( pItem->hstrSourceName && pItem->hstrContainerName)
{
nsFileSpec file;
if( !FindFile( pItem, file))
printf( "Can't find dropped file\n");
else
{
cData = file.GetFileSize();
pData = new char [ cData ];
nsInputFileStream istream( file);
istream.read( pData, (PRInt32) cData);
istream.close();
source_dry_p = TRUE;
}
}
// 2b. DRM_OS2FILE push - faff around endlessly, break out
// This is a bit tricky 'cos this method needs to be synchronous.
else
{
DoPushedOS2FILE( pItem, rf, &pData, &cData);
source_dry_p = TRUE;
}
}
else
{
const char *rmf = DecodeStrHandle( pItem->hstrRMF);
printf( "Incomprehensible DRM (%s)\n", rmf);
}
if( pData && cData)
aTransferable->SetTransferData( pFlavour, pData, cData);
if( source_dry_p)
break;
}
else if( pFlavour->Equals( kDropFilesMime))
{
// Moan if this isn't a filelisttransferable.
nsCOMPtr<nsIFileListTransferable> pFileList = do_QueryInterface(aTransferable);
if( !pFileList)
printf( "kDropFilesMime requested but no filelisttransferable!\n");
else
{
// Need a file.
nsFileSpec *pFileSpec = 0;
if( DrgVerifyRMF( pItem, "DRM_MOZILLA", 0))
{
void *pData = 0;
PRUint32 cData;
DoMozillaXfer( pItem, buff, &pData, &cData);
if( pData)
{
nsFileSpec tempfile;
GetTempFile( tempfile);
nsOutputFileStream stream(tempfile);
stream.write( pData, (PRInt32)cData);
stream.close();
// Make sure this temp file is erased eventually.
pFileSpec = new nsGCFileSpec( tempfile);
}
}
// 2. Some random process - use DRM_OS2FILE
else if( DrgVerifyRMF( pItem, "DRM_OS2FILE", 0))
{
if( pItem->hstrSourceName && pItem->hstrContainerName)
{
nsFileSpec file;
if( !FindFile( pItem, file))
printf( "Can't find dropped file\n");
else
pFileSpec = new nsFileSpec(file);
}
else
{
// (can't actually do source rendering yet)
DoPushedOS2FILE(0,0,0,0);
}
}
else
{
const char *rmf = DecodeStrHandle( pItem->hstrRMF);
printf( "Incomprehensible DRM -> file (%s)\n", rmf);
}
// Did we get one?
if( pFileSpec)
{
nsVoidArray array;
array.AppendElement(pFileSpec);
pFileList->SetFileList(&array);
}
}
}
}
return NS_OK;
}
nsresult nsDragService::GetNumDropItems( PRUint32 *aNumItems)
{
if( !aNumItems)
return NS_ERROR_NULL_POINTER;
*aNumItems = mDragInfo->cditem;
return NS_OK;
}
nsresult nsDragService::IsDataFlavorSupported( nsString *aDataFlavour)
{
// The idea here is to return NS_OK if any of the dragitems supports
// this flavour (yeah, hmm...)
//
// Maybe we should change it so they all have to be (which is what CUA
// says we should do...)
nsresult rc = NS_ERROR_FAILURE;
char buff[40];
gModuleData.ConvertFromUcs( *aDataFlavour, buff, 40);
const char *rf = MimeTypeToRF( buff);
#ifdef DEBUG
printf( "IsDataFlavorSupported %s\n", buff);
printf( "RF for that is %s\n", rf);
#endif
if( rf)
{
for( PRUint32 i = 0; i < mDragInfo->cditem; i++)
{
PDRAGITEM pItem = DrgQueryDragitemPtr( mDragInfo, i);
// this checks for ANY rm, which is a bit dubious.
if( DrgVerifyRMF( pItem, 0, rf))
{
rc = NS_OK;
break;
}
}
}
#ifdef DEBUG
printf( "Flavor is %ssupported.\n", rc == NS_OK ? "" : "not ");
#endif
return rc;
}
// Starting drag-over event block.
void nsDragService::InitDragOver( PDRAGINFO aDragInfo)
{
// If the drag's from another process, grab it
if( !mDragInfo)
{
DrgAccessDraginfo( aDragInfo);
mDragInfo = aDragInfo;
}
// Set xp flags
SetCanDrop( PR_FALSE);
SetDragAction( DragDropAction(mDragInfo->usOperation));
StartDragSession();
}
// end of drag-over event block; get xp settings & convert.
MRESULT nsDragService::TermDragOver()
{
MRESULT rc;
PRBool bCanDrop;
PRUint32 action;
EndDragSession();
GetCanDrop( &bCanDrop);
GetDragAction( &action);
rc = MPFROM2SHORT( bCanDrop ? DOR_DROP : DOR_NODROP, DragOperation(action));
// ...factor code...
TermDragExit();
return rc;
}
void nsDragService::InitDragExit( PDRAGINFO aDragInfo)
{
// Nothing else to do
InitDragOver( aDragInfo);
}
void nsDragService::TermDragExit()
{
// release draginfo if appropriate. Note we use the slightly icky way
// of looking at the value of mDragItems to see if we started the drag.
if( !mDragItems)
{
DrgFreeDraginfo( mDragInfo);
mDragInfo = 0;
}
}
void nsDragService::InitDrop( PDRAGINFO aDragInfo)
{
// again, doesn't look like there's anything else to do
InitDragOver( aDragInfo);
}
void nsDragService::TermDrop()
{
// do an end-conversation for each dragitem.
// Any actual rendering is done in response to the GetData method above.
for( PRUint32 i = 0; i < mDragInfo->cditem; i++)
{
PDRAGITEM pItem = DrgQueryDragitemPtr( mDragInfo, i);
DrgSendTransferMsg( pItem->hwndItem,
DM_ENDCONVERSATION,
MPFROMLONG(pItem->ulItemID),
MPFROMSHORT(DMFL_TARGETSUCCESSFUL)); // I suppose
}
TermDragExit();
}
// access the singleton
nsresult NS_GetDragService( nsISupports **aDragService)
{
if( !aDragService)
return NS_ERROR_NULL_POINTER;
*aDragService = (nsIDragService*)gModuleData.dragService;
NS_ADDREF(*aDragService);
return NS_OK;
}
// Examine a transferable and allocate & fill in appropriate DRAGITEMs
void nsDragService::CreateDragItems( PULONG pCount, PDRAGITEM *ppItems,
nsITransferable *aTransferable)
{
nsCOMPtr<nsIFileListTransferable> pFileList = do_QueryInterface(aTransferable);
if( pFileList)
{
nsVoidArray aFiles;
pFileList->GetFileList( &aFiles);
*pCount = aFiles.Count();
if( *pCount)
{
// Create a dragitem for each filespec
*ppItems = new DRAGITEM [*pCount];
for( PRUint32 i = 0; i < *pCount; i++)
{
nsFileSpec *pFile = (nsFileSpec*) aFiles.ElementAt(i);
FillDragItem( *ppItems + i, pFile);
}
}
}
else
{
*ppItems = new DRAGITEM [1]; // alloc w' new [] for uniform deletion
*pCount = 1;
FillDragItem( *ppItems, aTransferable);
}
}
void nsDragService::FillDragItem( PDRAGITEM aItem, nsFileSpec *aFilespec)
{
// We don't have to source-render these, 'cos they're unique files which
// already exist (we hope).
//
// On the down side, I have to trust nsFileSpec...
//
aItem->hwndItem = mDragWnd; // just for completeness
aItem->ulItemID = 0;
aItem->hstrType = DrgAddStrHandle( DRT_UNKNOWN);
// XXX print & discard to come ? Maybe not, actually.
aItem->hstrRMF = DrgAddStrHandle( "<DRM_OS2FILE,DRF_UNKNOWN>");
// (this is a really messy, unwieldy api)
nsFileSpec parentDir;
aFilespec->GetParent( parentDir);
aItem->hstrContainerName = DrgAddStrHandle( nsNSPRPath(parentDir));
char *pszLeaf = aFilespec->GetLeafName();
aItem->hstrSourceName = DrgAddStrHandle( pszLeaf);
aItem->hstrTargetName = DrgAddStrHandle( pszLeaf);
nsCRT::free( pszLeaf);
aItem->cxOffset = aItem->cyOffset = 0;
aItem->fsControl = 0;
aItem->fsSupportedOps = DO_COPYABLE | DO_MOVEABLE | DO_LINKABLE;
}
// Transferables passed in here are guaranteed not to be nsIFileListTransferables
//
void nsDragService::FillDragItem( PDRAGITEM aItem, nsITransferable *aTransferable)
{
aItem->hwndItem = mDragWnd;
// ref the transferable to write out the data when we know which is needed
aItem->ulItemID = (ULONG) aTransferable;
NS_ADDREF(aTransferable);
// Now go through transferable building things
nsVoidArray *pFormats = nsnull;
aTransferable->FlavorsTransferableCanExport( &pFormats);
// XXX DRM_DISCARD and DRM_PRINTFILE to come when xptoolkit decides how
// (whether...) to handle them
char rmf[200] = "(DRM_OS2FILE,DRM_MOZILLA) X (DRF_UNKNOWN";
char buff[40];
PRUint32 cFormats = pFormats->Count();
for( PRUint32 i = 0; i < cFormats; i++)
{
nsString *pFlavour = (nsString*) pFormats->ElementAt( i);
gModuleData.ConvertFromUcs( *pFlavour, buff, 40);
const char *rf = MimeTypeToRF( buff);
if( rf)
{
strcat( rmf, ",");
strcat( rmf, rf);
}
#if 0
else if( pFlavour->Equals( kURLMime))
{
// Abort any processing already done; the idea here is to provide
// the URL format so the WPS can do the Right Thing; we also need to
// provide some kind of text format for insertion into a program.
aItem->hstrType = DrgAddStrHandle( DRT_URL","DRT_TEXT);
aItem->hstrRMF = DrgAddStrHandle( "<DRM_OS2FILE,DRF_TEXT>,<DRM_STRHANDLES,DRF_URL>");
aItem->hstrContainerName = 0;
aItem->hstrSourceName = DrgAddStrHandle( full url );
aItem->hstrTargetName = DrgAddStrHandle( title for object );
aItem->cxOffset = aItem->cyOffset = 0;
aItem->fsControl = 0;
aItem->fsSupportedOps = DO_COPYABLE | DO_MOVEABLE | DO_LINKABLE;
return;
}
#endif
// Not sure what to do about 'Type'. Setting everything is wrong,
// but picking an arbitary one is also bad.
//
// So leave it as unknown for now.
}
delete pFormats;
strcat( rmf, ")");
aItem->hstrType = DrgAddStrHandle( DRT_UNKNOWN);
aItem->hstrRMF = DrgAddStrHandle( rmf);
// For source-rendering, don't supply `source name'
nsSpecialSystemDirectory tmpDir(nsSpecialSystemDirectory::OS_TemporaryDirectory);
aItem->hstrContainerName = DrgAddStrHandle( nsNSPRPath(tmpDir));
aItem->hstrSourceName = 0;
aItem->hstrTargetName = DrgAddStrHandle( "ATempFile");
aItem->cxOffset = aItem->cyOffset = 0; // DrgDrag() sets these
aItem->fsControl = 0;
aItem->fsSupportedOps = DO_COPYABLE | DO_MOVEABLE | DO_LINKABLE;
}
// Actually do the drag
nsresult nsDragService::InvokeDrag( PDRAGITEM aItems, ULONG aCItems,
PRUint32 aActionType)
{
// keep track of allocated draginfos
NS_ASSERTION(!mDragInfo,"Drag info leaked");
nsresult rc = NS_ERROR_FAILURE;
PDRAGINFO pDragInfo = DrgAllocDraginfo( aCItems);
if( pDragInfo)
{
pDragInfo->usOperation = DragOperation(aActionType);
pDragInfo->hwndSource = mDragWnd;
for( PRUint32 i = 0; i < aCItems; i++)
DrgSetDragitem( pDragInfo, aItems + i, sizeof(DRAGITEM), i);
// XXX Need to make a dragimage from somewhere. There ought to be an
// nsIImage passed in here, but let's just make something up for now.
//
// XXX also need to handle the multiple-dragitem case correctly
//
DRAGIMAGE dimage = { sizeof(DRAGIMAGE), 0, mIcon,
{ 0, 0 }, DRG_ICON, 0, 0 };
// Set draginfo pointer for reentrancy
mDragInfo = pDragInfo;
mDragItems = aCItems;
HWND hwndDest = DrgDrag( mDragWnd, pDragInfo, &dimage, 1, VK_ENDDRAG,
#ifdef DEBUG
(void*) 0x80000000L // makes IPMD happier
#else
0
#endif
);
rc = NS_OK; // hwndDest == 0 may be error or just cancelled; shrug.
if( !hwndDest)
{
// Clean up everything here; no async. case to consider.
DrgDeleteDraginfoStrHandles( pDragInfo);
DrgFreeDraginfo( pDragInfo);
mDragInfo = 0;
mDragItems = 0;
}
// We don't DrgFreeDragInfo() here if there is a transfer of some sort;
// instead this is done when we get the appropriate DM_ENDCONVERSATION.
}
return rc;
}
// Window-proc. for the drag-source window
MRESULT EXPENTRY fnwpDragSource( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
MRESULT mr;
if( gModuleData.dragService)
mr = gModuleData.dragService->HandleMessage( msg, mp1, mp2);
else
mr = WinDefWindowProc( hwnd, msg, mp1, mp2);
return mr;
}
MRESULT nsDragService::HandleMessage( ULONG msg, MPARAM mp1, MPARAM mp2)
{
switch(msg)
{
case DM_RENDER:
{
NS_ASSERTION(mDragItems && mDragInfo, "Spurious DM_RENDER");
// The target wants us to put some data somewhere.
PDRAGTRANSFER pXFer = (PDRAGTRANSFER) mp1;
BOOL rc = FALSE;
// This is vitally important, apparently.
pXFer->pditem->hstrSourceName = DrgAddStrHandle( "Dummy.fil");
if( !pXFer->pditem->ulItemID)
{
// the target (silly boy) has asked us to source-render something
// it's completely capable of rendering all by itself.
pXFer->fsReply = DMFL_NATIVERENDER;
DrgFreeDragtransfer( pXFer);
}
else
{
// Need to actually return from this call before we can render the
// thing...
WinPostMsg( mDragWnd, WM_USER, mp1, mp2);
rc = TRUE;
}
return MRFROMLONG(rc);
}
//
// Very possibly this should be in a fresh thread.
//
// This rather large block is the source-side of the source-render
// protocol; the target picks which format (from those provided by
// the transferable) it would like & where we should put it.
//
case WM_USER:
{
// Posted to ourselves in order to carry out a target's desired
// rendering.
PDRAGTRANSFER pXFer = (PDRAGTRANSFER) mp1;
nsITransferable *pTrans = (nsITransferable*) pXFer->pditem->ulItemID;
USHORT usFlags = DMFL_RENDERFAIL;
NS_ASSERTION(pTrans, "No transferable to source-render");
#ifdef DEBUG
char *target = DecodeStrHandle( pXFer->hstrRenderToName);
printf( "Source-rendering to %s\n", target);
nsFileSpec dest( target);
#else
nsFileSpec dest( DecodeStrHandle( pXFer->hstrRenderToName));
#endif
// Now, the fun bit is working out what format to use.
char *rmf = DecodeStrHandle( pXFer->hstrSelectedRMF);
char rm[50], rf[50];
int tokens = sscanf( rmf, "<%s,%s>", rm, rf);
NS_ASSERTION(tokens == 2, "Couldn't parse hstrSelectedRMF");
#ifdef DEBUG
printf( "%d - %s %s\n", tokens, rm, rf);
#endif
if( !strcmp( rm, "DRM_OS2FILE"))
{
// Go through the transferable's flavours looking for one which
// matches the requested rf.
nsVoidArray *pFormats = nsnull;
char buff[40];
pTrans->FlavorsTransferableCanExport( &pFormats);
PRUint32 cFormats = pFormats->Count(), i;
for( i = 0; i < cFormats; i++)
{
nsString *pFlavour = (nsString*) pFormats->ElementAt( i);
gModuleData.ConvertFromUcs( *pFlavour, buff, 40);
const char *this_rf = MimeTypeToRF( buff);
if( this_rf && !strcmp( this_rf, rf))
{
// Found it!
void *pData;
PRUint32 cData;
pTrans->GetTransferData( pFlavour, &pData, &cData);
// (uh-oh)
nsOutputFileStream stream(dest);
stream.write( pData, (PRInt32)cData);
stream.close();
usFlags = DMFL_RENDEROK;
break;
}
}
delete pFormats;
if( i == cFormats)
#ifdef DEBUG
printf( "Target asked for format %s which we can't do.\n", rf);
#endif
}
else
{
printf( "Unexpected rendering mechanism\n");
}
// Tell the target we're done.
DrgPostTransferMsg( pXFer->hwndClient,
DM_RENDERCOMPLETE,
pXFer,
usFlags,
0,
TRUE);
DrgFreeDragtransfer( pXFer);
// Note that the transferable we have here will be release'd in
// the DM_ENDCONVERSATION for the dragitem in question.
return 0;
}
// DRM_MOZILLA messages; see nsWidgetDefs.h for details
case WMU_GETFLAVOURLEN:
case WMU_GETFLAVOURDATA:
{
char buffer[40] = "";
PRUint32 cData = 0;
void *pData;
nsITransferable *pTrans = (nsITransferable*) mp1;
if( pTrans)
{
PWZDROPXFER pXFer = (PWZDROPXFER) mp2;
ATOM atom;
if( msg == WMU_GETFLAVOURLEN) atom = LONGFROMMP(mp2);
else atom = pXFer->hAtomFlavour;
WinQueryAtomName( WinQuerySystemAtomTable(), atom, buffer, 40);
nsAutoString str(buffer);
if( NS_SUCCEEDED(pTrans->GetTransferData( &str, &pData, &cData)))
{
if( msg == WMU_GETFLAVOURDATA)
{
memcpy( &pXFer->data[0], pData, cData);
DosFreeMem( pXFer);
return MPFROMLONG(TRUE);
}
}
}
return MRFROMLONG(cData);
}
case DM_ENDCONVERSATION:
{
NS_ASSERTION(mDragItems && mDragInfo, "Unexpected DM_ENDCONVERSATION");
// If it was necessary (for source-rendering), we kept a reference
// to the transferable in the dragitem. Now it's safe to release.
nsITransferable *pTransferable = (nsITransferable*) mp1;
NS_IF_RELEASE(pTransferable);
mDragItems--;
if( mDragItems == 0)
{
// the last of the dragitems has been ack'ed, so free the draginfo
DrgFreeDraginfo( mDragInfo);
mDragInfo = 0;
}
#ifdef DEBUG
printf( "DM_ENDCONVERSATION, mDragItems = %d\n", (int)mDragItems);
#endif
return 0;
}
}
return (*mWndProc)( mDragWnd, msg, mp1, mp2);
}
// Various forms of source-rendering, DRM_MOZILLA and "pushed-file" -------------
//
// Custom shared-memory rendering mechanism
//
// Probably ought to just get creative with DRAGTRANSFER as is, but that (a)
// confuses the DRM_OS2FILE source-rendering & (b) imposes unhelpful constraints
void nsDragService::DoMozillaXfer( PDRAGITEM pItem, char *szFlavour,
void **ppData, PRUint32 *cData)
{
// First check if this is an intra-process transfer!
if( mDragItems)
{
// Yes.
nsITransferable *pSource = (nsITransferable*) pItem->ulItemID;
if( !pSource)
printf( "intra-process xfer fails due to null ulItemID\n");
else
{
nsAutoString flavour(szFlavour);
if( NS_SUCCEEDED(pSource->GetTransferData( &flavour, ppData, cData)))
{
// need to make a copy...
char *tmp = new char [ *cData ];
memcpy( tmp, *ppData, *cData);
*ppData = tmp;
}
}
return;
}
HATOMTBL hAtomTbl = WinQuerySystemAtomTable();
ATOM hAtom = WinAddAtom( hAtomTbl, szFlavour);
ULONG ulLen = (ULONG) WinSendMsg( pItem->hwndItem, WMU_GETFLAVOURLEN,
MPFROMLONG(pItem->ulItemID),
MPFROMLONG(hAtom));
if( ulLen)
{
void *shmem = 0;
if( !DosAllocSharedMem( &shmem, 0, ulLen + sizeof(ATOM),
PAG_COMMIT | OBJ_GIVEABLE | PAG_WRITE))
{
// Find the tid of the source so we can give it the memory
PID pid;
TID tid;
WinQueryWindowProcess( pItem->hwndItem, &pid, &tid);
DosGiveSharedMem( shmem, pid, PAG_WRITE);
PWZDROPXFER pWzData = (PWZDROPXFER) shmem;
pWzData->hAtomFlavour = hAtom;
BOOL ok = (BOOL) WinSendMsg( pItem->hwndItem, WMU_GETFLAVOURDATA,
MPFROMLONG(pItem->ulItemID),
MPFROMP(pWzData));
if( ok)
{
// now allocate (too many copies I know, but transferable has
// restrictions...)
char *buf = new char [ ulLen ];
memcpy( buf, &pWzData->data[0], ulLen);
*cData = ulLen;
*ppData = buf;
}
// free shared memory
DosFreeMem( shmem);
}
}
WinDeleteAtom( hAtomTbl, hAtom);
}
void nsDragService::DoPushedOS2FILE( PDRAGITEM pItem, const char *szRf,
void **pData, PRUint32 *cData)
{
// Unfortunately there's no way we can do this: we must return from DM_DROP
// before having a "post-drop conversation" involving DM_RENDER.
//
// BUT we need to fill the transferable NOW, before we return from DM_DROP
// so that gecko (or whoever's underneath us).
//
// So we're stuck until there's some asynch. way of proceeding.
//
// But it's not all bad: not many people use source rendering; mozilla
// does, but we can use DRM_MOZILLA to do that.
printf( "\n\nSorry, source-rendering of DRM_OS2FILE not working.\n");
printf( "(see mozilla/widget/src/os2/nsDragService::DoPushedOS2FILE)\n\n");
}
// Quick utility functions ------------------------------------------------------
static char *DecodeStrHandle( HSTR hstr)
{
static char buf[CCHMAXPATH];
DrgQueryStrName( hstr, CCHMAXPATH, buf);
return buf;
}
// Table to map mozilla "mimetypes" to PM "rendering formats"
// Could optimize I guess, but not really important.
static const char *gFormatMap[][2] =
{
{ "DRF_TEXT", kTextMime },
{ "DRF_UNICODE", kUnicodeMime },
{ "DRF_HTML", kHTMLMime },
{ "DRF_XIF", kXIFMime },
{ "DRF_PNG", kPNGImageMime },
{ "DRF_GIF", kGIFImageMime },
{ "DRF_JPEG", kJPEGImageMime },
{ "DRF_AOLMAIL", kAOLMailMime },
{ 0, 0 }
};
static const char *MimeTypeToRF( const char *pcsz)
{
int i = 0;
while( gFormatMap[i][0])
if( !strcmp( pcsz, gFormatMap[i][1])) break;
return gFormatMap[i][0];
}
static const char *RFToMimeType( const char *pcsz)
{
int i = 0;
while( gFormatMap[i][0])
if( !strcmp( pcsz, gFormatMap[i][0])) break;
return gFormatMap[i][1];
}
static BOOL FindFile( PDRAGITEM pItem, nsFileSpec &aFileSpec)
{
const char *str = DecodeStrHandle( pItem->hstrContainerName);
#ifdef DEBUG
printf( "Getting drag data from `%s'", str);
#endif
aFileSpec = str;
str = DecodeStrHandle( pItem->hstrSourceName);
#ifdef DEBUG
printf( "`%s'\n", str);
#endif
aFileSpec += str;
return aFileSpec.Exists();
}
static void GetTempFile( nsFileSpec &tempfile)
{
nsSpecialSystemDirectory tmpDir(nsSpecialSystemDirectory::OS_TemporaryDirectory);
tmpDir += "tmpfile";
tmpDir.MakeUnique();
tempfile = tmpDir;
}