]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/clipbrd.cpp
Avoid using wxHtmlTag::HasParam() unnecessarily.
[wxWidgets.git] / src / gtk1 / clipbrd.cpp
CommitLineData
dc86cb34 1/////////////////////////////////////////////////////////////////////////////
e4db172a 2// Name: src/gtk1/clipbrd.cpp
dc86cb34
RR
3// Purpose:
4// Author: Robert Roebling
dc86cb34 5// Copyright: (c) 1998 Robert Roebling
65571936 6// Licence: wxWindows licence
dc86cb34
RR
7/////////////////////////////////////////////////////////////////////////////
8
14f355c2
VS
9// For compilers that support precompilation, includes "wx.h".
10#include "wx/wxprec.h"
11
e4db172a
WS
12#if wxUSE_CLIPBOARD
13
dc86cb34
RR
14#include "wx/clipbrd.h"
15
e4db172a
WS
16#ifndef WX_PRECOMP
17 #include "wx/log.h"
de6185e2 18 #include "wx/utils.h"
28f92d74 19 #include "wx/dataobj.h"
e4db172a 20#endif
ac57418f 21
071a2d78
RR
22#include <glib.h>
23#include <gdk/gdk.h>
24#include <gtk/gtk.h>
83624f79 25
dc86cb34
RR
26//-----------------------------------------------------------------------------
27// data
28//-----------------------------------------------------------------------------
29
fd0eed64 30GdkAtom g_clipboardAtom = 0;
b527aac5 31GdkAtom g_targetsAtom = 0;
d394f0c9 32GdkAtom g_timestampAtom = 0;
fd0eed64 33
61b04ac6
VZ
34// the trace mask we use with wxLogTrace() - call
35// wxLog::AddTraceMask(TRACE_CLIPBOARD) to enable the trace messages from here
36// (there will be a *lot* of them!)
cb1b8d41 37#define TRACE_CLIPBOARD "clipboard"
61b04ac6 38
dc86cb34 39//-----------------------------------------------------------------------------
b527aac5 40// reminder
dc86cb34
RR
41//-----------------------------------------------------------------------------
42
b527aac5 43/* The contents of a selection are returned in a GtkSelectionData
270c23f7 44 structure. selection/target identify the request.
b527aac5
RR
45 type specifies the type of the return; if length < 0, and
46 the data should be ignored. This structure has object semantics -
47 no fields should be modified directly, they should not be created
48 directly, and pointers to them should not be stored beyond the duration of
49 a callback. (If the last is changed, we'll need to add reference
50 counting)
51
52struct _GtkSelectionData
dc86cb34 53{
b527aac5
RR
54 GdkAtom selection;
55 GdkAtom target;
56 GdkAtom type;
61b04ac6 57 gint format;
b527aac5 58 guchar *data;
61b04ac6 59 gint length;
b527aac5
RR
60};
61
62*/
dc86cb34 63
b527aac5
RR
64//-----------------------------------------------------------------------------
65// "selection_received" for targets
66//-----------------------------------------------------------------------------
67
865bb325 68extern "C" {
b527aac5 69static void
270c23f7
VZ
70targets_selection_received( GtkWidget *WXUNUSED(widget),
71 GtkSelectionData *selection_data,
034be888 72 guint32 WXUNUSED(time),
66633398 73 wxClipboard *clipboard )
dc86cb34 74{
270c23f7 75 if ( wxTheClipboard && selection_data->length > 0 )
034be888 76 {
ca11abde 77 // make sure we got the data in the correct form
270c23f7
VZ
78 GdkAtom type = selection_data->type;
79 if ( type != GDK_SELECTION_TYPE_ATOM )
80 {
d394f0c9
MR
81 gchar* atom_name = gdk_atom_name(type);
82 if ( strcmp(atom_name, "TARGETS") )
61b04ac6
VZ
83 {
84 wxLogTrace( TRACE_CLIPBOARD,
9a83f860 85 wxT("got unsupported clipboard target") );
61b04ac6 86
de6185e2 87 clipboard->m_waiting = false;
d394f0c9 88 g_free(atom_name);
61b04ac6
VZ
89 return;
90 }
d394f0c9 91 g_free(atom_name);
270c23f7 92 }
b527aac5 93
270c23f7 94 wxDataFormat clip( selection_data->selection );
61b04ac6
VZ
95 wxLogTrace( TRACE_CLIPBOARD,
96 wxT("selection received for targets, clipboard %s"),
97 clip.GetId().c_str() );
270c23f7
VZ
98
99 // the atoms we received, holding a list of targets (= formats)
100 GdkAtom *atoms = (GdkAtom *)selection_data->data;
11e1c70d 101
270c23f7 102 for (unsigned int i=0; i<selection_data->length/sizeof(GdkAtom); i++)
8b53e5a2 103 {
270c23f7
VZ
104 wxDataFormat format( atoms[i] );
105
61b04ac6
VZ
106 wxLogTrace( TRACE_CLIPBOARD,
107 wxT("selection received for targets, format %s"),
108 format.GetId().c_str() );
270c23f7 109
3d257b8d 110// printf( "format %s requested %s\n",
ca11abde
RR
111// gdk_atom_name( atoms[i] ),
112// gdk_atom_name( clipboard->m_targetRequested ) );
113
270c23f7
VZ
114 if (format == clipboard->m_targetRequested)
115 {
de6185e2
WS
116 clipboard->m_waiting = false;
117 clipboard->m_formatSupported = true;
270c23f7
VZ
118 return;
119 }
8b53e5a2
RR
120 }
121 }
b527aac5 122
de6185e2 123 clipboard->m_waiting = false;
dc86cb34 124}
865bb325 125}
dc86cb34
RR
126
127//-----------------------------------------------------------------------------
b527aac5 128// "selection_received" for the actual data
dc86cb34
RR
129//-----------------------------------------------------------------------------
130
865bb325 131extern "C" {
270c23f7
VZ
132static void
133selection_received( GtkWidget *WXUNUSED(widget),
134 GtkSelectionData *selection_data,
034be888 135 guint32 WXUNUSED(time),
66633398 136 wxClipboard *clipboard )
dc86cb34 137{
034be888
RR
138 if (!wxTheClipboard)
139 {
de6185e2 140 clipboard->m_waiting = false;
034be888
RR
141 return;
142 }
270c23f7 143
8b53e5a2 144 wxDataObject *data_object = clipboard->m_receivedData;
1dd989e1 145
034be888
RR
146 if (!data_object)
147 {
de6185e2 148 clipboard->m_waiting = false;
034be888
RR
149 return;
150 }
270c23f7 151
034be888
RR
152 if (selection_data->length <= 0)
153 {
de6185e2 154 clipboard->m_waiting = false;
034be888
RR
155 return;
156 }
270c23f7 157
b068c4e8 158 wxDataFormat format( selection_data->target );
270c23f7 159
ca11abde 160 // make sure we got the data in the correct format
b068c4e8 161 if (!data_object->IsSupportedFormat( format ) )
034be888 162 {
de6185e2 163 clipboard->m_waiting = false;
034be888
RR
164 return;
165 }
e2acb9ae 166
c7d6d883
RR
167#if 0
168 This seems to cause problems somehow
169 // make sure we got the data in the correct form (selection type).
170 // if so, copy data to target object
e5d6aa22 171 if (selection_data->type != GDK_SELECTION_TYPE_STRING)
8b53e5a2 172 {
de6185e2 173 clipboard->m_waiting = false;
e5d6aa22 174 return;
8b53e5a2 175 }
c7d6d883 176#endif
270c23f7 177
e5d6aa22 178 data_object->SetData( format, (size_t) selection_data->length, (const char*) selection_data->data );
270c23f7 179
de6185e2
WS
180 wxTheClipboard->m_formatSupported = true;
181 clipboard->m_waiting = false;
dc86cb34 182}
865bb325 183}
fd0eed64
RR
184
185//-----------------------------------------------------------------------------
186// "selection_clear"
187//-----------------------------------------------------------------------------
188
865bb325 189extern "C" {
fd0eed64 190static gint
aeeb6a44 191selection_clear_clip( GtkWidget *WXUNUSED(widget), GdkEventSelection *event )
fd0eed64 192{
8b53e5a2 193 if (!wxTheClipboard) return TRUE;
270c23f7 194
aeeb6a44
RR
195 if (event->selection == GDK_SELECTION_PRIMARY)
196 {
de6185e2 197 wxTheClipboard->m_ownsPrimarySelection = false;
aeeb6a44
RR
198 }
199 else
200 if (event->selection == g_clipboardAtom)
201 {
de6185e2 202 wxTheClipboard->m_ownsClipboard = false;
aeeb6a44
RR
203 }
204 else
205 {
de6185e2 206 wxTheClipboard->m_waiting = false;
aeeb6a44
RR
207 return FALSE;
208 }
270c23f7 209
aeeb6a44
RR
210 if ((!wxTheClipboard->m_ownsPrimarySelection) &&
211 (!wxTheClipboard->m_ownsClipboard))
212 {
db2d879a 213 /* the clipboard is no longer in our hands. we can the delete clipboard data. */
1dd989e1 214 if (wxTheClipboard->m_data)
66633398 215 {
47cf53ef 216 wxLogTrace(TRACE_CLIPBOARD, wxT("wxClipboard will get cleared" ));
270c23f7 217
5276b0a5 218 wxDELETE(wxTheClipboard->m_data);
66633398 219 }
aeeb6a44 220 }
270c23f7 221
de6185e2 222 wxTheClipboard->m_waiting = false;
8b53e5a2 223 return TRUE;
fd0eed64 224}
865bb325 225}
fd0eed64
RR
226
227//-----------------------------------------------------------------------------
228// selection handler for supplying data
229//-----------------------------------------------------------------------------
230
865bb325 231extern "C" {
fd0eed64 232static void
19d89516
VZ
233selection_handler( GtkWidget *WXUNUSED(widget),
234 GtkSelectionData *selection_data,
235 guint WXUNUSED(info),
236 guint WXUNUSED(time),
d394f0c9 237 gpointer signal_data )
fd0eed64 238{
8b53e5a2 239 if (!wxTheClipboard) return;
270c23f7 240
1dd989e1 241 if (!wxTheClipboard->m_data) return;
270c23f7 242
1dd989e1 243 wxDataObject *data = wxTheClipboard->m_data;
270c23f7 244
d394f0c9
MR
245 // ICCCM says that TIMESTAMP is a required atom.
246 // In particular, it satisfies Klipper, which polls
247 // TIMESTAMP to see if the clipboards content has changed.
248 // It shall return the time which was used to set the data.
249 if (selection_data->target == g_timestampAtom)
250 {
d704d2f5 251 guint timestamp = GPOINTER_TO_UINT (signal_data);
d394f0c9
MR
252 gtk_selection_data_set(selection_data,
253 GDK_SELECTION_TYPE_INTEGER,
254 32,
255 (guchar*)&(timestamp),
256 sizeof(timestamp));
257 wxLogTrace(TRACE_CLIPBOARD,
9a83f860 258 wxT("Clipboard TIMESTAMP requested, returning timestamp=%u"),
d394f0c9
MR
259 timestamp);
260 return;
261 }
262
b068c4e8
RR
263 wxDataFormat format( selection_data->target );
264
ebe47451 265 wxLogTrace(TRACE_CLIPBOARD,
9a83f860 266 wxT("clipboard data in format %s, GtkSelectionData is target=%s type=%s selection=%s timestamp=%u"),
ebe47451
VS
267 format.GetId().c_str(),
268 wxString::FromAscii(gdk_atom_name(selection_data->target)).c_str(),
269 wxString::FromAscii(gdk_atom_name(selection_data->type)).c_str(),
d394f0c9
MR
270 wxString::FromAscii(gdk_atom_name(selection_data->selection)).c_str(),
271 GPOINTER_TO_UINT( signal_data )
ebe47451 272 );
3d257b8d 273
b068c4e8 274 if (!data->IsSupportedFormat( format )) return;
270c23f7 275
b068c4e8 276 int size = data->GetDataSize( format );
270c23f7 277
1dd989e1 278 if (size == 0) return;
270c23f7 279
33754c4d
VZ
280 void *d = malloc(size);
281
ca11abde 282 // Text data will be in UTF8 in Unicode mode.
33754c4d 283 data->GetDataHere( selection_data->target, d );
270c23f7 284
3cbab641 285 gtk_selection_data_set(
ebe47451
VS
286 selection_data,
287 GDK_SELECTION_TYPE_STRING,
3cbab641 288 8 * sizeof(gchar),
ebe47451 289 (unsigned char*) d,
2c906a49 290 size );
33754c4d
VZ
291
292 free(d);
fd0eed64 293}
865bb325 294}
dc86cb34
RR
295
296//-----------------------------------------------------------------------------
297// wxClipboard
298//-----------------------------------------------------------------------------
299
300IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
301
302wxClipboard::wxClipboard()
303{
de6185e2
WS
304 m_open = false;
305 m_waiting = false;
8b53e5a2 306
de6185e2
WS
307 m_ownsClipboard = false;
308 m_ownsPrimarySelection = false;
aeeb6a44 309
d3b9f782
VZ
310 m_data = NULL;
311 m_receivedData = NULL;
99c67c77 312
034be888 313 /* we use m_targetsWidget to query what formats are available */
270c23f7 314
034be888
RR
315 m_targetsWidget = gtk_window_new( GTK_WINDOW_POPUP );
316 gtk_widget_realize( m_targetsWidget );
317
270c23f7 318 gtk_signal_connect( GTK_OBJECT(m_targetsWidget),
034be888 319 "selection_received",
270c23f7 320 GTK_SIGNAL_FUNC( targets_selection_received ),
66633398 321 (gpointer) this );
270c23f7 322
034be888 323 /* we use m_clipboardWidget to get and to offer data */
270c23f7 324
8b53e5a2
RR
325 m_clipboardWidget = gtk_window_new( GTK_WINDOW_POPUP );
326 gtk_widget_realize( m_clipboardWidget );
327
270c23f7 328 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
034be888 329 "selection_received",
270c23f7 330 GTK_SIGNAL_FUNC( selection_received ),
66633398 331 (gpointer) this );
034be888 332
270c23f7 333 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
8b53e5a2 334 "selection_clear_event",
270c23f7 335 GTK_SIGNAL_FUNC( selection_clear_clip ),
66633398 336 (gpointer) NULL );
270c23f7 337
8b53e5a2 338 if (!g_clipboardAtom) g_clipboardAtom = gdk_atom_intern( "CLIPBOARD", FALSE );
8b53e5a2 339 if (!g_targetsAtom) g_targetsAtom = gdk_atom_intern ("TARGETS", FALSE);
d394f0c9 340 if (!g_timestampAtom) g_timestampAtom = gdk_atom_intern ("TIMESTAMP", FALSE);
270c23f7 341
de6185e2 342 m_formatSupported = false;
8b53e5a2 343 m_targetRequested = 0;
dc86cb34
RR
344}
345
346wxClipboard::~wxClipboard()
b527aac5 347{
270c23f7
VZ
348 Clear();
349
8b53e5a2 350 if (m_clipboardWidget) gtk_widget_destroy( m_clipboardWidget );
034be888 351 if (m_targetsWidget) gtk_widget_destroy( m_targetsWidget );
b527aac5
RR
352}
353
354void wxClipboard::Clear()
dc86cb34 355{
1dd989e1
RR
356 if (m_data)
357 {
b453e1b2
RR
358#if wxUSE_THREADS
359 /* disable GUI threads */
b453e1b2 360#endif
270c23f7 361
ca11abde
RR
362 // As we have data we also own the clipboard. Once we no longer own
363 // it, clear_selection is called which will set m_data to zero
aeeb6a44 364 if (gdk_selection_owner_get( g_clipboardAtom ) == m_clipboardWidget->window)
8b53e5a2 365 {
de6185e2 366 m_waiting = true;
270c23f7 367
d3b9f782 368 gtk_selection_owner_set( NULL, g_clipboardAtom,
b02da6b1 369 (guint32) GDK_CURRENT_TIME );
270c23f7 370
e5ea3f7a 371 while (m_waiting) gtk_main_iteration();
8b53e5a2 372 }
270c23f7 373
aeeb6a44
RR
374 if (gdk_selection_owner_get( GDK_SELECTION_PRIMARY ) == m_clipboardWidget->window)
375 {
de6185e2 376 m_waiting = true;
270c23f7 377
d3b9f782 378 gtk_selection_owner_set( NULL, GDK_SELECTION_PRIMARY,
b02da6b1 379 (guint32) GDK_CURRENT_TIME );
270c23f7 380
e5ea3f7a 381 while (m_waiting) gtk_main_iteration();
aeeb6a44 382 }
270c23f7 383
5276b0a5 384 wxDELETE(m_data);
270c23f7 385
b453e1b2
RR
386#if wxUSE_THREADS
387 /* re-enable GUI threads */
b453e1b2 388#endif
8b53e5a2 389 }
270c23f7 390
8b53e5a2 391 m_targetRequested = 0;
de6185e2 392 m_formatSupported = false;
8b53e5a2
RR
393}
394
395bool wxClipboard::Open()
396{
de6185e2 397 wxCHECK_MSG( !m_open, false, wxT("clipboard already open") );
270c23f7 398
de6185e2 399 m_open = true;
270c23f7 400
de6185e2 401 return true;
dc86cb34
RR
402}
403
75ce0581 404bool wxClipboard::SetData( wxDataObject *data )
dc86cb34 405{
de6185e2 406 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
270c23f7 407
de6185e2 408 wxCHECK_MSG( data, false, wxT("data is invalid") );
270c23f7 409
0d2a2b60 410 Clear();
75ce0581
RR
411
412 return AddData( data );
413}
414
415bool wxClipboard::AddData( wxDataObject *data )
416{
de6185e2 417 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
270c23f7 418
de6185e2 419 wxCHECK_MSG( data, false, wxT("data is invalid") );
270c23f7 420
ca11abde 421 // we can only store one wxDataObject
1dd989e1 422 Clear();
270c23f7 423
1dd989e1
RR
424 m_data = data;
425
ca11abde 426 // get formats from wxDataObjects
b068c4e8
RR
427 wxDataFormat *array = new wxDataFormat[ m_data->GetFormatCount() ];
428 m_data->GetAllFormats( array );
11e1c70d 429
ca11abde 430 // primary selection or clipboard
11e1c70d
RR
431 GdkAtom clipboard = m_usePrimary ? (GdkAtom)GDK_SELECTION_PRIMARY
432 : g_clipboardAtom;
433
d394f0c9
MR
434 // by default provide TIMESTAMP as a target
435 gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget),
436 clipboard,
437 g_timestampAtom,
438 0 );
270c23f7 439
b068c4e8
RR
440 for (size_t i = 0; i < m_data->GetFormatCount(); i++)
441 {
61b04ac6
VZ
442 wxLogTrace( TRACE_CLIPBOARD,
443 wxT("wxClipboard now supports atom %s"),
444 array[i].GetId().c_str() );
11e1c70d 445
3d257b8d 446// printf( "added %s\n",
ca11abde 447// gdk_atom_name( array[i].GetFormatId() ) );
3d257b8d 448
11e1c70d 449 gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget),
270c23f7
VZ
450 clipboard,
451 array[i],
11e1c70d 452 0 ); /* what is info ? */
b068c4e8
RR
453 }
454
455 delete[] array;
270c23f7
VZ
456
457 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
d345e841 458 "selection_get",
270c23f7 459 GTK_SIGNAL_FUNC(selection_handler),
4b84311a 460 GUINT_TO_POINTER( gdk_event_get_time(gtk_get_current_event()) ) );
d345e841 461
b453e1b2 462#if wxUSE_THREADS
11e1c70d 463 /* disable GUI threads */
b453e1b2 464#endif
270c23f7 465
75ce0581 466 /* Tell the world we offer clipboard data */
11e1c70d
RR
467 bool res = (gtk_selection_owner_set( m_clipboardWidget,
468 clipboard,
b02da6b1 469 (guint32) GDK_CURRENT_TIME ));
270c23f7 470
11e1c70d
RR
471 if (m_usePrimary)
472 m_ownsPrimarySelection = res;
473 else
474 m_ownsClipboard = res;
270c23f7 475
b453e1b2
RR
476#if wxUSE_THREADS
477 /* re-enable GUI threads */
b453e1b2 478#endif
270c23f7 479
11e1c70d 480 return res;
8b53e5a2 481}
db1b4961 482
8b53e5a2
RR
483void wxClipboard::Close()
484{
223d09f6 485 wxCHECK_RET( m_open, wxT("clipboard not open") );
270c23f7 486
de6185e2 487 m_open = false;
dc86cb34
RR
488}
489
f536e0f2
VZ
490bool wxClipboard::IsOpened() const
491{
492 return m_open;
493}
494
e1ee679c 495bool wxClipboard::IsSupported( const wxDataFormat& format )
b527aac5 496{
e5d6aa22 497 /* reentrance problems */
de6185e2 498 if (m_waiting) return false;
270c23f7 499
e5d6aa22 500 /* store requested format to be asked for by callbacks */
1dd989e1 501 m_targetRequested = format;
270c23f7 502
61b04ac6
VZ
503 wxLogTrace( TRACE_CLIPBOARD,
504 wxT("wxClipboard:IsSupported: requested format: %s"),
505 format.GetId().c_str() );
eff869aa 506
de6185e2 507 wxCHECK_MSG( m_targetRequested, false, wxT("invalid clipboard format") );
270c23f7 508
de6185e2 509 m_formatSupported = false;
270c23f7
VZ
510
511 /* perform query. this will set m_formatSupported to
de6185e2 512 true if m_targetRequested is supported.
270c23f7 513 also, we have to wait for the "answer" from the
034be888 514 clipboard owner which is an asynchronous process.
de6185e2 515 therefore we set m_waiting = true here and wait
270c23f7 516 until the callback "targets_selection_received"
de6185e2 517 sets it to false */
034be888 518
de6185e2 519 m_waiting = true;
ca35e608 520
034be888 521 gtk_selection_convert( m_targetsWidget,
66633398 522 m_usePrimary ? (GdkAtom)GDK_SELECTION_PRIMARY
270c23f7 523 : g_clipboardAtom,
66633398 524 g_targetsAtom,
b02da6b1 525 (guint32) GDK_CURRENT_TIME );
ca35e608 526
034be888 527 while (m_waiting) gtk_main_iteration();
270c23f7 528
ebe47451 529 return m_formatSupported;
270c23f7
VZ
530}
531
e1ee679c 532bool wxClipboard::GetData( wxDataObject& data )
75ce0581 533{
de6185e2 534 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
270c23f7 535
b068c4e8
RR
536 /* get formats from wxDataObjects */
537 wxDataFormat *array = new wxDataFormat[ data.GetFormatCount() ];
538 data.GetAllFormats( array );
270c23f7 539
b068c4e8
RR
540 for (size_t i = 0; i < data.GetFormatCount(); i++)
541 {
e5d6aa22 542 wxDataFormat format( array[i] );
270c23f7 543
61b04ac6
VZ
544 wxLogTrace( TRACE_CLIPBOARD,
545 wxT("wxClipboard::GetData: requested format: %s"),
546 format.GetId().c_str() );
270c23f7 547
b068c4e8 548 /* is data supported by clipboard ? */
270c23f7 549
11e1c70d
RR
550 /* store requested format to be asked for by callbacks */
551 m_targetRequested = format;
270c23f7 552
de6185e2 553 wxCHECK_MSG( m_targetRequested, false, wxT("invalid clipboard format") );
270c23f7 554
de6185e2 555 m_formatSupported = false;
270c23f7
VZ
556
557 /* perform query. this will set m_formatSupported to
de6185e2 558 true if m_targetRequested is supported.
270c23f7 559 also, we have to wait for the "answer" from the
11e1c70d 560 clipboard owner which is an asynchronous process.
de6185e2 561 therefore we set m_waiting = true here and wait
270c23f7 562 until the callback "targets_selection_received"
de6185e2 563 sets it to false */
11e1c70d 564
de6185e2 565 m_waiting = true;
11e1c70d
RR
566
567 gtk_selection_convert( m_targetsWidget,
568 m_usePrimary ? (GdkAtom)GDK_SELECTION_PRIMARY
270c23f7 569 : g_clipboardAtom,
11e1c70d 570 g_targetsAtom,
b02da6b1 571 (guint32) GDK_CURRENT_TIME );
11e1c70d
RR
572
573 while (m_waiting) gtk_main_iteration();
270c23f7 574
11e1c70d 575 if (!m_formatSupported) continue;
270c23f7 576
b068c4e8
RR
577 /* store pointer to data object to be filled up by callbacks */
578 m_receivedData = &data;
270c23f7 579
b068c4e8 580 /* store requested format to be asked for by callbacks */
e5d6aa22 581 m_targetRequested = format;
270c23f7 582
de6185e2 583 wxCHECK_MSG( m_targetRequested, false, wxT("invalid clipboard format") );
270c23f7 584
b068c4e8 585 /* start query */
de6185e2 586 m_formatSupported = false;
270c23f7
VZ
587
588 /* ask for clipboard contents. this will set
de6185e2 589 m_formatSupported to true if m_targetRequested
b068c4e8 590 is supported.
270c23f7 591 also, we have to wait for the "answer" from the
b068c4e8 592 clipboard owner which is an asynchronous process.
de6185e2 593 therefore we set m_waiting = true here and wait
270c23f7 594 until the callback "targets_selection_received"
de6185e2 595 sets it to false */
b068c4e8 596
de6185e2 597 m_waiting = true;
b068c4e8 598
47cf53ef
VZ
599 wxLogTrace( TRACE_CLIPBOARD,
600 wxT("wxClipboard::GetData: format found, start convert") );
270c23f7 601
b068c4e8 602 gtk_selection_convert( m_clipboardWidget,
66633398 603 m_usePrimary ? (GdkAtom)GDK_SELECTION_PRIMARY
270c23f7 604 : g_clipboardAtom,
66633398 605 m_targetRequested,
b02da6b1 606 (guint32) GDK_CURRENT_TIME );
270c23f7 607
b068c4e8 608 while (m_waiting) gtk_main_iteration();
b527aac5 609
be809e82
VZ
610 /*
611 Normally this is a true error as we checked for the presence of such
612 data before, but there are applications that may return an empty
613 string (e.g. Gnumeric-1.6.1 on Linux if an empty cell is copied)
614 which would produce a false error message here, so we check for the
615 size of the string first. In ansi, GetDataSize returns an extra
616 value (for the closing null?), with unicode, the exact number of
617 tokens is given (that is more than 1 for special characters)
618 (tested with Gnumeric-1.6.1 and OpenOffice.org-2.0.2)
619 */
620#if wxUSE_UNICODE
621 if ( format != wxDF_UNICODETEXT || data.GetDataSize(format) > 0 )
622#else // !UNICODE
623 if ( format != wxDF_TEXT || data.GetDataSize(format) > 1 )
624#endif // UNICODE / !UNICODE
625 {
626 wxCHECK_MSG( m_formatSupported, false,
627 wxT("error retrieving data from clipboard") );
628 }
270c23f7 629
66633398 630 /* return success */
b068c4e8 631 delete[] array;
de6185e2 632 return true;
b068c4e8 633 }
270c23f7 634
47cf53ef
VZ
635 wxLogTrace( TRACE_CLIPBOARD,
636 wxT("wxClipboard::GetData: format not found") );
270c23f7 637
b068c4e8
RR
638 /* return failure */
639 delete[] array;
de6185e2 640 return false;
b527aac5
RR
641}
642
ac57418f 643#endif
ac57418f 644 // wxUSE_CLIPBOARD