diff --git a/include/wx/mac/carbon/dataform.h b/include/wx/mac/carbon/dataform.h index ffc4f87a42..6942871ad9 100644 --- a/include/wx/mac/carbon/dataform.h +++ b/include/wx/mac/carbon/dataform.h @@ -22,6 +22,7 @@ public: wxDataFormat(const wxString& rId); wxDataFormat(const wxChar* pId); wxDataFormat(NativeFormat vFormat); + ~wxDataFormat(); wxDataFormat& operator=(NativeFormat vFormat) { SetId(vFormat); return *this; } diff --git a/include/wx/mac/carbon/dataobj.h b/include/wx/mac/carbon/dataobj.h index fa1aa17600..e5c0fda881 100644 --- a/include/wx/mac/carbon/dataobj.h +++ b/include/wx/mac/carbon/dataobj.h @@ -25,6 +25,12 @@ public: #endif virtual bool IsSupportedFormat( const wxDataFormat& format, Direction dir = Get ) const; + void AddToPasteboard( void * pasteboardRef , int itemID ); + // returns true if the passed in format is present in the pasteboard + static bool IsFormatInPasteboard( void * pasteboardRef, const wxDataFormat &dataFormat ); + // returns true if any of the accepted formats of this dataobj is in the pasteboard + bool HasDataInPasteboard( void * pasteboardRef ); + bool GetFromPasteboard( void * pasteboardRef ); }; #endif // _WX_MAC_DATAOBJ_H_ diff --git a/src/common/dobjcmn.cpp b/src/common/dobjcmn.cpp index 1dbe454bc0..673b3809dc 100644 --- a/src/common/dobjcmn.cpp +++ b/src/common/dobjcmn.cpp @@ -290,8 +290,6 @@ static inline wxMBConv& GetConv(const wxDataFormat& format) size_t wxTextDataObject::GetDataSize(const wxDataFormat& format) const { size_t len = GetConv(format).WC2MB( NULL, GetText().c_str(), 0 ); - len += (format == wxDF_UNICODETEXT ? 2 : 1); - return len; } @@ -301,11 +299,7 @@ bool wxTextDataObject::GetDataHere(const wxDataFormat& format, void *buf) const return false; wxCharBuffer buffer = GetConv(format).cWX2MB( GetText().c_str() ); - size_t len = GetConv(format).WC2MB( NULL, GetText().c_str(), 0 ); - len += (format == wxDF_UNICODETEXT ? 2 : 1); - - // trailing (uni)char 0 memcpy( (char*)buf, (const char*)buffer, len ); return true; diff --git a/src/mac/carbon/clipbrd.cpp b/src/mac/carbon/clipbrd.cpp index 9e818ec121..d3e7e847ec 100644 --- a/src/mac/carbon/clipbrd.cpp +++ b/src/mac/carbon/clipbrd.cpp @@ -43,150 +43,90 @@ // (there will be a *lot* of them!) static const wxChar *TRACE_CLIPBOARD = wxT("clipboard"); +IMPLEMENT_DYNAMIC_CLASS(wxClipboard, wxObject) -void * wxGetClipboardData( wxDataFormat dataFormat, long *len ) +// in order to keep the binary interface the same this class +// serves just to have a few additional member variables inside +// the clipboard class + +class wxMacBinaryCompatHelper : public wxDataObject { - OSStatus err = noErr; - void * data = NULL; - Size byteCount; - - switch (dataFormat.GetType()) +public : + wxMacBinaryCompatHelper() { - case wxDF_OEMTEXT: - dataFormat = wxDF_TEXT; - break; - - case wxDF_TEXT: - case wxDF_UNICODETEXT: - break; - - case wxDF_BITMAP: - case wxDF_METAFILE: - break; - - default: - // custom datatype - break; + m_trueData = NULL; } - -#if TARGET_CARBON - ScrapRef scrapRef; - - err = GetCurrentScrap( &scrapRef ); - if ( err != noTypeErr && err != memFullErr ) + + ~wxMacBinaryCompatHelper() { - ScrapFlavorFlags flavorFlags; - - err = GetScrapFlavorFlags( scrapRef, dataFormat.GetFormatId(), &flavorFlags ); - if (err == noErr) + if (m_trueData != NULL) { - err = GetScrapFlavorSize( scrapRef, dataFormat.GetFormatId(), &byteCount ); - if (err == noErr) - { - Size allocSize = byteCount; - if ( dataFormat.GetType() == wxDF_TEXT ) - allocSize += 1; - else if ( dataFormat.GetType() == wxDF_UNICODETEXT ) - allocSize += 2; - - data = new char[ allocSize ]; - - if (( err = GetScrapFlavorData( scrapRef, dataFormat.GetFormatId(), &byteCount , data )) == noErr ) - { - *len = allocSize; - if ( dataFormat.GetType() == wxDF_TEXT ) - ((char*)data)[ byteCount ] = 0; - if ( dataFormat.GetType() == wxDF_UNICODETEXT ) - { - // "data" format is UTF16, so 2 bytes = one character - // wxChar size depends on platform, so just clear last 2 bytes - ((char*)data)[ byteCount + 0 ] = - ((char*)data)[ byteCount + 1 ] = 0; - } - } - else - { - delete [] (char*)data; - data = NULL; - } - } + delete m_trueData; + m_trueData = NULL; } } - -#else - long offset; - Handle datahandle = NewHandle( 0 ); - HLock( datahandle ); - err = (OSStatus)GetScrap( datahandle, dataFormat.GetFormatId(), &offset ); - HUnlock( datahandle ); - if ( GetHandleSize( datahandle ) > 0 ) + + virtual wxDataFormat GetPreferredFormat(Direction dir = Get) const { - byteCount = GetHandleSize( datahandle ); - Size allocSize = byteCount; - if ( dataFormat.GetType() == wxDF_TEXT ) - allocSize += 1; - else if ( dataFormat.GetType() == wxDF_UNICODETEXT ) - allocSize += 2; - - data = new char[ allocSize ]; - - memcpy( (char*) data, (char*) *datahandle, byteCount ); - if ( dataFormat.GetType() == wxDF_TEXT ) - ((char*)data)[ byteCount ] = 0; - else if ( dataFormat.GetType() == wxDF_UNICODETEXT ) - ((wxChar*)data)[ byteCount / 2 ] = 0; - *len = byteCount; + return wxDataFormat(); } - DisposeHandle( datahandle ); -#endif - - if (err != noErr) + virtual size_t GetFormatCount(Direction dir = Get) const { - wxLogSysError(wxT("Failed to get clipboard data.")); - - return NULL; + return 0; } - if (dataFormat.GetType() == wxDF_TEXT) - wxMacConvertNewlines10To13( (char*)data ); + virtual void GetAllFormats(wxDataFormat *formats, + Direction dir = Get) const + { + } - return data; -} + virtual size_t GetDataSize(const wxDataFormat& format) const + { + return 0; + } -IMPLEMENT_DYNAMIC_CLASS(wxClipboard, wxObject) + virtual bool GetDataHere(const wxDataFormat& format, void *buf) const + { + return false; + } + + // only relevant from here on + + wxDataObject* m_trueData; + wxCFRef m_pasteboard; +}; + +#define M_CLIPBOARD ((wxMacBinaryCompatHelper*)m_data) wxClipboard::wxClipboard() { m_open = false; - m_data = NULL; + m_data = new wxMacBinaryCompatHelper() ; + PasteboardRef clipboard = 0; + OSStatus err = PasteboardCreate( kPasteboardClipboard, &clipboard ); + if (err != noErr) + { + wxLogSysError( wxT("Failed to create the clipboard.") ); + } + M_CLIPBOARD->m_pasteboard.reset(clipboard); } wxClipboard::~wxClipboard() { - if (m_data != NULL) - { - delete m_data; - m_data = NULL; - } + M_CLIPBOARD->m_pasteboard.reset((PasteboardRef)0); + delete m_data; } void wxClipboard::Clear() { - if (m_data != NULL) + if (M_CLIPBOARD->m_trueData != NULL) { - delete m_data; - m_data = NULL; + delete M_CLIPBOARD->m_trueData; + M_CLIPBOARD->m_trueData = NULL; } - -#if TARGET_CARBON - OSStatus err; - err = ClearCurrentScrap(); -#else - OSErr err; - err = ZeroScrap(); -#endif - + + OSStatus err = PasteboardClear( M_CLIPBOARD->m_pasteboard ); if (err != noErr) { wxLogSysError( wxT("Failed to empty the clipboard.") ); @@ -232,81 +172,14 @@ bool wxClipboard::AddData( wxDataObject *data ) // we can only store one wxDataObject Clear(); - m_data = data; + PasteboardSyncFlags syncFlags = PasteboardSynchronize( M_CLIPBOARD->m_pasteboard ); + wxCHECK_MSG( !(syncFlags&kPasteboardModified), false, wxT("clipboard modified after clear") ); + wxCHECK_MSG( (syncFlags&kPasteboardClientIsOwner), false, wxT("client couldn't own clipboard") ); - // get formats from wxDataObjects - wxDataFormat *array = new wxDataFormat[ m_data->GetFormatCount() ]; - m_data->GetAllFormats( array ); - - for (size_t i = 0; i < m_data->GetFormatCount(); i++) - { - if (array[i].IsStandard()) - { - wxLogTrace( TRACE_CLIPBOARD, - wxT("wxClipboard now supports standard atom type %d"), - array[i].GetType() ); - } - else - { - wxLogTrace( TRACE_CLIPBOARD, - wxT("wxClipboard now supports atom %s"), - array[i].GetId().c_str() ); - } - - size_t sz = data->GetDataSize( array[ i ] ); - void* buf = malloc( sz + 1 ); - if ( buf != NULL ) - { - // empty the buffer because in some case GetDataHere does not fill buf - memset( buf, 0, sz + 1 ); - data->GetDataHere( array[ i ], buf ); - OSType mactype = 0; - switch ( array[i].GetType() ) - { - case wxDF_TEXT: - case wxDF_OEMTEXT: - mactype = kScrapFlavorTypeText; - sz -= 1; - break; - -#if wxUSE_UNICODE - case wxDF_UNICODETEXT: - mactype = kScrapFlavorTypeUnicode; - sz -= 2; - break; -#endif - -#if wxUSE_DRAG_AND_DROP - case wxDF_METAFILE: -#if wxMAC_USE_CORE_GRAPHICS - mactype = 'PDF '; -#else - mactype = kScrapFlavorTypePicture; -#endif - break; -#endif - - case wxDF_BITMAP: - case wxDF_DIB: -#if wxMAC_USE_CORE_GRAPHICS - mactype = 'TIFF'; -#else - mactype = kScrapFlavorTypePicture; -#endif - break; - - default: - mactype = (OSType)(array[ i ].GetFormatId()); - break; - } - - UMAPutScrap( sz , mactype , buf ); - free( buf ); - } - } - - delete [] array; + M_CLIPBOARD->m_trueData = data; + data->AddToPasteboard( M_CLIPBOARD->m_pasteboard, 1 ); + return true; } @@ -319,61 +192,18 @@ void wxClipboard::Close() // Get rid of cached object. // If this is not done, copying data from // another application will only work once - if (m_data) + if (M_CLIPBOARD->m_trueData) { - delete m_data; - m_data = (wxDataObject*) NULL; + delete M_CLIPBOARD->m_trueData; + M_CLIPBOARD->m_trueData = (wxDataObject*) NULL; } } bool wxClipboard::IsSupported( const wxDataFormat &dataFormat ) { - if ( m_data ) - return m_data->IsSupported( dataFormat ); - - bool hasData = false; - -#if TARGET_CARBON - OSStatus err = noErr; - ScrapRef scrapRef; - - err = GetCurrentScrap( &scrapRef ); - if ( err != noTypeErr && err != memFullErr ) - { - ScrapFlavorFlags flavorFlags; - Size byteCount; - - err = GetScrapFlavorFlags( scrapRef, dataFormat.GetFormatId(), &flavorFlags ); - if (err == noErr) - { - err = GetScrapFlavorSize( scrapRef, dataFormat.GetFormatId(), &byteCount ); - if (err == noErr) - hasData = true; - } - else if ( dataFormat.GetType() == wxDF_UNICODETEXT ) - { - err = GetScrapFlavorFlags( scrapRef, 'TEXT', &flavorFlags ); - if (err == noErr) - { - err = GetScrapFlavorSize( scrapRef, 'TEXT', &byteCount ); - if (err == noErr) - hasData = true; - } - } - } - -#else - - long offset = 0; - Handle datahandle = NewHandle( 0 ); - HLock( datahandle ); - GetScrap( datahandle, dataFormat.GetFormatId(), &offset ); - HUnlock( datahandle ); - hasData = GetHandleSize( datahandle ) > 0; - DisposeHandle( datahandle ); -#endif - - return hasData; + if ( M_CLIPBOARD->m_trueData ) + return M_CLIPBOARD->m_trueData->IsSupported( dataFormat ); + return wxDataObject::IsFormatInPasteboard( M_CLIPBOARD->m_pasteboard, dataFormat ); } bool wxClipboard::GetData( wxDataObject& data ) @@ -387,14 +217,14 @@ bool wxClipboard::GetData( wxDataObject& data ) bool transferred = false; - if ( m_data ) + if ( M_CLIPBOARD->m_trueData ) { for (size_t i = 0; !transferred && i < formatcount; i++) { wxDataFormat format = array[ i ]; - if ( m_data->IsSupported( format ) ) + if ( M_CLIPBOARD->m_trueData->IsSupported( format ) ) { - int dataSize = m_data->GetDataSize( format ); + int dataSize = M_CLIPBOARD->m_trueData->GetDataSize( format ); transferred = true; if (dataSize == 0) @@ -404,7 +234,7 @@ bool wxClipboard::GetData( wxDataObject& data ) else { char *d = new char[ dataSize ]; - m_data->GetDataHere( format, (void*)d ); + M_CLIPBOARD->m_trueData->GetDataHere( format, (void*)d ); data.SetData( format, dataSize, d ); delete [] d; } @@ -415,33 +245,7 @@ bool wxClipboard::GetData( wxDataObject& data ) // get formats from wxDataObjects if ( !transferred ) { - for (size_t i = 0; !transferred && i < formatcount; i++) - { - wxDataFormat format = array[ i ]; - - switch ( format.GetType() ) - { - // NOTE: this is usable for all data types - case wxDF_TEXT: - case wxDF_UNICODETEXT: - case wxDF_OEMTEXT: - case wxDF_BITMAP: - case wxDF_METAFILE: - default: - { - long len; - char* s = (char*)wxGetClipboardData( format, &len ); - if (s != NULL) - { - data.SetData( format, len, s ); - delete [] s; - - transferred = true; - } - } - break; - } - } + transferred = data.GetFromPasteboard( M_CLIPBOARD->m_pasteboard ) ; } delete [] array; diff --git a/src/mac/carbon/dataobj.cpp b/src/mac/carbon/dataobj.cpp index d0435a7b69..efdacfd2c5 100644 --- a/src/mac/carbon/dataobj.cpp +++ b/src/mac/carbon/dataobj.cpp @@ -48,63 +48,85 @@ wxDataFormat::wxDataFormat() wxDataFormat::wxDataFormat( wxDataFormatId vType ) { + m_format = 0; + m_type = wxDF_INVALID; SetType( vType ); } wxDataFormat::wxDataFormat( const wxChar *zId ) { + m_format = 0; + m_type = wxDF_INVALID; SetId( zId ); } wxDataFormat::wxDataFormat( const wxString& rId ) { + m_format = 0; + m_type = wxDF_INVALID; SetId( rId ); } wxDataFormat::wxDataFormat( NativeFormat vFormat ) { + m_format = 0; + m_type = wxDF_INVALID; SetId( vFormat ); } +wxDataFormat::~wxDataFormat() +{ + if ( m_format != 0 ) + { + CFRelease( (CFStringRef) m_format ); + m_format = 0; + } +} + +// in order to be correct for 10.3 we restrict to the available types there +// http://developer.apple.com/qa/qa2005/qa1406.html +// TODO : Use UTCoreTypes.h constants once we support 10.4+ only + void wxDataFormat::SetType( wxDataFormatId dataType ) { m_type = dataType; + if ( m_format != 0 ) + { + CFRelease( (CFStringRef) m_format ); + m_format = 0; + } switch (m_type) { case wxDF_TEXT: - m_format = kScrapFlavorTypeText; + m_format = (long) CFStringCreateCopy( NULL, CFSTR("public.plain-text") ); break; case wxDF_UNICODETEXT: - m_format = kScrapFlavorTypeUnicode; + m_format = (long) CFStringCreateCopy( NULL, CFSTR("public.utf16-plain-text") ); break; case wxDF_BITMAP: #if wxMAC_USE_CORE_GRAPHICS - m_format = 'TIFF'; + m_format = (long) CFStringCreateCopy( NULL, CFSTR("public.tiff") ); #else - m_format = kScrapFlavorTypePicture; + m_format = (long) CFStringCreateCopy( NULL, CFSTR("com.apple.pict") ); #endif break; case wxDF_METAFILE: #if wxMAC_USE_CORE_GRAPHICS - m_format = 'PDF '; + m_format = (long) CFStringCreateCopy( NULL, CFSTR("com.adobe.pdf") ); #else - m_format = kScrapFlavorTypePicture; + m_format = (long) CFStringCreateCopy( NULL, CFSTR("com.apple.pict") ); #endif break; case wxDF_FILENAME: - m_format = kDragFlavorTypeHFS; + m_format = (long) CFStringCreateCopy( NULL, CFSTR("public.url") ); break; default: wxFAIL_MSG( wxT("invalid data format") ); - - // NB: this translates to '????' ASCII but it can't be used in the code - // because '??' will get parsed as a trigraph! - m_format = 0x3f3f3f3f; break; } } @@ -119,38 +141,43 @@ wxString wxDataFormat::GetId() const void wxDataFormat::SetId( NativeFormat format ) { - m_format = format; - - switch (m_format) + if ( m_format != 0 ) + { + CFRelease( (CFStringRef) m_format ); + m_format = 0; + } + m_format = (NativeFormat) CFStringCreateCopy(NULL, (CFStringRef)format); + if ( UTTypeConformsTo( (CFStringRef)format, CFSTR("public.plain-text") ) ) { - case kScrapFlavorTypeText: m_type = wxDF_TEXT; - break; - - case kScrapFlavorTypeUnicode: + } + else if ( UTTypeConformsTo( (CFStringRef)format, CFSTR("public.utf16-plain-text") ) ) + { m_type = wxDF_UNICODETEXT; - break; - -#if wxMAC_USE_CORE_GRAPHCIS - case 'TIFF': + } +#if wxMAC_USE_CORE_GRAPHICS + else if ( UTTypeConformsTo( (CFStringRef)format, CFSTR("public.tiff") ) ) + { m_type = wxDF_BITMAP; - break; -#endif - case kScrapFlavorTypePicture: + } + else if ( UTTypeConformsTo( (CFStringRef)format, CFSTR("com.adobe.pdf") ) ) + { m_type = wxDF_METAFILE; - break; - - case kDragFlavorTypeHFS: + } +#else + else if ( UTTypeConformsTo( (CFStringRef)format, CFSTR("com.apple.pict") ) ) + { + m_type = wxDF_METAFILE; + } +#endif + else if ( UTTypeConformsTo( (CFStringRef)format, CFSTR("public.file-url") ) ) + { m_type = wxDF_FILENAME; - break; - - default: + } + else + { m_type = wxDF_PRIVATE; - char text[5]; - memcpy( text, (const char*)&format, 4 ); - text[4] = 0; - m_id = wxString::FromAscii( text ); - break; + m_id = wxMacCFStringHolder( (CFStringRef) CFRetain((CFStringRef) format )).AsString(); } } @@ -158,15 +185,21 @@ void wxDataFormat::SetId( const wxChar* zId ) { m_type = wxDF_PRIVATE; m_id = zId; - m_format = 'WXPR'; + if ( m_format != 0 ) + { + CFRelease( (CFStringRef) m_format ); + m_format = 0; + } + // since it is private, no need to conform to anything ... + m_format = (long) wxMacCFStringHolder(m_id).Detach(); } bool wxDataFormat::operator==(const wxDataFormat& format) const { if (IsStandard() || format.IsStandard()) - return (format.m_type == m_type); + return ( format.m_type == m_type ); else - return (m_id == format.m_id); + return ( UTTypeConformsTo( (CFStringRef) m_format , (CFStringRef) format.m_format ) ); } //------------------------------------------------------------------------- @@ -206,6 +239,300 @@ bool wxDataObject::IsSupportedFormat( const wxDataFormat& rFormat, Direction vDi return found; } +void wxDataObject::AddToPasteboard( void * pb, int itemID ) +{ + PasteboardRef pasteboard = (PasteboardRef) pb; + // get formats from wxDataObjects + wxDataFormat *array = new wxDataFormat[ GetFormatCount() ]; + GetAllFormats( array ); + + for (size_t i = 0; i < GetFormatCount(); i++) + { + wxDataFormat thisFormat = array[ i ]; + + // add four bytes at the end for data objs like text that + // have a datasize = strlen but still need a buffer for the + // string including trailing zero + + size_t datasize = GetDataSize( thisFormat ); + size_t sz = datasize + 4; + void* buf = malloc( sz ); + if ( buf != NULL ) + { + // empty the buffer because in some case GetDataHere does not fill buf + memset( buf, 0, sz ); + GetDataHere( array[ i ], buf ); + int counter = 1 ; + if ( thisFormat.GetType() == wxDF_FILENAME ) + { + // the data is D-normalized UTF8 strings of filenames delimited with \n + char *fname = strtok((char*) buf,"\n"); + while (fname != NULL) + { + // translate the filepath into a fileurl and put that into the pasteobard + CFStringRef path = CFStringCreateWithBytes(NULL,(UInt8*)fname,strlen(fname),kCFStringEncodingUTF8,false); + CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path , kCFURLPOSIXPathStyle, false); + CFRelease(path); + CFDataRef data = CFURLCreateData(NULL,url,kCFStringEncodingUTF8,true); + CFRelease(url); + PasteboardPutItemFlavor( pasteboard, (PasteboardItemID) counter, + (CFStringRef) thisFormat.GetFormatId() , data, kPasteboardFlavorNoFlags); +// CFRelease(data); + counter++; + fname = strtok (NULL,"\n"); + } + + } + else + { + CFDataRef data = CFDataCreate( kCFAllocatorDefault, (UInt8*)buf, datasize ); + if ( thisFormat.GetType() == wxDF_TEXT ) + PasteboardPutItemFlavor( pasteboard, (PasteboardItemID) itemID, + CFSTR("com.apple.traditional-mac-plain-text") , data, kPasteboardFlavorNoFlags); + else + PasteboardPutItemFlavor( pasteboard, (PasteboardItemID) itemID, + (CFStringRef) thisFormat.GetFormatId() , data, kPasteboardFlavorNoFlags); +// CFRelease(data); + } + free( buf ); + } + } + + delete [] array; +} + +bool wxDataObject::IsFormatInPasteboard( void * pb, const wxDataFormat &dataFormat ) +{ + PasteboardRef pasteboard = (PasteboardRef) pb; + bool hasData = false; + OSStatus err = noErr; + ItemCount itemCount; + + // we synchronize here once again, so we don't mind which flags get returned + PasteboardSynchronize( pasteboard ); + + err = PasteboardGetItemCount( pasteboard, &itemCount ); + if ( err == noErr ) + { + for( UInt32 itemIndex = 1; itemIndex <= itemCount && hasData == false ; itemIndex++ ) + { + PasteboardItemID itemID; + CFArrayRef flavorTypeArray; + CFIndex flavorCount; + + err = PasteboardGetItemIdentifier( pasteboard, itemIndex, &itemID ); + if ( err != noErr ) + continue; + + err = PasteboardCopyItemFlavors( pasteboard, itemID, &flavorTypeArray ); + if ( err != noErr ) + continue; + + flavorCount = CFArrayGetCount( flavorTypeArray ); + + for( CFIndex flavorIndex = 0; flavorIndex < flavorCount && hasData == false ; flavorIndex++ ) + { + CFStringRef flavorType; + + flavorType = (CFStringRef)CFArrayGetValueAtIndex( flavorTypeArray, + flavorIndex ); + + wxDataFormat flavorFormat( (wxDataFormat::NativeFormat) flavorType ); + if ( dataFormat == flavorFormat ) + hasData = true; + else if ( dataFormat.GetType() == wxDF_UNICODETEXT && flavorFormat.GetType() == wxDF_TEXT ) + hasData = true; + } + CFRelease (flavorTypeArray); + } + } + + return hasData; +} + +bool wxDataObject::GetFromPasteboard( void * pb ) +{ + PasteboardRef pasteboard = (PasteboardRef) pb; + size_t formatcount = GetFormatCount() + 1; + wxDataFormat *array = new wxDataFormat[ formatcount ]; + array[0] = GetPreferredFormat(); + GetAllFormats( &array[1] ); + ItemCount itemCount = 0; + wxString filenamesPassed; + bool transferred = false; + + // we synchronize here once again, so we don't mind which flags get returned + PasteboardSynchronize( pasteboard ); + + OSStatus err = PasteboardGetItemCount( pasteboard, &itemCount ); + if ( err == noErr ) + { + for (size_t i = 0; !transferred && i < formatcount; i++) + { + // go through the data in our order of preference + wxDataFormat dataFormat = array[ i ]; + + for( UInt32 itemIndex = 1; itemIndex <= itemCount && transferred == false ; itemIndex++ ) + { + PasteboardItemID itemID = 0; + CFArrayRef flavorTypeArray = NULL; + CFIndex flavorCount = 0; + + err = PasteboardGetItemIdentifier( pasteboard, itemIndex, &itemID ); + if ( err != noErr ) + continue; + + err = PasteboardCopyItemFlavors( pasteboard, itemID, &flavorTypeArray ); + if ( err != noErr ) + continue; + + flavorCount = CFArrayGetCount( flavorTypeArray ); + + for( CFIndex flavorIndex = 0; !transferred && flavorIndex < flavorCount ; flavorIndex++ ) + { + CFStringRef flavorType; + CFDataRef flavorData; + CFIndex flavorDataSize; + + flavorType = (CFStringRef)CFArrayGetValueAtIndex( flavorTypeArray, + flavorIndex ); + + wxDataFormat flavorFormat( (wxDataFormat::NativeFormat) flavorType ); + + if ( dataFormat == flavorFormat ) + { + err = PasteboardCopyItemFlavorData( pasteboard, itemID, flavorType , &flavorData ); + if ( err == noErr ) + { + flavorDataSize = CFDataGetLength( flavorData ); + if (dataFormat.GetType() == wxDF_FILENAME ) + { + // revert the translation and decomposition to arrive at a proper utf8 string again + CFURLRef url = CFURLCreateWithBytes( kCFAllocatorDefault, CFDataGetBytePtr( flavorData ), flavorDataSize, kCFStringEncodingUTF8, NULL ); + CFStringRef cfString = CFURLCopyFileSystemPath( url, kCFURLPOSIXPathStyle ); + CFRelease( url ); + CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfString); + CFRelease( cfString ); + CFStringNormalize(cfMutableString,kCFStringNormalizationFormC); + wxString path = wxMacCFStringHolder(cfMutableString).AsString(); + if (!path.empty()) + filenamesPassed += path + wxT("\n"); + } + else + { + // because some data implementation expect trailing a trailing NUL, we add some headroom + void *buf = malloc( flavorDataSize + 4 ); + if ( buf ) + { + memset( buf, 0, flavorDataSize + 4 ); + memcpy( buf, CFDataGetBytePtr( flavorData ), flavorDataSize ); + + if (dataFormat.GetType() == wxDF_TEXT) + wxMacConvertNewlines10To13( (char*) buf ); + SetData( flavorFormat, flavorDataSize, buf ); + transferred = true; + free( buf ); + } + } + CFRelease (flavorData); + } + } + else if ( dataFormat.GetType() == wxDF_UNICODETEXT && flavorFormat.GetType() == wxDF_TEXT ) + { + err = PasteboardCopyItemFlavorData( pasteboard, itemID, flavorType, &flavorData ); + if ( err == noErr ) + { + flavorDataSize = CFDataGetLength( flavorData ); + void *asciibuf = malloc( flavorDataSize + 1 ); + if ( asciibuf ) + { + memset( asciibuf, 0, flavorDataSize + 1 ); + memcpy( asciibuf, CFDataGetBytePtr( flavorData ), flavorDataSize ); + CFRelease (flavorData); + + SetData( wxDF_TEXT, flavorDataSize, asciibuf ); + transferred = true; + free( asciibuf ); + } + else + CFRelease (flavorData); + } + } + } + CFRelease( flavorTypeArray ); + } + if (filenamesPassed.length() > 0) + { + wxCharBuffer buf = filenamesPassed.fn_str(); + SetData( wxDF_FILENAME, strlen( buf ), (const char*)buf ); + transferred = true; + } + } + } + return transferred; +} + +bool wxDataObject::HasDataInPasteboard( void * pb ) +{ + PasteboardRef pasteboard = (PasteboardRef) pb; + size_t formatcount = GetFormatCount() + 1; + wxDataFormat *array = new wxDataFormat[ formatcount ]; + array[0] = GetPreferredFormat(); + GetAllFormats( &array[1] ); + ItemCount itemCount = 0; + bool hasData = false; + + // we synchronize here once again, so we don't mind which flags get returned + PasteboardSynchronize( pasteboard ); + + OSStatus err = PasteboardGetItemCount( pasteboard, &itemCount ); + if ( err == noErr ) + { + for (size_t i = 0; !hasData && i < formatcount; i++) + { + // go through the data in our order of preference + wxDataFormat dataFormat = array[ i ]; + + for( UInt32 itemIndex = 1; itemIndex <= itemCount && hasData == false ; itemIndex++ ) + { + PasteboardItemID itemID = 0; + CFArrayRef flavorTypeArray = NULL; + CFIndex flavorCount = 0; + + err = PasteboardGetItemIdentifier( pasteboard, itemIndex, &itemID ); + if ( err != noErr ) + continue; + + err = PasteboardCopyItemFlavors( pasteboard, itemID, &flavorTypeArray ); + if ( err != noErr ) + continue; + + flavorCount = CFArrayGetCount( flavorTypeArray ); + + for( CFIndex flavorIndex = 0; !hasData && flavorIndex < flavorCount ; flavorIndex++ ) + { + CFStringRef flavorType; + + flavorType = (CFStringRef)CFArrayGetValueAtIndex( flavorTypeArray, + flavorIndex ); + + CFShow( flavorType ); + + wxDataFormat flavorFormat( (wxDataFormat::NativeFormat) flavorType ); + + if ( dataFormat == flavorFormat || + dataFormat.GetType() == wxDF_UNICODETEXT && flavorFormat.GetType() == wxDF_TEXT ) + { + hasData = true; + } + } + CFRelease( flavorTypeArray ); + } + } + } + return hasData; +} + // ---------------------------------------------------------------------------- // wxTextDataObject // ---------------------------------------------------------------------------- @@ -257,7 +584,7 @@ size_t wxFileDataObject::GetDataSize() const GetFileNames( buf ); buffLength = strlen( buf ); - + // terminating 0 return buffLength + 1; } diff --git a/src/mac/carbon/dnd.cpp b/src/mac/carbon/dnd.cpp index 6f5a325730..0e3302f2a7 100644 --- a/src/mac/carbon/dnd.cpp +++ b/src/mac/carbon/dnd.cpp @@ -112,27 +112,11 @@ bool wxDropTarget::CurrentDragHasSupportedFormat() if ( !supported ) { - UInt16 items; - ItemReference theItem; - FlavorType theType; - UInt16 flavors = 0; + PasteboardRef pasteboard; - CountDragItems( (DragReference)m_currentDrag, &items ); - for (UInt16 index = 1; index <= items && !supported; ++index) + if ( GetDragPasteboard( (DragReference)m_currentDrag, &pasteboard ) == noErr ) { - flavors = 0; - GetDragItemReferenceNumber( (DragReference)m_currentDrag, index, &theItem ); - CountDragItemFlavors( (DragReference)m_currentDrag, theItem, &flavors ); - - for ( UInt16 flavor = 1; flavor <= flavors; ++flavor ) - { - GetFlavorType( (DragReference)m_currentDrag, theItem, flavor, &theType ); - if ( m_dataObject->IsSupportedFormat( wxDataFormat( theType ) ) ) - { - supported = true; - break; - } - } + supported = m_dataObject->HasDataInPasteboard( pasteboard ); } } @@ -185,116 +169,15 @@ bool wxDropTarget::GetData() if ( !transferred ) { - UInt16 items; - OSErr result; - ItemReference theItem; - FlavorType theType; - FlavorFlags theFlags; - UInt16 flavors; - wxString filenamesPassed; + PasteboardRef pasteboard; - CountDragItems( (DragReference)m_currentDrag, &items ); - for (UInt16 index = 1; index <= items; ++index) + if ( GetDragPasteboard( (DragReference)m_currentDrag, &pasteboard ) == noErr ) { - flavors = 0; - GetDragItemReferenceNumber( (DragReference)m_currentDrag, index, &theItem ); - CountDragItemFlavors( (DragReference)m_currentDrag, theItem, &flavors ); - wxDataFormat preferredFormat = m_dataObject->GetPreferredFormat( wxDataObject::Set ); - bool hasPreferredFormat = false; - - for (UInt16 flavor = 1; flavor <= flavors; ++flavor) - { - result = GetFlavorType( (DragReference)m_currentDrag, theItem, flavor, &theType ); - wxDataFormat format( theType ); - if (preferredFormat == format) - { - hasPreferredFormat = true; - break; - } - } - - for (UInt16 flavor = 1; flavor <= flavors; ++flavor) - { - result = GetFlavorType( (DragReference)m_currentDrag, theItem, flavor, &theType ); - wxDataFormat format( theType ); - if ((hasPreferredFormat && format == preferredFormat) - || (!hasPreferredFormat && m_dataObject->IsSupportedFormat( format ))) - { - result = GetFlavorFlags( (DragReference)m_currentDrag, theItem, theType, &theFlags ); - if (result == noErr) - { - Size dataSize; - Ptr theData; - - GetFlavorDataSize( (DragReference)m_currentDrag, theItem, theType, &dataSize ); - if (theType == kScrapFlavorTypeText) - { - // this increment is only valid for allocating: - // on the next GetFlavorData call it is reset again to the original value - dataSize++; - } - else if (theType == kScrapFlavorTypeUnicode) - { - // this increment is only valid for allocating: - // on the next GetFlavorData call it is reset again to the original value - dataSize++; - dataSize++; - } - - if (dataSize > 0) - theData = new char[dataSize]; - else - theData = NULL; - - GetFlavorData( (DragReference)m_currentDrag, theItem, theType, (void*)theData, &dataSize, 0L ); - switch (theType) - { - case kScrapFlavorTypeText: - theData[dataSize] = 0; - m_dataObject->SetData( wxDataFormat(wxDF_TEXT), dataSize, theData ); - break; - -#if wxUSE_UNICODE - case kScrapFlavorTypeUnicode: - theData[dataSize + 0] = - theData[dataSize + 1] = 0; - m_dataObject->SetData( wxDataFormat(wxDF_UNICODETEXT), dataSize, theData ); - break; -#endif - - case kDragFlavorTypeHFS: - if (theData != NULL) - { - HFSFlavor* theFile = (HFSFlavor*)theData; -#ifndef __LP64__ - wxString name = wxMacFSSpec2MacFilename( &theFile->fileSpec ); - - if (!name.empty()) - filenamesPassed += name + wxT("\n"); -#endif - } - break; - - default: - m_dataObject->SetData( format, dataSize, theData ); - break; - } - - delete [] theData; - } - break; - } - } - } - - if (filenamesPassed.length() > 0) - { - wxCharBuffer buf = filenamesPassed.fn_str(); - m_dataObject->SetData( wxDataFormat(wxDF_FILENAME), strlen( buf ), (const char*)buf ); + transferred = m_dataObject->GetFromPasteboard( pasteboard ); } } - return true; + return transferred; } //------------------------------------------------------------------------- @@ -341,114 +224,53 @@ wxDragResult wxDropSource::DoDragDrop(int flags) DragReference theDrag; RgnHandle dragRegion; - - if (NewDrag( &theDrag ) != noErr) - return wxDragNone; + OSStatus err = noErr; + PasteboardRef pasteboard; // add data to drag - size_t formatCount = m_data->GetFormatCount(); - wxDataFormat *formats = new wxDataFormat[formatCount]; - m_data->GetAllFormats( formats ); - ItemReference theItem = (ItemReference) 1; - - for ( size_t i = 0; i < formatCount; ++i ) + + err = PasteboardCreate( kPasteboardUniqueName, &pasteboard ); + if ( err != noErr ) + return wxDragNone; + + err = PasteboardClear( pasteboard ); + if ( err != noErr ) { - size_t dataSize = m_data->GetDataSize( formats[i] ); - Ptr dataPtr = new char[dataSize]; - m_data->GetDataHere( formats[i], dataPtr ); - OSType type = formats[i].GetFormatId(); - if ( type == 'TEXT' || type == 'utxt' ) - { - if ( dataSize > 0 ) - dataSize--; - dataPtr[ dataSize ] = 0; - if ( type == 'utxt' ) - { - if ( dataSize > 0 ) - dataSize--; - dataPtr[ dataSize ] = 0; - } - - AddDragItemFlavor( theDrag, theItem, type, dataPtr, dataSize, 0 ); - } - else if (type == kDragFlavorTypeHFS ) - { - HFSFlavor theFlavor; - OSErr err = noErr; -#ifndef __LP64__ - CInfoPBRec cat; - - wxMacFilename2FSSpec( wxString( dataPtr, *wxConvCurrent ), &theFlavor.fileSpec ); - - memset( &cat, 0, sizeof(cat) ); - cat.hFileInfo.ioNamePtr = theFlavor.fileSpec.name; - cat.hFileInfo.ioVRefNum = theFlavor.fileSpec.vRefNum; - cat.hFileInfo.ioDirID = theFlavor.fileSpec.parID; - cat.hFileInfo.ioFDirIndex = 0; - err = PBGetCatInfoSync( &cat ); -#endif - if (err == noErr) - { -#ifndef __LP64__ - theFlavor.fdFlags = cat.hFileInfo.ioFlFndrInfo.fdFlags; - if (theFlavor.fileSpec.parID == fsRtParID) - { - theFlavor.fileCreator = 'MACS'; - theFlavor.fileType = 'disk'; - } - else if ((cat.hFileInfo.ioFlAttrib & ioDirMask) != 0) - { - theFlavor.fileCreator = 'MACS'; - theFlavor.fileType = 'fold'; - } - else - { - theFlavor.fileCreator = cat.hFileInfo.ioFlFndrInfo.fdCreator; - theFlavor.fileType = cat.hFileInfo.ioFlFndrInfo.fdType; - } -#endif - AddDragItemFlavor( theDrag, theItem, type, &theFlavor, sizeof(theFlavor), 0 ); - } - } - else - { - AddDragItemFlavor( theDrag, theItem, type, dataPtr, dataSize, 0 ); - } - - delete [] dataPtr; + CFRelease( pasteboard ); + return wxDragNone; } + PasteboardSynchronize( pasteboard ); - delete [] formats; + m_data->AddToPasteboard( pasteboard, 1 ); + + if (NewDragWithPasteboard( pasteboard , &theDrag) != noErr) + { + CFRelease( pasteboard ); + return wxDragNone; + } dragRegion = NewRgn(); RgnHandle tempRgn = NewRgn(); - EventRecord* ev = NULL; - -#if !TARGET_CARBON // TODO - ev = (EventRecord*) wxTheApp->MacGetCurrentEvent(); -#else EventRecord rec; - ev = &rec; - wxMacConvertEventToRecord( (EventRef) wxTheApp->MacGetCurrentEvent(), &rec ); -#endif + ConvertEventRefToEventRecord( (EventRef) wxTheApp->MacGetCurrentEvent(), &rec ); const short dragRegionOuterBoundary = 10; const short dragRegionInnerBoundary = 9; SetRectRgn( dragRegion, - ev->where.h - dragRegionOuterBoundary, - ev->where.v - dragRegionOuterBoundary, - ev->where.h + dragRegionOuterBoundary, - ev->where.v + dragRegionOuterBoundary ); + rec.where.h - dragRegionOuterBoundary, + rec.where.v - dragRegionOuterBoundary, + rec.where.h + dragRegionOuterBoundary, + rec.where.v + dragRegionOuterBoundary ); SetRectRgn( tempRgn, - ev->where.h - dragRegionInnerBoundary, - ev->where.v - dragRegionInnerBoundary, - ev->where.h + dragRegionInnerBoundary, - ev->where.v + dragRegionInnerBoundary ); + rec.where.h - dragRegionInnerBoundary, + rec.where.v - dragRegionInnerBoundary, + rec.where.h + dragRegionInnerBoundary, + rec.where.v + dragRegionInnerBoundary ); DiffRgn( dragRegion, tempRgn, dragRegion ); DisposeRgn( tempRgn ); @@ -460,7 +282,9 @@ wxDragResult wxDropSource::DoDragDrop(int flags) gTrackingGlobals.m_result = wxDragNone; gTrackingGlobals.m_flags = flags; - TrackDrag( theDrag, ev, dragRegion ); + err = TrackDrag( theDrag, &rec, dragRegion ); + + CFRelease( pasteboard ); DisposeRgn( dragRegion ); DisposeDrag( theDrag ); gTrackingGlobals.m_currentSource = NULL;