Clipboard update
[wxWidgets.git] / src / gtk1 / clipbrd.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: clipbrd.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "clipbrd.h"
12 #endif
13
14 #include "wx/clipbrd.h"
15
16 //-----------------------------------------------------------------------------
17 // data
18 //-----------------------------------------------------------------------------
19
20 wxClipboard *wxTheClipboard = (wxClipboard*) NULL;
21
22 GdkAtom g_textAtom = 0;
23 GdkAtom g_clipboardAtom = 0;
24 GdkAtom g_targetsAtom = 0;
25
26 //-----------------------------------------------------------------------------
27 // reminder
28 //-----------------------------------------------------------------------------
29
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
37 counting)
38
39 struct _GtkSelectionData
40 {
41 GdkAtom selection;
42 GdkAtom target;
43 GdkAtom type;
44 gint format;
45 guchar *data;
46 gint length;
47 };
48
49 */
50
51 //-----------------------------------------------------------------------------
52 // "selection_received" for targets
53 //-----------------------------------------------------------------------------
54
55 static void
56 targets_selection_received( GtkWidget *WXUNUSED(widget),
57 GtkSelectionData *selection_data,
58 wxClipboard *clipboard )
59 {
60 if (!wxTheClipboard) return;
61
62 if (selection_data->length <= 0) return;
63
64 // make sure we got the data in the correct form
65 if (selection_data->type != GDK_SELECTION_TYPE_ATOM) return;
66
67 // the atoms we received, holding a list of targets (= formats)
68 GdkAtom *atoms = (GdkAtom *)selection_data->data;
69
70 for (unsigned int i=0; i<selection_data->length/sizeof(GdkAtom); i++)
71 {
72 if (atoms[i] == clipboard->m_targetRequested)
73 {
74 clipboard->m_formatSupported = TRUE;
75 return;
76 }
77 }
78
79 return;
80 }
81
82 //-----------------------------------------------------------------------------
83 // "selection_received" for the actual data
84 //-----------------------------------------------------------------------------
85
86 static void
87 selection_received( GtkWidget *WXUNUSED(widget),
88 GtkSelectionData *selection_data,
89 wxClipboard *clipboard )
90 {
91 if (!wxTheClipboard) return;
92
93 if (selection_data->length <= 0) return;
94
95 size_t size = (size_t) selection_data->length;
96
97 // make sure we got the data in the correct form
98 if (selection_data->type != GDK_SELECTION_TYPE_STRING) return;
99
100 clipboard->m_receivedSize = size;
101
102 clipboard->m_receivedData = new char[size+1];
103
104 memcpy( clipboard->m_receivedData, selection_data->data, size);
105 }
106
107 //-----------------------------------------------------------------------------
108 // "selection_clear"
109 //-----------------------------------------------------------------------------
110
111 static gint
112 selection_clear( GtkWidget *WXUNUSED(widget), GdkEventSelection *WXUNUSED(event) )
113 {
114 if (!wxTheClipboard) return TRUE;
115
116 /* the clipboard is no longer in our hands. we can delete the
117 * clipboard data. I hope I got that one right... */
118
119 wxTheClipboard->SetData( (wxDataObject*) NULL );
120
121 return TRUE;
122 }
123
124 //-----------------------------------------------------------------------------
125 // selection handler for supplying data
126 //-----------------------------------------------------------------------------
127
128 static void
129 selection_handler( GtkWidget *WXUNUSED(widget), GtkSelectionData *selection_data, gpointer WXUNUSED(data) )
130 {
131 if (!wxTheClipboard) return;
132
133 wxDataObject *data_object = wxTheClipboard->m_data;
134
135 if (!data_object) return;
136
137 if (data_object->GetDataSize() == 0) return;
138
139
140
141 gint len = data_object->GetDataSize();
142 guchar *bin_data = (guchar*) malloc( len );
143 data_object->GetDataHere( (void*)bin_data );
144
145 if (selection_data->target == GDK_TARGET_STRING)
146 {
147 gtk_selection_data_set(
148 selection_data, GDK_SELECTION_TYPE_STRING, 8*sizeof(gchar), bin_data, len );
149 }
150 /*
151 else if (selection_data->target == g_textAtom)
152 {
153 gtk_selection_data_set(
154 selection_data, g_textAtom, 8*sizeof(gchar), bin_data, len );
155 }
156 */
157 free( bin_data );
158 }
159
160 //-----------------------------------------------------------------------------
161 // wxClipboard
162 //-----------------------------------------------------------------------------
163
164 IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
165
166 wxClipboard::wxClipboard()
167 {
168 m_data = (wxDataObject*) NULL;
169
170 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
171 "selection_clear_event",
172 GTK_SIGNAL_FUNC( selection_clear ),
173 (gpointer) NULL );
174
175 if (!g_clipboardAtom) g_clipboardAtom = gdk_atom_intern( "CLIPBOARD", FALSE );
176 if (!g_textAtom) g_textAtom = gdk_atom_intern( "TEXT", FALSE );
177 if (!g_targetsAtom) g_targetsAtom = gdk_atom_intern ("TARGETS", FALSE);
178
179 m_receivedData = (char*)NULL;
180 m_receivedSize = 0;
181 m_formatSupported = FALSE;
182 m_targetRequested = 0;
183 }
184
185 wxClipboard::~wxClipboard()
186 {
187 Clear();
188
189 if (m_clipboardWidget) gtk_widget_destroy( m_clipboardWidget );
190 }
191
192 void wxClipboard::Clear()
193 {
194 /* As we have data we also own the clipboard. Once we no longer own
195 it, clear_selection is called which will set m_data to zero */
196
197 if (m_data)
198 {
199 if (gdk_selection_owner_get( g_clipboardAtom) == m_clipboardWidget->window)
200 {
201 gtk_selection_owner_set( (GtkWidget*) NULL, g_clipboardAtom, GDK_CURRENT_TIME );
202 }
203
204 delete m_data;
205 m_data = (wxDataObject*) NULL;
206 }
207
208 m_receivedSize = 0;
209
210 if (m_receivedData)
211 {
212 delete[] m_receivedData;
213 m_receivedData = (char*) NULL;
214 }
215
216 m_targetRequested = 0;
217
218 m_formatSupported = FALSE;
219 }
220
221 void wxClipboard::SetData( wxDataObject *data )
222 {
223 Clear();
224
225 /*
226 GTK 1.0.X cannot remove a target from a widget so if a widget
227 at first offers text and then a bitmap (and no longer text) to
228 the clipboard, we seem too have to delete it.
229 */
230
231 if (m_clipboardWidget) gtk_widget_destroy( m_clipboardWidget );
232
233 m_clipboardWidget = gtk_window_new( GTK_WINDOW_POPUP );
234 gtk_widget_realize( m_clipboardWidget );
235
236
237 if (m_data) delete m_data;
238 m_data = data;
239 if (!m_data) return;
240
241 if (!gtk_selection_owner_set( m_clipboardWidget,
242 g_clipboardAtom,
243 GDK_CURRENT_TIME))
244 {
245 delete m_data;
246 m_data = (wxDataObject*) NULL;
247 return;
248 }
249
250 switch (m_data->GetPreferredFormat())
251 {
252 case wxDF_TEXT:
253 gtk_selection_add_handler( m_clipboardWidget,
254 g_clipboardAtom,
255 // g_textAtom,
256 GDK_TARGET_STRING,
257 selection_handler,
258 NULL );
259 break;
260 default:
261 break;
262 }
263 }
264
265 bool wxClipboard::IsSupportedFormat( wxDataFormat format )
266 {
267 m_targetRequested = 0;
268
269 if (format == wxDF_TEXT)
270 {
271 // m_targetRequested = g_textAtom;
272 m_targetRequested = GDK_TARGET_STRING;
273 }
274
275 if (m_targetRequested == 0) return FALSE;
276
277 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
278 "selection_received",
279 GTK_SIGNAL_FUNC( targets_selection_received ),
280 (gpointer) this );
281
282 m_formatSupported = FALSE;
283
284 gtk_selection_convert( m_clipboardWidget,
285 g_clipboardAtom,
286 g_targetsAtom,
287 GDK_CURRENT_TIME );
288
289 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget),
290 GTK_SIGNAL_FUNC( targets_selection_received ),
291 (gpointer) this );
292
293 if (!m_formatSupported) return FALSE;
294
295 return TRUE;
296 }
297
298 bool wxClipboard::ObtainData( wxDataFormat format )
299 {
300 m_receivedSize = 0;
301
302 if (m_receivedData)
303 {
304 delete[] m_receivedData;
305 m_receivedData = (char*) NULL;
306 }
307
308 m_targetRequested = 0;
309
310 if (format == wxDF_TEXT)
311 {
312 // m_targetRequested = g_textAtom;
313 m_targetRequested = GDK_TARGET_STRING;
314 }
315
316 if (m_targetRequested == 0) return FALSE;
317
318 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
319 "selection_received",
320 GTK_SIGNAL_FUNC( selection_received ),
321 (gpointer) this );
322
323 gtk_selection_convert( m_clipboardWidget,
324 g_clipboardAtom,
325 m_targetRequested,
326 GDK_CURRENT_TIME );
327
328 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget),
329 GTK_SIGNAL_FUNC( selection_received ),
330 (gpointer) this );
331
332 if (m_receivedSize == 0) return FALSE;
333
334 return TRUE;
335 }
336
337 size_t wxClipboard::GetDataSize() const
338 {
339 return m_receivedSize;
340 }
341
342 void wxClipboard::GetDataHere( void *data ) const
343 {
344 memcpy(data, m_receivedData, m_receivedSize );
345 }
346
347 //-----------------------------------------------------------------------------
348 // wxClipboardModule
349 //-----------------------------------------------------------------------------
350
351 IMPLEMENT_DYNAMIC_CLASS(wxClipboardModule,wxModule)
352
353 bool wxClipboardModule::OnInit()
354 {
355 wxTheClipboard = new wxClipboard();
356
357 return TRUE;
358 }
359
360 void wxClipboardModule::OnExit()
361 {
362 if (wxTheClipboard) delete wxTheClipboard;
363 wxTheClipboard = (wxClipboard*) NULL;
364 }