update position for widgets in native containers, fixes #15231
[wxWidgets.git] / src / gtk / clipbrd.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/clipbrd.cpp
3 // Purpose: wxClipboard implementation for wxGTK
4 // Author: Robert Roebling, Vadim Zeitlin
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // (c) 2007 Vadim Zeitlin
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #if wxUSE_CLIPBOARD
23
24 #include "wx/clipbrd.h"
25
26 #ifndef WX_PRECOMP
27 #include "wx/app.h"
28 #include "wx/log.h"
29 #include "wx/utils.h"
30 #include "wx/dataobj.h"
31 #endif
32
33 #include "wx/scopedarray.h"
34 #include "wx/scopeguard.h"
35 #include "wx/evtloop.h"
36
37 #include "wx/gtk/private.h"
38
39 typedef wxScopedArray<wxDataFormat> wxDataFormatArray;
40
41 // ----------------------------------------------------------------------------
42 // data
43 // ----------------------------------------------------------------------------
44
45 static GdkAtom g_clipboardAtom = 0;
46 static GdkAtom g_targetsAtom = 0;
47 static GdkAtom g_timestampAtom = 0;
48
49 #if wxUSE_UNICODE
50 extern GdkAtom g_altTextAtom;
51 #endif
52
53 // the trace mask we use with wxLogTrace() - call
54 // wxLog::AddTraceMask(TRACE_CLIPBOARD) to enable the trace messages from here
55 // (there will be a *lot* of them!)
56 #define TRACE_CLIPBOARD wxT("clipboard")
57
58 // ----------------------------------------------------------------------------
59 // wxClipboardSync: used to perform clipboard operations synchronously
60 // ----------------------------------------------------------------------------
61
62 // constructing this object on stack will wait wait until the latest clipboard
63 // operation is finished on block exit
64 //
65 // notice that there can be no more than one such object alive at any moment,
66 // i.e. reentrancies are not allowed
67 class wxClipboardSync
68 {
69 public:
70 wxClipboardSync(wxClipboard& clipboard)
71 {
72 wxASSERT_MSG( !ms_clipboard, wxT("reentrancy in clipboard code") );
73 ms_clipboard = &clipboard;
74 }
75
76 ~wxClipboardSync()
77 {
78 #if wxUSE_CONSOLE_EVENTLOOP
79 // ensure that there is a running event loop: this might not be the
80 // case if we're called before the main event loop startup
81 wxEventLoopGuarantor ensureEventLoop;
82 #endif
83 while (ms_clipboard)
84 wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_CLIPBOARD);
85 }
86
87 // this method must be called by GTK+ callbacks to indicate that we got the
88 // result for our clipboard operation
89 static void OnDone(wxClipboard * WXUNUSED_UNLESS_DEBUG(clipboard))
90 {
91 wxASSERT_MSG( clipboard == ms_clipboard,
92 wxT("got notification for alien clipboard") );
93
94 ms_clipboard = NULL;
95 }
96
97 // this method should be called if it's possible that no async clipboard
98 // operation is currently in progress (like it can be the case when the
99 // clipboard is cleared but not because we asked about it), it should only
100 // be called if such situation is expected -- otherwise call OnDone() which
101 // would assert in this case
102 static void OnDoneIfInProgress(wxClipboard *clipboard)
103 {
104 if ( ms_clipboard )
105 OnDone(clipboard);
106 }
107
108 private:
109 static wxClipboard *ms_clipboard;
110
111 wxDECLARE_NO_COPY_CLASS(wxClipboardSync);
112 };
113
114 wxClipboard *wxClipboardSync::ms_clipboard = NULL;
115
116 // ============================================================================
117 // clipboard callbacks implementation
118 // ============================================================================
119
120 //-----------------------------------------------------------------------------
121 // "selection_received" for targets
122 //-----------------------------------------------------------------------------
123
124 extern "C" {
125 static void
126 targets_selection_received( GtkWidget *WXUNUSED(widget),
127 GtkSelectionData *selection_data,
128 guint32 WXUNUSED(time),
129 wxClipboard *clipboard )
130 {
131 if ( !clipboard )
132 return;
133
134 wxON_BLOCK_EXIT1(wxClipboardSync::OnDone, clipboard);
135
136 if (!selection_data)
137 return;
138
139 const int selection_data_length = gtk_selection_data_get_length(selection_data);
140 if (selection_data_length <= 0)
141 return;
142
143 // make sure we got the data in the correct form
144 GdkAtom type = gtk_selection_data_get_data_type(selection_data);
145 if ( type != GDK_SELECTION_TYPE_ATOM )
146 {
147 if ( strcmp(wxGtkString(gdk_atom_name(type)), "TARGETS") != 0 )
148 {
149 wxLogTrace( TRACE_CLIPBOARD,
150 wxT("got unsupported clipboard target") );
151
152 return;
153 }
154 }
155
156 // it's not really a format, of course, but we can reuse its GetId() method
157 // to format this atom as string
158 wxDataFormat clip(gtk_selection_data_get_selection(selection_data));
159 wxLogTrace( TRACE_CLIPBOARD,
160 wxT("Received available formats for clipboard %s"),
161 clip.GetId().c_str() );
162
163 // the atoms we received, holding a list of targets (= formats)
164 const GdkAtom* const atoms = (GdkAtom*)gtk_selection_data_get_data(selection_data);
165 for (size_t i = 0; i < selection_data_length / sizeof(GdkAtom); i++)
166 {
167 const wxDataFormat format(atoms[i]);
168
169 wxLogTrace(TRACE_CLIPBOARD, wxT("\t%s"), format.GetId().c_str());
170
171 if ( clipboard->GTKOnTargetReceived(format) )
172 return;
173 }
174 }
175 }
176
177 bool wxClipboard::GTKOnTargetReceived(const wxDataFormat& format)
178 {
179 if ( format != m_targetRequested )
180 return false;
181
182 m_formatSupported = true;
183 return true;
184 }
185
186 //-----------------------------------------------------------------------------
187 // "selection_received" for the actual data
188 //-----------------------------------------------------------------------------
189
190 extern "C" {
191 static void
192 selection_received( GtkWidget *WXUNUSED(widget),
193 GtkSelectionData *selection_data,
194 guint32 WXUNUSED(time),
195 wxClipboard *clipboard )
196 {
197 if ( !clipboard )
198 return;
199
200 wxON_BLOCK_EXIT1(wxClipboardSync::OnDone, clipboard);
201
202 if (!selection_data || gtk_selection_data_get_length(selection_data) <= 0)
203 return;
204
205 clipboard->GTKOnSelectionReceived(*selection_data);
206 }
207 }
208
209 //-----------------------------------------------------------------------------
210 // "selection_clear"
211 //-----------------------------------------------------------------------------
212
213 extern "C" {
214 static gint
215 selection_clear_clip( GtkWidget *WXUNUSED(widget), GdkEventSelection *event )
216 {
217 wxClipboard * const clipboard = wxTheClipboard;
218 if ( !clipboard )
219 return TRUE;
220
221 // notice the use of OnDoneIfInProgress() here instead of just OnDone():
222 // it's perfectly possible that we're receiving this notification from GTK+
223 // even though we hadn't cleared the clipboard ourselves but because
224 // another application (or even another window in the same program)
225 // acquired it
226 wxON_BLOCK_EXIT1(wxClipboardSync::OnDoneIfInProgress, clipboard);
227
228 wxClipboard::Kind kind;
229 if (event->selection == GDK_SELECTION_PRIMARY)
230 {
231 wxLogTrace(TRACE_CLIPBOARD, wxT("Lost primary selection" ));
232
233 kind = wxClipboard::Primary;
234 }
235 else if (event->selection == g_clipboardAtom)
236 {
237 wxLogTrace(TRACE_CLIPBOARD, wxT("Lost clipboard" ));
238
239 kind = wxClipboard::Clipboard;
240 }
241 else // some other selection, we're not concerned
242 {
243 return FALSE;
244 }
245
246 // the clipboard is no longer in our hands, we don't need data any more
247 clipboard->GTKClearData(kind);
248
249 return TRUE;
250 }
251 }
252
253 //-----------------------------------------------------------------------------
254 // selection handler for supplying data
255 //-----------------------------------------------------------------------------
256
257 extern "C" {
258 static void
259 selection_handler( GtkWidget *WXUNUSED(widget),
260 GtkSelectionData *selection_data,
261 guint WXUNUSED(info),
262 guint WXUNUSED(time),
263 gpointer signal_data )
264 {
265 wxClipboard * const clipboard = wxTheClipboard;
266 if ( !clipboard )
267 return;
268
269 wxDataObject * const data = clipboard->GTKGetDataObject(
270 gtk_selection_data_get_selection(selection_data));
271 if ( !data )
272 return;
273
274 // ICCCM says that TIMESTAMP is a required atom.
275 // In particular, it satisfies Klipper, which polls
276 // TIMESTAMP to see if the clipboards content has changed.
277 // It shall return the time which was used to set the data.
278 if (gtk_selection_data_get_target(selection_data) == g_timestampAtom)
279 {
280 guint timestamp = GPOINTER_TO_UINT (signal_data);
281 gtk_selection_data_set(selection_data,
282 GDK_SELECTION_TYPE_INTEGER,
283 32,
284 (guchar*)&(timestamp),
285 sizeof(timestamp));
286 wxLogTrace(TRACE_CLIPBOARD,
287 wxT("Clipboard TIMESTAMP requested, returning timestamp=%u"),
288 timestamp);
289 return;
290 }
291
292 wxDataFormat format(gtk_selection_data_get_target(selection_data));
293
294 wxLogTrace(TRACE_CLIPBOARD,
295 wxT("clipboard data in format %s, GtkSelectionData is target=%s type=%s selection=%s timestamp=%u"),
296 format.GetId().c_str(),
297 wxString::FromAscii(wxGtkString(gdk_atom_name(gtk_selection_data_get_target(selection_data)))).c_str(),
298 wxString::FromAscii(wxGtkString(gdk_atom_name(gtk_selection_data_get_data_type(selection_data)))).c_str(),
299 wxString::FromAscii(wxGtkString(gdk_atom_name(gtk_selection_data_get_selection(selection_data)))).c_str(),
300 GPOINTER_TO_UINT( signal_data )
301 );
302
303 if ( !data->IsSupportedFormat( format ) )
304 return;
305
306 int size = data->GetDataSize( format );
307 if ( !size )
308 return;
309
310 wxCharBuffer buf(size - 1); // it adds 1 internally (for NUL)
311
312 // text data must be returned in UTF8 if format is wxDF_UNICODETEXT
313 if ( !data->GetDataHere(format, buf.data()) )
314 return;
315
316 // use UTF8_STRING format if requested in Unicode build but just plain
317 // STRING one in ANSI or if explicitly asked in Unicode
318 #if wxUSE_UNICODE
319 if (format == wxDataFormat(wxDF_UNICODETEXT))
320 {
321 gtk_selection_data_set_text(
322 selection_data,
323 (const gchar*)buf.data(),
324 size );
325 }
326 else
327 #endif // wxUSE_UNICODE
328 {
329 gtk_selection_data_set(
330 selection_data,
331 format.GetFormatId(),
332 8*sizeof(gchar),
333 (const guchar*)buf.data(),
334 size );
335 }
336 }
337 }
338
339 void wxClipboard::GTKOnSelectionReceived(const GtkSelectionData& sel)
340 {
341 wxCHECK_RET( m_receivedData, wxT("should be inside GetData()") );
342
343 const wxDataFormat format(gtk_selection_data_get_target(const_cast<GtkSelectionData*>(&sel)));
344 wxLogTrace(TRACE_CLIPBOARD, wxT("Received selection %s"),
345 format.GetId().c_str());
346
347 if ( !m_receivedData->IsSupportedFormat(format, wxDataObject::Set) )
348 return;
349
350 m_receivedData->SetData(format,
351 gtk_selection_data_get_length(const_cast<GtkSelectionData*>(&sel)),
352 gtk_selection_data_get_data(const_cast<GtkSelectionData*>(&sel)));
353 m_formatSupported = true;
354 }
355
356 //-----------------------------------------------------------------------------
357 // asynchronous "selection_received" for targets
358 //-----------------------------------------------------------------------------
359
360 extern "C" {
361 static void
362 async_targets_selection_received( GtkWidget *WXUNUSED(widget),
363 GtkSelectionData *selection_data,
364 guint32 WXUNUSED(time),
365 wxClipboard *clipboard )
366 {
367 if ( !clipboard ) // Assert?
368 return;
369
370 if (!clipboard->m_sink)
371 return;
372
373 wxClipboardEvent *event = new wxClipboardEvent(wxEVT_CLIPBOARD_CHANGED);
374 event->SetEventObject( clipboard );
375
376 int selection_data_length = 0;
377 if (selection_data)
378 selection_data_length = gtk_selection_data_get_length(selection_data);
379
380 if (selection_data_length <= 0)
381 {
382 clipboard->m_sink->QueueEvent( event );
383 clipboard->m_sink.Release();
384 return;
385 }
386
387 // make sure we got the data in the correct form
388 GdkAtom type = gtk_selection_data_get_data_type(selection_data);
389 if ( type != GDK_SELECTION_TYPE_ATOM )
390 {
391 if ( strcmp(wxGtkString(gdk_atom_name(type)), "TARGETS") != 0 )
392 {
393 wxLogTrace( TRACE_CLIPBOARD,
394 wxT("got unsupported clipboard target") );
395
396 clipboard->m_sink->QueueEvent( event );
397 clipboard->m_sink.Release();
398 return;
399 }
400 }
401
402 // it's not really a format, of course, but we can reuse its GetId() method
403 // to format this atom as string
404 wxDataFormat clip(gtk_selection_data_get_selection(selection_data));
405 wxLogTrace( TRACE_CLIPBOARD,
406 wxT("Received available formats for clipboard %s"),
407 clip.GetId().c_str() );
408
409 // the atoms we received, holding a list of targets (= formats)
410 const GdkAtom* const atoms = (GdkAtom*)gtk_selection_data_get_data(selection_data);
411 for (size_t i = 0; i < selection_data_length / sizeof(GdkAtom); i++)
412 {
413 const wxDataFormat format(atoms[i]);
414
415 wxLogTrace(TRACE_CLIPBOARD, wxT("\t%s"), format.GetId().c_str());
416
417 event->AddFormat( format );
418 }
419
420 clipboard->m_sink->QueueEvent( event );
421 clipboard->m_sink.Release();
422 }
423 }
424
425 // ============================================================================
426 // wxClipboard implementation
427 // ============================================================================
428
429 // ----------------------------------------------------------------------------
430 // wxClipboard ctor/dtor
431 // ----------------------------------------------------------------------------
432
433 IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
434
435 wxClipboard::wxClipboard()
436 {
437 m_idSelectionGetHandler = 0;
438
439 m_open = false;
440
441 m_dataPrimary =
442 m_dataClipboard =
443 m_receivedData = NULL;
444
445 m_formatSupported = false;
446 m_targetRequested = 0;
447
448 // we use m_targetsWidget to query what formats are available
449 m_targetsWidget = gtk_window_new( GTK_WINDOW_POPUP );
450 gtk_widget_realize( m_targetsWidget );
451
452 g_signal_connect (m_targetsWidget, "selection_received",
453 G_CALLBACK (targets_selection_received), this);
454
455 // we use m_targetsWidgetAsync to query what formats are available asynchronously
456 m_targetsWidgetAsync = gtk_window_new( GTK_WINDOW_POPUP );
457 gtk_widget_realize( m_targetsWidgetAsync );
458
459 g_signal_connect (m_targetsWidgetAsync, "selection_received",
460 G_CALLBACK (async_targets_selection_received), this);
461
462 // we use m_clipboardWidget to get and to offer data
463 m_clipboardWidget = gtk_window_new( GTK_WINDOW_POPUP );
464 gtk_widget_realize( m_clipboardWidget );
465
466 g_signal_connect (m_clipboardWidget, "selection_received",
467 G_CALLBACK (selection_received), this);
468
469 g_signal_connect (m_clipboardWidget, "selection_clear_event",
470 G_CALLBACK (selection_clear_clip), NULL);
471
472 // initialize atoms we use if not done yet
473 if ( !g_clipboardAtom )
474 g_clipboardAtom = gdk_atom_intern( "CLIPBOARD", FALSE );
475 if ( !g_targetsAtom )
476 g_targetsAtom = gdk_atom_intern ("TARGETS", FALSE);
477 if ( !g_timestampAtom )
478 g_timestampAtom = gdk_atom_intern ("TIMESTAMP", FALSE);
479 }
480
481 wxClipboard::~wxClipboard()
482 {
483 Clear();
484
485 gtk_widget_destroy( m_clipboardWidget );
486 gtk_widget_destroy( m_targetsWidget );
487 }
488
489 // ----------------------------------------------------------------------------
490 // wxClipboard helper functions
491 // ----------------------------------------------------------------------------
492
493 GdkAtom wxClipboard::GTKGetClipboardAtom() const
494 {
495 return m_usePrimary ? (GdkAtom)GDK_SELECTION_PRIMARY
496 : g_clipboardAtom;
497 }
498
499 void wxClipboard::GTKClearData(Kind kind)
500 {
501 wxDataObject *&data = Data(kind);
502 wxDELETE(data);
503 }
504
505 bool wxClipboard::SetSelectionOwner(bool set)
506 {
507 bool rc = gtk_selection_owner_set
508 (
509 set ? m_clipboardWidget : NULL,
510 GTKGetClipboardAtom(),
511 (guint32)GDK_CURRENT_TIME
512 ) != 0;
513
514 if ( !rc )
515 {
516 wxLogTrace(TRACE_CLIPBOARD, wxT("Failed to %sset selection owner"),
517 set ? wxT("") : wxT("un"));
518 }
519
520 return rc;
521 }
522
523 void wxClipboard::AddSupportedTarget(GdkAtom atom)
524 {
525 gtk_selection_add_target
526 (
527 m_clipboardWidget,
528 GTKGetClipboardAtom(),
529 atom,
530 0 // info (same as client data) unused
531 );
532 }
533
534 bool wxClipboard::IsSupportedAsync(wxEvtHandler *sink)
535 {
536 if (m_sink.get())
537 return false; // currently busy, come back later
538
539 wxCHECK_MSG( sink, false, wxT("no sink given") );
540
541 m_sink = sink;
542 gtk_selection_convert( m_targetsWidgetAsync,
543 GTKGetClipboardAtom(),
544 g_targetsAtom,
545 (guint32) GDK_CURRENT_TIME );
546
547 return true;
548 }
549
550 bool wxClipboard::DoIsSupported(const wxDataFormat& format)
551 {
552 wxCHECK_MSG( format, false, wxT("invalid clipboard format") );
553
554 wxLogTrace(TRACE_CLIPBOARD, wxT("Checking if format %s is available"),
555 format.GetId().c_str());
556
557 // these variables will be used by our GTKOnTargetReceived()
558 m_targetRequested = format;
559 m_formatSupported = false;
560
561 // block until m_formatSupported is set from targets_selection_received
562 // callback
563 {
564 wxClipboardSync sync(*this);
565
566 gtk_selection_convert( m_targetsWidget,
567 GTKGetClipboardAtom(),
568 g_targetsAtom,
569 (guint32) GDK_CURRENT_TIME );
570 }
571
572 return m_formatSupported;
573 }
574
575 // ----------------------------------------------------------------------------
576 // wxClipboard public API implementation
577 // ----------------------------------------------------------------------------
578
579 void wxClipboard::Clear()
580 {
581 gtk_selection_clear_targets( m_clipboardWidget, GTKGetClipboardAtom() );
582
583 if ( gdk_selection_owner_get(GTKGetClipboardAtom()) ==
584 gtk_widget_get_window(m_clipboardWidget) )
585 {
586 wxClipboardSync sync(*this);
587
588 // this will result in selection_clear_clip callback being called and
589 // it will free our data
590 SetSelectionOwner(false);
591 }
592
593 m_targetRequested = 0;
594 m_formatSupported = false;
595 }
596
597 bool wxClipboard::Open()
598 {
599 wxCHECK_MSG( !m_open, false, wxT("clipboard already open") );
600
601 m_open = true;
602
603 return true;
604 }
605
606 bool wxClipboard::SetData( wxDataObject *data )
607 {
608 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
609
610 wxCHECK_MSG( data, false, wxT("data is invalid") );
611
612 Clear();
613
614 return AddData( data );
615 }
616
617 bool wxClipboard::AddData( wxDataObject *data )
618 {
619 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
620
621 wxCHECK_MSG( data, false, wxT("data is invalid") );
622
623 // we can only store one wxDataObject so clear the old one
624 Clear();
625
626 Data() = data;
627
628 // get formats from wxDataObjects
629 const size_t count = data->GetFormatCount();
630 wxDataFormatArray formats(new wxDataFormat[count]);
631 data->GetAllFormats(formats.get());
632
633 // always provide TIMESTAMP as a target, see comments in selection_handler
634 // for explanation
635 AddSupportedTarget(g_timestampAtom);
636
637 for ( size_t i = 0; i < count; i++ )
638 {
639 const wxDataFormat format(formats[i]);
640
641 wxLogTrace(TRACE_CLIPBOARD, wxT("Adding support for %s"),
642 format.GetId().c_str());
643
644 AddSupportedTarget(format);
645 }
646
647 if ( !m_idSelectionGetHandler )
648 {
649 m_idSelectionGetHandler = g_signal_connect (
650 m_clipboardWidget, "selection_get",
651 G_CALLBACK (selection_handler),
652 GUINT_TO_POINTER (gtk_get_current_event_time()) );
653 }
654
655 // tell the world we offer clipboard data
656 return SetSelectionOwner();
657 }
658
659 void wxClipboard::Close()
660 {
661 wxCHECK_RET( m_open, wxT("clipboard not open") );
662
663 m_open = false;
664 }
665
666 bool wxClipboard::IsOpened() const
667 {
668 return m_open;
669 }
670
671 bool wxClipboard::IsSupported( const wxDataFormat& format )
672 {
673 if ( DoIsSupported(format) )
674 return true;
675
676 #if wxUSE_UNICODE
677 if ( format == wxDF_UNICODETEXT )
678 {
679 // also with plain STRING format
680 return DoIsSupported(g_altTextAtom);
681 }
682 #endif // wxUSE_UNICODE
683
684 return false;
685 }
686
687 bool wxClipboard::GetData( wxDataObject& data )
688 {
689 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
690
691 // get all supported formats from wxDataObjects: notice that we are setting
692 // the object data, so we need them in "Set" direction
693 const size_t count = data.GetFormatCount(wxDataObject::Set);
694 wxDataFormatArray formats(new wxDataFormat[count]);
695 data.GetAllFormats(formats.get(), wxDataObject::Set);
696
697 for ( size_t i = 0; i < count; i++ )
698 {
699 const wxDataFormat format(formats[i]);
700
701 // is this format supported by clipboard ?
702 if ( !DoIsSupported(format) )
703 continue;
704
705 wxLogTrace(TRACE_CLIPBOARD, wxT("Requesting format %s"),
706 format.GetId().c_str());
707
708 // these variables will be used by our GTKOnSelectionReceived()
709 m_receivedData = &data;
710 m_formatSupported = false;
711
712 {
713 wxClipboardSync sync(*this);
714
715 gtk_selection_convert(m_clipboardWidget,
716 GTKGetClipboardAtom(),
717 format,
718 (guint32) GDK_CURRENT_TIME );
719 } // wait until we get the results
720
721 /*
722 Normally this is a true error as we checked for the presence of such
723 data before, but there are applications that may return an empty
724 string (e.g. Gnumeric-1.6.1 on Linux if an empty cell is copied)
725 which would produce a false error message here, so we check for the
726 size of the string first. With ANSI, GetDataSize returns an extra
727 value (for the closing null?), with unicode, the exact number of
728 tokens is given (that is more than 1 for non-ASCII characters)
729 (tested with Gnumeric-1.6.1 and OpenOffice.org-2.0.2)
730 */
731 #if wxUSE_UNICODE
732 if ( format != wxDF_UNICODETEXT || data.GetDataSize(format) > 0 )
733 #else // !UNICODE
734 if ( format != wxDF_TEXT || data.GetDataSize(format) > 1 )
735 #endif // UNICODE / !UNICODE
736 {
737 wxCHECK_MSG( m_formatSupported, false,
738 wxT("error retrieving data from clipboard") );
739 }
740
741 return true;
742 }
743
744 wxLogTrace(TRACE_CLIPBOARD, wxT("GetData(): format not found"));
745
746 return false;
747 }
748
749 wxDataObject* wxClipboard::GTKGetDataObject( GdkAtom atom )
750 {
751 if ( atom == GDK_NONE )
752 return Data();
753
754 if ( atom == GDK_SELECTION_PRIMARY )
755 {
756 wxLogTrace(TRACE_CLIPBOARD, wxT("Primary selection requested" ));
757
758 return Data( wxClipboard::Primary );
759 }
760 else if ( atom == g_clipboardAtom )
761 {
762 wxLogTrace(TRACE_CLIPBOARD, wxT("Clipboard data requested" ));
763
764 return Data( wxClipboard::Clipboard );
765 }
766 else // some other selection, we're not concerned
767 {
768 return (wxDataObject*)NULL;
769 }
770 }
771
772 #endif // wxUSE_CLIPBOARD