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"
16 //-----------------------------------------------------------------------------
18 //-----------------------------------------------------------------------------
20 wxClipboard
*wxTheClipboard
= (wxClipboard
*) NULL
;
22 GdkAtom g_textAtom
= 0;
23 GdkAtom g_clipboardAtom
= 0;
24 GdkAtom g_targetsAtom
= 0;
26 //-----------------------------------------------------------------------------
28 //-----------------------------------------------------------------------------
30 /* The contents of a selection are returned in a GtkSelectionData
31 structure. selection/target identify the request.
32 type specifies the type of the return; if length < 0, and
33 the data should be ignored. This structure has object semantics -
34 no fields should be modified directly, they should not be created
35 directly, and pointers to them should not be stored beyond the duration of
36 a callback. (If the last is changed, we'll need to add reference
39 struct _GtkSelectionData
51 //-----------------------------------------------------------------------------
52 // "selection_received" for targets
53 //-----------------------------------------------------------------------------
56 targets_selection_received( GtkWidget
*WXUNUSED(widget
),
57 GtkSelectionData
*selection_data
,
58 wxClipboard
*clipboard
)
60 if (!wxTheClipboard
) return;
62 if (selection_data
->length
<= 0) return;
64 // make sure we got the data in the correct form
65 if (selection_data
->type
!= GDK_SELECTION_TYPE_ATOM
) return;
67 // the atoms we received, holding a list of targets (= formats)
68 GdkAtom
*atoms
= (GdkAtom
*)selection_data
->data
;
70 for (unsigned int i
=0; i
<selection_data
->length
/sizeof(GdkAtom
); i
++)
72 if (atoms
[i
] == clipboard
->m_targetRequested
)
74 clipboard
->m_formatSupported
= TRUE
;
82 //-----------------------------------------------------------------------------
83 // "selection_received" for the actual data
84 //-----------------------------------------------------------------------------
87 selection_received( GtkWidget
*WXUNUSED(widget
),
88 GtkSelectionData
*selection_data
,
89 wxClipboard
*clipboard
)
91 if (!wxTheClipboard
) return;
93 wxDataObject
*data_object
= clipboard
->m_receivedData
;
95 if (!data_object
) return;
97 if (selection_data
->length
<= 0) return;
99 // make sure we got the data in the correct format
101 if (data_object
->m_formatAtom
!= selection_data
->target
) return;
103 // make sure we got the data in the correct form (selection type).
104 // if so, copy data to target object
106 switch (data_object
->GetFormat())
110 if (selection_data
->type
!= GDK_SELECTION_TYPE_STRING
) return;
112 wxTextDataObject
*text_object
= (wxTextDataObject
*) data_object
;
114 wxString text
= (const char*) selection_data
->data
;
116 text_object
->SetText( text
);
123 if (selection_data
->type
!= GDK_SELECTION_TYPE_BITMAP
) return;
132 if (selection_data
->type
!= GDK_SELECTION_TYPE_STRING
) return;
134 wxPrivateDataObject
*private_object
= (wxPrivateDataObject
*) data_object
;
136 private_object
->SetData( (const char*) selection_data
->data
, (size_t) selection_data
->length
);
147 wxTheClipboard
->m_formatSupported
= TRUE
;
150 //-----------------------------------------------------------------------------
152 //-----------------------------------------------------------------------------
155 selection_clear_clip( GtkWidget
*WXUNUSED(widget
), GdkEventSelection
*event
)
157 if (!wxTheClipboard
) return TRUE
;
159 if (event
->selection
== GDK_SELECTION_PRIMARY
)
161 wxTheClipboard
->m_ownsPrimarySelection
= FALSE
;
164 if (event
->selection
== g_clipboardAtom
)
166 wxTheClipboard
->m_ownsClipboard
= FALSE
;
173 if ((!wxTheClipboard
->m_ownsPrimarySelection
) &&
174 (!wxTheClipboard
->m_ownsClipboard
))
176 // the clipboard is no longer in our hands. we can the
179 wxTheClipboard
->m_dataObjects
.Clear();
185 //-----------------------------------------------------------------------------
186 // selection handler for supplying data
187 //-----------------------------------------------------------------------------
190 selection_handler( GtkWidget
*WXUNUSED(widget
), GtkSelectionData
*selection_data
, gpointer
WXUNUSED(data
) )
192 if (!wxTheClipboard
) return;
194 wxNode
*node
= wxTheClipboard
->m_dataObjects
.First();
198 wxDataObject
*data_object
= (wxDataObject
*)node
->Data();
200 if (data_object
->m_formatAtom
!= selection_data
->target
)
206 switch (data_object
->GetFormat())
210 wxTextDataObject
*text_object
= (wxTextDataObject
*) data_object
;
212 wxString text
= text_object
->GetText();
214 char *s
= WXSTRINGCAST text
;
215 int len
= (int) text
.Length();
217 gtk_selection_data_set(
219 GDK_SELECTION_TYPE_STRING
,
229 // wxBitmapDataObject *private_object = (wxBitmapDataObject*) data_object;
231 // how do we do that ?
238 wxPrivateDataObject
*private_object
= (wxPrivateDataObject
*) data_object
;
240 if (private_object
->GetDataSize() == 0) return;
242 gtk_selection_data_set(
244 GDK_SELECTION_TYPE_STRING
,
246 (unsigned char*) private_object
->GetData(),
247 (int) private_object
->GetDataSize() );
258 //-----------------------------------------------------------------------------
260 //-----------------------------------------------------------------------------
262 IMPLEMENT_DYNAMIC_CLASS(wxClipboard
,wxObject
)
264 wxClipboard::wxClipboard()
268 m_ownsClipboard
= FALSE
;
269 m_ownsPrimarySelection
= FALSE
;
271 m_dataObjects
.DeleteContents( TRUE
);
273 m_receivedData
= (wxDataObject
*) NULL
;
275 m_clipboardWidget
= gtk_window_new( GTK_WINDOW_POPUP
);
276 gtk_widget_realize( m_clipboardWidget
);
278 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
279 "selection_clear_event",
280 GTK_SIGNAL_FUNC( selection_clear_clip
),
283 if (!g_clipboardAtom
) g_clipboardAtom
= gdk_atom_intern( "CLIPBOARD", FALSE
);
284 if (!g_textAtom
) g_textAtom
= gdk_atom_intern( "TEXT", FALSE
);
285 if (!g_targetsAtom
) g_targetsAtom
= gdk_atom_intern ("TARGETS", FALSE
);
287 m_formatSupported
= FALSE
;
288 m_targetRequested
= 0;
291 wxClipboard::~wxClipboard()
295 if (m_clipboardWidget
) gtk_widget_destroy( m_clipboardWidget
);
298 void wxClipboard::Clear()
300 if (m_dataObjects
.GetCount())
302 /* As we have data we also own the clipboard. Once we no longer own
303 it, clear_selection is called which will set m_data to zero */
305 if (gdk_selection_owner_get( g_clipboardAtom
) == m_clipboardWidget
->window
)
307 gtk_selection_owner_set( (GtkWidget
*) NULL
, g_clipboardAtom
, GDK_CURRENT_TIME
);
310 if (gdk_selection_owner_get( GDK_SELECTION_PRIMARY
) == m_clipboardWidget
->window
)
312 gtk_selection_owner_set( (GtkWidget
*) NULL
, GDK_SELECTION_PRIMARY
, GDK_CURRENT_TIME
);
315 m_dataObjects
.Clear();
318 m_targetRequested
= 0;
320 m_formatSupported
= FALSE
;
323 bool wxClipboard::Open()
325 wxCHECK_MSG( !m_open
, FALSE
, "clipboard already open" );
332 bool wxClipboard::SetData( wxDataObject
*data
)
334 wxCHECK_MSG( data
, FALSE
, "data is invalid" );
336 wxNode
*node
= m_dataObjects
.First();
340 wxDataObject
*d
= (wxDataObject
*)node
->Data();
342 if (d
->GetFormat() == data
->GetFormat())
344 m_dataObjects
.DeleteNode( node
);
352 m_dataObjects
.Append( data
);
354 wxCHECK_MSG( m_open
, FALSE
, "clipboard not open" );
356 if (data
->GetFormat() == wxDF_PRIVATE
)
358 wxPrivateDataObject
* pd
= (wxPrivateDataObject
*) data
;
360 wxCHECK_MSG( !pd
->GetId().IsEmpty(), FALSE
, "private clipboard format requires ID string" );
362 data
->m_formatAtom
= GetTargetAtom( data
->GetFormat(), pd
->GetId() );
366 data
->m_formatAtom
= GetTargetAtom( data
->GetFormat() );
369 // This should happen automatically
371 m_ownsClipboard
= FALSE
;
372 m_ownsPrimarySelection
= FALSE
;
374 // Add handlers if someone requests data
376 gtk_selection_add_handler( m_clipboardWidget
,
382 gtk_selection_add_handler( m_clipboardWidget
,
383 GDK_SELECTION_PRIMARY
,
388 // Tell the world we offer clipboard data
390 if (!gtk_selection_owner_set( m_clipboardWidget
,
396 m_ownsClipboard
= TRUE
;
398 if (!gtk_selection_owner_set( m_clipboardWidget
,
399 GDK_SELECTION_PRIMARY
,
404 m_ownsPrimarySelection
= TRUE
;
409 void wxClipboard::Close()
411 wxCHECK_RET( m_open
, "clipboard not open" );
416 bool wxClipboard::IsSupportedFormat( wxDataFormat format
, const wxString
&id
)
418 m_targetRequested
= GetTargetAtom( format
, id
);
420 if (m_targetRequested
== 0) return FALSE
;
422 // add handler for target (= format) query
424 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
425 "selection_received",
426 GTK_SIGNAL_FUNC( targets_selection_received
),
429 m_formatSupported
= FALSE
;
431 // perform query. this will set m_formatSupported to
432 // TRUE if m_targetRequested is supported
434 gtk_selection_convert( m_clipboardWidget
,
439 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget
),
440 GTK_SIGNAL_FUNC( targets_selection_received
),
443 if (!m_formatSupported
) return FALSE
;
448 bool wxClipboard::GetData( wxDataObject
*data
)
450 wxCHECK_MSG( m_open
, FALSE
, "clipboard not open" );
452 m_receivedData
= data
;
454 wxCHECK_MSG( m_receivedData
, FALSE
, "invalid data object" );
456 if (m_receivedData
->GetFormat() == wxDF_PRIVATE
)
458 wxPrivateDataObject
* pd
= (wxPrivateDataObject
*) m_receivedData
;
460 wxCHECK_MSG( !pd
->GetId().IsEmpty(), FALSE
, "private clipboard format requires ID string" );
462 m_targetRequested
= GetTargetAtom( m_receivedData
->GetFormat(), pd
->GetId() );
466 m_targetRequested
= GetTargetAtom( m_receivedData
->GetFormat() );
469 data
->m_formatAtom
= m_targetRequested
;
471 wxCHECK_MSG( m_targetRequested
, FALSE
, "unsupported clipboard format" );
473 m_formatSupported
= FALSE
;
475 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
476 "selection_received",
477 GTK_SIGNAL_FUNC( selection_received
),
480 gtk_selection_convert( m_clipboardWidget
,
485 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget
),
486 GTK_SIGNAL_FUNC( selection_received
),
489 wxCHECK_MSG( m_formatSupported
, FALSE
, "error retrieving data from clipboard" );
494 GdkAtom
wxClipboard::GetTargetAtom( wxDataFormat format
, const wxString
&id
)
496 // What is X representation of that format?
502 return GDK_TARGET_STRING
;
508 return GDK_TARGET_BITMAP
;
514 // we create our own X representation
516 return gdk_atom_intern( WXSTRINGCAST( id
), FALSE
);
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
;