]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/clipbrd.cpp
Improve wxMenu docs
[wxWidgets.git] / src / gtk / clipbrd.cpp
CommitLineData
dc86cb34 1/////////////////////////////////////////////////////////////////////////////
e4db172a 2// Name: src/gtk/clipbrd.cpp
06f5d975 3// Purpose: wxClipboard implementation for wxGTK
eddb9644 4// Author: Robert Roebling, Vadim Zeitlin
dc86cb34
RR
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling
eddb9644 7// (c) 2007 Vadim Zeitlin
65571936 8// Licence: wxWindows licence
dc86cb34
RR
9/////////////////////////////////////////////////////////////////////////////
10
06f5d975
VZ
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
14f355c2
VS
19// For compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
e4db172a
WS
22#if wxUSE_CLIPBOARD
23
dc86cb34
RR
24#include "wx/clipbrd.h"
25
e4db172a
WS
26#ifndef WX_PRECOMP
27 #include "wx/log.h"
de6185e2 28 #include "wx/utils.h"
28f92d74 29 #include "wx/dataobj.h"
e4db172a 30#endif
ac57418f 31
eddb9644 32#include "wx/ptr_scpd.h"
06f5d975
VZ
33#include "wx/scopeguard.h"
34
67756da4 35#include "wx/gtk/private.h"
83624f79 36
eddb9644
VZ
37wxDECLARE_SCOPED_ARRAY(wxDataFormat, wxDataFormatArray)
38wxDEFINE_SCOPED_ARRAY(wxDataFormat, wxDataFormatArray)
39
40// ----------------------------------------------------------------------------
dc86cb34 41// data
eddb9644 42// ----------------------------------------------------------------------------
dc86cb34 43
06f5d975
VZ
44static GdkAtom g_clipboardAtom = 0;
45static GdkAtom g_targetsAtom = 0;
46static GdkAtom g_timestampAtom = 0;
fd0eed64 47
5e081315 48#if wxUSE_UNICODE
c7d6d883
RR
49extern GdkAtom g_altTextAtom;
50#endif
51
61b04ac6
VZ
52// the trace mask we use with wxLogTrace() - call
53// wxLog::AddTraceMask(TRACE_CLIPBOARD) to enable the trace messages from here
54// (there will be a *lot* of them!)
1457f12c 55#define TRACE_CLIPBOARD _T("clipboard")
61b04ac6 56
06f5d975
VZ
57// ----------------------------------------------------------------------------
58// wxClipboardSync: used to perform clipboard operations synchronously
59// ----------------------------------------------------------------------------
b527aac5 60
06f5d975
VZ
61// constructing this object on stack will wait wait until the latest clipboard
62// operation is finished on block exit
63//
64// notice that there can be no more than one such object alive at any moment,
65// i.e. reentrancies are not allowed
66class wxClipboardSync
dc86cb34 67{
06f5d975
VZ
68public:
69 wxClipboardSync(wxClipboard& clipboard)
70 {
71 wxASSERT_MSG( !ms_clipboard, _T("reentrancy in clipboard code") );
72 ms_clipboard = &clipboard;
73 }
74
75 ~wxClipboardSync()
76 {
77 while ( ms_clipboard )
78 gtk_main_iteration();
79 }
80
81 // this method must be called by GTK+ callbacks to indicate that we got the
82 // result for our clipboard operation
e0d1fd7f 83 static void OnDone(wxClipboard * WXUNUSED_UNLESS_DEBUG(clipboard))
06f5d975
VZ
84 {
85 wxASSERT_MSG( clipboard == ms_clipboard,
86 _T("got notification for alien clipboard") );
87
88 ms_clipboard = NULL;
89 }
90
b2b51072
VZ
91 // this method should be called if it's possible that no async clipboard
92 // operation is currently in progress (like it can be the case when the
93 // clipboard is cleared but not because we asked about it), it should only
94 // be called if such situation is expected -- otherwise call OnDone() which
95 // would assert in this case
96 static void OnDoneIfInProgress(wxClipboard *clipboard)
97 {
98 if ( ms_clipboard )
99 OnDone(clipboard);
100 }
101
06f5d975
VZ
102private:
103 static wxClipboard *ms_clipboard;
104
105 DECLARE_NO_COPY_CLASS(wxClipboardSync)
b527aac5
RR
106};
107
06f5d975 108wxClipboard *wxClipboardSync::ms_clipboard = NULL;
dc86cb34 109
eddb9644
VZ
110// ============================================================================
111// clipboard ca;backs implementation
112// ============================================================================
113
b527aac5
RR
114//-----------------------------------------------------------------------------
115// "selection_received" for targets
116//-----------------------------------------------------------------------------
117
865bb325 118extern "C" {
b527aac5 119static void
270c23f7
VZ
120targets_selection_received( GtkWidget *WXUNUSED(widget),
121 GtkSelectionData *selection_data,
034be888 122 guint32 WXUNUSED(time),
66633398 123 wxClipboard *clipboard )
dc86cb34 124{
eddb9644
VZ
125 if ( !clipboard )
126 return;
127
06f5d975
VZ
128 wxON_BLOCK_EXIT1(wxClipboardSync::OnDone, clipboard);
129
eddb9644
VZ
130 if ( !selection_data || selection_data->length <= 0 )
131 return;
132
133 // make sure we got the data in the correct form
134 GdkAtom type = selection_data->type;
135 if ( type != GDK_SELECTION_TYPE_ATOM )
034be888 136 {
eddb9644 137 if ( strcmp(wxGtkString(gdk_atom_name(type)), "TARGETS") != 0 )
270c23f7 138 {
eddb9644
VZ
139 wxLogTrace( TRACE_CLIPBOARD,
140 _T("got unsupported clipboard target") );
61b04ac6 141
eddb9644 142 return;
270c23f7 143 }
eddb9644 144 }
b527aac5 145
61b04ac6 146#ifdef __WXDEBUG__
eddb9644
VZ
147 // it's not really a format, of course, but we can reuse its GetId() method
148 // to format this atom as string
149 wxDataFormat clip(selection_data->selection);
150 wxLogTrace( TRACE_CLIPBOARD,
151 wxT("Received available formats for clipboard %s"),
152 clip.GetId().c_str() );
61b04ac6 153#endif // __WXDEBUG__
270c23f7 154
eddb9644
VZ
155 // the atoms we received, holding a list of targets (= formats)
156 const GdkAtom * const atoms = (GdkAtom *)selection_data->data;
157 for ( size_t i = 0; i < selection_data->length/sizeof(GdkAtom); i++ )
158 {
159 const wxDataFormat format(atoms[i]);
11e1c70d 160
eddb9644 161 wxLogTrace(TRACE_CLIPBOARD, wxT("\t%s"), format.GetId().c_str());
270c23f7 162
eddb9644
VZ
163 if ( clipboard->GTKOnTargetReceived(format) )
164 return;
8b53e5a2 165 }
dc86cb34 166}
865bb325 167}
dc86cb34 168
eddb9644
VZ
169bool wxClipboard::GTKOnTargetReceived(const wxDataFormat& format)
170{
171 if ( format != m_targetRequested )
172 return false;
173
174 m_formatSupported = true;
175 return true;
176}
177
dc86cb34 178//-----------------------------------------------------------------------------
b527aac5 179// "selection_received" for the actual data
dc86cb34
RR
180//-----------------------------------------------------------------------------
181
865bb325 182extern "C" {
270c23f7
VZ
183static void
184selection_received( GtkWidget *WXUNUSED(widget),
185 GtkSelectionData *selection_data,
034be888 186 guint32 WXUNUSED(time),
66633398 187 wxClipboard *clipboard )
dc86cb34 188{
eddb9644 189 if ( !clipboard )
034be888 190 return;
270c23f7 191
eddb9644 192 wxON_BLOCK_EXIT1(wxClipboardSync::OnDone, clipboard);
270c23f7 193
eddb9644 194 if ( !selection_data || selection_data->length <= 0 )
e5d6aa22 195 return;
270c23f7 196
eddb9644 197 clipboard->GTKOnSelectionReceived(*selection_data);
dc86cb34 198}
865bb325 199}
fd0eed64
RR
200
201//-----------------------------------------------------------------------------
202// "selection_clear"
203//-----------------------------------------------------------------------------
204
865bb325 205extern "C" {
fd0eed64 206static gint
aeeb6a44 207selection_clear_clip( GtkWidget *WXUNUSED(widget), GdkEventSelection *event )
fd0eed64 208{
eddb9644
VZ
209 wxClipboard * const clipboard = wxTheClipboard;
210 if ( !clipboard )
211 return TRUE;
06f5d975 212
b2b51072
VZ
213 // notice the use of OnDoneIfInProgress() here instead of just OnDone():
214 // it's perfectly possible that we're receiving this notification from GTK+
215 // even though we hadn't cleared the clipboard ourselves but because
216 // another application (or even another window in the same program)
217 // acquired it
218 wxON_BLOCK_EXIT1(wxClipboardSync::OnDoneIfInProgress, clipboard);
270c23f7 219
eddb9644 220 wxClipboard::Kind kind;
aeeb6a44
RR
221 if (event->selection == GDK_SELECTION_PRIMARY)
222 {
eddb9644
VZ
223 wxLogTrace(TRACE_CLIPBOARD, wxT("Lost primary selection" ));
224
225 kind = wxClipboard::Primary;
aeeb6a44 226 }
eddb9644 227 else if (event->selection == g_clipboardAtom)
aeeb6a44 228 {
eddb9644
VZ
229 wxLogTrace(TRACE_CLIPBOARD, wxT("Lost clipboard" ));
230
231 kind = wxClipboard::Clipboard;
aeeb6a44 232 }
eddb9644 233 else // some other selection, we're not concerned
aeeb6a44
RR
234 {
235 return FALSE;
236 }
270c23f7 237
eddb9644
VZ
238 // the clipboard is no longer in our hands, we don't need data any more
239 clipboard->GTKClearData(kind);
270c23f7 240
8b53e5a2 241 return TRUE;
fd0eed64 242}
865bb325 243}
fd0eed64
RR
244
245//-----------------------------------------------------------------------------
246// selection handler for supplying data
247//-----------------------------------------------------------------------------
248
865bb325 249extern "C" {
fd0eed64 250static void
19d89516
VZ
251selection_handler( GtkWidget *WXUNUSED(widget),
252 GtkSelectionData *selection_data,
253 guint WXUNUSED(info),
254 guint WXUNUSED(time),
d394f0c9 255 gpointer signal_data )
fd0eed64 256{
eddb9644
VZ
257 wxClipboard * const clipboard = wxTheClipboard;
258 if ( !clipboard )
259 return;
270c23f7 260
eddb9644
VZ
261 wxDataObject * const data = clipboard->GTKGetDataObject();
262 if ( !data )
263 return;
270c23f7 264
d394f0c9
MR
265 // ICCCM says that TIMESTAMP is a required atom.
266 // In particular, it satisfies Klipper, which polls
267 // TIMESTAMP to see if the clipboards content has changed.
268 // It shall return the time which was used to set the data.
269 if (selection_data->target == g_timestampAtom)
270 {
d704d2f5 271 guint timestamp = GPOINTER_TO_UINT (signal_data);
d394f0c9
MR
272 gtk_selection_data_set(selection_data,
273 GDK_SELECTION_TYPE_INTEGER,
274 32,
275 (guchar*)&(timestamp),
276 sizeof(timestamp));
277 wxLogTrace(TRACE_CLIPBOARD,
278 _T("Clipboard TIMESTAMP requested, returning timestamp=%u"),
279 timestamp);
280 return;
281 }
282
b068c4e8
RR
283 wxDataFormat format( selection_data->target );
284
ebe47451
VS
285#ifdef __WXDEBUG__
286 wxLogTrace(TRACE_CLIPBOARD,
d394f0c9 287 _T("clipboard data in format %s, GtkSelectionData is target=%s type=%s selection=%s timestamp=%u"),
ebe47451 288 format.GetId().c_str(),
67756da4
MR
289 wxString::FromAscii(wxGtkString(gdk_atom_name(selection_data->target))).c_str(),
290 wxString::FromAscii(wxGtkString(gdk_atom_name(selection_data->type))).c_str(),
291 wxString::FromAscii(wxGtkString(gdk_atom_name(selection_data->selection))).c_str(),
d394f0c9 292 GPOINTER_TO_UINT( signal_data )
ebe47451
VS
293 );
294#endif
3d257b8d 295
b068c4e8 296 if (!data->IsSupportedFormat( format )) return;
270c23f7 297
b068c4e8 298 int size = data->GetDataSize( format );
270c23f7 299
1dd989e1 300 if (size == 0) return;
270c23f7 301
33754c4d 302 void *d = malloc(size);
eddb9644 303 wxON_BLOCK_EXIT1(free, d);
33754c4d 304
ca11abde 305 // Text data will be in UTF8 in Unicode mode.
33754c4d 306 data->GetDataHere( selection_data->target, d );
270c23f7 307
ebe47451
VS
308 // NB: GTK+ requires special treatment of UTF8_STRING data, the text
309 // would show as UTF-8 data interpreted as latin1 (?) in other
310 // GTK+ apps if we used gtk_selection_data_set()
311 if (format == wxDataFormat(wxDF_UNICODETEXT))
312 {
313 gtk_selection_data_set_text(
314 selection_data,
315 (const gchar*)d,
2c906a49 316 size );
ebe47451
VS
317 }
318 else
ebe47451
VS
319 {
320 gtk_selection_data_set(
321 selection_data,
322 GDK_SELECTION_TYPE_STRING,
323 8*sizeof(gchar),
324 (unsigned char*) d,
2c906a49 325 size );
ebe47451 326 }
fd0eed64 327}
865bb325 328}
dc86cb34 329
eddb9644
VZ
330void wxClipboard::GTKOnSelectionReceived(const GtkSelectionData& sel)
331{
332 wxCHECK_RET( m_receivedData, _T("should be inside GetData()") );
333
334 const wxDataFormat format(sel.target);
335 wxLogTrace(TRACE_CLIPBOARD, _T("Received selection %s"),
336 format.GetId().c_str());
337
338 if ( !m_receivedData->IsSupportedFormat(format) )
339 return;
340
341 m_receivedData->SetData(format, sel.length, sel.data);
342 m_formatSupported = true;
343}
344
345// ============================================================================
346// wxClipboard implementation
347// ============================================================================
348
349// ----------------------------------------------------------------------------
350// wxClipboard ctor/dtor
351// ----------------------------------------------------------------------------
dc86cb34
RR
352
353IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
354
355wxClipboard::wxClipboard()
356{
de6185e2 357 m_open = false;
8b53e5a2 358
eddb9644
VZ
359 m_dataPrimary =
360 m_dataClipboard =
361 m_receivedData = NULL;
aeeb6a44 362
eddb9644
VZ
363 m_formatSupported = false;
364 m_targetRequested = 0;
99c67c77 365
eddb9644 366 // we use m_targetsWidget to query what formats are available
034be888
RR
367 m_targetsWidget = gtk_window_new( GTK_WINDOW_POPUP );
368 gtk_widget_realize( m_targetsWidget );
369
9fa72bd2
MR
370 g_signal_connect (m_targetsWidget, "selection_received",
371 G_CALLBACK (targets_selection_received), this);
270c23f7 372
eddb9644 373 // we use m_clipboardWidget to get and to offer data
8b53e5a2
RR
374 m_clipboardWidget = gtk_window_new( GTK_WINDOW_POPUP );
375 gtk_widget_realize( m_clipboardWidget );
376
9fa72bd2
MR
377 g_signal_connect (m_clipboardWidget, "selection_received",
378 G_CALLBACK (selection_received), this);
034be888 379
9fa72bd2
MR
380 g_signal_connect (m_clipboardWidget, "selection_clear_event",
381 G_CALLBACK (selection_clear_clip), NULL);
270c23f7 382
eddb9644
VZ
383 // initialize atoms we use if not done yet
384 if ( !g_clipboardAtom )
385 g_clipboardAtom = gdk_atom_intern( "CLIPBOARD", FALSE );
386 if ( !g_targetsAtom )
387 g_targetsAtom = gdk_atom_intern ("TARGETS", FALSE);
388 if ( !g_timestampAtom )
389 g_timestampAtom = gdk_atom_intern ("TIMESTAMP", FALSE);
dc86cb34
RR
390}
391
392wxClipboard::~wxClipboard()
b527aac5 393{
270c23f7
VZ
394 Clear();
395
05492dd1
VZ
396 gtk_widget_destroy( m_clipboardWidget );
397 gtk_widget_destroy( m_targetsWidget );
b527aac5
RR
398}
399
eddb9644
VZ
400// ----------------------------------------------------------------------------
401// wxClipboard helper functions
402// ----------------------------------------------------------------------------
403
404GdkAtom wxClipboard::GTKGetClipboardAtom() const
405{
406 return m_usePrimary ? (GdkAtom)GDK_SELECTION_PRIMARY
407 : g_clipboardAtom;
408}
409
410void wxClipboard::GTKClearData(Kind kind)
dc86cb34 411{
511383f9 412 wxDataObject *&data = Data(kind);
eddb9644 413 if ( data )
1dd989e1 414 {
eddb9644
VZ
415 delete data;
416 data = NULL;
417 }
418}
270c23f7 419
eddb9644
VZ
420bool wxClipboard::SetSelectionOwner(bool set)
421{
422 bool rc = gtk_selection_owner_set
423 (
424 set ? m_clipboardWidget : NULL,
425 GTKGetClipboardAtom(),
426 (guint32)GDK_CURRENT_TIME
427 );
428
429 if ( !rc )
430 {
431 wxLogTrace(TRACE_CLIPBOARD, _T("Failed to %sset selection owner"),
432 set ? _T("") : _T("un"));
433 }
270c23f7 434
eddb9644
VZ
435 return rc;
436}
270c23f7 437
eddb9644
VZ
438void wxClipboard::AddSupportedTarget(GdkAtom atom)
439{
440 gtk_selection_add_target
441 (
10bd1f7d 442 m_clipboardWidget,
eddb9644
VZ
443 GTKGetClipboardAtom(),
444 atom,
445 0 // info (same as client data) unused
446 );
447}
448
449bool wxClipboard::DoIsSupported(const wxDataFormat& format)
450{
451 wxCHECK_MSG( format, false, wxT("invalid clipboard format") );
270c23f7 452
eddb9644
VZ
453 wxLogTrace(TRACE_CLIPBOARD, wxT("Checking if format %s is available"),
454 format.GetId().c_str());
455
456 // these variables will be used by our GTKOnTargetReceived()
457 m_targetRequested = format;
458 m_formatSupported = false;
459
460 // block until m_formatSupported is set from targets_selection_received
461 // callback
462 {
463 wxClipboardSync sync(*this);
464
465 gtk_selection_convert( m_targetsWidget,
466 GTKGetClipboardAtom(),
467 g_targetsAtom,
468 (guint32) GDK_CURRENT_TIME );
469 }
470
471 return m_formatSupported;
472}
473
474// ----------------------------------------------------------------------------
475// wxClipboard public API implementation
476// ----------------------------------------------------------------------------
477
478void wxClipboard::Clear()
479{
480 if ( gdk_selection_owner_get(GTKGetClipboardAtom()) ==
481 m_clipboardWidget->window )
482 {
483 wxClipboardSync sync(*this);
484
485 // this will result in selection_clear_clip callback being called and
486 // it will free our data
487 SetSelectionOwner(false);
8b53e5a2 488 }
270c23f7 489
8b53e5a2 490 m_targetRequested = 0;
de6185e2 491 m_formatSupported = false;
8b53e5a2
RR
492}
493
494bool wxClipboard::Open()
495{
de6185e2 496 wxCHECK_MSG( !m_open, false, wxT("clipboard already open") );
270c23f7 497
de6185e2 498 m_open = true;
270c23f7 499
de6185e2 500 return true;
dc86cb34
RR
501}
502
75ce0581 503bool wxClipboard::SetData( wxDataObject *data )
dc86cb34 504{
de6185e2 505 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
270c23f7 506
de6185e2 507 wxCHECK_MSG( data, false, wxT("data is invalid") );
270c23f7 508
0d2a2b60 509 Clear();
75ce0581
RR
510
511 return AddData( data );
512}
513
514bool wxClipboard::AddData( wxDataObject *data )
515{
de6185e2 516 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
270c23f7 517
de6185e2 518 wxCHECK_MSG( data, false, wxT("data is invalid") );
270c23f7 519
eddb9644 520 // we can only store one wxDataObject so clear the old one
1dd989e1 521 Clear();
270c23f7 522
eddb9644 523 Data() = data;
1dd989e1 524
ca11abde 525 // get formats from wxDataObjects
eddb9644
VZ
526 const size_t count = data->GetFormatCount();
527 wxDataFormatArray formats(new wxDataFormat[count]);
528 data->GetAllFormats(formats.get());
11e1c70d 529
eddb9644
VZ
530 // always provide TIMESTAMP as a target, see comments in selection_handler
531 // for explanation
532 AddSupportedTarget(g_timestampAtom);
11e1c70d 533
eddb9644 534 for ( size_t i = 0; i < count; i++ )
b068c4e8 535 {
eddb9644 536 const wxDataFormat format(formats[i]);
11e1c70d 537
eddb9644
VZ
538 wxLogTrace(TRACE_CLIPBOARD, wxT("Adding support for %s"),
539 format.GetId().c_str());
3d257b8d 540
eddb9644 541 AddSupportedTarget(format);
b068c4e8
RR
542 }
543
9fa72bd2 544 g_signal_connect (m_clipboardWidget, "selection_get",
d394f0c9
MR
545 G_CALLBACK (selection_handler),
546 GUINT_TO_POINTER (gtk_get_current_event_time()) );
d345e841 547
eddb9644
VZ
548 // tell the world we offer clipboard data
549 return SetSelectionOwner();
8b53e5a2 550}
db1b4961 551
8b53e5a2
RR
552void wxClipboard::Close()
553{
223d09f6 554 wxCHECK_RET( m_open, wxT("clipboard not open") );
270c23f7 555
de6185e2 556 m_open = false;
dc86cb34
RR
557}
558
f536e0f2
VZ
559bool wxClipboard::IsOpened() const
560{
561 return m_open;
562}
563
e1ee679c 564bool wxClipboard::IsSupported( const wxDataFormat& format )
b527aac5 565{
eddb9644
VZ
566 if ( DoIsSupported(format) )
567 return true;
270c23f7 568
5e081315 569#if wxUSE_UNICODE
eddb9644 570 if ( format == wxDF_UNICODETEXT )
c7d6d883 571 {
eddb9644
VZ
572 // also with plain STRING format
573 return DoIsSupported(g_altTextAtom);
c7d6d883 574 }
eddb9644 575#endif // wxUSE_UNICODE
c7d6d883 576
eddb9644 577 return false;
270c23f7
VZ
578}
579
e1ee679c 580bool wxClipboard::GetData( wxDataObject& data )
75ce0581 581{
de6185e2 582 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
270c23f7 583
eddb9644
VZ
584 // get all supported formats from wxDataObjects
585 const size_t count = data.GetFormatCount();
586 wxDataFormatArray formats(new wxDataFormat[count]);
587 data.GetAllFormats(formats.get());
270c23f7 588
eddb9644 589 for ( size_t i = 0; i < count; i++ )
b068c4e8 590 {
eddb9644 591 const wxDataFormat format(formats[i]);
11e1c70d 592
eddb9644
VZ
593 // is this format supported by clipboard ?
594 if ( !DoIsSupported(format) )
595 continue;
270c23f7 596
eddb9644
VZ
597 wxLogTrace(TRACE_CLIPBOARD, wxT("Requesting format %s"),
598 format.GetId().c_str());
270c23f7 599
eddb9644 600 // these variables will be used by our GTKOnSelectionReceived()
b068c4e8 601 m_receivedData = &data;
de6185e2 602 m_formatSupported = false;
270c23f7 603
06f5d975
VZ
604 {
605 wxClipboardSync sync(*this);
606
eddb9644
VZ
607 gtk_selection_convert(m_clipboardWidget,
608 GTKGetClipboardAtom(),
609 format,
610 (guint32) GDK_CURRENT_TIME );
06f5d975 611 } // wait until we get the results
b527aac5 612
be809e82
VZ
613 /*
614 Normally this is a true error as we checked for the presence of such
615 data before, but there are applications that may return an empty
616 string (e.g. Gnumeric-1.6.1 on Linux if an empty cell is copied)
617 which would produce a false error message here, so we check for the
eddb9644 618 size of the string first. With ANSI, GetDataSize returns an extra
be809e82 619 value (for the closing null?), with unicode, the exact number of
eddb9644 620 tokens is given (that is more than 1 for non-ASCII characters)
be809e82
VZ
621 (tested with Gnumeric-1.6.1 and OpenOffice.org-2.0.2)
622 */
623#if wxUSE_UNICODE
624 if ( format != wxDF_UNICODETEXT || data.GetDataSize(format) > 0 )
625#else // !UNICODE
626 if ( format != wxDF_TEXT || data.GetDataSize(format) > 1 )
627#endif // UNICODE / !UNICODE
628 {
629 wxCHECK_MSG( m_formatSupported, false,
630 wxT("error retrieving data from clipboard") );
631 }
270c23f7 632
de6185e2 633 return true;
b068c4e8 634 }
270c23f7 635
eddb9644 636 wxLogTrace(TRACE_CLIPBOARD, wxT("GetData(): format not found"));
270c23f7 637
de6185e2 638 return false;
b527aac5
RR
639}
640
eddb9644 641#endif // wxUSE_CLIPBOARD