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_clipboardAtom
= 0;
29 GdkAtom g_targetsAtom
= 0;
31 //-----------------------------------------------------------------------------
33 //-----------------------------------------------------------------------------
35 /* The contents of a selection are returned in a GtkSelectionData
36 structure. selection/target identify the request.
37 type specifies the type of the return; if length < 0, and
38 the data should be ignored. This structure has object semantics -
39 no fields should be modified directly, they should not be created
40 directly, and pointers to them should not be stored beyond the duration of
41 a callback. (If the last is changed, we'll need to add reference
44 struct _GtkSelectionData
56 //-----------------------------------------------------------------------------
57 // "selection_received" for targets
58 //-----------------------------------------------------------------------------
61 targets_selection_received( GtkWidget
*WXUNUSED(widget
),
62 GtkSelectionData
*selection_data
,
63 wxClipboard
*clipboard
)
65 if (!wxTheClipboard
) return;
67 if (selection_data
->length
<= 0) return;
69 // make sure we got the data in the correct form
70 if (selection_data
->type
!= GDK_SELECTION_TYPE_ATOM
) return;
72 // the atoms we received, holding a list of targets (= formats)
73 GdkAtom
*atoms
= (GdkAtom
*)selection_data
->data
;
75 for (unsigned int i
=0; i
<selection_data
->length
/sizeof(GdkAtom
); i
++)
77 char *name
= gdk_atom_name (atoms
[i
]);
78 if (name
) printf( "Format available: %s.\n", name
);
80 if (atoms
[i
] == clipboard
->m_targetRequested
)
82 clipboard
->m_formatSupported
= TRUE
;
90 //-----------------------------------------------------------------------------
91 // "selection_received" for the actual data
92 //-----------------------------------------------------------------------------
95 selection_received( GtkWidget
*WXUNUSED(widget
),
96 GtkSelectionData
*selection_data
,
97 wxClipboard
*clipboard
)
99 if (!wxTheClipboard
) return;
101 wxDataObject
*data_object
= clipboard
->m_receivedData
;
103 if (!data_object
) return;
105 if (selection_data
->length
<= 0) return;
107 // make sure we got the data in the correct format
109 if (data_object
->GetFormat().GetAtom() != selection_data
->target
) return;
111 // make sure we got the data in the correct form (selection type).
112 // if so, copy data to target object
114 switch (data_object
->GetFormat().GetType())
118 if (selection_data
->type
!= GDK_SELECTION_TYPE_STRING
) return;
120 wxTextDataObject
*text_object
= (wxTextDataObject
*) data_object
;
122 wxString text
= (const char*) selection_data
->data
;
124 text_object
->SetText( text
);
131 if (selection_data
->type
!= GDK_SELECTION_TYPE_BITMAP
) return;
140 if (selection_data
->type
!= GDK_SELECTION_TYPE_STRING
) return;
142 wxPrivateDataObject
*private_object
= (wxPrivateDataObject
*) data_object
;
144 private_object
->SetData( (const char*) selection_data
->data
, (size_t) selection_data
->length
);
155 wxTheClipboard
->m_formatSupported
= TRUE
;
158 //-----------------------------------------------------------------------------
160 //-----------------------------------------------------------------------------
163 selection_clear_clip( GtkWidget
*WXUNUSED(widget
), GdkEventSelection
*event
)
165 if (!wxTheClipboard
) return TRUE
;
167 if (event
->selection
== GDK_SELECTION_PRIMARY
)
169 wxTheClipboard
->m_ownsPrimarySelection
= FALSE
;
172 if (event
->selection
== g_clipboardAtom
)
174 wxTheClipboard
->m_ownsClipboard
= FALSE
;
181 if ((!wxTheClipboard
->m_ownsPrimarySelection
) &&
182 (!wxTheClipboard
->m_ownsClipboard
))
184 /* the clipboard is no longer in our hands. we can the clipboard data. */
186 if (wxTheClipboard
->m_dataBroker
)
188 delete wxTheClipboard
->m_dataBroker
;
189 wxTheClipboard
->m_dataBroker
= (wxDataBroker
*) NULL
;
196 //-----------------------------------------------------------------------------
197 // selection handler for supplying data
198 //-----------------------------------------------------------------------------
201 selection_handler( GtkWidget
*WXUNUSED(widget
), GtkSelectionData
*selection_data
, gpointer
WXUNUSED(data
) )
203 if (!wxTheClipboard
) return;
205 if (!wxTheClipboard
->m_dataBroker
) return;
207 wxNode
*node
= wxTheClipboard
->m_dataBroker
->m_dataObjects
.First();
211 wxDataObject
*data_object
= (wxDataObject
*)node
->Data();
213 if (data_object
->GetFormat().GetAtom() != selection_data
->target
)
219 switch (data_object
->GetFormat().GetType())
223 wxTextDataObject
*text_object
= (wxTextDataObject
*) data_object
;
225 wxString text
= text_object
->GetText();
227 char *s
= WXSTRINGCAST text
;
228 int len
= (int) text
.Length();
230 gtk_selection_data_set(
232 GDK_SELECTION_TYPE_STRING
,
242 // wxBitmapDataObject *private_object = (wxBitmapDataObject*) data_object;
244 // how do we do that ?
251 wxPrivateDataObject
*private_object
= (wxPrivateDataObject
*) data_object
;
253 if (private_object
->GetSize() == 0) return;
255 gtk_selection_data_set(
257 GDK_SELECTION_TYPE_STRING
,
259 (unsigned char*) private_object
->GetData(),
260 (int) private_object
->GetSize() );
271 //-----------------------------------------------------------------------------
273 //-----------------------------------------------------------------------------
275 IMPLEMENT_DYNAMIC_CLASS(wxClipboard
,wxObject
)
277 wxClipboard::wxClipboard()
281 m_ownsClipboard
= FALSE
;
282 m_ownsPrimarySelection
= FALSE
;
284 m_dataBroker
= (wxDataBroker
*) NULL
;
286 m_receivedData
= (wxDataObject
*) NULL
;
288 m_clipboardWidget
= gtk_window_new( GTK_WINDOW_POPUP
);
289 gtk_widget_realize( m_clipboardWidget
);
291 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
292 "selection_clear_event",
293 GTK_SIGNAL_FUNC( selection_clear_clip
),
296 if (!g_clipboardAtom
) g_clipboardAtom
= gdk_atom_intern( "CLIPBOARD", FALSE
);
297 if (!g_targetsAtom
) g_targetsAtom
= gdk_atom_intern ("TARGETS", FALSE
);
299 m_formatSupported
= FALSE
;
300 m_targetRequested
= 0;
303 wxClipboard::~wxClipboard()
307 if (m_clipboardWidget
) gtk_widget_destroy( m_clipboardWidget
);
310 void wxClipboard::Clear()
314 /* As we have data we also own the clipboard. Once we no longer own
315 it, clear_selection is called which will set m_data to zero */
317 if (gdk_selection_owner_get( g_clipboardAtom
) == m_clipboardWidget
->window
)
319 gtk_selection_owner_set( (GtkWidget
*) NULL
, g_clipboardAtom
, GDK_CURRENT_TIME
);
322 if (gdk_selection_owner_get( GDK_SELECTION_PRIMARY
) == m_clipboardWidget
->window
)
324 gtk_selection_owner_set( (GtkWidget
*) NULL
, GDK_SELECTION_PRIMARY
, GDK_CURRENT_TIME
);
330 m_dataBroker
= (wxDataBroker
*) NULL
;
334 m_targetRequested
= 0;
336 m_formatSupported
= FALSE
;
339 bool wxClipboard::Open()
341 wxCHECK_MSG( !m_open
, FALSE
, "clipboard already open" );
348 bool wxClipboard::SetData( wxDataObject
*data
)
350 wxCHECK_MSG( m_open
, FALSE
, "clipboard not open" );
352 wxCHECK_MSG( data
, FALSE
, "data is invalid" );
356 return AddData( data
);
359 bool wxClipboard::AddData( wxDataObject
*data
)
361 wxCHECK_MSG( m_open
, FALSE
, "clipboard not open" );
363 wxCHECK_MSG( data
, FALSE
, "data is invalid" );
365 /* if clipboard has been cleared before, create new data broker */
367 if (!m_dataBroker
) m_dataBroker
= new wxDataBroker();
369 /* add new data to list of offered data objects */
371 m_dataBroker
->Add( data
);
373 /* get native format id of new data object */
375 GdkAtom format
= data
->GetFormat().GetAtom();
377 wxCHECK_MSG( format
, FALSE
, "data has invalid format" );
379 /* This should happen automatically, but to be on the safe side */
381 m_ownsClipboard
= FALSE
;
382 m_ownsPrimarySelection
= FALSE
;
384 /* Add handlers if someone requests data */
387 #if (GTK_MINOR_VERSION > 0)
389 gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget
),
390 GDK_SELECTION_PRIMARY
,
392 0 ); /* what is info ? */
394 gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget
),
397 0 ); /* what is info ? */
399 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
401 GTK_SIGNAL_FUNC(selection_handler
),
406 gtk_selection_add_handler( m_clipboardWidget
,
412 gtk_selection_add_handler( m_clipboardWidget
,
413 GDK_SELECTION_PRIMARY
,
419 /* Tell the world we offer clipboard data */
421 if (!gtk_selection_owner_set( m_clipboardWidget
,
427 m_ownsClipboard
= TRUE
;
429 if (!gtk_selection_owner_set( m_clipboardWidget
,
430 GDK_SELECTION_PRIMARY
,
435 m_ownsPrimarySelection
= TRUE
;
440 void wxClipboard::Close()
442 wxCHECK_RET( m_open
, "clipboard not open" );
447 bool wxClipboard::IsSupported( wxDataFormat format
)
449 wxCHECK_MSG( m_open
, FALSE
, "clipboard not open" );
451 /* store requested format to be asked for by callbacks */
453 m_targetRequested
= format
.GetAtom();
455 wxCHECK_MSG( m_targetRequested
, FALSE
, "invalid clipboard format" );
457 /* add handler for target (= format) query */
459 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
460 "selection_received",
461 GTK_SIGNAL_FUNC( targets_selection_received
),
464 m_formatSupported
= FALSE
;
466 /* perform query. this will set m_formatSupported to
467 * TRUE if m_targetRequested is supported */
469 gtk_selection_convert( m_clipboardWidget
,
474 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget
),
475 GTK_SIGNAL_FUNC( targets_selection_received
),
478 if (!m_formatSupported
) return FALSE
;
483 bool wxClipboard::GetData( wxDataObject
*data
)
485 wxCHECK_MSG( m_open
, FALSE
, "clipboard not open" );
487 /* is data supported by clipboard ? */
489 if (!IsSupported( data
->GetFormat() )) return FALSE
;
491 /* store pointer to data object to be filled up by callbacks */
493 m_receivedData
= data
;
495 /* store requested format to be asked for by callbacks */
497 m_targetRequested
= data
->GetFormat().GetAtom();
499 wxCHECK_MSG( m_targetRequested
, FALSE
, "invalid clipboard format" );
503 m_formatSupported
= FALSE
;
505 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
506 "selection_received",
507 GTK_SIGNAL_FUNC( selection_received
),
510 /* ask for clipboard contents */
512 gtk_selection_convert( m_clipboardWidget
,
517 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget
),
518 GTK_SIGNAL_FUNC( selection_received
),
521 /* this is a true error as we checked for the presence of such data before */
523 wxCHECK_MSG( m_formatSupported
, FALSE
, "error retrieving data from clipboard" );
528 //-----------------------------------------------------------------------------
530 //-----------------------------------------------------------------------------
532 IMPLEMENT_DYNAMIC_CLASS(wxClipboardModule
,wxModule
)
534 bool wxClipboardModule::OnInit()
536 wxTheClipboard
= new wxClipboard();
541 void wxClipboardModule::OnExit()
543 if (wxTheClipboard
) delete wxTheClipboard
;
544 wxTheClipboard
= (wxClipboard
*) NULL
;