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