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"
20 //-----------------------------------------------------------------------------
22 //-----------------------------------------------------------------------------
24 wxClipboard
*wxTheClipboard
= (wxClipboard
*) NULL
;
26 GdkAtom g_textAtom
= 0;
27 GdkAtom g_clipboardAtom
= 0;
28 GdkAtom g_targetsAtom
= 0;
30 //-----------------------------------------------------------------------------
32 //-----------------------------------------------------------------------------
34 /* The contents of a selection are returned in a GtkSelectionData
35 structure. selection/target identify the request.
36 type specifies the type of the return; if length < 0, and
37 the data should be ignored. This structure has object semantics -
38 no fields should be modified directly, they should not be created
39 directly, and pointers to them should not be stored beyond the duration of
40 a callback. (If the last is changed, we'll need to add reference
43 struct _GtkSelectionData
55 //-----------------------------------------------------------------------------
56 // "selection_received" for targets
57 //-----------------------------------------------------------------------------
60 targets_selection_received( GtkWidget
*WXUNUSED(widget
),
61 GtkSelectionData
*selection_data
,
62 wxClipboard
*clipboard
)
64 if (!wxTheClipboard
) return;
66 if (selection_data
->length
<= 0) return;
68 // make sure we got the data in the correct form
69 if (selection_data
->type
!= GDK_SELECTION_TYPE_ATOM
) return;
71 // the atoms we received, holding a list of targets (= formats)
72 GdkAtom
*atoms
= (GdkAtom
*)selection_data
->data
;
74 for (unsigned int i
=0; i
<selection_data
->length
/sizeof(GdkAtom
); i
++)
76 if (atoms
[i
] == clipboard
->m_targetRequested
)
78 clipboard
->m_formatSupported
= TRUE
;
86 //-----------------------------------------------------------------------------
87 // "selection_received" for the actual data
88 //-----------------------------------------------------------------------------
91 selection_received( GtkWidget
*WXUNUSED(widget
),
92 GtkSelectionData
*selection_data
,
93 wxClipboard
*clipboard
)
95 if (!wxTheClipboard
) return;
97 wxDataObject
*data_object
= clipboard
->m_receivedData
;
99 if (!data_object
) return;
101 if (selection_data
->length
<= 0) return;
103 // make sure we got the data in the correct format
105 if (data_object
->m_formatAtom
!= selection_data
->target
) return;
107 // make sure we got the data in the correct form (selection type).
108 // if so, copy data to target object
110 switch (data_object
->GetFormat())
114 if (selection_data
->type
!= GDK_SELECTION_TYPE_STRING
) return;
116 wxTextDataObject
*text_object
= (wxTextDataObject
*) data_object
;
118 wxString text
= (const char*) selection_data
->data
;
120 text_object
->SetText( text
);
127 if (selection_data
->type
!= GDK_SELECTION_TYPE_BITMAP
) return;
136 if (selection_data
->type
!= GDK_SELECTION_TYPE_STRING
) return;
138 wxPrivateDataObject
*private_object
= (wxPrivateDataObject
*) data_object
;
140 private_object
->SetData( (const char*) selection_data
->data
, (size_t) selection_data
->length
);
151 wxTheClipboard
->m_formatSupported
= TRUE
;
154 //-----------------------------------------------------------------------------
156 //-----------------------------------------------------------------------------
159 selection_clear_clip( GtkWidget
*WXUNUSED(widget
), GdkEventSelection
*event
)
161 if (!wxTheClipboard
) return TRUE
;
163 if (event
->selection
== GDK_SELECTION_PRIMARY
)
165 wxTheClipboard
->m_ownsPrimarySelection
= FALSE
;
168 if (event
->selection
== g_clipboardAtom
)
170 wxTheClipboard
->m_ownsClipboard
= FALSE
;
177 if ((!wxTheClipboard
->m_ownsPrimarySelection
) &&
178 (!wxTheClipboard
->m_ownsClipboard
))
180 // the clipboard is no longer in our hands. we can the
183 wxTheClipboard
->m_dataObjects
.Clear();
189 //-----------------------------------------------------------------------------
190 // selection handler for supplying data
191 //-----------------------------------------------------------------------------
194 selection_handler( GtkWidget
*WXUNUSED(widget
), GtkSelectionData
*selection_data
, gpointer
WXUNUSED(data
) )
196 if (!wxTheClipboard
) return;
198 wxNode
*node
= wxTheClipboard
->m_dataObjects
.First();
202 wxDataObject
*data_object
= (wxDataObject
*)node
->Data();
204 if (data_object
->m_formatAtom
!= selection_data
->target
)
210 switch (data_object
->GetFormat())
214 wxTextDataObject
*text_object
= (wxTextDataObject
*) data_object
;
216 wxString text
= text_object
->GetText();
218 char *s
= WXSTRINGCAST text
;
219 int len
= (int) text
.Length();
221 gtk_selection_data_set(
223 GDK_SELECTION_TYPE_STRING
,
233 // wxBitmapDataObject *private_object = (wxBitmapDataObject*) data_object;
235 // how do we do that ?
242 wxPrivateDataObject
*private_object
= (wxPrivateDataObject
*) data_object
;
244 if (private_object
->GetDataSize() == 0) return;
246 gtk_selection_data_set(
248 GDK_SELECTION_TYPE_STRING
,
250 (unsigned char*) private_object
->GetData(),
251 (int) private_object
->GetDataSize() );
262 //-----------------------------------------------------------------------------
264 //-----------------------------------------------------------------------------
266 IMPLEMENT_DYNAMIC_CLASS(wxClipboard
,wxObject
)
268 wxClipboard::wxClipboard()
272 m_ownsClipboard
= FALSE
;
273 m_ownsPrimarySelection
= FALSE
;
275 m_dataObjects
.DeleteContents( TRUE
);
277 m_receivedData
= (wxDataObject
*) NULL
;
279 m_clipboardWidget
= gtk_window_new( GTK_WINDOW_POPUP
);
280 gtk_widget_realize( m_clipboardWidget
);
282 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
283 "selection_clear_event",
284 GTK_SIGNAL_FUNC( selection_clear_clip
),
287 if (!g_clipboardAtom
) g_clipboardAtom
= gdk_atom_intern( "CLIPBOARD", FALSE
);
288 if (!g_textAtom
) g_textAtom
= gdk_atom_intern( "TEXT", FALSE
);
289 if (!g_targetsAtom
) g_targetsAtom
= gdk_atom_intern ("TARGETS", FALSE
);
291 m_formatSupported
= FALSE
;
292 m_targetRequested
= 0;
295 wxClipboard::~wxClipboard()
299 if (m_clipboardWidget
) gtk_widget_destroy( m_clipboardWidget
);
302 void wxClipboard::Clear()
304 if (m_dataObjects
.GetCount())
306 /* As we have data we also own the clipboard. Once we no longer own
307 it, clear_selection is called which will set m_data to zero */
309 if (gdk_selection_owner_get( g_clipboardAtom
) == m_clipboardWidget
->window
)
311 gtk_selection_owner_set( (GtkWidget
*) NULL
, g_clipboardAtom
, GDK_CURRENT_TIME
);
314 if (gdk_selection_owner_get( GDK_SELECTION_PRIMARY
) == m_clipboardWidget
->window
)
316 gtk_selection_owner_set( (GtkWidget
*) NULL
, GDK_SELECTION_PRIMARY
, GDK_CURRENT_TIME
);
319 m_dataObjects
.Clear();
322 m_targetRequested
= 0;
324 m_formatSupported
= FALSE
;
327 bool wxClipboard::Open()
329 wxCHECK_MSG( !m_open
, FALSE
, "clipboard already open" );
336 bool wxClipboard::SetData( wxDataObject
*data
)
338 wxCHECK_MSG( data
, FALSE
, "data is invalid" );
340 wxNode
*node
= m_dataObjects
.First();
344 wxDataObject
*d
= (wxDataObject
*)node
->Data();
346 if (d
->GetFormat() == data
->GetFormat())
348 m_dataObjects
.DeleteNode( node
);
356 m_dataObjects
.Append( data
);
358 wxCHECK_MSG( m_open
, FALSE
, "clipboard not open" );
360 if (data
->GetFormat() == wxDF_PRIVATE
)
362 wxPrivateDataObject
* pd
= (wxPrivateDataObject
*) data
;
364 wxCHECK_MSG( !pd
->GetId().IsEmpty(), FALSE
, "private clipboard format requires ID string" );
366 data
->m_formatAtom
= GetTargetAtom( data
->GetFormat(), pd
->GetId() );
370 data
->m_formatAtom
= GetTargetAtom( data
->GetFormat() );
373 // This should happen automatically
375 m_ownsClipboard
= FALSE
;
376 m_ownsPrimarySelection
= FALSE
;
378 // Add handlers if someone requests data
380 gtk_selection_add_handler( m_clipboardWidget
,
386 gtk_selection_add_handler( m_clipboardWidget
,
387 GDK_SELECTION_PRIMARY
,
392 // Tell the world we offer clipboard data
394 if (!gtk_selection_owner_set( m_clipboardWidget
,
400 m_ownsClipboard
= TRUE
;
402 if (!gtk_selection_owner_set( m_clipboardWidget
,
403 GDK_SELECTION_PRIMARY
,
408 m_ownsPrimarySelection
= TRUE
;
413 void wxClipboard::Close()
415 wxCHECK_RET( m_open
, "clipboard not open" );
420 bool wxClipboard::IsSupportedFormat( wxDataFormat format
, const wxString
&id
)
422 m_targetRequested
= GetTargetAtom( format
, id
);
424 if (m_targetRequested
== 0) return FALSE
;
426 // add handler for target (= format) query
428 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
429 "selection_received",
430 GTK_SIGNAL_FUNC( targets_selection_received
),
433 m_formatSupported
= FALSE
;
435 // perform query. this will set m_formatSupported to
436 // TRUE if m_targetRequested is supported
438 gtk_selection_convert( m_clipboardWidget
,
443 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget
),
444 GTK_SIGNAL_FUNC( targets_selection_received
),
447 if (!m_formatSupported
) return FALSE
;
452 bool wxClipboard::GetData( wxDataObject
*data
)
454 wxCHECK_MSG( m_open
, FALSE
, "clipboard not open" );
456 m_receivedData
= data
;
458 wxCHECK_MSG( m_receivedData
, FALSE
, "invalid data object" );
460 if (m_receivedData
->GetFormat() == wxDF_PRIVATE
)
462 wxPrivateDataObject
* pd
= (wxPrivateDataObject
*) m_receivedData
;
464 wxCHECK_MSG( !pd
->GetId().IsEmpty(), FALSE
, "private clipboard format requires ID string" );
466 m_targetRequested
= GetTargetAtom( m_receivedData
->GetFormat(), pd
->GetId() );
470 m_targetRequested
= GetTargetAtom( m_receivedData
->GetFormat() );
473 data
->m_formatAtom
= m_targetRequested
;
475 wxCHECK_MSG( m_targetRequested
, FALSE
, "unsupported clipboard format" );
477 m_formatSupported
= FALSE
;
479 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
480 "selection_received",
481 GTK_SIGNAL_FUNC( selection_received
),
484 gtk_selection_convert( m_clipboardWidget
,
489 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget
),
490 GTK_SIGNAL_FUNC( selection_received
),
493 wxCHECK_MSG( m_formatSupported
, FALSE
, "error retrieving data from clipboard" );
498 GdkAtom
wxClipboard::GetTargetAtom( wxDataFormat format
, const wxString
&id
)
500 // What is X representation of that format?
506 return GDK_TARGET_STRING
;
512 return GDK_TARGET_BITMAP
;
518 // we create our own X representation
520 return gdk_atom_intern( WXSTRINGCAST( id
), FALSE
);
532 //-----------------------------------------------------------------------------
534 //-----------------------------------------------------------------------------
536 IMPLEMENT_DYNAMIC_CLASS(wxClipboardModule
,wxModule
)
538 bool wxClipboardModule::OnInit()
540 wxTheClipboard
= new wxClipboard();
545 void wxClipboardModule::OnExit()
547 if (wxTheClipboard
) delete wxTheClipboard
;
548 wxTheClipboard
= (wxClipboard
*) NULL
;