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