]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/clipbrd.cpp
don't save the initial selection if it's invalid in CBN_DROPDOWN (refixes #8474 witho...
[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 293 );
157a8f70 294#endif // __WXDEBUG__
3d257b8d 295
157a8f70
VZ
296 if ( !data->IsSupportedFormat( format ) )
297 return;
270c23f7 298
b068c4e8 299 int size = data->GetDataSize( format );
157a8f70
VZ
300 if ( !size )
301 return;
270c23f7 302
157a8f70 303 wxCharBuffer buf(size - 1); // it adds 1 internally (for NUL)
33754c4d 304
b82c3e60 305 // text data must be returned in UTF8 if format is wxDF_UNICODETEXT
157a8f70
VZ
306 if ( !data->GetDataHere(format, buf.data()) )
307 return;
270c23f7 308
b82c3e60
VZ
309 // use UTF8_STRING format if requested in Unicode build but just plain
310 // STRING one in ANSI or if explicitly asked in Unicode
311#if wxUSE_UNICODE
ebe47451
VS
312 if (format == wxDataFormat(wxDF_UNICODETEXT))
313 {
314 gtk_selection_data_set_text(
315 selection_data,
b82c3e60 316 (const gchar*)buf.data(),
2c906a49 317 size );
ebe47451
VS
318 }
319 else
157a8f70 320#endif // wxUSE_UNICODE
ebe47451
VS
321 {
322 gtk_selection_data_set(
323 selection_data,
324 GDK_SELECTION_TYPE_STRING,
325 8*sizeof(gchar),
b82c3e60 326 (const guchar*)buf.data(),
2c906a49 327 size );
ebe47451 328 }
fd0eed64 329}
865bb325 330}
dc86cb34 331
eddb9644
VZ
332void wxClipboard::GTKOnSelectionReceived(const GtkSelectionData& sel)
333{
334 wxCHECK_RET( m_receivedData, _T("should be inside GetData()") );
335
336 const wxDataFormat format(sel.target);
337 wxLogTrace(TRACE_CLIPBOARD, _T("Received selection %s"),
338 format.GetId().c_str());
339
340 if ( !m_receivedData->IsSupportedFormat(format) )
341 return;
342
343 m_receivedData->SetData(format, sel.length, sel.data);
344 m_formatSupported = true;
345}
346
347// ============================================================================
348// wxClipboard implementation
349// ============================================================================
350
351// ----------------------------------------------------------------------------
352// wxClipboard ctor/dtor
353// ----------------------------------------------------------------------------
dc86cb34
RR
354
355IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
356
357wxClipboard::wxClipboard()
358{
de6185e2 359 m_open = false;
8b53e5a2 360
eddb9644
VZ
361 m_dataPrimary =
362 m_dataClipboard =
363 m_receivedData = NULL;
aeeb6a44 364
eddb9644
VZ
365 m_formatSupported = false;
366 m_targetRequested = 0;
99c67c77 367
eddb9644 368 // we use m_targetsWidget to query what formats are available
034be888
RR
369 m_targetsWidget = gtk_window_new( GTK_WINDOW_POPUP );
370 gtk_widget_realize( m_targetsWidget );
371
9fa72bd2
MR
372 g_signal_connect (m_targetsWidget, "selection_received",
373 G_CALLBACK (targets_selection_received), this);
270c23f7 374
eddb9644 375 // we use m_clipboardWidget to get and to offer data
8b53e5a2
RR
376 m_clipboardWidget = gtk_window_new( GTK_WINDOW_POPUP );
377 gtk_widget_realize( m_clipboardWidget );
378
9fa72bd2
MR
379 g_signal_connect (m_clipboardWidget, "selection_received",
380 G_CALLBACK (selection_received), this);
034be888 381
9fa72bd2
MR
382 g_signal_connect (m_clipboardWidget, "selection_clear_event",
383 G_CALLBACK (selection_clear_clip), NULL);
270c23f7 384
eddb9644
VZ
385 // initialize atoms we use if not done yet
386 if ( !g_clipboardAtom )
387 g_clipboardAtom = gdk_atom_intern( "CLIPBOARD", FALSE );
388 if ( !g_targetsAtom )
389 g_targetsAtom = gdk_atom_intern ("TARGETS", FALSE);
390 if ( !g_timestampAtom )
391 g_timestampAtom = gdk_atom_intern ("TIMESTAMP", FALSE);
dc86cb34
RR
392}
393
394wxClipboard::~wxClipboard()
b527aac5 395{
270c23f7
VZ
396 Clear();
397
05492dd1
VZ
398 gtk_widget_destroy( m_clipboardWidget );
399 gtk_widget_destroy( m_targetsWidget );
b527aac5
RR
400}
401
eddb9644
VZ
402// ----------------------------------------------------------------------------
403// wxClipboard helper functions
404// ----------------------------------------------------------------------------
405
406GdkAtom wxClipboard::GTKGetClipboardAtom() const
407{
408 return m_usePrimary ? (GdkAtom)GDK_SELECTION_PRIMARY
409 : g_clipboardAtom;
410}
411
412void wxClipboard::GTKClearData(Kind kind)
dc86cb34 413{
511383f9 414 wxDataObject *&data = Data(kind);
eddb9644 415 if ( data )
1dd989e1 416 {
eddb9644
VZ
417 delete data;
418 data = NULL;
419 }
420}
270c23f7 421
eddb9644
VZ
422bool wxClipboard::SetSelectionOwner(bool set)
423{
424 bool rc = gtk_selection_owner_set
425 (
426 set ? m_clipboardWidget : NULL,
427 GTKGetClipboardAtom(),
428 (guint32)GDK_CURRENT_TIME
429 );
430
431 if ( !rc )
432 {
433 wxLogTrace(TRACE_CLIPBOARD, _T("Failed to %sset selection owner"),
434 set ? _T("") : _T("un"));
435 }
270c23f7 436
eddb9644
VZ
437 return rc;
438}
270c23f7 439
eddb9644
VZ
440void wxClipboard::AddSupportedTarget(GdkAtom atom)
441{
442 gtk_selection_add_target
443 (
10bd1f7d 444 m_clipboardWidget,
eddb9644
VZ
445 GTKGetClipboardAtom(),
446 atom,
447 0 // info (same as client data) unused
448 );
449}
450
451bool wxClipboard::DoIsSupported(const wxDataFormat& format)
452{
453 wxCHECK_MSG( format, false, wxT("invalid clipboard format") );
270c23f7 454
eddb9644
VZ
455 wxLogTrace(TRACE_CLIPBOARD, wxT("Checking if format %s is available"),
456 format.GetId().c_str());
457
458 // these variables will be used by our GTKOnTargetReceived()
459 m_targetRequested = format;
460 m_formatSupported = false;
461
462 // block until m_formatSupported is set from targets_selection_received
463 // callback
464 {
465 wxClipboardSync sync(*this);
466
467 gtk_selection_convert( m_targetsWidget,
468 GTKGetClipboardAtom(),
469 g_targetsAtom,
470 (guint32) GDK_CURRENT_TIME );
471 }
472
473 return m_formatSupported;
474}
475
476// ----------------------------------------------------------------------------
477// wxClipboard public API implementation
478// ----------------------------------------------------------------------------
479
480void wxClipboard::Clear()
481{
482 if ( gdk_selection_owner_get(GTKGetClipboardAtom()) ==
483 m_clipboardWidget->window )
484 {
485 wxClipboardSync sync(*this);
486
487 // this will result in selection_clear_clip callback being called and
488 // it will free our data
489 SetSelectionOwner(false);
8b53e5a2 490 }
270c23f7 491
8b53e5a2 492 m_targetRequested = 0;
de6185e2 493 m_formatSupported = false;
8b53e5a2
RR
494}
495
496bool wxClipboard::Open()
497{
de6185e2 498 wxCHECK_MSG( !m_open, false, wxT("clipboard already open") );
270c23f7 499
de6185e2 500 m_open = true;
270c23f7 501
de6185e2 502 return true;
dc86cb34
RR
503}
504
75ce0581 505bool wxClipboard::SetData( wxDataObject *data )
dc86cb34 506{
de6185e2 507 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
270c23f7 508
de6185e2 509 wxCHECK_MSG( data, false, wxT("data is invalid") );
270c23f7 510
0d2a2b60 511 Clear();
75ce0581
RR
512
513 return AddData( data );
514}
515
516bool wxClipboard::AddData( wxDataObject *data )
517{
de6185e2 518 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
270c23f7 519
de6185e2 520 wxCHECK_MSG( data, false, wxT("data is invalid") );
270c23f7 521
eddb9644 522 // we can only store one wxDataObject so clear the old one
1dd989e1 523 Clear();
270c23f7 524
eddb9644 525 Data() = data;
1dd989e1 526
ca11abde 527 // get formats from wxDataObjects
eddb9644
VZ
528 const size_t count = data->GetFormatCount();
529 wxDataFormatArray formats(new wxDataFormat[count]);
530 data->GetAllFormats(formats.get());
11e1c70d 531
eddb9644
VZ
532 // always provide TIMESTAMP as a target, see comments in selection_handler
533 // for explanation
534 AddSupportedTarget(g_timestampAtom);
11e1c70d 535
eddb9644 536 for ( size_t i = 0; i < count; i++ )
b068c4e8 537 {
eddb9644 538 const wxDataFormat format(formats[i]);
11e1c70d 539
eddb9644
VZ
540 wxLogTrace(TRACE_CLIPBOARD, wxT("Adding support for %s"),
541 format.GetId().c_str());
3d257b8d 542
eddb9644 543 AddSupportedTarget(format);
b068c4e8
RR
544 }
545
9fa72bd2 546 g_signal_connect (m_clipboardWidget, "selection_get",
d394f0c9
MR
547 G_CALLBACK (selection_handler),
548 GUINT_TO_POINTER (gtk_get_current_event_time()) );
d345e841 549
eddb9644
VZ
550 // tell the world we offer clipboard data
551 return SetSelectionOwner();
8b53e5a2 552}
db1b4961 553
8b53e5a2
RR
554void wxClipboard::Close()
555{
223d09f6 556 wxCHECK_RET( m_open, wxT("clipboard not open") );
270c23f7 557
de6185e2 558 m_open = false;
dc86cb34
RR
559}
560
f536e0f2
VZ
561bool wxClipboard::IsOpened() const
562{
563 return m_open;
564}
565
e1ee679c 566bool wxClipboard::IsSupported( const wxDataFormat& format )
b527aac5 567{
eddb9644
VZ
568 if ( DoIsSupported(format) )
569 return true;
270c23f7 570
5e081315 571#if wxUSE_UNICODE
eddb9644 572 if ( format == wxDF_UNICODETEXT )
c7d6d883 573 {
eddb9644
VZ
574 // also with plain STRING format
575 return DoIsSupported(g_altTextAtom);
c7d6d883 576 }
eddb9644 577#endif // wxUSE_UNICODE
c7d6d883 578
eddb9644 579 return false;
270c23f7
VZ
580}
581
e1ee679c 582bool wxClipboard::GetData( wxDataObject& data )
75ce0581 583{
de6185e2 584 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
270c23f7 585
eddb9644
VZ
586 // get all supported formats from wxDataObjects
587 const size_t count = data.GetFormatCount();
588 wxDataFormatArray formats(new wxDataFormat[count]);
589 data.GetAllFormats(formats.get());
270c23f7 590
eddb9644 591 for ( size_t i = 0; i < count; i++ )
b068c4e8 592 {
eddb9644 593 const wxDataFormat format(formats[i]);
11e1c70d 594
eddb9644
VZ
595 // is this format supported by clipboard ?
596 if ( !DoIsSupported(format) )
597 continue;
270c23f7 598
eddb9644
VZ
599 wxLogTrace(TRACE_CLIPBOARD, wxT("Requesting format %s"),
600 format.GetId().c_str());
270c23f7 601
eddb9644 602 // these variables will be used by our GTKOnSelectionReceived()
b068c4e8 603 m_receivedData = &data;
de6185e2 604 m_formatSupported = false;
270c23f7 605
06f5d975
VZ
606 {
607 wxClipboardSync sync(*this);
608
eddb9644
VZ
609 gtk_selection_convert(m_clipboardWidget,
610 GTKGetClipboardAtom(),
611 format,
612 (guint32) GDK_CURRENT_TIME );
06f5d975 613 } // wait until we get the results
b527aac5 614
be809e82
VZ
615 /*
616 Normally this is a true error as we checked for the presence of such
617 data before, but there are applications that may return an empty
618 string (e.g. Gnumeric-1.6.1 on Linux if an empty cell is copied)
619 which would produce a false error message here, so we check for the
eddb9644 620 size of the string first. With ANSI, GetDataSize returns an extra
be809e82 621 value (for the closing null?), with unicode, the exact number of
eddb9644 622 tokens is given (that is more than 1 for non-ASCII characters)
be809e82
VZ
623 (tested with Gnumeric-1.6.1 and OpenOffice.org-2.0.2)
624 */
625#if wxUSE_UNICODE
626 if ( format != wxDF_UNICODETEXT || data.GetDataSize(format) > 0 )
627#else // !UNICODE
628 if ( format != wxDF_TEXT || data.GetDataSize(format) > 1 )
629#endif // UNICODE / !UNICODE
630 {
631 wxCHECK_MSG( m_formatSupported, false,
632 wxT("error retrieving data from clipboard") );
633 }
270c23f7 634
de6185e2 635 return true;
b068c4e8 636 }
270c23f7 637
eddb9644 638 wxLogTrace(TRACE_CLIPBOARD, wxT("GetData(): format not found"));
270c23f7 639
de6185e2 640 return false;
b527aac5
RR
641}
642
eddb9644 643#endif // wxUSE_CLIPBOARD