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