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