]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/clipbrd.cpp
use CanSetValueAs() instead of CanGetValueAs() in wxGridCellBoolEditor::EndEdit
[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 110// ============================================================================
3eef425f 111// clipboard callbacks implementation
eddb9644
VZ
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
3eef425f
RR
347//-----------------------------------------------------------------------------
348// asynchronous "selection_received" for targets
349//-----------------------------------------------------------------------------
350
351extern "C" {
352static void
353async_targets_selection_received( GtkWidget *WXUNUSED(widget),
354 GtkSelectionData *selection_data,
355 guint32 WXUNUSED(time),
356 wxClipboard *clipboard )
357{
358 if ( !clipboard ) // Assert?
359 return;
360
361 if (!clipboard->m_sink)
362 return;
363
364 wxClipboardEvent *event = new wxClipboardEvent(wxEVT_CLIPBOARD_CHANGED);
365
366 if ( !selection_data || selection_data->length <= 0 )
367 {
368 clipboard->m_sink->QueueEvent( event );
369 return;
370 }
371
372 // make sure we got the data in the correct form
373 GdkAtom type = selection_data->type;
374 if ( type != GDK_SELECTION_TYPE_ATOM )
375 {
376 if ( strcmp(wxGtkString(gdk_atom_name(type)), "TARGETS") != 0 )
377 {
378 wxLogTrace( TRACE_CLIPBOARD,
379 _T("got unsupported clipboard target") );
380
381 clipboard->m_sink->QueueEvent( event );
382 return;
383 }
384 }
385
386#ifdef __WXDEBUG__
387 // it's not really a format, of course, but we can reuse its GetId() method
388 // to format this atom as string
389 wxDataFormat clip(selection_data->selection);
390 wxLogTrace( TRACE_CLIPBOARD,
391 wxT("Received available formats for clipboard %s"),
392 clip.GetId().c_str() );
393#endif // __WXDEBUG__
394
395 // the atoms we received, holding a list of targets (= formats)
396 const GdkAtom * const atoms = (GdkAtom *)selection_data->data;
397 for ( size_t i = 0; i < selection_data->length/sizeof(GdkAtom); i++ )
398 {
399 const wxDataFormat format(atoms[i]);
400
401 wxLogTrace(TRACE_CLIPBOARD, wxT("\t%s"), format.GetId().c_str());
402
403 event->AddFormat( format );
404 }
405
406 clipboard->m_sink->QueueEvent( event );
407}
408}
409
eddb9644
VZ
410// ============================================================================
411// wxClipboard implementation
412// ============================================================================
413
414// ----------------------------------------------------------------------------
415// wxClipboard ctor/dtor
416// ----------------------------------------------------------------------------
dc86cb34
RR
417
418IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
419
420wxClipboard::wxClipboard()
421{
de6185e2 422 m_open = false;
8b53e5a2 423
eddb9644
VZ
424 m_dataPrimary =
425 m_dataClipboard =
426 m_receivedData = NULL;
aeeb6a44 427
eddb9644
VZ
428 m_formatSupported = false;
429 m_targetRequested = 0;
99c67c77 430
eddb9644 431 // we use m_targetsWidget to query what formats are available
034be888
RR
432 m_targetsWidget = gtk_window_new( GTK_WINDOW_POPUP );
433 gtk_widget_realize( m_targetsWidget );
434
9fa72bd2
MR
435 g_signal_connect (m_targetsWidget, "selection_received",
436 G_CALLBACK (targets_selection_received), this);
270c23f7 437
3eef425f
RR
438 // we use m_targetsWidgetAsync to query what formats asynchronously
439 m_targetsWidgetAsync = gtk_window_new( GTK_WINDOW_POPUP );
440 gtk_widget_realize( m_targetsWidgetAsync );
441
442 g_signal_connect (m_targetsWidgetAsync, "selection_received",
443 G_CALLBACK (async_targets_selection_received), this);
444
eddb9644 445 // we use m_clipboardWidget to get and to offer data
8b53e5a2
RR
446 m_clipboardWidget = gtk_window_new( GTK_WINDOW_POPUP );
447 gtk_widget_realize( m_clipboardWidget );
448
9fa72bd2
MR
449 g_signal_connect (m_clipboardWidget, "selection_received",
450 G_CALLBACK (selection_received), this);
034be888 451
9fa72bd2
MR
452 g_signal_connect (m_clipboardWidget, "selection_clear_event",
453 G_CALLBACK (selection_clear_clip), NULL);
270c23f7 454
eddb9644
VZ
455 // initialize atoms we use if not done yet
456 if ( !g_clipboardAtom )
457 g_clipboardAtom = gdk_atom_intern( "CLIPBOARD", FALSE );
458 if ( !g_targetsAtom )
459 g_targetsAtom = gdk_atom_intern ("TARGETS", FALSE);
460 if ( !g_timestampAtom )
461 g_timestampAtom = gdk_atom_intern ("TIMESTAMP", FALSE);
dc86cb34
RR
462}
463
464wxClipboard::~wxClipboard()
b527aac5 465{
270c23f7
VZ
466 Clear();
467
05492dd1
VZ
468 gtk_widget_destroy( m_clipboardWidget );
469 gtk_widget_destroy( m_targetsWidget );
b527aac5
RR
470}
471
eddb9644
VZ
472// ----------------------------------------------------------------------------
473// wxClipboard helper functions
474// ----------------------------------------------------------------------------
475
476GdkAtom wxClipboard::GTKGetClipboardAtom() const
477{
478 return m_usePrimary ? (GdkAtom)GDK_SELECTION_PRIMARY
479 : g_clipboardAtom;
480}
481
482void wxClipboard::GTKClearData(Kind kind)
dc86cb34 483{
511383f9 484 wxDataObject *&data = Data(kind);
eddb9644 485 if ( data )
1dd989e1 486 {
eddb9644
VZ
487 delete data;
488 data = NULL;
489 }
490}
270c23f7 491
eddb9644
VZ
492bool wxClipboard::SetSelectionOwner(bool set)
493{
494 bool rc = gtk_selection_owner_set
495 (
496 set ? m_clipboardWidget : NULL,
497 GTKGetClipboardAtom(),
498 (guint32)GDK_CURRENT_TIME
499 );
500
501 if ( !rc )
502 {
503 wxLogTrace(TRACE_CLIPBOARD, _T("Failed to %sset selection owner"),
504 set ? _T("") : _T("un"));
505 }
270c23f7 506
eddb9644
VZ
507 return rc;
508}
270c23f7 509
eddb9644
VZ
510void wxClipboard::AddSupportedTarget(GdkAtom atom)
511{
512 gtk_selection_add_target
513 (
10bd1f7d 514 m_clipboardWidget,
eddb9644
VZ
515 GTKGetClipboardAtom(),
516 atom,
517 0 // info (same as client data) unused
518 );
519}
520
3eef425f
RR
521bool wxClipboard::IsSupportedAsync(wxEvtHandler *sink)
522{
523 m_sink = sink;
524
525 gtk_selection_convert( m_targetsWidgetAsync,
526 GTKGetClipboardAtom(),
527 g_targetsAtom,
528 (guint32) GDK_CURRENT_TIME );
529
530 return true;
531}
532
eddb9644
VZ
533bool wxClipboard::DoIsSupported(const wxDataFormat& format)
534{
535 wxCHECK_MSG( format, false, wxT("invalid clipboard format") );
270c23f7 536
eddb9644
VZ
537 wxLogTrace(TRACE_CLIPBOARD, wxT("Checking if format %s is available"),
538 format.GetId().c_str());
539
540 // these variables will be used by our GTKOnTargetReceived()
541 m_targetRequested = format;
542 m_formatSupported = false;
543
544 // block until m_formatSupported is set from targets_selection_received
545 // callback
546 {
547 wxClipboardSync sync(*this);
548
549 gtk_selection_convert( m_targetsWidget,
550 GTKGetClipboardAtom(),
551 g_targetsAtom,
552 (guint32) GDK_CURRENT_TIME );
553 }
554
555 return m_formatSupported;
556}
557
558// ----------------------------------------------------------------------------
559// wxClipboard public API implementation
560// ----------------------------------------------------------------------------
561
562void wxClipboard::Clear()
563{
564 if ( gdk_selection_owner_get(GTKGetClipboardAtom()) ==
565 m_clipboardWidget->window )
566 {
567 wxClipboardSync sync(*this);
568
569 // this will result in selection_clear_clip callback being called and
570 // it will free our data
571 SetSelectionOwner(false);
8b53e5a2 572 }
270c23f7 573
8b53e5a2 574 m_targetRequested = 0;
de6185e2 575 m_formatSupported = false;
8b53e5a2
RR
576}
577
578bool wxClipboard::Open()
579{
de6185e2 580 wxCHECK_MSG( !m_open, false, wxT("clipboard already open") );
270c23f7 581
de6185e2 582 m_open = true;
270c23f7 583
de6185e2 584 return true;
dc86cb34
RR
585}
586
75ce0581 587bool wxClipboard::SetData( wxDataObject *data )
dc86cb34 588{
de6185e2 589 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
270c23f7 590
de6185e2 591 wxCHECK_MSG( data, false, wxT("data is invalid") );
270c23f7 592
0d2a2b60 593 Clear();
75ce0581
RR
594
595 return AddData( data );
596}
597
598bool wxClipboard::AddData( wxDataObject *data )
599{
de6185e2 600 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
270c23f7 601
de6185e2 602 wxCHECK_MSG( data, false, wxT("data is invalid") );
270c23f7 603
eddb9644 604 // we can only store one wxDataObject so clear the old one
1dd989e1 605 Clear();
270c23f7 606
eddb9644 607 Data() = data;
1dd989e1 608
ca11abde 609 // get formats from wxDataObjects
eddb9644
VZ
610 const size_t count = data->GetFormatCount();
611 wxDataFormatArray formats(new wxDataFormat[count]);
612 data->GetAllFormats(formats.get());
11e1c70d 613
eddb9644
VZ
614 // always provide TIMESTAMP as a target, see comments in selection_handler
615 // for explanation
616 AddSupportedTarget(g_timestampAtom);
11e1c70d 617
eddb9644 618 for ( size_t i = 0; i < count; i++ )
b068c4e8 619 {
eddb9644 620 const wxDataFormat format(formats[i]);
11e1c70d 621
eddb9644
VZ
622 wxLogTrace(TRACE_CLIPBOARD, wxT("Adding support for %s"),
623 format.GetId().c_str());
3d257b8d 624
eddb9644 625 AddSupportedTarget(format);
b068c4e8
RR
626 }
627
9fa72bd2 628 g_signal_connect (m_clipboardWidget, "selection_get",
d394f0c9
MR
629 G_CALLBACK (selection_handler),
630 GUINT_TO_POINTER (gtk_get_current_event_time()) );
d345e841 631
eddb9644
VZ
632 // tell the world we offer clipboard data
633 return SetSelectionOwner();
8b53e5a2 634}
db1b4961 635
8b53e5a2
RR
636void wxClipboard::Close()
637{
223d09f6 638 wxCHECK_RET( m_open, wxT("clipboard not open") );
270c23f7 639
de6185e2 640 m_open = false;
dc86cb34
RR
641}
642
f536e0f2
VZ
643bool wxClipboard::IsOpened() const
644{
645 return m_open;
646}
647
e1ee679c 648bool wxClipboard::IsSupported( const wxDataFormat& format )
b527aac5 649{
eddb9644
VZ
650 if ( DoIsSupported(format) )
651 return true;
270c23f7 652
5e081315 653#if wxUSE_UNICODE
eddb9644 654 if ( format == wxDF_UNICODETEXT )
c7d6d883 655 {
eddb9644
VZ
656 // also with plain STRING format
657 return DoIsSupported(g_altTextAtom);
c7d6d883 658 }
eddb9644 659#endif // wxUSE_UNICODE
c7d6d883 660
eddb9644 661 return false;
270c23f7
VZ
662}
663
e1ee679c 664bool wxClipboard::GetData( wxDataObject& data )
75ce0581 665{
de6185e2 666 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
270c23f7 667
eddb9644
VZ
668 // get all supported formats from wxDataObjects
669 const size_t count = data.GetFormatCount();
670 wxDataFormatArray formats(new wxDataFormat[count]);
671 data.GetAllFormats(formats.get());
270c23f7 672
eddb9644 673 for ( size_t i = 0; i < count; i++ )
b068c4e8 674 {
eddb9644 675 const wxDataFormat format(formats[i]);
11e1c70d 676
eddb9644
VZ
677 // is this format supported by clipboard ?
678 if ( !DoIsSupported(format) )
679 continue;
270c23f7 680
eddb9644
VZ
681 wxLogTrace(TRACE_CLIPBOARD, wxT("Requesting format %s"),
682 format.GetId().c_str());
270c23f7 683
eddb9644 684 // these variables will be used by our GTKOnSelectionReceived()
b068c4e8 685 m_receivedData = &data;
de6185e2 686 m_formatSupported = false;
270c23f7 687
06f5d975
VZ
688 {
689 wxClipboardSync sync(*this);
690
eddb9644
VZ
691 gtk_selection_convert(m_clipboardWidget,
692 GTKGetClipboardAtom(),
693 format,
694 (guint32) GDK_CURRENT_TIME );
06f5d975 695 } // wait until we get the results
b527aac5 696
be809e82
VZ
697 /*
698 Normally this is a true error as we checked for the presence of such
699 data before, but there are applications that may return an empty
700 string (e.g. Gnumeric-1.6.1 on Linux if an empty cell is copied)
701 which would produce a false error message here, so we check for the
eddb9644 702 size of the string first. With ANSI, GetDataSize returns an extra
be809e82 703 value (for the closing null?), with unicode, the exact number of
eddb9644 704 tokens is given (that is more than 1 for non-ASCII characters)
be809e82
VZ
705 (tested with Gnumeric-1.6.1 and OpenOffice.org-2.0.2)
706 */
707#if wxUSE_UNICODE
708 if ( format != wxDF_UNICODETEXT || data.GetDataSize(format) > 0 )
709#else // !UNICODE
710 if ( format != wxDF_TEXT || data.GetDataSize(format) > 1 )
711#endif // UNICODE / !UNICODE
712 {
713 wxCHECK_MSG( m_formatSupported, false,
714 wxT("error retrieving data from clipboard") );
715 }
270c23f7 716
de6185e2 717 return true;
b068c4e8 718 }
270c23f7 719
eddb9644 720 wxLogTrace(TRACE_CLIPBOARD, wxT("GetData(): format not found"));
270c23f7 721
de6185e2 722 return false;
b527aac5
RR
723}
724
eddb9644 725#endif // wxUSE_CLIPBOARD