1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk1/clipbrd.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
15 #include "wx/clipbrd.h"
20 #include "wx/dataobj.h"
27 //-----------------------------------------------------------------------------
29 //-----------------------------------------------------------------------------
31 GdkAtom g_clipboardAtom
= 0;
32 GdkAtom g_targetsAtom
= 0;
33 GdkAtom g_timestampAtom
= 0;
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!)
38 static const wxChar
*TRACE_CLIPBOARD
= _T("clipboard");
40 //-----------------------------------------------------------------------------
42 //-----------------------------------------------------------------------------
44 /* The contents of a selection are returned in a GtkSelectionData
45 structure. selection/target identify the request.
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
53 struct _GtkSelectionData
65 //-----------------------------------------------------------------------------
66 // "selection_received" for targets
67 //-----------------------------------------------------------------------------
71 targets_selection_received( GtkWidget
*WXUNUSED(widget
),
72 GtkSelectionData
*selection_data
,
73 guint32
WXUNUSED(time
),
74 wxClipboard
*clipboard
)
76 if ( wxTheClipboard
&& selection_data
->length
> 0 )
78 // make sure we got the data in the correct form
79 GdkAtom type
= selection_data
->type
;
80 if ( type
!= GDK_SELECTION_TYPE_ATOM
)
82 gchar
* atom_name
= gdk_atom_name(type
);
83 if ( strcmp(atom_name
, "TARGETS") )
85 wxLogTrace( TRACE_CLIPBOARD
,
86 _T("got unsupported clipboard target") );
88 clipboard
->m_waiting
= false;
96 wxDataFormat
clip( selection_data
->selection
);
97 wxLogTrace( TRACE_CLIPBOARD
,
98 wxT("selection received for targets, clipboard %s"),
99 clip
.GetId().c_str() );
100 #endif // __WXDEBUG__
102 // the atoms we received, holding a list of targets (= formats)
103 GdkAtom
*atoms
= (GdkAtom
*)selection_data
->data
;
105 for (unsigned int i
=0; i
<selection_data
->length
/sizeof(GdkAtom
); i
++)
107 wxDataFormat
format( atoms
[i
] );
109 wxLogTrace( TRACE_CLIPBOARD
,
110 wxT("selection received for targets, format %s"),
111 format
.GetId().c_str() );
113 // printf( "format %s requested %s\n",
114 // gdk_atom_name( atoms[i] ),
115 // gdk_atom_name( clipboard->m_targetRequested ) );
117 if (format
== clipboard
->m_targetRequested
)
119 clipboard
->m_waiting
= false;
120 clipboard
->m_formatSupported
= true;
126 clipboard
->m_waiting
= false;
130 //-----------------------------------------------------------------------------
131 // "selection_received" for the actual data
132 //-----------------------------------------------------------------------------
136 selection_received( GtkWidget
*WXUNUSED(widget
),
137 GtkSelectionData
*selection_data
,
138 guint32
WXUNUSED(time
),
139 wxClipboard
*clipboard
)
143 clipboard
->m_waiting
= false;
147 wxDataObject
*data_object
= clipboard
->m_receivedData
;
151 clipboard
->m_waiting
= false;
155 if (selection_data
->length
<= 0)
157 clipboard
->m_waiting
= false;
161 wxDataFormat
format( selection_data
->target
);
163 // make sure we got the data in the correct format
164 if (!data_object
->IsSupportedFormat( format
) )
166 clipboard
->m_waiting
= false;
171 This seems to cause problems somehow
172 // make sure we got the data in the correct form (selection type).
173 // if so, copy data to target object
174 if (selection_data
->type
!= GDK_SELECTION_TYPE_STRING
)
176 clipboard
->m_waiting
= false;
181 data_object
->SetData( format
, (size_t) selection_data
->length
, (const char*) selection_data
->data
);
183 wxTheClipboard
->m_formatSupported
= true;
184 clipboard
->m_waiting
= false;
188 //-----------------------------------------------------------------------------
190 //-----------------------------------------------------------------------------
194 selection_clear_clip( GtkWidget
*WXUNUSED(widget
), GdkEventSelection
*event
)
196 if (!wxTheClipboard
) return TRUE
;
198 if (event
->selection
== GDK_SELECTION_PRIMARY
)
200 wxTheClipboard
->m_ownsPrimarySelection
= false;
203 if (event
->selection
== g_clipboardAtom
)
205 wxTheClipboard
->m_ownsClipboard
= false;
209 wxTheClipboard
->m_waiting
= false;
213 if ((!wxTheClipboard
->m_ownsPrimarySelection
) &&
214 (!wxTheClipboard
->m_ownsClipboard
))
216 /* the clipboard is no longer in our hands. we can the delete clipboard data. */
217 if (wxTheClipboard
->m_data
)
219 wxLogTrace(TRACE_CLIPBOARD
, wxT("wxClipboard will get cleared" ));
221 delete wxTheClipboard
->m_data
;
222 wxTheClipboard
->m_data
= (wxDataObject
*) NULL
;
226 wxTheClipboard
->m_waiting
= false;
231 //-----------------------------------------------------------------------------
232 // selection handler for supplying data
233 //-----------------------------------------------------------------------------
237 selection_handler( GtkWidget
*WXUNUSED(widget
),
238 GtkSelectionData
*selection_data
,
239 guint
WXUNUSED(info
),
240 guint
WXUNUSED(time
),
241 gpointer signal_data
)
243 if (!wxTheClipboard
) return;
245 if (!wxTheClipboard
->m_data
) return;
247 wxDataObject
*data
= wxTheClipboard
->m_data
;
249 // ICCCM says that TIMESTAMP is a required atom.
250 // In particular, it satisfies Klipper, which polls
251 // TIMESTAMP to see if the clipboards content has changed.
252 // It shall return the time which was used to set the data.
253 if (selection_data
->target
== g_timestampAtom
)
255 guint timestamp
= GPOINTER_TO_UINT (signal_data
);
256 gtk_selection_data_set(selection_data
,
257 GDK_SELECTION_TYPE_INTEGER
,
259 (guchar
*)&(timestamp
),
261 wxLogTrace(TRACE_CLIPBOARD
,
262 _T("Clipboard TIMESTAMP requested, returning timestamp=%u"),
267 wxDataFormat
format( selection_data
->target
);
270 wxLogTrace(TRACE_CLIPBOARD
,
271 _T("clipboard data in format %s, GtkSelectionData is target=%s type=%s selection=%s timestamp=%u"),
272 format
.GetId().c_str(),
273 wxString::FromAscii(gdk_atom_name(selection_data
->target
)).c_str(),
274 wxString::FromAscii(gdk_atom_name(selection_data
->type
)).c_str(),
275 wxString::FromAscii(gdk_atom_name(selection_data
->selection
)).c_str(),
276 GPOINTER_TO_UINT( signal_data
)
280 if (!data
->IsSupportedFormat( format
)) return;
282 int size
= data
->GetDataSize( format
);
284 if (size
== 0) return;
286 void *d
= malloc(size
);
288 // Text data will be in UTF8 in Unicode mode.
289 data
->GetDataHere( selection_data
->target
, d
);
291 gtk_selection_data_set(
293 GDK_SELECTION_TYPE_STRING
,
302 //-----------------------------------------------------------------------------
304 //-----------------------------------------------------------------------------
306 IMPLEMENT_DYNAMIC_CLASS(wxClipboard
,wxObject
)
308 wxClipboard::wxClipboard()
313 m_ownsClipboard
= false;
314 m_ownsPrimarySelection
= false;
316 m_data
= (wxDataObject
*) NULL
;
317 m_receivedData
= (wxDataObject
*) NULL
;
319 /* we use m_targetsWidget to query what formats are available */
321 m_targetsWidget
= gtk_window_new( GTK_WINDOW_POPUP
);
322 gtk_widget_realize( m_targetsWidget
);
324 gtk_signal_connect( GTK_OBJECT(m_targetsWidget
),
325 "selection_received",
326 GTK_SIGNAL_FUNC( targets_selection_received
),
329 /* we use m_clipboardWidget to get and to offer data */
331 m_clipboardWidget
= gtk_window_new( GTK_WINDOW_POPUP
);
332 gtk_widget_realize( m_clipboardWidget
);
334 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
335 "selection_received",
336 GTK_SIGNAL_FUNC( selection_received
),
339 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
340 "selection_clear_event",
341 GTK_SIGNAL_FUNC( selection_clear_clip
),
344 if (!g_clipboardAtom
) g_clipboardAtom
= gdk_atom_intern( "CLIPBOARD", FALSE
);
345 if (!g_targetsAtom
) g_targetsAtom
= gdk_atom_intern ("TARGETS", FALSE
);
346 if (!g_timestampAtom
) g_timestampAtom
= gdk_atom_intern ("TIMESTAMP", FALSE
);
348 m_formatSupported
= false;
349 m_targetRequested
= 0;
351 m_usePrimary
= false;
354 wxClipboard::~wxClipboard()
358 if (m_clipboardWidget
) gtk_widget_destroy( m_clipboardWidget
);
359 if (m_targetsWidget
) gtk_widget_destroy( m_targetsWidget
);
362 void wxClipboard::Clear()
367 /* disable GUI threads */
370 // As we have data we also own the clipboard. Once we no longer own
371 // it, clear_selection is called which will set m_data to zero
372 if (gdk_selection_owner_get( g_clipboardAtom
) == m_clipboardWidget
->window
)
376 gtk_selection_owner_set( (GtkWidget
*) NULL
, g_clipboardAtom
,
377 (guint32
) GDK_CURRENT_TIME
);
379 while (m_waiting
) gtk_main_iteration();
382 if (gdk_selection_owner_get( GDK_SELECTION_PRIMARY
) == m_clipboardWidget
->window
)
386 gtk_selection_owner_set( (GtkWidget
*) NULL
, GDK_SELECTION_PRIMARY
,
387 (guint32
) GDK_CURRENT_TIME
);
389 while (m_waiting
) gtk_main_iteration();
395 m_data
= (wxDataObject
*) NULL
;
399 /* re-enable GUI threads */
403 m_targetRequested
= 0;
404 m_formatSupported
= false;
407 bool wxClipboard::Open()
409 wxCHECK_MSG( !m_open
, false, wxT("clipboard already open") );
416 bool wxClipboard::SetData( wxDataObject
*data
)
418 wxCHECK_MSG( m_open
, false, wxT("clipboard not open") );
420 wxCHECK_MSG( data
, false, wxT("data is invalid") );
424 return AddData( data
);
427 bool wxClipboard::AddData( wxDataObject
*data
)
429 wxCHECK_MSG( m_open
, false, wxT("clipboard not open") );
431 wxCHECK_MSG( data
, false, wxT("data is invalid") );
433 // we can only store one wxDataObject
438 // get formats from wxDataObjects
439 wxDataFormat
*array
= new wxDataFormat
[ m_data
->GetFormatCount() ];
440 m_data
->GetAllFormats( array
);
442 // primary selection or clipboard
443 GdkAtom clipboard
= m_usePrimary
? (GdkAtom
)GDK_SELECTION_PRIMARY
446 // by default provide TIMESTAMP as a target
447 gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget
),
452 for (size_t i
= 0; i
< m_data
->GetFormatCount(); i
++)
454 wxLogTrace( TRACE_CLIPBOARD
,
455 wxT("wxClipboard now supports atom %s"),
456 array
[i
].GetId().c_str() );
458 // printf( "added %s\n",
459 // gdk_atom_name( array[i].GetFormatId() ) );
461 gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget
),
464 0 ); /* what is info ? */
469 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
471 GTK_SIGNAL_FUNC(selection_handler
),
472 GUINT_TO_POINTER( gdk_event_get_time(gtk_get_current_event()) ) );
475 /* disable GUI threads */
478 /* Tell the world we offer clipboard data */
479 bool res
= (gtk_selection_owner_set( m_clipboardWidget
,
481 (guint32
) GDK_CURRENT_TIME
));
484 m_ownsPrimarySelection
= res
;
486 m_ownsClipboard
= res
;
489 /* re-enable GUI threads */
495 void wxClipboard::Close()
497 wxCHECK_RET( m_open
, wxT("clipboard not open") );
502 bool wxClipboard::IsOpened() const
507 bool wxClipboard::IsSupported( const wxDataFormat
& format
)
509 /* reentrance problems */
510 if (m_waiting
) return false;
512 /* store requested format to be asked for by callbacks */
513 m_targetRequested
= format
;
515 wxLogTrace( TRACE_CLIPBOARD
,
516 wxT("wxClipboard:IsSupported: requested format: %s"),
517 format
.GetId().c_str() );
519 wxCHECK_MSG( m_targetRequested
, false, wxT("invalid clipboard format") );
521 m_formatSupported
= false;
523 /* perform query. this will set m_formatSupported to
524 true if m_targetRequested is supported.
525 also, we have to wait for the "answer" from the
526 clipboard owner which is an asynchronous process.
527 therefore we set m_waiting = true here and wait
528 until the callback "targets_selection_received"
533 gtk_selection_convert( m_targetsWidget
,
534 m_usePrimary
? (GdkAtom
)GDK_SELECTION_PRIMARY
537 (guint32
) GDK_CURRENT_TIME
);
539 while (m_waiting
) gtk_main_iteration();
541 return m_formatSupported
;
544 bool wxClipboard::GetData( wxDataObject
& data
)
546 wxCHECK_MSG( m_open
, false, wxT("clipboard not open") );
548 /* get formats from wxDataObjects */
549 wxDataFormat
*array
= new wxDataFormat
[ data
.GetFormatCount() ];
550 data
.GetAllFormats( array
);
552 for (size_t i
= 0; i
< data
.GetFormatCount(); i
++)
554 wxDataFormat
format( array
[i
] );
556 wxLogTrace( TRACE_CLIPBOARD
,
557 wxT("wxClipboard::GetData: requested format: %s"),
558 format
.GetId().c_str() );
560 /* is data supported by clipboard ? */
562 /* store requested format to be asked for by callbacks */
563 m_targetRequested
= format
;
565 wxCHECK_MSG( m_targetRequested
, false, wxT("invalid clipboard format") );
567 m_formatSupported
= false;
569 /* perform query. this will set m_formatSupported to
570 true if m_targetRequested is supported.
571 also, we have to wait for the "answer" from the
572 clipboard owner which is an asynchronous process.
573 therefore we set m_waiting = true here and wait
574 until the callback "targets_selection_received"
579 gtk_selection_convert( m_targetsWidget
,
580 m_usePrimary
? (GdkAtom
)GDK_SELECTION_PRIMARY
583 (guint32
) GDK_CURRENT_TIME
);
585 while (m_waiting
) gtk_main_iteration();
587 if (!m_formatSupported
) continue;
589 /* store pointer to data object to be filled up by callbacks */
590 m_receivedData
= &data
;
592 /* store requested format to be asked for by callbacks */
593 m_targetRequested
= format
;
595 wxCHECK_MSG( m_targetRequested
, false, wxT("invalid clipboard format") );
598 m_formatSupported
= false;
600 /* ask for clipboard contents. this will set
601 m_formatSupported to true if m_targetRequested
603 also, we have to wait for the "answer" from the
604 clipboard owner which is an asynchronous process.
605 therefore we set m_waiting = true here and wait
606 until the callback "targets_selection_received"
611 wxLogTrace( TRACE_CLIPBOARD
,
612 wxT("wxClipboard::GetData: format found, start convert") );
614 gtk_selection_convert( m_clipboardWidget
,
615 m_usePrimary
? (GdkAtom
)GDK_SELECTION_PRIMARY
618 (guint32
) GDK_CURRENT_TIME
);
620 while (m_waiting
) gtk_main_iteration();
623 Normally this is a true error as we checked for the presence of such
624 data before, but there are applications that may return an empty
625 string (e.g. Gnumeric-1.6.1 on Linux if an empty cell is copied)
626 which would produce a false error message here, so we check for the
627 size of the string first. In ansi, GetDataSize returns an extra
628 value (for the closing null?), with unicode, the exact number of
629 tokens is given (that is more than 1 for special characters)
630 (tested with Gnumeric-1.6.1 and OpenOffice.org-2.0.2)
633 if ( format
!= wxDF_UNICODETEXT
|| data
.GetDataSize(format
) > 0 )
635 if ( format
!= wxDF_TEXT
|| data
.GetDataSize(format
) > 1 )
636 #endif // UNICODE / !UNICODE
638 wxCHECK_MSG( m_formatSupported
, false,
639 wxT("error retrieving data from clipboard") );
647 wxLogTrace( TRACE_CLIPBOARD
,
648 wxT("wxClipboard::GetData: format not found") );