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"
22 //-----------------------------------------------------------------------------
24 //-----------------------------------------------------------------------------
26 wxClipboard
*wxTheClipboard
= (wxClipboard
*) NULL
;
28 GdkAtom g_textAtom
= 0;
29 GdkAtom g_clipboardAtom
= 0;
30 GdkAtom g_targetsAtom
= 0;
32 //-----------------------------------------------------------------------------
34 //-----------------------------------------------------------------------------
36 /* The contents of a selection are returned in a GtkSelectionData
37 structure. selection/target identify the request.
38 type specifies the type of the return; if length < 0, and
39 the data should be ignored. This structure has object semantics -
40 no fields should be modified directly, they should not be created
41 directly, and pointers to them should not be stored beyond the duration of
42 a callback. (If the last is changed, we'll need to add reference
45 struct _GtkSelectionData
57 //-----------------------------------------------------------------------------
58 // "selection_received" for targets
59 //-----------------------------------------------------------------------------
62 targets_selection_received( GtkWidget
*WXUNUSED(widget
),
63 GtkSelectionData
*selection_data
,
64 wxClipboard
*clipboard
)
66 if (!wxTheClipboard
) return;
68 if (selection_data
->length
<= 0) return;
70 // make sure we got the data in the correct form
71 if (selection_data
->type
!= GDK_SELECTION_TYPE_ATOM
) return;
73 // the atoms we received, holding a list of targets (= formats)
74 GdkAtom
*atoms
= (GdkAtom
*)selection_data
->data
;
76 for (unsigned int i
=0; i
<selection_data
->length
/sizeof(GdkAtom
); i
++)
78 if (atoms
[i
] == clipboard
->m_targetRequested
)
80 clipboard
->m_formatSupported
= TRUE
;
88 //-----------------------------------------------------------------------------
89 // "selection_received" for the actual data
90 //-----------------------------------------------------------------------------
93 selection_received( GtkWidget
*WXUNUSED(widget
),
94 GtkSelectionData
*selection_data
,
95 wxClipboard
*clipboard
)
97 if (!wxTheClipboard
) return;
99 wxDataObject
*data_object
= clipboard
->m_receivedData
;
101 if (!data_object
) return;
103 if (selection_data
->length
<= 0) return;
105 // make sure we got the data in the correct format
107 if (data_object
->GetFormat().GetAtom() != selection_data
->target
) return;
109 // make sure we got the data in the correct form (selection type).
110 // if so, copy data to target object
112 switch (data_object
->GetFormat().GetType())
116 if (selection_data
->type
!= GDK_SELECTION_TYPE_STRING
) return;
118 wxTextDataObject
*text_object
= (wxTextDataObject
*) data_object
;
120 wxString text
= (const char*) selection_data
->data
;
122 text_object
->SetText( text
);
129 if (selection_data
->type
!= GDK_SELECTION_TYPE_BITMAP
) return;
138 if (selection_data
->type
!= GDK_SELECTION_TYPE_STRING
) return;
140 wxPrivateDataObject
*private_object
= (wxPrivateDataObject
*) data_object
;
142 private_object
->SetData( (const char*) selection_data
->data
, (size_t) selection_data
->length
);
153 wxTheClipboard
->m_formatSupported
= TRUE
;
156 //-----------------------------------------------------------------------------
158 //-----------------------------------------------------------------------------
161 selection_clear_clip( GtkWidget
*WXUNUSED(widget
), GdkEventSelection
*event
)
163 if (!wxTheClipboard
) return TRUE
;
165 if (event
->selection
== GDK_SELECTION_PRIMARY
)
167 wxTheClipboard
->m_ownsPrimarySelection
= FALSE
;
170 if (event
->selection
== g_clipboardAtom
)
172 wxTheClipboard
->m_ownsClipboard
= FALSE
;
179 if ((!wxTheClipboard
->m_ownsPrimarySelection
) &&
180 (!wxTheClipboard
->m_ownsClipboard
))
182 /* the clipboard is no longer in our hands. we can the clipboard data. */
184 if (wxTheClipboard
->m_dataBroker
)
186 delete wxTheClipboard
->m_dataBroker
;
187 wxTheClipboard
->m_dataBroker
= (wxDataBroker
*) NULL
;
194 //-----------------------------------------------------------------------------
195 // selection handler for supplying data
196 //-----------------------------------------------------------------------------
199 selection_handler( GtkWidget
*WXUNUSED(widget
), GtkSelectionData
*selection_data
, gpointer
WXUNUSED(data
) )
201 if (!wxTheClipboard
) return;
203 if (!wxTheClipboard
->m_dataBroker
) return;
205 wxNode
*node
= wxTheClipboard
->m_dataBroker
->m_dataObjects
.First();
209 wxDataObject
*data_object
= (wxDataObject
*)node
->Data();
211 if (data_object
->GetFormat().GetAtom() != selection_data
->target
)
217 switch (data_object
->GetFormat().GetType())
221 wxTextDataObject
*text_object
= (wxTextDataObject
*) data_object
;
223 wxString text
= text_object
->GetText();
225 char *s
= WXSTRINGCAST text
;
226 int len
= (int) text
.Length();
228 gtk_selection_data_set(
230 GDK_SELECTION_TYPE_STRING
,
240 // wxBitmapDataObject *private_object = (wxBitmapDataObject*) data_object;
242 // how do we do that ?
249 wxPrivateDataObject
*private_object
= (wxPrivateDataObject
*) data_object
;
251 if (private_object
->GetSize() == 0) return;
253 gtk_selection_data_set(
255 GDK_SELECTION_TYPE_STRING
,
257 (unsigned char*) private_object
->GetData(),
258 (int) private_object
->GetSize() );
269 //-----------------------------------------------------------------------------
271 //-----------------------------------------------------------------------------
273 IMPLEMENT_DYNAMIC_CLASS(wxClipboard
,wxObject
)
275 wxClipboard::wxClipboard()
279 m_ownsClipboard
= FALSE
;
280 m_ownsPrimarySelection
= FALSE
;
282 m_dataBroker
= (wxDataBroker
*) NULL
;
284 m_receivedData
= (wxDataObject
*) NULL
;
286 m_clipboardWidget
= gtk_window_new( GTK_WINDOW_POPUP
);
287 gtk_widget_realize( m_clipboardWidget
);
289 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
290 "selection_clear_event",
291 GTK_SIGNAL_FUNC( selection_clear_clip
),
294 if (!g_clipboardAtom
) g_clipboardAtom
= gdk_atom_intern( "CLIPBOARD", FALSE
);
295 if (!g_textAtom
) g_textAtom
= gdk_atom_intern( "TEXT", FALSE
);
296 if (!g_targetsAtom
) g_targetsAtom
= gdk_atom_intern ("TARGETS", FALSE
);
298 m_formatSupported
= FALSE
;
299 m_targetRequested
= 0;
302 wxClipboard::~wxClipboard()
306 if (m_clipboardWidget
) gtk_widget_destroy( m_clipboardWidget
);
309 void wxClipboard::Clear()
313 /* As we have data we also own the clipboard. Once we no longer own
314 it, clear_selection is called which will set m_data to zero */
316 if (gdk_selection_owner_get( g_clipboardAtom
) == m_clipboardWidget
->window
)
318 gtk_selection_owner_set( (GtkWidget
*) NULL
, g_clipboardAtom
, GDK_CURRENT_TIME
);
321 if (gdk_selection_owner_get( GDK_SELECTION_PRIMARY
) == m_clipboardWidget
->window
)
323 gtk_selection_owner_set( (GtkWidget
*) NULL
, GDK_SELECTION_PRIMARY
, GDK_CURRENT_TIME
);
329 m_dataBroker
= (wxDataBroker
*) NULL
;
333 m_targetRequested
= 0;
335 m_formatSupported
= FALSE
;
338 bool wxClipboard::Open()
340 wxCHECK_MSG( !m_open
, FALSE
, "clipboard already open" );
347 bool wxClipboard::SetData( wxDataObject
*data
)
349 wxCHECK_MSG( m_open
, FALSE
, "clipboard not open" );
351 wxCHECK_MSG( data
, FALSE
, "data is invalid" );
355 return AddData( data
);
358 bool wxClipboard::AddData( wxDataObject
*data
)
360 wxCHECK_MSG( m_open
, FALSE
, "clipboard not open" );
362 wxCHECK_MSG( data
, FALSE
, "data is invalid" );
364 /* if clipboard has been cleared before, create new data broker */
366 if (!m_dataBroker
) m_dataBroker
= new wxDataBroker();
368 /* add new data to list of offered data objects */
370 m_dataBroker
->Add( data
);
372 /* get native format id of new data object */
374 GdkAtom format
= data
->GetFormat().GetAtom();
376 wxCHECK_MSG( format
, FALSE
, "data has invalid format" );
378 /* This should happen automatically, but to be on the safe side */
380 m_ownsClipboard
= FALSE
;
381 m_ownsPrimarySelection
= FALSE
;
383 /* Add handlers if someone requests data */
385 gtk_selection_add_handler( m_clipboardWidget
,
391 gtk_selection_add_handler( m_clipboardWidget
,
392 GDK_SELECTION_PRIMARY
,
397 /* Tell the world we offer clipboard data */
399 if (!gtk_selection_owner_set( m_clipboardWidget
,
405 m_ownsClipboard
= TRUE
;
407 if (!gtk_selection_owner_set( m_clipboardWidget
,
408 GDK_SELECTION_PRIMARY
,
413 m_ownsPrimarySelection
= TRUE
;
418 void wxClipboard::Close()
420 wxCHECK_RET( m_open
, "clipboard not open" );
425 bool wxClipboard::IsSupported( wxDataFormat format
)
427 wxCHECK_MSG( m_open
, FALSE
, "clipboard not open" );
429 /* store requested format to be asked for by callbacks */
431 m_targetRequested
= format
.GetAtom();
433 wxCHECK_MSG( m_targetRequested
, FALSE
, "invalid clipboard format" );
435 /* add handler for target (= format) query */
437 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
438 "selection_received",
439 GTK_SIGNAL_FUNC( targets_selection_received
),
442 m_formatSupported
= FALSE
;
444 /* perform query. this will set m_formatSupported to
445 * TRUE if m_targetRequested is supported */
447 gtk_selection_convert( m_clipboardWidget
,
452 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget
),
453 GTK_SIGNAL_FUNC( targets_selection_received
),
456 if (!m_formatSupported
) return FALSE
;
461 bool wxClipboard::GetData( wxDataObject
*data
)
463 wxCHECK_MSG( m_open
, FALSE
, "clipboard not open" );
465 /* is data supported by clipboard ? */
467 if (!IsSupported( data
->GetFormat() )) return FALSE
;
469 /* store pointer to data object to be filled up by callbacks */
471 m_receivedData
= data
;
473 /* store requested format to be asked for by callbacks */
475 m_targetRequested
= data
->GetFormat().GetAtom();
477 wxCHECK_MSG( m_targetRequested
, FALSE
, "invalid clipboard format" );
481 m_formatSupported
= FALSE
;
483 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
484 "selection_received",
485 GTK_SIGNAL_FUNC( selection_received
),
488 /* ask for clipboard contents */
490 gtk_selection_convert( m_clipboardWidget
,
495 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget
),
496 GTK_SIGNAL_FUNC( selection_received
),
499 /* this is a true error as we checked for the presence of such data before */
501 wxCHECK_MSG( m_formatSupported
, FALSE
, "error retrieving data from clipboard" );
506 //-----------------------------------------------------------------------------
508 //-----------------------------------------------------------------------------
510 IMPLEMENT_DYNAMIC_CLASS(wxClipboardModule
,wxModule
)
512 bool wxClipboardModule::OnInit()
514 wxTheClipboard
= new wxClipboard();
519 void wxClipboardModule::OnExit()
521 if (wxTheClipboard
) delete wxTheClipboard
;
522 wxTheClipboard
= (wxClipboard
*) NULL
;