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: clipbrd.cpp 46161 2007-05-22 06:02:49Z SC $
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#include "wx/mac/uma.h"
31
32#define wxUSE_DATAOBJ 1
33
34#include <string.h>
35
36
37// the trace mask we use with wxLogTrace() - call
38// wxLog::AddTraceMask(TRACE_CLIPBOARD) to enable the trace messages from here
39// (there will be a *lot* of them!)
40static const wxChar *TRACE_CLIPBOARD = wxT("clipboard");
41
42IMPLEMENT_DYNAMIC_CLASS(wxClipboard, wxObject)
43
44// in order to keep the binary interface the same this class
45// serves just to have a few additional member variables inside
46// the clipboard class
47
48class wxMacBinaryCompatHelper : public wxDataObject
49{
50public :
51    wxMacBinaryCompatHelper()
52    {
53        m_trueData = NULL;
54    }
55
56    ~wxMacBinaryCompatHelper()
57    {
58        if (m_trueData != NULL)
59        {
60            delete m_trueData;
61            m_trueData = NULL;
62        }
63    }
64
65    virtual wxDataFormat GetPreferredFormat(Direction dir = Get) const
66    {
67        return wxDataFormat();
68    }
69
70    virtual size_t GetFormatCount(Direction dir = Get) const
71    {
72        return 0;
73    }
74
75    virtual void GetAllFormats(wxDataFormat *formats,
76                               Direction dir = Get) const
77    {
78    }
79
80    virtual size_t GetDataSize(const wxDataFormat& format) const
81    {
82        return 0;
83    }
84
85    virtual bool GetDataHere(const wxDataFormat& format, void *buf) const
86    {
87        return false;
88    }
89
90    // only relevant from here on
91
92    wxDataObject* m_trueData;
93    wxCFRef<PasteboardRef> m_pasteboard;
94};
95
96#define M_CLIPBOARD ((wxMacBinaryCompatHelper*)m_data)
97
98wxClipboard::wxClipboard()
99{
100    m_open = false;
101    m_data = new wxMacBinaryCompatHelper() ;
102    PasteboardRef clipboard = 0;
103    OSStatus err = PasteboardCreate( kPasteboardClipboard, &clipboard );
104    if (err != noErr)
105    {
106        wxLogSysError( wxT("Failed to create the clipboard.") );
107    }
108    M_CLIPBOARD->m_pasteboard.reset(clipboard);
109}
110
111wxClipboard::~wxClipboard()
112{
113    M_CLIPBOARD->m_pasteboard.reset((PasteboardRef)0);
114    delete m_data;
115}
116
117void wxClipboard::Clear()
118{
119    if (M_CLIPBOARD->m_trueData != NULL)
120    {
121        delete M_CLIPBOARD->m_trueData;
122        M_CLIPBOARD->m_trueData = NULL;
123    }
124
125    OSStatus err = PasteboardClear( M_CLIPBOARD->m_pasteboard );
126    if (err != noErr)
127    {
128        wxLogSysError( wxT("Failed to empty the clipboard.") );
129    }
130}
131
132bool wxClipboard::Flush()
133{
134    return false;
135}
136
137bool wxClipboard::Open()
138{
139    wxCHECK_MSG( !m_open, false, wxT("clipboard already open") );
140
141    m_open = true;
142
143    return true;
144}
145
146bool wxClipboard::IsOpened() const
147{
148    return m_open;
149}
150
151bool wxClipboard::SetData( wxDataObject *data )
152{
153    wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
154    wxCHECK_MSG( data, false, wxT("data is invalid") );
155
156    Clear();
157
158    // as we can only store one wxDataObject,
159    // this is the same in this implementation
160    return AddData( data );
161}
162
163bool wxClipboard::AddData( wxDataObject *data )
164{
165    wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
166    wxCHECK_MSG( data, false, wxT("data is invalid") );
167
168    // we can only store one wxDataObject
169    Clear();
170
171    PasteboardSyncFlags syncFlags = PasteboardSynchronize( M_CLIPBOARD->m_pasteboard );
172    wxCHECK_MSG( !(syncFlags&kPasteboardModified), false, wxT("clipboard modified after clear") );
173    wxCHECK_MSG( (syncFlags&kPasteboardClientIsOwner), false, wxT("client couldn't own clipboard") );
174
175    M_CLIPBOARD->m_trueData = data;
176
177    data->AddToPasteboard( M_CLIPBOARD->m_pasteboard, 1 );
178
179    return true;
180}
181
182void wxClipboard::Close()
183{
184    wxCHECK_RET( m_open, wxT("clipboard not open") );
185
186    m_open = false;
187
188    // Get rid of cached object.
189    // If this is not done, copying data from
190    // another application will only work once
191    if (M_CLIPBOARD->m_trueData)
192    {
193        delete M_CLIPBOARD->m_trueData;
194        M_CLIPBOARD->m_trueData = (wxDataObject*) NULL;
195    }
196}
197
198bool wxClipboard::IsSupported( const wxDataFormat &dataFormat )
199{
200    if ( M_CLIPBOARD->m_trueData )
201        return M_CLIPBOARD->m_trueData->IsSupported( dataFormat );
202    return wxDataObject::IsFormatInPasteboard( M_CLIPBOARD->m_pasteboard, dataFormat );
203}
204
205bool wxClipboard::GetData( wxDataObject& data )
206{
207    wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
208
209    size_t formatcount = data.GetFormatCount() + 1;
210    wxDataFormat *array = new wxDataFormat[ formatcount ];
211    array[0] = data.GetPreferredFormat();
212    data.GetAllFormats( &array[1] );
213
214    bool transferred = false;
215
216    if ( M_CLIPBOARD->m_trueData )
217    {
218        for (size_t i = 0; !transferred && i < formatcount; i++)
219        {
220            wxDataFormat format = array[ i ];
221            if ( M_CLIPBOARD->m_trueData->IsSupported( format ) )
222            {
223                int dataSize = M_CLIPBOARD->m_trueData->GetDataSize( format );
224                transferred = true;
225
226                if (dataSize == 0)
227                {
228                    data.SetData( format, 0, 0 );
229                }
230                else
231                {
232                    char *d = new char[ dataSize ];
233                    M_CLIPBOARD->m_trueData->GetDataHere( format, (void*)d );
234                    data.SetData( format, dataSize, d );
235                    delete [] d;
236                }
237            }
238        }
239    }
240
241    // get formats from wxDataObjects
242    if ( !transferred )
243    {
244        transferred = data.GetFromPasteboard( M_CLIPBOARD->m_pasteboard ) ;
245    }
246
247    delete [] array;
248
249    return transferred;
250}
251
252#endif
253