Fix bug with not selecting wxAuiNotebook page when its child was focused.
[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 // 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
50 bool wxOpenClipboard()
51 {
52 return wxTheClipboard->Open();
53 }
54
55 bool wxCloseClipboard()
56 {
57 wxTheClipboard->Close();
58
59 return true;
60 }
61
62 bool wxEmptyClipboard()
63 {
64 wxTheClipboard->Clear();
65 return true;
66 }
67
68 bool wxClipboardOpen()
69 {
70 return wxTheClipboard->IsOpened();
71 }
72
73 bool wxIsClipboardFormatAvailable(const wxDataFormat& dataFormat)
74 {
75 return wxTheClipboard->IsSupported( dataFormat );
76 }
77
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
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
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
144 wxDataFormat wxRegisterClipboardFormat(char *WXUNUSED(formatName))
145 {
146 // Not supported
147 return wxDF_INVALID;
148 }
149
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 {
164 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)
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
188 IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
189
190 wxClipboard::wxClipboard()
191 {
192 m_open = false;
193 }
194
195 wxClipboard::~wxClipboard()
196 {
197 Clear();
198 }
199
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
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
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()
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
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
326 void wxClipboard::Close()
327 {
328 wxCHECK_RET( m_open, "clipboard not open" );
329
330 m_open = false;
331 }
332
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:
379 wxClipboardEndRetrieve( Display* display, Window window )
380 : m_display( display ), m_window( window ) { }
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
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