]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/clipbrd.cpp
Fix stc doxygen warnings and regen stc files.
[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 5// Copyright: (c) 1998 Robert Roebling
eddb9644 6// (c) 2007 Vadim Zeitlin
65571936 7// Licence: wxWindows licence
dc86cb34
RR
8/////////////////////////////////////////////////////////////////////////////
9
06f5d975
VZ
10// ============================================================================
11// declarations
12// ============================================================================
13
14// ----------------------------------------------------------------------------
15// headers
16// ----------------------------------------------------------------------------
17
14f355c2
VS
18// For compilers that support precompilation, includes "wx.h".
19#include "wx/wxprec.h"
20
e4db172a
WS
21#if wxUSE_CLIPBOARD
22
dc86cb34
RR
23#include "wx/clipbrd.h"
24
e4db172a 25#ifndef WX_PRECOMP
5efeac9f 26 #include "wx/app.h"
e4db172a 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 33#include "wx/scopeguard.h"
dde19c21 34#include "wx/evtloop.h"
06f5d975 35
67756da4 36#include "wx/gtk/private.h"
83624f79 37
664e1314 38typedef wxScopedArray<wxDataFormat> wxDataFormatArray;
eddb9644
VZ
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!)
9a83f860 55#define TRACE_CLIPBOARD wxT("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 {
9a83f860 71 wxASSERT_MSG( !ms_clipboard, wxT("reentrancy in clipboard code") );
06f5d975
VZ
72 ms_clipboard = &clipboard;
73 }
74
75 ~wxClipboardSync()
76 {
e4c3d940 77#if wxUSE_CONSOLE_EVENTLOOP
439c7eae
VZ
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;
e4c3d940 81#endif
d48b06bd 82 while (ms_clipboard)
dde19c21 83 wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_CLIPBOARD);
06f5d975
VZ
84 }
85
86 // this method must be called by GTK+ callbacks to indicate that we got the
87 // result for our clipboard operation
e0d1fd7f 88 static void OnDone(wxClipboard * WXUNUSED_UNLESS_DEBUG(clipboard))
06f5d975
VZ
89 {
90 wxASSERT_MSG( clipboard == ms_clipboard,
9a83f860 91 wxT("got notification for alien clipboard") );
06f5d975
VZ
92
93 ms_clipboard = NULL;
94 }
95
b2b51072
VZ
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
06f5d975
VZ
107private:
108 static wxClipboard *ms_clipboard;
109
c0c133e1 110 wxDECLARE_NO_COPY_CLASS(wxClipboardSync);
b527aac5
RR
111};
112
06f5d975 113wxClipboard *wxClipboardSync::ms_clipboard = NULL;
dc86cb34 114
eddb9644 115// ============================================================================
3eef425f 116// clipboard callbacks implementation
eddb9644
VZ
117// ============================================================================
118
b527aac5
RR
119//-----------------------------------------------------------------------------
120// "selection_received" for targets
121//-----------------------------------------------------------------------------
122
865bb325 123extern "C" {
b527aac5 124static void
270c23f7
VZ
125targets_selection_received( GtkWidget *WXUNUSED(widget),
126 GtkSelectionData *selection_data,
034be888 127 guint32 WXUNUSED(time),
66633398 128 wxClipboard *clipboard )
dc86cb34 129{
eddb9644
VZ
130 if ( !clipboard )
131 return;
132
06f5d975
VZ
133 wxON_BLOCK_EXIT1(wxClipboardSync::OnDone, clipboard);
134
385e8575
PC
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)
eddb9644
VZ
140 return;
141
142 // make sure we got the data in the correct form
385e8575 143 GdkAtom type = gtk_selection_data_get_data_type(selection_data);
eddb9644 144 if ( type != GDK_SELECTION_TYPE_ATOM )
034be888 145 {
eddb9644 146 if ( strcmp(wxGtkString(gdk_atom_name(type)), "TARGETS") != 0 )
270c23f7 147 {
eddb9644 148 wxLogTrace( TRACE_CLIPBOARD,
9a83f860 149 wxT("got unsupported clipboard target") );
61b04ac6 150
eddb9644 151 return;
270c23f7 152 }
eddb9644 153 }
b527aac5 154
eddb9644
VZ
155 // it's not really a format, of course, but we can reuse its GetId() method
156 // to format this atom as string
385e8575 157 wxDataFormat clip(gtk_selection_data_get_selection(selection_data));
eddb9644
VZ
158 wxLogTrace( TRACE_CLIPBOARD,
159 wxT("Received available formats for clipboard %s"),
160 clip.GetId().c_str() );
270c23f7 161
eddb9644 162 // the atoms we received, holding a list of targets (= formats)
385e8575
PC
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++)
eddb9644
VZ
165 {
166 const wxDataFormat format(atoms[i]);
11e1c70d 167
eddb9644 168 wxLogTrace(TRACE_CLIPBOARD, wxT("\t%s"), format.GetId().c_str());
270c23f7 169
eddb9644
VZ
170 if ( clipboard->GTKOnTargetReceived(format) )
171 return;
8b53e5a2 172 }
dc86cb34 173}
865bb325 174}
dc86cb34 175
eddb9644
VZ
176bool wxClipboard::GTKOnTargetReceived(const wxDataFormat& format)
177{
178 if ( format != m_targetRequested )
179 return false;
180
181 m_formatSupported = true;
182 return true;
183}
184
dc86cb34 185//-----------------------------------------------------------------------------
b527aac5 186// "selection_received" for the actual data
dc86cb34
RR
187//-----------------------------------------------------------------------------
188
865bb325 189extern "C" {
270c23f7
VZ
190static void
191selection_received( GtkWidget *WXUNUSED(widget),
192 GtkSelectionData *selection_data,
034be888 193 guint32 WXUNUSED(time),
66633398 194 wxClipboard *clipboard )
dc86cb34 195{
eddb9644 196 if ( !clipboard )
034be888 197 return;
270c23f7 198
eddb9644 199 wxON_BLOCK_EXIT1(wxClipboardSync::OnDone, clipboard);
270c23f7 200
385e8575 201 if (!selection_data || gtk_selection_data_get_length(selection_data) <= 0)
e5d6aa22 202 return;
270c23f7 203
eddb9644 204 clipboard->GTKOnSelectionReceived(*selection_data);
dc86cb34 205}
865bb325 206}
fd0eed64
RR
207
208//-----------------------------------------------------------------------------
209// "selection_clear"
210//-----------------------------------------------------------------------------
211
865bb325 212extern "C" {
fd0eed64 213static gint
aeeb6a44 214selection_clear_clip( GtkWidget *WXUNUSED(widget), GdkEventSelection *event )
fd0eed64 215{
eddb9644
VZ
216 wxClipboard * const clipboard = wxTheClipboard;
217 if ( !clipboard )
218 return TRUE;
06f5d975 219
b2b51072
VZ
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);
270c23f7 226
eddb9644 227 wxClipboard::Kind kind;
aeeb6a44
RR
228 if (event->selection == GDK_SELECTION_PRIMARY)
229 {
eddb9644
VZ
230 wxLogTrace(TRACE_CLIPBOARD, wxT("Lost primary selection" ));
231
232 kind = wxClipboard::Primary;
aeeb6a44 233 }
eddb9644 234 else if (event->selection == g_clipboardAtom)
aeeb6a44 235 {
eddb9644
VZ
236 wxLogTrace(TRACE_CLIPBOARD, wxT("Lost clipboard" ));
237
238 kind = wxClipboard::Clipboard;
aeeb6a44 239 }
eddb9644 240 else // some other selection, we're not concerned
aeeb6a44
RR
241 {
242 return FALSE;
243 }
270c23f7 244
eddb9644
VZ
245 // the clipboard is no longer in our hands, we don't need data any more
246 clipboard->GTKClearData(kind);
270c23f7 247
8b53e5a2 248 return TRUE;
fd0eed64 249}
865bb325 250}
fd0eed64
RR
251
252//-----------------------------------------------------------------------------
253// selection handler for supplying data
254//-----------------------------------------------------------------------------
255
865bb325 256extern "C" {
fd0eed64 257static void
19d89516
VZ
258selection_handler( GtkWidget *WXUNUSED(widget),
259 GtkSelectionData *selection_data,
260 guint WXUNUSED(info),
261 guint WXUNUSED(time),
d394f0c9 262 gpointer signal_data )
fd0eed64 263{
eddb9644
VZ
264 wxClipboard * const clipboard = wxTheClipboard;
265 if ( !clipboard )
266 return;
270c23f7 267
385e8575
PC
268 wxDataObject * const data = clipboard->GTKGetDataObject(
269 gtk_selection_data_get_selection(selection_data));
eddb9644
VZ
270 if ( !data )
271 return;
270c23f7 272
d394f0c9
MR
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.
385e8575 277 if (gtk_selection_data_get_target(selection_data) == g_timestampAtom)
d394f0c9 278 {
d704d2f5 279 guint timestamp = GPOINTER_TO_UINT (signal_data);
d394f0c9
MR
280 gtk_selection_data_set(selection_data,
281 GDK_SELECTION_TYPE_INTEGER,
282 32,
283 (guchar*)&(timestamp),
284 sizeof(timestamp));
285 wxLogTrace(TRACE_CLIPBOARD,
9a83f860 286 wxT("Clipboard TIMESTAMP requested, returning timestamp=%u"),
d394f0c9
MR
287 timestamp);
288 return;
289 }
290
385e8575 291 wxDataFormat format(gtk_selection_data_get_target(selection_data));
b068c4e8 292
ebe47451 293 wxLogTrace(TRACE_CLIPBOARD,
9a83f860 294 wxT("clipboard data in format %s, GtkSelectionData is target=%s type=%s selection=%s timestamp=%u"),
ebe47451 295 format.GetId().c_str(),
385e8575
PC
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(),
d394f0c9 299 GPOINTER_TO_UINT( signal_data )
ebe47451 300 );
3d257b8d 301
157a8f70
VZ
302 if ( !data->IsSupportedFormat( format ) )
303 return;
270c23f7 304
b068c4e8 305 int size = data->GetDataSize( format );
157a8f70
VZ
306 if ( !size )
307 return;
270c23f7 308
157a8f70 309 wxCharBuffer buf(size - 1); // it adds 1 internally (for NUL)
33754c4d 310
b82c3e60 311 // text data must be returned in UTF8 if format is wxDF_UNICODETEXT
157a8f70
VZ
312 if ( !data->GetDataHere(format, buf.data()) )
313 return;
270c23f7 314
b82c3e60
VZ
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
ebe47451
VS
318 if (format == wxDataFormat(wxDF_UNICODETEXT))
319 {
320 gtk_selection_data_set_text(
321 selection_data,
b82c3e60 322 (const gchar*)buf.data(),
2c906a49 323 size );
ebe47451
VS
324 }
325 else
157a8f70 326#endif // wxUSE_UNICODE
ebe47451
VS
327 {
328 gtk_selection_data_set(
329 selection_data,
616c0d1f 330 format.GetFormatId(),
ebe47451 331 8*sizeof(gchar),
b82c3e60 332 (const guchar*)buf.data(),
2c906a49 333 size );
ebe47451 334 }
fd0eed64 335}
865bb325 336}
dc86cb34 337
eddb9644
VZ
338void wxClipboard::GTKOnSelectionReceived(const GtkSelectionData& sel)
339{
9a83f860 340 wxCHECK_RET( m_receivedData, wxT("should be inside GetData()") );
eddb9644 341
385e8575 342 const wxDataFormat format(gtk_selection_data_get_target(const_cast<GtkSelectionData*>(&sel)));
9a83f860 343 wxLogTrace(TRACE_CLIPBOARD, wxT("Received selection %s"),
eddb9644
VZ
344 format.GetId().c_str());
345
d5363c04 346 if ( !m_receivedData->IsSupportedFormat(format, wxDataObject::Set) )
eddb9644
VZ
347 return;
348
385e8575
PC
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)));
eddb9644
VZ
352 m_formatSupported = true;
353}
354
3eef425f
RR
355//-----------------------------------------------------------------------------
356// asynchronous "selection_received" for targets
357//-----------------------------------------------------------------------------
358
359extern "C" {
360static void
361async_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;
d48b06bd 371
3eef425f 372 wxClipboardEvent *event = new wxClipboardEvent(wxEVT_CLIPBOARD_CHANGED);
311c1be9 373 event->SetEventObject( clipboard );
d48b06bd 374
385e8575
PC
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)
3eef425f
RR
380 {
381 clipboard->m_sink->QueueEvent( event );
b4705641 382 clipboard->m_sink.Release();
3eef425f
RR
383 return;
384 }
385
386 // make sure we got the data in the correct form
385e8575 387 GdkAtom type = gtk_selection_data_get_data_type(selection_data);
3eef425f
RR
388 if ( type != GDK_SELECTION_TYPE_ATOM )
389 {
390 if ( strcmp(wxGtkString(gdk_atom_name(type)), "TARGETS") != 0 )
391 {
392 wxLogTrace( TRACE_CLIPBOARD,
9a83f860 393 wxT("got unsupported clipboard target") );
3eef425f
RR
394
395 clipboard->m_sink->QueueEvent( event );
b4705641 396 clipboard->m_sink.Release();
3eef425f
RR
397 return;
398 }
399 }
400
3eef425f
RR
401 // it's not really a format, of course, but we can reuse its GetId() method
402 // to format this atom as string
385e8575 403 wxDataFormat clip(gtk_selection_data_get_selection(selection_data));
3eef425f
RR
404 wxLogTrace( TRACE_CLIPBOARD,
405 wxT("Received available formats for clipboard %s"),
406 clip.GetId().c_str() );
3eef425f
RR
407
408 // the atoms we received, holding a list of targets (= formats)
385e8575
PC
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++)
3eef425f
RR
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 }
d48b06bd 418
3eef425f 419 clipboard->m_sink->QueueEvent( event );
b4705641 420 clipboard->m_sink.Release();
3eef425f
RR
421}
422}
423
eddb9644
VZ
424// ============================================================================
425// wxClipboard implementation
426// ============================================================================
427
428// ----------------------------------------------------------------------------
429// wxClipboard ctor/dtor
430// ----------------------------------------------------------------------------
dc86cb34
RR
431
432IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
433
434wxClipboard::wxClipboard()
435{
bdffa920
VZ
436 m_idSelectionGetHandler = 0;
437
de6185e2 438 m_open = false;
8b53e5a2 439
eddb9644
VZ
440 m_dataPrimary =
441 m_dataClipboard =
442 m_receivedData = NULL;
aeeb6a44 443
eddb9644
VZ
444 m_formatSupported = false;
445 m_targetRequested = 0;
99c67c77 446
eddb9644 447 // we use m_targetsWidget to query what formats are available
034be888
RR
448 m_targetsWidget = gtk_window_new( GTK_WINDOW_POPUP );
449 gtk_widget_realize( m_targetsWidget );
450
9fa72bd2
MR
451 g_signal_connect (m_targetsWidget, "selection_received",
452 G_CALLBACK (targets_selection_received), this);
270c23f7 453
d48b06bd 454 // we use m_targetsWidgetAsync to query what formats are available asynchronously
3eef425f
RR
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
eddb9644 461 // we use m_clipboardWidget to get and to offer data
8b53e5a2
RR
462 m_clipboardWidget = gtk_window_new( GTK_WINDOW_POPUP );
463 gtk_widget_realize( m_clipboardWidget );
464
9fa72bd2
MR
465 g_signal_connect (m_clipboardWidget, "selection_received",
466 G_CALLBACK (selection_received), this);
034be888 467
9fa72bd2
MR
468 g_signal_connect (m_clipboardWidget, "selection_clear_event",
469 G_CALLBACK (selection_clear_clip), NULL);
270c23f7 470
eddb9644
VZ
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);
dc86cb34
RR
478}
479
480wxClipboard::~wxClipboard()
b527aac5 481{
270c23f7
VZ
482 Clear();
483
05492dd1
VZ
484 gtk_widget_destroy( m_clipboardWidget );
485 gtk_widget_destroy( m_targetsWidget );
b527aac5
RR
486}
487
eddb9644
VZ
488// ----------------------------------------------------------------------------
489// wxClipboard helper functions
490// ----------------------------------------------------------------------------
491
492GdkAtom wxClipboard::GTKGetClipboardAtom() const
493{
494 return m_usePrimary ? (GdkAtom)GDK_SELECTION_PRIMARY
495 : g_clipboardAtom;
496}
497
498void wxClipboard::GTKClearData(Kind kind)
dc86cb34 499{
511383f9 500 wxDataObject *&data = Data(kind);
5276b0a5 501 wxDELETE(data);
eddb9644 502}
270c23f7 503
eddb9644
VZ
504bool 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
d5027818 511 ) != 0;
eddb9644
VZ
512
513 if ( !rc )
514 {
9a83f860
VZ
515 wxLogTrace(TRACE_CLIPBOARD, wxT("Failed to %sset selection owner"),
516 set ? wxT("") : wxT("un"));
eddb9644 517 }
270c23f7 518
eddb9644
VZ
519 return rc;
520}
270c23f7 521
eddb9644
VZ
522void wxClipboard::AddSupportedTarget(GdkAtom atom)
523{
524 gtk_selection_add_target
525 (
10bd1f7d 526 m_clipboardWidget,
eddb9644
VZ
527 GTKGetClipboardAtom(),
528 atom,
529 0 // info (same as client data) unused
530 );
531}
532
3eef425f
RR
533bool wxClipboard::IsSupportedAsync(wxEvtHandler *sink)
534{
b4705641
RR
535 if (m_sink.get())
536 return false; // currently busy, come back later
d48b06bd 537
b4705641 538 wxCHECK_MSG( sink, false, wxT("no sink given") );
d48b06bd 539
3eef425f 540 m_sink = sink;
3eef425f
RR
541 gtk_selection_convert( m_targetsWidgetAsync,
542 GTKGetClipboardAtom(),
543 g_targetsAtom,
544 (guint32) GDK_CURRENT_TIME );
d48b06bd 545
3eef425f
RR
546 return true;
547}
548
eddb9644
VZ
549bool wxClipboard::DoIsSupported(const wxDataFormat& format)
550{
551 wxCHECK_MSG( format, false, wxT("invalid clipboard format") );
270c23f7 552
eddb9644
VZ
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
578void wxClipboard::Clear()
579{
1c54277e
VZ
580 gtk_selection_clear_targets( m_clipboardWidget, GTKGetClipboardAtom() );
581
eddb9644 582 if ( gdk_selection_owner_get(GTKGetClipboardAtom()) ==
385e8575 583 gtk_widget_get_window(m_clipboardWidget) )
eddb9644
VZ
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);
8b53e5a2 590 }
270c23f7 591
8b53e5a2 592 m_targetRequested = 0;
de6185e2 593 m_formatSupported = false;
8b53e5a2
RR
594}
595
596bool wxClipboard::Open()
597{
de6185e2 598 wxCHECK_MSG( !m_open, false, wxT("clipboard already open") );
270c23f7 599
de6185e2 600 m_open = true;
270c23f7 601
de6185e2 602 return true;
dc86cb34
RR
603}
604
75ce0581 605bool wxClipboard::SetData( wxDataObject *data )
dc86cb34 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
0d2a2b60 611 Clear();
75ce0581
RR
612
613 return AddData( data );
614}
615
616bool wxClipboard::AddData( wxDataObject *data )
617{
de6185e2 618 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
270c23f7 619
de6185e2 620 wxCHECK_MSG( data, false, wxT("data is invalid") );
270c23f7 621
eddb9644 622 // we can only store one wxDataObject so clear the old one
1dd989e1 623 Clear();
270c23f7 624
eddb9644 625 Data() = data;
1dd989e1 626
ca11abde 627 // get formats from wxDataObjects
eddb9644
VZ
628 const size_t count = data->GetFormatCount();
629 wxDataFormatArray formats(new wxDataFormat[count]);
630 data->GetAllFormats(formats.get());
11e1c70d 631
eddb9644
VZ
632 // always provide TIMESTAMP as a target, see comments in selection_handler
633 // for explanation
634 AddSupportedTarget(g_timestampAtom);
11e1c70d 635
eddb9644 636 for ( size_t i = 0; i < count; i++ )
b068c4e8 637 {
eddb9644 638 const wxDataFormat format(formats[i]);
11e1c70d 639
eddb9644
VZ
640 wxLogTrace(TRACE_CLIPBOARD, wxT("Adding support for %s"),
641 format.GetId().c_str());
3d257b8d 642
eddb9644 643 AddSupportedTarget(format);
b068c4e8
RR
644 }
645
bdffa920
VZ
646 if ( !m_idSelectionGetHandler )
647 {
648 m_idSelectionGetHandler = g_signal_connect (
649 m_clipboardWidget, "selection_get",
d394f0c9
MR
650 G_CALLBACK (selection_handler),
651 GUINT_TO_POINTER (gtk_get_current_event_time()) );
bdffa920 652 }
d345e841 653
eddb9644
VZ
654 // tell the world we offer clipboard data
655 return SetSelectionOwner();
8b53e5a2 656}
db1b4961 657
8b53e5a2
RR
658void wxClipboard::Close()
659{
223d09f6 660 wxCHECK_RET( m_open, wxT("clipboard not open") );
270c23f7 661
de6185e2 662 m_open = false;
dc86cb34
RR
663}
664
f536e0f2
VZ
665bool wxClipboard::IsOpened() const
666{
667 return m_open;
668}
669
e1ee679c 670bool wxClipboard::IsSupported( const wxDataFormat& format )
b527aac5 671{
eddb9644
VZ
672 if ( DoIsSupported(format) )
673 return true;
270c23f7 674
5e081315 675#if wxUSE_UNICODE
eddb9644 676 if ( format == wxDF_UNICODETEXT )
c7d6d883 677 {
eddb9644
VZ
678 // also with plain STRING format
679 return DoIsSupported(g_altTextAtom);
c7d6d883 680 }
eddb9644 681#endif // wxUSE_UNICODE
c7d6d883 682
eddb9644 683 return false;
270c23f7
VZ
684}
685
e1ee679c 686bool wxClipboard::GetData( wxDataObject& data )
75ce0581 687{
de6185e2 688 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
270c23f7 689
7eb670ac
VZ
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);
eddb9644 693 wxDataFormatArray formats(new wxDataFormat[count]);
7eb670ac 694 data.GetAllFormats(formats.get(), wxDataObject::Set);
270c23f7 695
eddb9644 696 for ( size_t i = 0; i < count; i++ )
b068c4e8 697 {
eddb9644 698 const wxDataFormat format(formats[i]);
11e1c70d 699
eddb9644
VZ
700 // is this format supported by clipboard ?
701 if ( !DoIsSupported(format) )
702 continue;
270c23f7 703
eddb9644
VZ
704 wxLogTrace(TRACE_CLIPBOARD, wxT("Requesting format %s"),
705 format.GetId().c_str());
270c23f7 706
eddb9644 707 // these variables will be used by our GTKOnSelectionReceived()
b068c4e8 708 m_receivedData = &data;
de6185e2 709 m_formatSupported = false;
270c23f7 710
06f5d975
VZ
711 {
712 wxClipboardSync sync(*this);
713
eddb9644
VZ
714 gtk_selection_convert(m_clipboardWidget,
715 GTKGetClipboardAtom(),
716 format,
717 (guint32) GDK_CURRENT_TIME );
06f5d975 718 } // wait until we get the results
b527aac5 719
be809e82
VZ
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
eddb9644 725 size of the string first. With ANSI, GetDataSize returns an extra
be809e82 726 value (for the closing null?), with unicode, the exact number of
eddb9644 727 tokens is given (that is more than 1 for non-ASCII characters)
be809e82
VZ
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 }
270c23f7 739
de6185e2 740 return true;
b068c4e8 741 }
270c23f7 742
eddb9644 743 wxLogTrace(TRACE_CLIPBOARD, wxT("GetData(): format not found"));
270c23f7 744
de6185e2 745 return false;
b527aac5
RR
746}
747
37204b5d
VZ
748wxDataObject* 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
eddb9644 771#endif // wxUSE_CLIPBOARD