1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/motif/clipbrd.cpp
3 // Purpose:     Clipboard functionality
4 // Author:      Julian Smart
5 // Modified by: Mattia Barbon (added support for generic wxDataObjects)
6 // Created:     17/09/98
7 // Copyright:   (c) Julian Smart
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13 
14 #ifdef __VMS
15 #include "wx/vms_x_fix.h"
16 #define XtWindow XTWINDOW
17 #define XtScreen XTSCREEN
18 #define XtParent XTPARENT
19 #define XtIsRealized XTISREALIZED
20 #define XtDisplay XTDISPLAY
21 #endif
22 
23 #if wxUSE_CLIPBOARD
24 
25 #include "wx/clipbrd.h"
26 
27 #ifndef WX_PRECOMP
28     #include "wx/app.h"
29     #include "wx/utils.h"
30     #include "wx/bitmap.h"
31     #include "wx/dataobj.h"
32 #endif
33 
34 #include "wx/scopedarray.h"
35 
36 typedef wxScopedArray<wxDataFormat> wxDataFormatScopedArray;
37 
38 #ifdef __VMS__
39 #pragma message disable nosimpint
40 
41 #endif
42 #include <Xm/Xm.h>
43 #include <Xm/CutPaste.h>
44 #ifdef __VMS__
45 #pragma message enable nosimpint
46 #endif
47 
48 #include "wx/motif/private.h"
49 
wxOpenClipboard()50 bool wxOpenClipboard()
51 {
52     return wxTheClipboard->Open();
53 }
54 
wxCloseClipboard()55 bool wxCloseClipboard()
56 {
57     wxTheClipboard->Close();
58 
59     return true;
60 }
61 
wxEmptyClipboard()62 bool wxEmptyClipboard()
63 {
64     wxTheClipboard->Clear();
65     return true;
66 }
67 
wxClipboardOpen()68 bool wxClipboardOpen()
69 {
70     return wxTheClipboard->IsOpened();
71 }
72 
wxIsClipboardFormatAvailable(const wxDataFormat & dataFormat)73 bool wxIsClipboardFormatAvailable(const wxDataFormat& dataFormat)
74 {
75     return wxTheClipboard->IsSupported( dataFormat );
76 }
77 
wxSetClipboardData(wxDataFormat dataFormat,wxObject * obj,int WXUNUSED (width),int WXUNUSED (height))78 bool wxSetClipboardData(wxDataFormat dataFormat, wxObject *obj,
79                         int WXUNUSED(width), int WXUNUSED(height))
80 {
81     wxDataObject* dobj = NULL;
82 
83     if( dataFormat == wxDF_TEXT )
84     {
85         wxChar* data = (wxChar*)obj;
86         dobj = new wxTextDataObject( data );
87     }
88     else if( dataFormat = wxDF_BITMAP )
89     {
90         wxBitmap* data = (wxBitmap*)obj;
91         dobj = new wxBitmapDataObject( *data );
92     }
93 
94     if( !dobj )
95         return false;
96 
97     return wxTheClipboard->SetData( dobj );
98 }
99 
wxGetClipboardData(wxDataFormat dataFormat,long * len)100 wxObject *wxGetClipboardData(wxDataFormat dataFormat, long *len)
101 {
102     wxDataObject* dobj = NULL;
103     wxTextDataObject* tobj = NULL;
104     wxBitmapDataObject* bobj = NULL;
105 
106     if( dataFormat == wxDF_TEXT )
107     {
108         dobj = tobj = new wxTextDataObject;
109     }
110     else if( dataFormat = wxDF_BITMAP )
111     {
112         dobj = bobj = new wxBitmapDataObject;
113     }
114 
115     if( !dobj || !wxTheClipboard->GetData( *dobj ) )
116         return NULL;
117 
118     if( tobj )
119     {
120         wxString text = tobj->GetText();
121         wxChar* buf = new wxChar[text.length() + 1];
122 
123         if( len ) *len = text.length();
124         return (wxObject*)wxStrcpy( buf, text.c_str() );
125     }
126     else if( bobj )
127     {
128         if( len ) *len = 0;
129         return new wxBitmap( bobj->GetBitmap() );
130     }
131 
132     return NULL; // just in case...
133 }
134 
wxEnumClipboardFormats(const wxDataFormat & dataFormat)135 wxDataFormat wxEnumClipboardFormats(const wxDataFormat& dataFormat)
136 {
137     // Only wxDF_TEXT supported
138     if (dataFormat == wxDF_TEXT)
139        return wxDF_TEXT;
140     else
141        return wxDF_INVALID;
142 }
143 
wxRegisterClipboardFormat(char * WXUNUSED (formatName))144 wxDataFormat wxRegisterClipboardFormat(char *WXUNUSED(formatName))
145 {
146     // Not supported
147     return wxDF_INVALID;
148 }
149 
wxGetClipboardFormatName(const wxDataFormat & dataFormat,char * formatName,int maxCount)150 bool wxGetClipboardFormatName(const wxDataFormat& dataFormat, char *formatName,
151                               int maxCount)
152 {
153     wxStrlcpy( formatName, dataFormat.GetId().c_str(), maxCount );
154 
155     return true;
156 }
157 
158 //-----------------------------------------------------------------------------
159 // wxClipboard
160 //-----------------------------------------------------------------------------
161 
162 struct wxDataIdToDataObject
163 {
wxDataIdToDataObjectwxDataIdToDataObject164     wxDataIdToDataObject( wxDataObject* o, long d, size_t s )
165         : object( o ), size( s ), dataId( d ) { }
166 
167     wxDataObject* object;
168     size_t        size;
169     long          dataId;
170 };
171 
172 #include "wx/listimpl.cpp"
173 
174 WX_DEFINE_LIST(wxDataObjectList)
WX_DEFINE_LIST(wxDataIdToDataObjectList)175 WX_DEFINE_LIST(wxDataIdToDataObjectList)
176 
177 extern "C"
178 {
179 #if wxCHECK_LESSTIF()
180 static void wxClipboardCallback( Widget widget, int* data_id,
181                                  int* priv, int* reason );
182 #else // Motif
183 static void wxClipboardCallback( Widget widget, long* data_id,
184                                  long* priv, int* reason );
185 #endif // Less/Motif
186 }
187 
IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)188 IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
189 
190 wxClipboard::wxClipboard()
191 {
192     m_open = false;
193 }
194 
~wxClipboard()195 wxClipboard::~wxClipboard()
196 {
197     Clear();
198 }
199 
Clear()200 void wxClipboard::Clear()
201 {
202     wxDataObjectList::compatibility_iterator node = m_data.GetFirst();
203     while (node)
204     {
205         delete node->GetData();
206         node = node->GetNext();
207     }
208     m_data.Clear();
209 
210     for( wxDataIdToDataObjectList::compatibility_iterator node2 = m_idToObject.GetFirst();
211          node2; node2 = node2->GetNext() )
212     {
213         delete node2->GetData();
214     }
215     m_idToObject.Clear();
216 }
217 
Open()218 bool wxClipboard::Open()
219 {
220     wxCHECK_MSG( !m_open, false, "clipboard already open" );
221 
222     m_open = true;
223 
224     return true;
225 }
226 
SetData(wxDataObject * data)227 bool wxClipboard::SetData( wxDataObject *data )
228 {
229     wxCHECK_MSG( data, false, "data is invalid" );
230     wxCHECK_MSG( m_open, false, "clipboard not open" );
231 
232     Clear();
233 
234     return AddData( data );
235 }
236 
237 #if wxCHECK_LESSTIF()
wxClipboardCallback(Widget xwidget,int * data_id,int * priv,int * WXUNUSED (reason))238 void wxClipboardCallback( Widget xwidget, int* data_id,
239                           int* priv, int* WXUNUSED(reason) )
240 #else
241 void wxClipboardCallback( Widget xwidget, long* data_id,
242                           long* priv, int* WXUNUSED(reason) )
243 #endif
244 {
245     Display* xdisplay = XtDisplay( xwidget );
246     Window xwindow = XtWindow( xwidget );
247     wxDataObject* dobj = NULL;
248     size_t size = 0;
249 
250     for( wxDataIdToDataObjectList::compatibility_iterator node2 =
251              wxTheClipboard->m_idToObject.GetFirst();
252          node2; node2 = node2->GetNext() )
253     {
254         wxDataIdToDataObject* dido = node2->GetData();
255         if( dido->dataId == *data_id )
256         {
257             dobj = dido->object;
258             size = dido->size;
259             break;
260         }
261     }
262 
263     if( !dobj ) return;
264 
265     wxCharBuffer buffer(size);
266     size_t count = dobj->GetFormatCount( wxDataObject::Get );
267     wxDataFormatScopedArray dfarr( new wxDataFormat[count] );
268     dobj->GetAllFormats( dfarr.get(), wxDataObject::Get );
269 
270     if( !dobj->GetDataHere( dfarr[*priv], buffer.data() ) )
271         return;
272 
273     while( XmClipboardCopyByName( xdisplay, xwindow, *data_id,
274                                   buffer.data(), size, 0 )
275            == XmClipboardLocked );
276 }
277 
AddData(wxDataObject * data)278 bool wxClipboard::AddData( wxDataObject *data )
279 {
280     wxCHECK_MSG( data, false, "data is invalid" );
281     wxCHECK_MSG( m_open, false, "clipboard not open" );
282 
283     m_data.Append( data );
284 
285     Display* xdisplay = wxGlobalDisplay();
286     Widget xwidget = (Widget)wxTheApp->GetTopLevelRealizedWidget();
287     Window xwindow = XtWindow( xwidget );
288     wxXmString label( wxTheApp->GetAppDisplayName() );
289     Time timestamp = XtLastTimestampProcessed( xdisplay );
290     long itemId;
291 
292     int retval;
293 
294     while( ( retval = XmClipboardStartCopy( xdisplay, xwindow, label(),
295                                             timestamp, xwidget,
296                                             wxClipboardCallback,
297                                             &itemId ) )
298            == XmClipboardLocked );
299     if( retval != XmClipboardSuccess )
300         return false;
301 
302     size_t count = data->GetFormatCount( wxDataObject::Get );
303     wxDataFormatScopedArray dfarr( new wxDataFormat[count] );
304     data->GetAllFormats( dfarr.get(), wxDataObject::Get );
305 
306     for( size_t i = 0; i < count; ++i )
307     {
308         size_t size = data->GetDataSize( dfarr[i] );
309         long data_id;
310         wxString id = dfarr[i].GetId();
311 
312         while( ( retval = XmClipboardCopy( xdisplay, xwindow, itemId,
313                                            id.char_str(),
314                                            NULL, size, i, &data_id ) )
315                == XmClipboardLocked );
316 
317         m_idToObject.Append( new wxDataIdToDataObject( data, data_id, size ) );
318     }
319 
320     while( XmClipboardEndCopy( xdisplay, xwindow, itemId )
321            == XmClipboardLocked );
322 
323     return true;
324 }
325 
Close()326 void wxClipboard::Close()
327 {
328     wxCHECK_RET( m_open, "clipboard not open" );
329 
330     m_open = false;
331 }
332 
IsSupported(const wxDataFormat & format)333 bool wxClipboard::IsSupported(const wxDataFormat& format)
334 {
335     Display* xdisplay = wxGlobalDisplay();
336     Window xwindow = XtWindow( (Widget)wxTheApp->GetTopLevelRealizedWidget() );
337     bool isSupported = false;
338     int retval, count;
339     unsigned long  max_name_length;
340     wxString id = format.GetId();
341 
342     while( ( retval = XmClipboardLock( xdisplay, xwindow ) )
343            == XmClipboardLocked );
344     if( retval != XmClipboardSuccess )
345         return false;
346 
347     if( XmClipboardInquireCount( xdisplay, xwindow, &count, &max_name_length )
348         == XmClipboardSuccess )
349     {
350         wxCharBuffer buf( max_name_length + 1 );
351         unsigned long copied;
352 
353         for( int i = 0; i < count; ++i )
354         {
355             if( XmClipboardInquireFormat( xdisplay, xwindow, i + 1,
356                                           (XtPointer)buf.data(),
357                                           max_name_length, &copied )
358                 != XmClipboardSuccess )
359                 continue;
360 
361             buf.data()[copied] = '\0';
362 
363             if( buf == id )
364             {
365                 isSupported = true;
366                 break;
367             }
368         }
369     }
370 
371     XmClipboardUnlock( xdisplay, xwindow, False );
372 
373     return isSupported;
374 }
375 
376 class wxClipboardEndRetrieve
377 {
378 public:
wxClipboardEndRetrieve(Display * display,Window window)379     wxClipboardEndRetrieve( Display* display, Window window )
380         : m_display( display ), m_window( window ) { }
~wxClipboardEndRetrieve()381     ~wxClipboardEndRetrieve()
382     {
383         while( XmClipboardEndRetrieve( m_display, m_window )
384                == XmClipboardLocked );
385     }
386 private:
387     Display* m_display;
388     Window m_window;
389 };
390 
GetData(wxDataObject & data)391 bool wxClipboard::GetData( wxDataObject& data )
392 {
393     wxCHECK_MSG( m_open, false, "clipboard not open" );
394 
395     Display* xdisplay = wxGlobalDisplay();
396     Window xwindow = XtWindow( (Widget)wxTheApp->GetTopLevelRealizedWidget() );
397     Time timestamp = XtLastTimestampProcessed( xdisplay );
398 
399     wxDataFormat chosenFormat;
400     int retval;
401 
402     ///////////////////////////////////////////////////////////////////////////
403     // determine if the cliboard holds any format we like
404     ///////////////////////////////////////////////////////////////////////////
405     while( ( retval = XmClipboardStartRetrieve( xdisplay, xwindow,
406                                                 timestamp ) )
407            == XmClipboardLocked );
408     if( retval != XmClipboardSuccess )
409         return false;
410 
411     wxClipboardEndRetrieve endRetrieve( xdisplay, xwindow );
412 
413     int count;
414     unsigned long max_name_length;
415     size_t dfcount = data.GetFormatCount( wxDataObject::Set );
416     wxDataFormatScopedArray dfarr( new wxDataFormat[dfcount] );
417     data.GetAllFormats( dfarr.get(), wxDataObject::Set );
418 
419     if( XmClipboardInquireCount( xdisplay, xwindow, &count, &max_name_length )
420         == XmClipboardSuccess )
421     {
422         wxCharBuffer buf( max_name_length + 1 );
423         unsigned long copied;
424 
425         for( int i = 0; i < count; ++i )
426         {
427             if( XmClipboardInquireFormat( xdisplay, xwindow, i + 1,
428                                           (XtPointer)buf.data(),
429                                           max_name_length, &copied )
430                 != XmClipboardSuccess )
431                 continue;
432 
433             buf.data()[copied] = '\0';
434 
435             // try preferred format
436             if( buf == data.GetPreferredFormat( wxDataObject::Set ).GetId() )
437             {
438                 chosenFormat = data.GetPreferredFormat( wxDataObject::Set );
439                 break;
440             }
441 
442             // try all other formats
443             for( size_t i = 0; i < dfcount; ++i )
444             {
445                 if( buf == dfarr[i].GetId() )
446                     chosenFormat = dfarr[i];
447             }
448         }
449     }
450 
451     if( chosenFormat == wxDF_INVALID )
452         return false;
453 
454     ///////////////////////////////////////////////////////////////////////////
455     // now retrieve the data
456     ///////////////////////////////////////////////////////////////////////////
457     unsigned long length, dummy1;
458     long dummy2;
459     wxString id = chosenFormat.GetId();
460 
461     while( ( retval = XmClipboardInquireLength( xdisplay, xwindow,
462                                                 id.char_str(),
463                                                 &length ) )
464            == XmClipboardLocked );
465     if( retval != XmClipboardSuccess )
466         return false;
467 
468     wxCharBuffer buf(length);
469 
470     while( ( retval = XmClipboardRetrieve( xdisplay, xwindow,
471                                            id.char_str(),
472                                            (XtPointer)buf.data(),
473                                            length, &dummy1, &dummy2 ) )
474            == XmClipboardLocked );
475     if( retval != XmClipboardSuccess )
476         return false;
477 
478     if( !data.SetData( chosenFormat, length, buf.data() ) )
479         return false;
480 
481     return true;
482 }
483 
484 #endif // wxUSE_CLIPBOARD
485