1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "clipbrd.h"
14 #include "wx/clipbrd.h"
18 #include "wx/dataobj.h"
25 //-----------------------------------------------------------------------------
27 //-----------------------------------------------------------------------------
30 extern void wxapp_install_thread_wakeup();
31 extern void wxapp_uninstall_thread_wakeup();
34 //-----------------------------------------------------------------------------
36 //-----------------------------------------------------------------------------
38 wxClipboard
*wxTheClipboard
= (wxClipboard
*) NULL
;
40 GdkAtom g_clipboardAtom
= 0;
41 GdkAtom g_targetsAtom
= 0;
43 //-----------------------------------------------------------------------------
45 //-----------------------------------------------------------------------------
47 /* The contents of a selection are returned in a GtkSelectionData
48 structure. selection/target identify the request.
49 type specifies the type of the return; if length < 0, and
50 the data should be ignored. This structure has object semantics -
51 no fields should be modified directly, they should not be created
52 directly, and pointers to them should not be stored beyond the duration of
53 a callback. (If the last is changed, we'll need to add reference
56 struct _GtkSelectionData
68 //-----------------------------------------------------------------------------
69 // "selection_received" for targets
70 //-----------------------------------------------------------------------------
73 targets_selection_received( GtkWidget
*WXUNUSED(widget
),
74 GtkSelectionData
*selection_data
,
75 #if (GTK_MINOR_VERSION > 0)
76 guint32
WXUNUSED(time
),
78 wxClipboard
*clipboard
)
82 clipboard
->m_waiting
= FALSE
;
86 if (selection_data
->length
<= 0)
88 clipboard
->m_waiting
= FALSE
;
92 /* make sure we got the data in the correct form */
93 if (selection_data
->type
!= GDK_SELECTION_TYPE_ATOM
)
95 clipboard
->m_waiting
= FALSE
;
99 // the atoms we received, holding a list of targets (= formats)
100 GdkAtom
*atoms
= (GdkAtom
*)selection_data
->data
;
102 for (unsigned int i
=0; i
<selection_data
->length
/sizeof(GdkAtom
); i
++)
105 char *name = gdk_atom_name (atoms[i]);
106 if (name) printf( "Format available: %s.\n", name ); */
108 if (atoms
[i
] == clipboard
->m_targetRequested
)
110 clipboard
->m_waiting
= FALSE
;
111 clipboard
->m_formatSupported
= TRUE
;
116 clipboard
->m_waiting
= FALSE
;
120 //-----------------------------------------------------------------------------
121 // "selection_received" for the actual data
122 //-----------------------------------------------------------------------------
125 selection_received( GtkWidget
*WXUNUSED(widget
),
126 GtkSelectionData
*selection_data
,
127 #if (GTK_MINOR_VERSION > 0)
128 guint32
WXUNUSED(time
),
130 wxClipboard
*clipboard
)
134 clipboard
->m_waiting
= FALSE
;
138 wxDataObject
*data_object
= clipboard
->m_receivedData
;
142 clipboard
->m_waiting
= FALSE
;
146 if (selection_data
->length
<= 0)
148 clipboard
->m_waiting
= FALSE
;
152 /* make sure we got the data in the correct format */
153 if (data_object
->GetFormat() != selection_data
->target
)
155 clipboard
->m_waiting
= FALSE
;
159 /* make sure we got the data in the correct form (selection type).
160 if so, copy data to target object */
162 switch (data_object
->GetFormat().GetType())
166 if (selection_data
->type
!= GDK_SELECTION_TYPE_STRING
)
168 clipboard
->m_waiting
= FALSE
;
172 wxTextDataObject
*text_object
= (wxTextDataObject
*) data_object
;
174 wxString text
= (const char*) selection_data
->data
;
176 text_object
->SetText( text
);
183 if (selection_data
->type
!= GDK_SELECTION_TYPE_STRING
)
185 clipboard
->m_waiting
= FALSE
;
189 wxBitmapDataObject
*bitmap_object
= (wxBitmapDataObject
*) data_object
;
191 bitmap_object
->SetPngData( (const void*) selection_data
->data
, (size_t) selection_data
->length
);
198 if (selection_data
->type
!= GDK_SELECTION_TYPE_STRING
)
200 clipboard
->m_waiting
= FALSE
;
204 wxPrivateDataObject
*private_object
= (wxPrivateDataObject
*) data_object
;
206 private_object
->SetData( (const char*) selection_data
->data
, (size_t) selection_data
->length
);
213 clipboard
->m_waiting
= FALSE
;
218 wxTheClipboard
->m_formatSupported
= TRUE
;
219 clipboard
->m_waiting
= FALSE
;
222 //-----------------------------------------------------------------------------
224 //-----------------------------------------------------------------------------
227 selection_clear_clip( GtkWidget
*WXUNUSED(widget
), GdkEventSelection
*event
)
229 if (!wxTheClipboard
) return TRUE
;
231 if (event
->selection
== GDK_SELECTION_PRIMARY
)
233 wxTheClipboard
->m_ownsPrimarySelection
= FALSE
;
236 if (event
->selection
== g_clipboardAtom
)
238 wxTheClipboard
->m_ownsClipboard
= FALSE
;
242 wxTheClipboard
->m_waiting
= FALSE
;
246 if ((!wxTheClipboard
->m_ownsPrimarySelection
) &&
247 (!wxTheClipboard
->m_ownsClipboard
))
249 /* the clipboard is no longer in our hands. we can the delete clipboard data. */
250 if (wxTheClipboard
->m_data
)
252 delete wxTheClipboard
->m_data
;
253 wxTheClipboard
->m_data
= (wxDataObject
*) NULL
;
257 wxTheClipboard
->m_waiting
= FALSE
;
261 //-----------------------------------------------------------------------------
262 // selection handler for supplying data
263 //-----------------------------------------------------------------------------
266 selection_handler( GtkWidget
*WXUNUSED(widget
), GtkSelectionData
*selection_data
, gpointer
WXUNUSED(data
) )
268 if (!wxTheClipboard
) return;
270 if (!wxTheClipboard
->m_data
) return;
272 wxDataObject
*data
= wxTheClipboard
->m_data
;
274 if (!data
->IsSupportedFormat( selection_data
->target
)) return;
276 if (data
->GetFormat().GetType() == wxDF_TEXT
)
278 wxTextDataObject
*text_object
= (wxTextDataObject
*) data
;
279 wxString
text( text_object
->GetText() );
282 const wxWX2MBbuf s
= text
.mbc_str();
284 #else // more efficient in non-Unicode
285 const char *s
= text
.c_str();
286 int len
= (int) text
.Length();
288 gtk_selection_data_set(
290 GDK_SELECTION_TYPE_STRING
,
292 (unsigned char*) (const char*) s
,
298 if (data
->GetFormat().GetType() == wxDF_BITMAP
)
300 wxBitmapDataObject
*bitmap_object
= (wxBitmapDataObject
*) data
;
302 if (bitmap_object
->GetDataSize(wxDF_BITMAP
) == 0) return;
304 gtk_selection_data_set(
306 GDK_SELECTION_TYPE_STRING
,
308 (unsigned char*) bitmap_object
->GetData(),
309 (int) bitmap_object
->GetDataSize(wxDF_BITMAP
) );
314 int size
= data
->GetDataSize( selection_data
->target
);
316 if (size
== 0) return;
318 char *d
= new char[size
];
320 data
->GetDataHere( selection_data
->target
, (void*) d
);
322 gtk_selection_data_set(
324 GDK_SELECTION_TYPE_STRING
,
330 //-----------------------------------------------------------------------------
332 //-----------------------------------------------------------------------------
334 IMPLEMENT_DYNAMIC_CLASS(wxClipboard
,wxObject
)
336 wxClipboard::wxClipboard()
340 m_ownsClipboard
= FALSE
;
341 m_ownsPrimarySelection
= FALSE
;
343 m_data
= (wxDataObject
*) NULL
;
344 m_receivedData
= (wxDataObject
*) NULL
;
346 /* we use m_targetsWidget to query what formats are available */
348 m_targetsWidget
= gtk_window_new( GTK_WINDOW_POPUP
);
349 gtk_widget_realize( m_targetsWidget
);
351 gtk_signal_connect( GTK_OBJECT(m_targetsWidget
),
352 "selection_received",
353 GTK_SIGNAL_FUNC( targets_selection_received
),
356 /* we use m_clipboardWidget to get and to offer data */
358 m_clipboardWidget
= gtk_window_new( GTK_WINDOW_POPUP
);
359 gtk_widget_realize( m_clipboardWidget
);
361 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
362 "selection_received",
363 GTK_SIGNAL_FUNC( selection_received
),
366 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
367 "selection_clear_event",
368 GTK_SIGNAL_FUNC( selection_clear_clip
),
371 if (!g_clipboardAtom
) g_clipboardAtom
= gdk_atom_intern( "CLIPBOARD", FALSE
);
372 if (!g_targetsAtom
) g_targetsAtom
= gdk_atom_intern ("TARGETS", FALSE
);
374 m_formatSupported
= FALSE
;
375 m_targetRequested
= 0;
377 m_usePrimary
= FALSE
;
380 wxClipboard::~wxClipboard()
384 if (m_clipboardWidget
) gtk_widget_destroy( m_clipboardWidget
);
385 if (m_targetsWidget
) gtk_widget_destroy( m_targetsWidget
);
388 void wxClipboard::Clear()
393 /* disable GUI threads */
394 wxapp_uninstall_thread_wakeup();
397 /* As we have data we also own the clipboard. Once we no longer own
398 it, clear_selection is called which will set m_data to zero */
399 if (gdk_selection_owner_get( g_clipboardAtom
) == m_clipboardWidget
->window
)
403 gtk_selection_owner_set( (GtkWidget
*) NULL
, g_clipboardAtom
, GDK_CURRENT_TIME
);
405 while (m_waiting
) gtk_main_iteration();
408 if (gdk_selection_owner_get( GDK_SELECTION_PRIMARY
) == m_clipboardWidget
->window
)
412 gtk_selection_owner_set( (GtkWidget
*) NULL
, GDK_SELECTION_PRIMARY
, GDK_CURRENT_TIME
);
414 while (m_waiting
) gtk_main_iteration();
420 m_data
= (wxDataObject
*) NULL
;
424 /* re-enable GUI threads */
425 wxapp_install_thread_wakeup();
429 m_targetRequested
= 0;
430 m_formatSupported
= FALSE
;
433 bool wxClipboard::Open()
435 wxCHECK_MSG( !m_open
, FALSE
, wxT("clipboard already open") );
442 bool wxClipboard::SetData( wxDataObject
*data
)
444 wxCHECK_MSG( m_open
, FALSE
, wxT("clipboard not open") );
446 wxCHECK_MSG( data
, FALSE
, wxT("data is invalid") );
450 return AddData( data
);
453 bool wxClipboard::AddData( wxDataObject
*data
)
455 wxCHECK_MSG( m_open
, FALSE
, wxT("clipboard not open") );
457 wxCHECK_MSG( data
, FALSE
, wxT("data is invalid") );
459 // we can only store one wxDataObject
464 /* get native format id of new data object */
465 GdkAtom format
= data
->GetFormat();
467 wxCHECK_MSG( format
, FALSE
, wxT("data has invalid format") );
469 /* This should happen automatically, but to be on the safe side */
470 m_ownsClipboard
= FALSE
;
471 m_ownsPrimarySelection
= FALSE
;
473 /* Add handlers if someone requests data */
475 #if (GTK_MINOR_VERSION > 0)
477 gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget
),
478 GDK_SELECTION_PRIMARY
,
480 0 ); /* what is info ? */
482 gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget
),
485 0 ); /* what is info ? */
487 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
489 GTK_SIGNAL_FUNC(selection_handler
),
494 gtk_selection_add_handler( m_clipboardWidget
,
500 gtk_selection_add_handler( m_clipboardWidget
,
501 GDK_SELECTION_PRIMARY
,
508 /* disable GUI threads */
509 wxapp_uninstall_thread_wakeup();
512 /* Tell the world we offer clipboard data */
513 if (!gtk_selection_owner_set( m_clipboardWidget
,
518 /* re-enable GUI threads */
519 wxapp_install_thread_wakeup();
523 m_ownsClipboard
= TRUE
;
525 if (!gtk_selection_owner_set( m_clipboardWidget
,
526 GDK_SELECTION_PRIMARY
,
530 /* re-enable GUI threads */
531 wxapp_install_thread_wakeup();
535 m_ownsPrimarySelection
= TRUE
;
538 /* re-enable GUI threads */
539 wxapp_install_thread_wakeup();
545 void wxClipboard::Close()
547 wxCHECK_RET( m_open
, wxT("clipboard not open") );
552 bool wxClipboard::IsSupported( const wxDataFormat
& format
)
554 /* store requested format to be asked for by callbacks */
556 m_targetRequested
= format
;
558 wxCHECK_MSG( m_targetRequested
, FALSE
, wxT("invalid clipboard format") );
560 m_formatSupported
= FALSE
;
562 /* perform query. this will set m_formatSupported to
563 TRUE if m_targetRequested is supported.
564 alsom we have to wait for the "answer" from the
565 clipboard owner which is an asynchronous process.
566 therefore we set m_waiting = TRUE here and wait
567 until the callback "targets_selection_received"
572 gtk_selection_convert( m_targetsWidget
,
573 m_usePrimary
? GDK_SELECTION_PRIMARY
: g_clipboardAtom
,
577 while (m_waiting
) gtk_main_iteration();
579 if (!m_formatSupported
) return FALSE
;
584 bool wxClipboard::GetData( wxDataObject
& data
)
586 wxCHECK_MSG( m_open
, FALSE
, wxT("clipboard not open") );
588 /* is data supported by clipboard ? */
590 if (!IsSupported( data
->GetFormat() )) return FALSE
;
592 /* store pointer to data object to be filled up by callbacks */
594 m_receivedData
= data
;
596 /* store requested format to be asked for by callbacks */
598 m_targetRequested
= data
->GetFormat();
600 wxCHECK_MSG( m_targetRequested
, FALSE
, wxT("invalid clipboard format") );
604 m_formatSupported
= FALSE
;
606 /* ask for clipboard contents. this will set
607 m_formatSupported to TRUE if m_targetRequested
609 also, we have to wait for the "answer" from the
610 clipboard owner which is an asynchronous process.
611 therefore we set m_waiting = TRUE here and wait
612 until the callback "targets_selection_received"
617 gtk_selection_convert( m_clipboardWidget
,
618 m_usePrimary
? GDK_SELECTION_PRIMARY
: g_clipboardAtom
,
622 while (m_waiting
) gtk_main_iteration();
624 /* this is a true error as we checked for the presence of such data before */
626 wxCHECK_MSG( m_formatSupported
, FALSE
, wxT("error retrieving data from clipboard") );