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