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