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