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
->m_formatAtom
!= 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())
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
185 wxTheClipboard
->m_dataObjects
.Clear();
191 //-----------------------------------------------------------------------------
192 // selection handler for supplying data
193 //-----------------------------------------------------------------------------
196 selection_handler( GtkWidget
*WXUNUSED(widget
), GtkSelectionData
*selection_data
, gpointer
WXUNUSED(data
) )
198 if (!wxTheClipboard
) return;
200 wxNode
*node
= wxTheClipboard
->m_dataObjects
.First();
204 wxDataObject
*data_object
= (wxDataObject
*)node
->Data();
206 if (data_object
->m_formatAtom
!= selection_data
->target
)
212 switch (data_object
->GetFormat())
216 wxTextDataObject
*text_object
= (wxTextDataObject
*) data_object
;
218 wxString text
= text_object
->GetText();
220 char *s
= WXSTRINGCAST text
;
221 int len
= (int) text
.Length();
223 gtk_selection_data_set(
225 GDK_SELECTION_TYPE_STRING
,
235 // wxBitmapDataObject *private_object = (wxBitmapDataObject*) data_object;
237 // how do we do that ?
244 wxPrivateDataObject
*private_object
= (wxPrivateDataObject
*) data_object
;
246 if (private_object
->GetDataSize() == 0) return;
248 gtk_selection_data_set(
250 GDK_SELECTION_TYPE_STRING
,
252 (unsigned char*) private_object
->GetData(),
253 (int) private_object
->GetDataSize() );
264 //-----------------------------------------------------------------------------
266 //-----------------------------------------------------------------------------
268 IMPLEMENT_DYNAMIC_CLASS(wxClipboard
,wxObject
)
270 wxClipboard::wxClipboard()
274 m_ownsClipboard
= FALSE
;
275 m_ownsPrimarySelection
= FALSE
;
277 m_dataObjects
.DeleteContents( TRUE
);
279 m_receivedData
= (wxDataObject
*) NULL
;
281 m_clipboardWidget
= gtk_window_new( GTK_WINDOW_POPUP
);
282 gtk_widget_realize( m_clipboardWidget
);
284 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
285 "selection_clear_event",
286 GTK_SIGNAL_FUNC( selection_clear_clip
),
289 if (!g_clipboardAtom
) g_clipboardAtom
= gdk_atom_intern( "CLIPBOARD", FALSE
);
290 if (!g_textAtom
) g_textAtom
= gdk_atom_intern( "TEXT", FALSE
);
291 if (!g_targetsAtom
) g_targetsAtom
= gdk_atom_intern ("TARGETS", FALSE
);
293 m_formatSupported
= FALSE
;
294 m_targetRequested
= 0;
297 wxClipboard::~wxClipboard()
301 if (m_clipboardWidget
) gtk_widget_destroy( m_clipboardWidget
);
304 void wxClipboard::Clear()
306 if (m_dataObjects
.GetCount())
308 /* As we have data we also own the clipboard. Once we no longer own
309 it, clear_selection is called which will set m_data to zero */
311 if (gdk_selection_owner_get( g_clipboardAtom
) == m_clipboardWidget
->window
)
313 gtk_selection_owner_set( (GtkWidget
*) NULL
, g_clipboardAtom
, GDK_CURRENT_TIME
);
316 if (gdk_selection_owner_get( GDK_SELECTION_PRIMARY
) == m_clipboardWidget
->window
)
318 gtk_selection_owner_set( (GtkWidget
*) NULL
, GDK_SELECTION_PRIMARY
, GDK_CURRENT_TIME
);
321 m_dataObjects
.Clear();
324 m_targetRequested
= 0;
326 m_formatSupported
= FALSE
;
329 bool wxClipboard::Open()
331 wxCHECK_MSG( !m_open
, FALSE
, "clipboard already open" );
338 bool wxClipboard::SetData( wxDataObject
*data
)
340 wxCHECK_MSG( data
, FALSE
, "data is invalid" );
342 wxNode
*node
= m_dataObjects
.First();
346 wxDataObject
*d
= (wxDataObject
*)node
->Data();
348 if (d
->GetFormat() == data
->GetFormat())
350 m_dataObjects
.DeleteNode( node
);
358 m_dataObjects
.Append( data
);
360 wxCHECK_MSG( m_open
, FALSE
, "clipboard not open" );
362 if (data
->GetFormat() == wxDF_PRIVATE
)
364 wxPrivateDataObject
* pd
= (wxPrivateDataObject
*) data
;
366 wxCHECK_MSG( !pd
->GetId().IsEmpty(), FALSE
, "private clipboard format requires ID string" );
368 data
->m_formatAtom
= GetTargetAtom( data
->GetFormat(), pd
->GetId() );
372 data
->m_formatAtom
= GetTargetAtom( data
->GetFormat() );
375 // This should happen automatically
377 m_ownsClipboard
= FALSE
;
378 m_ownsPrimarySelection
= FALSE
;
380 // Add handlers if someone requests data
382 gtk_selection_add_handler( m_clipboardWidget
,
388 gtk_selection_add_handler( m_clipboardWidget
,
389 GDK_SELECTION_PRIMARY
,
394 // Tell the world we offer clipboard data
396 if (!gtk_selection_owner_set( m_clipboardWidget
,
402 m_ownsClipboard
= TRUE
;
404 if (!gtk_selection_owner_set( m_clipboardWidget
,
405 GDK_SELECTION_PRIMARY
,
410 m_ownsPrimarySelection
= TRUE
;
415 void wxClipboard::Close()
417 wxCHECK_RET( m_open
, "clipboard not open" );
422 bool wxClipboard::IsSupportedFormat( wxDataFormat format
, const wxString
&id
)
424 m_targetRequested
= GetTargetAtom( format
, id
);
426 if (m_targetRequested
== 0) return FALSE
;
428 // add handler for target (= format) query
430 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
431 "selection_received",
432 GTK_SIGNAL_FUNC( targets_selection_received
),
435 m_formatSupported
= FALSE
;
437 // perform query. this will set m_formatSupported to
438 // TRUE if m_targetRequested is supported
440 gtk_selection_convert( m_clipboardWidget
,
445 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget
),
446 GTK_SIGNAL_FUNC( targets_selection_received
),
449 if (!m_formatSupported
) return FALSE
;
454 bool wxClipboard::GetData( wxDataObject
*data
)
456 wxCHECK_MSG( m_open
, FALSE
, "clipboard not open" );
458 m_receivedData
= data
;
460 wxCHECK_MSG( m_receivedData
, FALSE
, "invalid data object" );
462 if (m_receivedData
->GetFormat() == wxDF_PRIVATE
)
464 wxPrivateDataObject
* pd
= (wxPrivateDataObject
*) m_receivedData
;
466 wxCHECK_MSG( !pd
->GetId().IsEmpty(), FALSE
, "private clipboard format requires ID string" );
468 m_targetRequested
= GetTargetAtom( m_receivedData
->GetFormat(), pd
->GetId() );
472 m_targetRequested
= GetTargetAtom( m_receivedData
->GetFormat() );
475 data
->m_formatAtom
= m_targetRequested
;
477 wxCHECK_MSG( m_targetRequested
, FALSE
, "unsupported clipboard format" );
479 m_formatSupported
= FALSE
;
481 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
),
482 "selection_received",
483 GTK_SIGNAL_FUNC( selection_received
),
486 gtk_selection_convert( m_clipboardWidget
,
491 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget
),
492 GTK_SIGNAL_FUNC( selection_received
),
495 wxCHECK_MSG( m_formatSupported
, FALSE
, "error retrieving data from clipboard" );
500 GdkAtom
wxClipboard::GetTargetAtom( wxDataFormat format
, const wxString
&id
)
502 // What is X representation of that format?
508 return GDK_TARGET_STRING
;
514 return GDK_TARGET_BITMAP
;
520 // we create our own X representation
522 return gdk_atom_intern( WXSTRINGCAST( id
), FALSE
);
534 //-----------------------------------------------------------------------------
536 //-----------------------------------------------------------------------------
538 IMPLEMENT_DYNAMIC_CLASS(wxClipboardModule
,wxModule
)
540 bool wxClipboardModule::OnInit()
542 wxTheClipboard
= new wxClipboard();
547 void wxClipboardModule::OnExit()
549 if (wxTheClipboard
) delete wxTheClipboard
;
550 wxTheClipboard
= (wxClipboard
*) NULL
;