X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0df4f2ffa0c351e509715d8e870ff516bcc492cb..137c8bde085d6d5b7c459902d2ea1a198ab48765:/src/motif/clipbrd.cpp?ds=inline diff --git a/src/motif/clipbrd.cpp b/src/motif/clipbrd.cpp index 0ee8acb958..7a5763a69b 100644 --- a/src/motif/clipbrd.cpp +++ b/src/motif/clipbrd.cpp @@ -1,33 +1,42 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: clipbrd.cpp +// Name: src/motif/clipbrd.cpp // Purpose: Clipboard functionality // Author: Julian Smart -// Modified by: +// Modified by: Mattia Barbon (added support for generic wxDataObjects) // Created: 17/09/98 // RCS-ID: $Id$ // Copyright: (c) Julian Smart -// Licence: wxWindows licence +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation -#pragma implementation "clipbrd.h" -#endif +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" -#include "wx/defs.h" +#ifdef __VMS +#include "wx/vms_x_fix.h" +#define XtWindow XTWINDOW +#define XtScreen XTSCREEN +#define XtParent XTPARENT +#define XtIsRealized XTISREALIZED +#define XtDisplay XTDISPLAY +#endif #if wxUSE_CLIPBOARD -#include "wx/app.h" -#include "wx/frame.h" -#include "wx/bitmap.h" -#include "wx/utils.h" -#include "wx/metafile.h" #include "wx/clipbrd.h" + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/utils.h" + #include "wx/bitmap.h" +#endif + #include "wx/dataobj.h" +#include "wx/ptr_scpd.h" #ifdef __VMS__ #pragma message disable nosimpint + #endif #include #include @@ -35,180 +44,94 @@ #pragma message enable nosimpint #endif -#include - -// IMPLEMENT_DYNAMIC_CLASS(wxClipboard, wxObject) -// IMPLEMENT_ABSTRACT_CLASS(wxClipboardClient, wxObject) - -static bool gs_clipboardIsOpen = FALSE; +#include "wx/motif/private.h" bool wxOpenClipboard() { - if (!gs_clipboardIsOpen) - { - gs_clipboardIsOpen = TRUE; - return TRUE; - } - else - return FALSE; + return wxTheClipboard->Open(); } bool wxCloseClipboard() { - if (gs_clipboardIsOpen) - { - gs_clipboardIsOpen = FALSE; - return TRUE; - } - else - return FALSE; + wxTheClipboard->Close(); + + return true; } bool wxEmptyClipboard() { - // No equivalent in Motif - return TRUE; + wxTheClipboard->Clear(); + return true; } bool wxClipboardOpen() { - return gs_clipboardIsOpen; + return wxTheClipboard->IsOpened(); } -bool wxIsClipboardFormatAvailable(wxDataFormat dataFormat) +bool wxIsClipboardFormatAvailable(const wxDataFormat& dataFormat) { - // Only text is supported. - if (dataFormat != wxDF_TEXT) - return FALSE; - - unsigned long numBytes = 0; - long privateId = 0; - - Window window = (Window) 0; - if (wxTheApp->GetTopWindow()) - window = XtWindow( (Widget) wxTheApp->GetTopWindow()->GetTopWidget() ); - - int success = XmClipboardRetrieve((Display*) wxGetDisplay(), - window, "TEXT", (XtPointer) 0, 0, & numBytes, & privateId) ; - - // Assume only text is supported. If we have anything at all, - // or the clipboard is locked so we're not sure, we say we support it. - if (success == ClipboardNoData) - return FALSE; - else - return TRUE; + return wxTheClipboard->IsSupported( dataFormat ); } -bool wxSetClipboardData(wxDataFormat dataFormat, wxObject *obj, int WXUNUSED(width), int WXUNUSED(height)) +bool wxSetClipboardData(wxDataFormat dataFormat, wxObject *obj, + int WXUNUSED(width), int WXUNUSED(height)) { - if (dataFormat != wxDF_TEXT) - return FALSE; - - char* data = (char*) obj; - - XmString text = XmStringCreateSimple ("CLIPBOARD"); - Window window = (Window) 0; - if (wxTheApp->GetTopWindow()) - window = XtWindow( (Widget) wxTheApp->GetTopWindow()->GetTopWidget() ); - - long itemId = 0; - int result = 0; - - while ((result = - XmClipboardStartCopy((Display*) wxGetDisplay(), - window, - text, - XtLastTimestampProcessed((Display*) wxGetDisplay()), - (Widget) 0, - (XmCutPasteProc) 0, - & itemId)) != ClipboardSuccess) - - ; - - XmStringFree (text); - - long dataId = 0; - while ((result = - XmClipboardCopy((Display*) wxGetDisplay(), - window, - itemId, - "TEXT", - (XtPointer) data, - strlen(data) + 1, - 0, - & dataId)) != ClipboardSuccess) - - ; - - while (( result = - XmClipboardEndCopy((Display*) wxGetDisplay(), - window, itemId) ) != ClipboardSuccess) - - ; - - return TRUE; + wxDataObject* dobj = NULL; + + if( dataFormat == wxDF_TEXT ) + { + wxChar* data = (wxChar*)obj; + dobj = new wxTextDataObject( data ); + } + else if( dataFormat = wxDF_BITMAP ) + { + wxBitmap* data = (wxBitmap*)obj; + dobj = new wxBitmapDataObject( *data ); + } + + if( !dobj ) + return false; + + return wxTheClipboard->SetData( dobj ); } wxObject *wxGetClipboardData(wxDataFormat dataFormat, long *len) { - if (dataFormat != wxDF_TEXT) - return (wxObject*) NULL; + wxDataObject* dobj = NULL; + wxTextDataObject* tobj = NULL; + wxBitmapDataObject* bobj = NULL; + + if( dataFormat == wxDF_TEXT ) + { + dobj = tobj = new wxTextDataObject; + } + else if( dataFormat = wxDF_BITMAP ) + { + dobj = bobj = new wxBitmapDataObject; + } - bool done = FALSE; - long id = 0; - unsigned long numBytes = 0; - int result = 0; - Window window = (Window) 0; - if (wxTheApp->GetTopWindow()) - window = XtWindow( (Widget) wxTheApp->GetTopWindow()->GetTopWidget() ); + if( !dobj || !wxTheClipboard->GetData( *dobj ) ) + return NULL; - int currentDataSize = 256; - char* data = new char[currentDataSize]; + if( tobj ) + { + wxString text = tobj->GetText(); + wxChar* buf = new wxChar[text.length() + 1]; - while (!done) + if( len ) *len = text.length(); + return (wxObject*)wxStrcpy( buf, text.c_str() ); + } + else if( bobj ) { - if (result == ClipboardTruncate) - { - delete[] data; - currentDataSize = 2*currentDataSize; - data = new char[currentDataSize]; - } - result = XmClipboardRetrieve((Display*) wxGetDisplay(), - window, - "TEXT", - (XtPointer) data, - currentDataSize, - &numBytes, - &id); - - switch (result) - { - case ClipboardSuccess: - { - if (len) - *len = strlen(data) + 1; - return (wxObject*) data; - break; - } - case ClipboardTruncate: - case ClipboardLocked: - { - break; - } - default: - case ClipboardNoData: - { - return (wxObject*) NULL; - break; - } - } - + if( len ) *len = 0; + return new wxBitmap( bobj->GetBitmap() ); } - return NULL; + return NULL; // just in case... } -wxDataFormat wxEnumClipboardFormats(wxDataFormat dataFormat) +wxDataFormat wxEnumClipboardFormats(const wxDataFormat& dataFormat) { // Only wxDF_TEXT supported if (dataFormat == wxDF_TEXT) @@ -217,313 +140,347 @@ wxDataFormat wxEnumClipboardFormats(wxDataFormat dataFormat) return wxDF_INVALID; } -wxDataFormat wxRegisterClipboardFormat(char *WXUNUSED(formatName)) +wxDataFormat wxRegisterClipboardFormat(char *WXUNUSED(formatName)) { // Not supported - return (wxDataFormat) wxDF_INVALID; + return wxDF_INVALID; } -bool wxGetClipboardFormatName(wxDataFormat dataFormat, char *formatName, int WXUNUSED(maxCount)) +bool wxGetClipboardFormatName(const wxDataFormat& dataFormat, char *formatName, + int maxCount) { - // Only wxDF_TEXT supported - if (dataFormat == wxDF_TEXT) - { - strcpy(formatName, "TEXT"); - return TRUE; - } - else - return FALSE; + wxStrncpy( formatName, dataFormat.GetId().c_str(), maxCount ); + + return true; } //----------------------------------------------------------------------------- // wxClipboard //----------------------------------------------------------------------------- +struct wxDataIdToDataObject +{ + wxDataIdToDataObject( wxDataObject* o, long d, size_t s ) + : object( o ), size( s ), dataId( d ) { } + + wxDataObject* object; + size_t size; + long dataId; +}; + +#include "wx/listimpl.cpp" + +WX_DEFINE_LIST(wxDataObjectList) +WX_DEFINE_LIST(wxDataIdToDataObjectList) + +extern "C" +{ +#if wxCHECK_LESSTIF() +static void wxClipboardCallback( Widget widget, int* data_id, + int* priv, int* reason ); +#else // Motif +static void wxClipboardCallback( Widget widget, long* data_id, + long* priv, int* reason ); +#endif // Less/Motif +} + IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject) wxClipboard::wxClipboard() { - m_open = FALSE; + m_open = false; } wxClipboard::~wxClipboard() { - Clear(); + Clear(); } void wxClipboard::Clear() { - wxNode* node = m_data.First(); + wxDataObjectList::compatibility_iterator node = m_data.GetFirst(); while (node) { - wxDataObject* data = (wxDataObject*) node->Data(); - delete data; - node = node->Next(); + delete node->GetData(); + node = node->GetNext(); } m_data.Clear(); + + for( wxDataIdToDataObjectList::compatibility_iterator node2 = m_idToObject.GetFirst(); + node2; node2 = node2->GetNext() ) + { + delete node2->GetData(); + } + m_idToObject.Clear(); } bool wxClipboard::Open() { - wxCHECK_MSG( !m_open, FALSE, "clipboard already open" ); - - m_open = TRUE; + wxCHECK_MSG( !m_open, false, "clipboard already open" ); + + m_open = true; - return wxOpenClipboard(); + return true; } bool wxClipboard::SetData( wxDataObject *data ) { - wxCHECK_MSG( data, FALSE, "data is invalid" ); - wxCHECK_MSG( m_open, FALSE, "clipboard not open" ); + wxCHECK_MSG( data, false, "data is invalid" ); + wxCHECK_MSG( m_open, false, "clipboard not open" ); Clear(); return AddData( data ); } -bool wxClipboard::AddData( wxDataObject *data ) -{ - wxCHECK_MSG( data, FALSE, "data is invalid" ); - wxCHECK_MSG( m_open, FALSE, "clipboard not open" ); +wxDECLARE_SCOPED_ARRAY( wxDataFormat, wxDataFormatScopedArray ) +wxDEFINE_SCOPED_ARRAY( wxDataFormat, wxDataFormatScopedArray ) - wxDataFormat::NativeFormat format = data->GetPreferredFormat().GetType(); - switch ( format ) +#if wxCHECK_LESSTIF() +void wxClipboardCallback( Widget xwidget, int* data_id, + int* priv, int* WXUNUSED(reason) ) +#else +void wxClipboardCallback( Widget xwidget, long* data_id, + long* priv, int* WXUNUSED(reason) ) +#endif +{ + Display* xdisplay = XtDisplay( xwidget ); + Window xwindow = XtWindow( xwidget ); + wxDataObject* dobj = NULL; + size_t size = 0; + + for( wxDataIdToDataObjectList::compatibility_iterator node2 = + wxTheClipboard->m_idToObject.GetFirst(); + node2; node2 = node2->GetNext() ) { - case wxDF_TEXT: - case wxDF_OEMTEXT: - { - wxTextDataObject* textDataObject = (wxTextDataObject*) data; - wxString str(textDataObject->GetText()); - return wxSetClipboardData(format, (wxObject*) (const char*) str); - } -#if 0 - case wxDF_BITMAP: - case wxDF_DIB: + wxDataIdToDataObject* dido = node2->GetData(); + if( dido->dataId == *data_id ) { - wxBitmapDataObject* bitmapDataObject = (wxBitmapDataObject*) data; - wxBitmap bitmap(bitmapDataObject->GetBitmap()); - return wxSetClipboardData(data->GetType(), & bitmap); + dobj = dido->object; + size = dido->size; break; } -#endif // 0 } - - return FALSE; -} -void wxClipboard::Close() -{ - wxCHECK_RET( m_open, "clipboard not open" ); - - m_open = FALSE; - wxCloseClipboard(); -} + if( !dobj ) return; -bool wxClipboard::IsSupported( const wxDataFormat& format) -{ - return wxIsClipboardFormatAvailable(format); + wxCharBuffer buffer(size); + size_t count = dobj->GetFormatCount( wxDataObject::Get ); + wxDataFormatScopedArray dfarr( new wxDataFormat[count] ); + dobj->GetAllFormats( dfarr.get(), wxDataObject::Get ); + + if( !dobj->GetDataHere( dfarr[*priv], buffer.data() ) ) + return; + + while( XmClipboardCopyByName( xdisplay, xwindow, *data_id, + buffer.data(), size, 0 ) + == XmClipboardLocked ); } -bool wxClipboard::GetData( wxDataObject& data ) +bool wxClipboard::AddData( wxDataObject *data ) { - wxCHECK_MSG( m_open, FALSE, "clipboard not open" ); - - wxDataFormat::NativeFormat format = data.GetPreferredFormat().GetType(); - switch ( format ) + wxCHECK_MSG( data, false, "data is invalid" ); + wxCHECK_MSG( m_open, false, "clipboard not open" ); + + m_data.Append( data ); + + Display* xdisplay = wxGlobalDisplay(); + Widget xwidget = (Widget)wxTheApp->GetTopLevelRealizedWidget(); + Window xwindow = XtWindow( xwidget ); + wxXmString label( wxTheApp->GetAppName() ); + Time timestamp = XtLastTimestampProcessed( xdisplay ); + long itemId; + + int retval; + + while( ( retval = XmClipboardStartCopy( xdisplay, xwindow, label(), + timestamp, xwidget, + wxClipboardCallback, + &itemId ) ) + == XmClipboardLocked ); + if( retval != XmClipboardSuccess ) + return false; + + size_t count = data->GetFormatCount( wxDataObject::Get ); + wxDataFormatScopedArray dfarr( new wxDataFormat[count] ); + data->GetAllFormats( dfarr.get(), wxDataObject::Get ); + + for( size_t i = 0; i < count; ++i ) { - case wxDF_TEXT: - case wxDF_OEMTEXT: - { - wxTextDataObject& textDataObject = (wxTextDataObject &) data; - char* s = (char*) wxGetClipboardData(format); - if (s) - { - textDataObject.SetText(s); - delete[] s; - return TRUE; - } - else - return FALSE; - break; - } -/* - case wxDF_BITMAP: - case wxDF_DIB: - { - wxBitmapDataObject* bitmapDataObject = (wxBitmapDataObject*) data; - wxBitmap* bitmap = (wxBitmap*) wxGetClipboardData(data->GetType()); - if (bitmap) - { - bitmapDataObject->SetBitmap(* bitmap); - delete bitmap; - return TRUE; - } - else - return FALSE; - break; - } -*/ - default: - { -#ifndef __VMS - // VMS complains that this statement is/causes unreachability - return FALSE; -#endif - } - } - - return FALSE; -} + size_t size = data->GetDataSize( dfarr[i] ); + long data_id; + wxString id = dfarr[i].GetId(); -#if 0 + while( ( retval = XmClipboardCopy( xdisplay, xwindow, itemId, + wxConstCast(id.c_str(), char), + NULL, size, i, &data_id ) ) + == XmClipboardLocked ); -/* -* Old clipboard implementation by Matthew Flatt -*/ + m_idToObject.Append( new wxDataIdToDataObject( data, data_id, size ) ); + } -wxClipboard *wxTheClipboard = NULL; + while( XmClipboardEndCopy( xdisplay, xwindow, itemId ) + == XmClipboardLocked ); -void wxInitClipboard() -{ - if (!wxTheClipboard) - wxTheClipboard = new wxClipboard; + return true; } -wxClipboard::wxClipboard() +void wxClipboard::Close() { - clipOwner = NULL; - cbString = NULL; -} + wxCHECK_RET( m_open, "clipboard not open" ); -wxClipboard::~wxClipboard() -{ - if (clipOwner) - clipOwner->BeingReplaced(); - if (cbString) - delete[] cbString; + m_open = false; } -static int FormatStringToID(char *str) +bool wxClipboard::IsSupported(const wxDataFormat& format) { - if (!strcmp(str, "TEXT")) - return wxDF_TEXT; - - return wxRegisterClipboardFormat(str); -} + Display* xdisplay = wxGlobalDisplay(); + Window xwindow = XtWindow( (Widget)wxTheApp->GetTopLevelRealizedWidget() ); + bool isSupported = false; + int retval, count; + unsigned long max_name_length; + wxString id = format.GetId(); + + while( ( retval = XmClipboardLock( xdisplay, xwindow ) ) + == XmClipboardLocked ); + if( retval != XmClipboardSuccess ) + return false; + + if( XmClipboardInquireCount( xdisplay, xwindow, &count, &max_name_length ) + == XmClipboardSuccess ) + { + wxCharBuffer buf( max_name_length + 1 ); + unsigned long copied; -void wxClipboard::SetClipboardClient(wxClipboardClient *client, long time) -{ - bool got_selection; - - if (clipOwner) - clipOwner->BeingReplaced(); - clipOwner = client; - if (cbString) { - delete[] cbString; - cbString = NULL; - } - - if (wxOpenClipboard()) { - char **formats, *data; - int i; - int ftype; - long size; - - formats = clipOwner->formats.ListToArray(FALSE); - for (i = clipOwner->formats.Number(); i--; ) { - ftype = FormatStringToID(formats[i]); - data = clipOwner->GetData(formats[i], &size); - if (!wxSetClipboardData(ftype, (wxObject *)data, size, 1)) { - got_selection = FALSE; + for( int i = 0; i < count; ++i ) + { + if( XmClipboardInquireFormat( xdisplay, xwindow, i + 1, + (XtPointer)buf.data(), + max_name_length, &copied ) + != XmClipboardSuccess ) + continue; + + buf.data()[copied] = '\0'; + + if( buf == id ) + { + isSupported = true; break; } } - - if (i < 0) - got_selection = wxCloseClipboard(); - } else - got_selection = FALSE; - - got_selection = FALSE; // Assume another process takes over - - if (!got_selection) { - clipOwner->BeingReplaced(); - clipOwner = NULL; } -} -wxClipboardClient *wxClipboard::GetClipboardClient() -{ - return clipOwner; -} + XmClipboardUnlock( xdisplay, xwindow, False ); -void wxClipboard::SetClipboardString(char *str, long time) -{ - bool got_selection; - - if (clipOwner) { - clipOwner->BeingReplaced(); - clipOwner = NULL; - } - if (cbString) - delete[] cbString; - - cbString = str; - - if (wxOpenClipboard()) { - if (!wxSetClipboardData(wxDF_TEXT, (wxObject *)str)) - got_selection = FALSE; - else - got_selection = wxCloseClipboard(); - } else - got_selection = FALSE; - - got_selection = FALSE; // Assume another process takes over - - if (!got_selection) { - delete[] cbString; - cbString = NULL; - } + return isSupported; } -char *wxClipboard::GetClipboardString(long time) +class wxClipboardEndRetrieve { - char *str; - long length; - - str = GetClipboardData("TEXT", &length, time); - if (!str) { - str = new char[1]; - *str = 0; +public: + wxClipboardEndRetrieve( Display* display, Window window ) + : m_display( display ), m_window( window ) { } + ~wxClipboardEndRetrieve() + { + while( XmClipboardEndRetrieve( m_display, m_window ) + == XmClipboardLocked ); } - - return str; -} +private: + Display* m_display; + Window m_window; +}; -char *wxClipboard::GetClipboardData(char *format, long *length, long time) +bool wxClipboard::GetData( wxDataObject& data ) { - if (clipOwner) { - if (clipOwner->formats.Member(format)) - return clipOwner->GetData(format, length); - else - return NULL; - } else if (cbString) { - if (!strcmp(format, "TEXT")) - return copystring(cbString); - else - return NULL; - } else { - if (wxOpenClipboard()) { - receivedString = (char *)wxGetClipboardData(FormatStringToID(format), - length); - wxCloseClipboard(); - } else - receivedString = NULL; - - return receivedString; + wxCHECK_MSG( m_open, false, "clipboard not open" ); + + Display* xdisplay = wxGlobalDisplay(); + Window xwindow = XtWindow( (Widget)wxTheApp->GetTopLevelRealizedWidget() ); + Time timestamp = XtLastTimestampProcessed( xdisplay ); + + wxDataFormat chosenFormat; + int retval; + + /////////////////////////////////////////////////////////////////////////// + // determine if the cliboard holds any format we like + /////////////////////////////////////////////////////////////////////////// + while( ( retval = XmClipboardStartRetrieve( xdisplay, xwindow, + timestamp ) ) + == XmClipboardLocked ); + if( retval != XmClipboardSuccess ) + return false; + + wxClipboardEndRetrieve endRetrieve( xdisplay, xwindow ); + + int count; + unsigned long max_name_length; + size_t dfcount = data.GetFormatCount( wxDataObject::Set ); + wxDataFormatScopedArray dfarr( new wxDataFormat[dfcount] ); + data.GetAllFormats( dfarr.get(), wxDataObject::Set ); + + if( XmClipboardInquireCount( xdisplay, xwindow, &count, &max_name_length ) + == XmClipboardSuccess ) + { + wxCharBuffer buf( max_name_length + 1 ); + unsigned long copied; + + for( int i = 0; i < count; ++i ) + { + if( XmClipboardInquireFormat( xdisplay, xwindow, i + 1, + (XtPointer)buf.data(), + max_name_length, &copied ) + != XmClipboardSuccess ) + continue; + + buf.data()[copied] = '\0'; + + // try preferred format + if( buf == data.GetPreferredFormat( wxDataObject::Set ).GetId() ) + { + chosenFormat = data.GetPreferredFormat( wxDataObject::Set ); + break; + } + + // try all other formats + for( size_t i = 0; i < dfcount; ++i ) + { + if( buf == dfarr[i].GetId() ) + chosenFormat = dfarr[i]; + } + } } + + if( chosenFormat == wxDF_INVALID ) + return false; + + /////////////////////////////////////////////////////////////////////////// + // now retrieve the data + /////////////////////////////////////////////////////////////////////////// + unsigned long length, dummy1; + long dummy2; + wxString id = chosenFormat.GetId(); + + while( ( retval = XmClipboardInquireLength( xdisplay, xwindow, + wxConstCast(id.c_str(), char), + &length ) ) + == XmClipboardLocked ); + if( retval != XmClipboardSuccess ) + return false; + + wxCharBuffer buf(length); + + while( ( retval = XmClipboardRetrieve( xdisplay, xwindow, + wxConstCast(id.c_str(), char), + (XtPointer)buf.data(), + length, &dummy1, &dummy2 ) ) + == XmClipboardLocked ); + if( retval != XmClipboardSuccess ) + return false; + + if( !data.SetData( chosenFormat, length, buf.data() ) ) + return false; + + return true; } -#endif #endif // wxUSE_CLIPBOARD