]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/clipbrd.cpp
enter wxPendingEventLocker critical section in ProcessPendingEvents() (fixes 1720352)
[wxWidgets.git] / src / mac / carbon / clipbrd.cpp
CommitLineData
e9576ca5 1/////////////////////////////////////////////////////////////////////////////
3e822cd8 2// Name: src/mac/carbon/clipbrd.cpp
e9576ca5 3// Purpose: Clipboard functionality
3e822cd8 4// Author: Stefan Csomor;
de6185e2 5// Generalized clipboard implementation by Matthew Flatt
e9576ca5 6// Modified by:
a31a5f85 7// Created: 1998-01-01
e9576ca5 8// RCS-ID: $Id$
a31a5f85 9// Copyright: (c) Stefan Csomor
65571936 10// Licence: wxWindows licence
e9576ca5
SC
11/////////////////////////////////////////////////////////////////////////////
12
a8e9860d
SC
13#include "wx/wxprec.h"
14
179e085f
RN
15#if wxUSE_CLIPBOARD
16
88a7a4e1
WS
17#include "wx/clipbrd.h"
18
19#ifndef WX_PRECOMP
20 #include "wx/intl.h"
e4db172a 21 #include "wx/log.h"
670f9935 22 #include "wx/app.h"
de6185e2 23 #include "wx/utils.h"
76b49cf4 24 #include "wx/frame.h"
0bca0373 25 #include "wx/bitmap.h"
88a7a4e1
WS
26#endif
27
e9576ca5 28#include "wx/metafile.h"
e9576ca5 29
66a09d47
SC
30#ifndef __DARWIN__
31#include <Scrap.h>
32#endif
3e822cd8 33
9c3c5849 34#include "wx/mac/uma.h"
76a5e5d2 35
2f1ae414
SC
36#define wxUSE_DATAOBJ 1
37
e9576ca5
SC
38#include <string.h>
39
3e822cd8 40
f0822896
SC
41// the trace mask we use with wxLogTrace() - call
42// wxLog::AddTraceMask(TRACE_CLIPBOARD) to enable the trace messages from here
43// (there will be a *lot* of them!)
3e822cd8
DS
44static const wxChar *TRACE_CLIPBOARD = wxT("clipboard");
45
2f1ae414 46
3e822cd8 47void * wxGetClipboardData( wxDataFormat dataFormat, long *len )
e9576ca5 48{
3e822cd8
DS
49 OSStatus err = noErr;
50 void * data = NULL;
e40298d5 51 Size byteCount;
e135f093 52
2f1ae414
SC
53 switch (dataFormat.GetType())
54 {
e40298d5
JS
55 case wxDF_OEMTEXT:
56 dataFormat = wxDF_TEXT;
3e822cd8 57 break;
e135f093 58
e40298d5 59 case wxDF_TEXT:
427ff662
SC
60 case wxDF_UNICODETEXT:
61 break;
3e822cd8
DS
62
63 case wxDF_BITMAP:
64 case wxDF_METAFILE:
65 break;
66
e40298d5 67 default:
21ec3bf9 68 // custom datatype
3e822cd8 69 break;
97af5088 70 }
e135f093 71
97af5088 72#if TARGET_CARBON
ed60b502 73 ScrapRef scrapRef;
e135f093 74
ed60b502 75 err = GetCurrentScrap( &scrapRef );
e135f093 76 if ( err != noTypeErr && err != memFullErr )
ed60b502
RR
77 {
78 ScrapFlavorFlags flavorFlags;
e135f093 79
3e822cd8
DS
80 err = GetScrapFlavorFlags( scrapRef, dataFormat.GetFormatId(), &flavorFlags );
81 if (err == noErr)
ed60b502 82 {
3e822cd8
DS
83 err = GetScrapFlavorSize( scrapRef, dataFormat.GetFormatId(), &byteCount );
84 if (err == noErr)
ed60b502 85 {
3e822cd8 86 Size allocSize = byteCount;
e135f093 87 if ( dataFormat.GetType() == wxDF_TEXT )
3e822cd8 88 allocSize += 1;
e135f093 89 else if ( dataFormat.GetType() == wxDF_UNICODETEXT )
3e822cd8 90 allocSize += 2;
e135f093 91
3e822cd8 92 data = new char[ allocSize ];
e135f093 93
e40298d5
JS
94 if (( err = GetScrapFlavorData( scrapRef, dataFormat.GetFormatId(), &byteCount , data )) == noErr )
95 {
3e822cd8 96 *len = allocSize;
e135f093 97 if ( dataFormat.GetType() == wxDF_TEXT )
3e822cd8 98 ((char*)data)[ byteCount ] = 0;
e135f093 99 if ( dataFormat.GetType() == wxDF_UNICODETEXT )
99b62b5f
KH
100 {
101 // "data" format is UTF16, so 2 bytes = one character
102 // wxChar size depends on platform, so just clear last 2 bytes
3e822cd8
DS
103 ((char*)data)[ byteCount + 0 ] =
104 ((char*)data)[ byteCount + 1 ] = 0;
99b62b5f 105 }
e40298d5
JS
106 }
107 else
108 {
3e822cd8
DS
109 delete [] (char*)data;
110 data = NULL;
e40298d5 111 }
ed60b502
RR
112 }
113 }
114 }
e135f093 115
97af5088 116#else
3e822cd8
DS
117 long offset;
118 Handle datahandle = NewHandle( 0 );
119 HLock( datahandle );
120 err = (OSStatus)GetScrap( datahandle, dataFormat.GetFormatId(), &offset );
121 HUnlock( datahandle );
ed60b502
RR
122 if ( GetHandleSize( datahandle ) > 0 )
123 {
3e822cd8
DS
124 byteCount = GetHandleSize( datahandle );
125 Size allocSize = byteCount;
e135f093 126 if ( dataFormat.GetType() == wxDF_TEXT )
3e822cd8 127 allocSize += 1;
e135f093 128 else if ( dataFormat.GetType() == wxDF_UNICODETEXT )
3e822cd8 129 allocSize += 2;
427ff662 130
3e822cd8 131 data = new char[ allocSize ];
427ff662 132
3e822cd8 133 memcpy( (char*) data, (char*) *datahandle, byteCount );
e135f093 134 if ( dataFormat.GetType() == wxDF_TEXT )
3e822cd8
DS
135 ((char*)data)[ byteCount ] = 0;
136 else if ( dataFormat.GetType() == wxDF_UNICODETEXT )
137 ((wxChar*)data)[ byteCount / 2 ] = 0;
138 *len = byteCount;
ed60b502 139 }
3e822cd8
DS
140
141 DisposeHandle( datahandle );
97af5088 142#endif
3e822cd8
DS
143
144 if (err != noErr)
97af5088 145 {
3e822cd8 146 wxLogSysError(wxT("Failed to get clipboard data."));
e135f093 147
3e822cd8 148 return NULL;
97af5088 149 }
427ff662 150
e542ecc6 151 if (dataFormat.GetType() == wxDF_TEXT)
3e822cd8 152 wxMacConvertNewlines10To13( (char*)data );
427ff662 153
97af5088 154 return data;
2f1ae414
SC
155}
156
528e2293 157IMPLEMENT_DYNAMIC_CLASS(wxClipboard, wxObject)
7c74e7fe 158
e7549107
SC
159wxClipboard::wxClipboard()
160{
3e822cd8
DS
161 m_open = false;
162 m_data = NULL;
e7549107 163}
e9576ca5 164
e7549107 165wxClipboard::~wxClipboard()
e9576ca5 166{
e542ecc6 167 if (m_data != NULL)
e7549107 168 {
f0822896 169 delete m_data;
e542ecc6 170 m_data = NULL;
e7549107 171 }
e9576ca5
SC
172}
173
e7549107 174void wxClipboard::Clear()
e9576ca5 175{
9005f2ed
VZ
176 if ( IsUsingPrimarySelection() )
177 return;
178
e542ecc6 179 if (m_data != NULL)
f0822896
SC
180 {
181 delete m_data;
e542ecc6 182 m_data = NULL;
f0822896 183 }
3e822cd8 184
f0822896 185#if TARGET_CARBON
3e822cd8
DS
186 OSStatus err;
187 err = ClearCurrentScrap();
f0822896 188#else
3e822cd8
DS
189 OSErr err;
190 err = ZeroScrap();
f0822896 191#endif
3e822cd8
DS
192
193 if (err != noErr)
ed60b502 194 {
3e822cd8 195 wxLogSysError( wxT("Failed to empty the clipboard.") );
ed60b502 196 }
e9576ca5
SC
197}
198
e7549107 199bool wxClipboard::Flush()
e9576ca5 200{
3dee36ae 201 return false;
e7549107
SC
202}
203
204bool wxClipboard::Open()
205{
3dee36ae 206 wxCHECK_MSG( !m_open, false, wxT("clipboard already open") );
3e822cd8
DS
207
208 m_open = true;
209
210 return true;
e7549107
SC
211}
212
213bool wxClipboard::IsOpened() const
214{
f0822896 215 return m_open;
e9576ca5
SC
216}
217
f0822896 218bool wxClipboard::SetData( wxDataObject *data )
e9576ca5 219{
9005f2ed
VZ
220 if ( IsUsingPrimarySelection() )
221 return false;
222
3dee36ae 223 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
3dee36ae 224 wxCHECK_MSG( data, false, wxT("data is invalid") );
634bafa9
SC
225
226 Clear();
3e822cd8
DS
227
228 // as we can only store one wxDataObject,
229 // this is the same in this implementation
f0822896 230 return AddData( data );
e7549107
SC
231}
232
233bool wxClipboard::AddData( wxDataObject *data )
234{
9005f2ed
VZ
235 if ( IsUsingPrimarySelection() )
236 return false;
237
3dee36ae 238 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
3dee36ae 239 wxCHECK_MSG( data, false, wxT("data is invalid") );
e7549107 240
3e822cd8 241 // we can only store one wxDataObject
f0822896 242 Clear();
e7549107 243
f0822896 244 m_data = data;
e7549107 245
21ec3bf9 246 // get formats from wxDataObjects
f0822896
SC
247 wxDataFormat *array = new wxDataFormat[ m_data->GetFormatCount() ];
248 m_data->GetAllFormats( array );
e7549107 249
f0822896
SC
250 for (size_t i = 0; i < m_data->GetFormatCount(); i++)
251 {
89a3d0f7
RD
252 if (array[i].IsStandard())
253 {
254 wxLogTrace( TRACE_CLIPBOARD,
255 wxT("wxClipboard now supports standard atom type %d"),
256 array[i].GetType() );
257 }
258 else
259 {
260 wxLogTrace( TRACE_CLIPBOARD,
261 wxT("wxClipboard now supports atom %s"),
262 array[i].GetId().c_str() );
263 }
e7549107 264
3e822cd8
DS
265 size_t sz = data->GetDataSize( array[ i ] );
266 void* buf = malloc( sz + 1 );
e542ecc6 267 if ( buf != NULL )
3dee36ae 268 {
99b62b5f 269 // empty the buffer because in some case GetDataHere does not fill buf
e542ecc6
DS
270 memset( buf, 0, sz + 1 );
271 data->GetDataHere( array[ i ], buf );
3e822cd8 272 OSType mactype = 0;
634bafa9
SC
273 switch ( array[i].GetType() )
274 {
3e822cd8
DS
275 case wxDF_TEXT:
276 case wxDF_OEMTEXT:
277 mactype = kScrapFlavorTypeText;
278 sz -= 1;
279 break;
280
281#if wxUSE_UNICODE
282 case wxDF_UNICODETEXT:
283 mactype = kScrapFlavorTypeUnicode;
284 sz -= 2;
285 break;
286#endif
287
288#if wxUSE_DRAG_AND_DROP
634bafa9 289 case wxDF_METAFILE:
3e822cd8
DS
290 mactype = kScrapFlavorTypePicture;
291 break;
292#endif
293
294 case wxDF_BITMAP:
295 case wxDF_DIB:
296 mactype = kScrapFlavorTypePicture;
297 break;
298
299 default:
e542ecc6 300 mactype = (OSType)(array[ i ].GetFormatId());
3e822cd8 301 break;
634bafa9 302 }
3e822cd8
DS
303
304 UMAPutScrap( sz , mactype , buf );
305 free( buf );
634bafa9 306 }
e9576ca5
SC
307 }
308
3e822cd8 309 delete [] array;
e9576ca5 310
3e822cd8 311 return true;
e9576ca5
SC
312}
313
f0822896 314void wxClipboard::Close()
e9576ca5 315{
634bafa9
SC
316 wxCHECK_RET( m_open, wxT("clipboard not open") );
317
3e822cd8 318 m_open = false;
3dee36ae 319
3e822cd8
DS
320 // Get rid of cached object.
321 // If this is not done, copying data from
322 // another application will only work once
89a69c60
SC
323 if (m_data)
324 {
325 delete m_data;
326 m_data = (wxDataObject*) NULL;
3dee36ae 327 }
e9576ca5
SC
328}
329
f0822896 330bool wxClipboard::IsSupported( const wxDataFormat &dataFormat )
e7549107 331{
9005f2ed
VZ
332 if ( IsUsingPrimarySelection() )
333 return false;
334
3dee36ae 335 if ( m_data )
3e822cd8
DS
336 return m_data->IsSupported( dataFormat );
337
e542ecc6
DS
338 bool hasData = false;
339
f0822896 340#if TARGET_CARBON
ed60b502
RR
341 OSStatus err = noErr;
342 ScrapRef scrapRef;
e135f093 343
ed60b502 344 err = GetCurrentScrap( &scrapRef );
e135f093 345 if ( err != noTypeErr && err != memFullErr )
ed60b502 346 {
3e822cd8
DS
347 ScrapFlavorFlags flavorFlags;
348 Size byteCount;
e135f093 349
3e822cd8
DS
350 err = GetScrapFlavorFlags( scrapRef, dataFormat.GetFormatId(), &flavorFlags );
351 if (err == noErr)
ed60b502 352 {
3e822cd8
DS
353 err = GetScrapFlavorSize( scrapRef, dataFormat.GetFormatId(), &byteCount );
354 if (err == noErr)
e542ecc6 355 hasData = true;
ed60b502 356 }
3271d737
SC
357 else if ( dataFormat.GetType() == wxDF_UNICODETEXT )
358 {
359 err = GetScrapFlavorFlags( scrapRef, 'TEXT', &flavorFlags );
360 if (err == noErr)
361 {
362 err = GetScrapFlavorSize( scrapRef, 'TEXT', &byteCount );
363 if (err == noErr)
364 hasData = true;
365 }
366 }
ed60b502 367 }
3e822cd8 368
f0822896 369#else
e542ecc6
DS
370
371 long offset = 0;
3e822cd8
DS
372 Handle datahandle = NewHandle( 0 );
373 HLock( datahandle );
374 GetScrap( datahandle, dataFormat.GetFormatId(), &offset );
375 HUnlock( datahandle );
e542ecc6 376 hasData = GetHandleSize( datahandle ) > 0;
3e822cd8 377 DisposeHandle( datahandle );
e542ecc6 378#endif
3e822cd8
DS
379
380 return hasData;
e9576ca5 381}
f0822896
SC
382
383bool wxClipboard::GetData( wxDataObject& data )
e9576ca5 384{
9005f2ed
VZ
385 if ( IsUsingPrimarySelection() )
386 return false;
387
3dee36ae 388 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
e9576ca5 389
3e822cd8
DS
390 size_t formatcount = data.GetFormatCount() + 1;
391 wxDataFormat *array = new wxDataFormat[ formatcount ];
f0822896
SC
392 array[0] = data.GetPreferredFormat();
393 data.GetAllFormats( &array[1] );
e9576ca5 394
3e822cd8 395 bool transferred = false;
e9576ca5 396
f0822896
SC
397 if ( m_data )
398 {
3e822cd8 399 for (size_t i = 0; !transferred && i < formatcount; i++)
21ec3bf9 400 {
3e822cd8 401 wxDataFormat format = array[ i ];
21ec3bf9 402 if ( m_data->IsSupported( format ) )
f0822896 403 {
3e822cd8
DS
404 int dataSize = m_data->GetDataSize( format );
405 transferred = true;
21ec3bf9 406
3e822cd8 407 if (dataSize == 0)
21ec3bf9 408 {
3e822cd8 409 data.SetData( format, 0, 0 );
21ec3bf9
SC
410 }
411 else
412 {
3e822cd8 413 char *d = new char[ dataSize ];
e542ecc6 414 m_data->GetDataHere( format, (void*)d );
3e822cd8
DS
415 data.SetData( format, dataSize, d );
416 delete [] d;
21ec3bf9 417 }
f0822896 418 }
21ec3bf9 419 }
f0822896 420 }
3e822cd8
DS
421
422 // get formats from wxDataObjects
e135f093 423 if ( !transferred )
f0822896 424 {
3e822cd8 425 for (size_t i = 0; !transferred && i < formatcount; i++)
21ec3bf9 426 {
3e822cd8 427 wxDataFormat format = array[ i ];
21ec3bf9
SC
428
429 switch ( format.GetType() )
430 {
431 // NOTE: this is usable for all data types
3e822cd8 432 case wxDF_TEXT:
21ec3bf9 433 case wxDF_UNICODETEXT:
3e822cd8
DS
434 case wxDF_OEMTEXT:
435 case wxDF_BITMAP:
436 case wxDF_METAFILE:
437 default:
21ec3bf9 438 {
3e822cd8
DS
439 long len;
440 char* s = (char*)wxGetClipboardData( format, &len );
441 if (s != NULL)
21ec3bf9 442 {
3e822cd8 443 data.SetData( format, len, s );
21ec3bf9
SC
444 delete [] s;
445
3e822cd8 446 transferred = true;
21ec3bf9
SC
447 }
448 }
3e822cd8 449 break;
21ec3bf9
SC
450 }
451 }
f0822896 452 }
e9576ca5 453
3e822cd8 454 delete [] array;
e542ecc6 455
3e822cd8 456 return transferred;
f0822896 457}
179e085f
RN
458
459#endif