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