Changed clipboard text format id from "STRING" to "TEXT"
[wxWidgets.git] / src / gtk / 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 #if wxUSE_CLIPBOARD
17
18 #include "glib.h"
19 #include "gdk/gdk.h"
20 #include "gtk/gtk.h"
21
22 //-----------------------------------------------------------------------------
23 // data
24 //-----------------------------------------------------------------------------
25
26 wxClipboard *wxTheClipboard = (wxClipboard*) NULL;
27
28 GdkAtom g_clipboardAtom = 0;
29 GdkAtom g_targetsAtom = 0;
30
31 //-----------------------------------------------------------------------------
32 // reminder
33 //-----------------------------------------------------------------------------
34
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
42 counting)
43
44 struct _GtkSelectionData
45 {
46 GdkAtom selection;
47 GdkAtom target;
48 GdkAtom type;
49 gint format;
50 guchar *data;
51 gint length;
52 };
53
54 */
55
56 //-----------------------------------------------------------------------------
57 // "selection_received" for targets
58 //-----------------------------------------------------------------------------
59
60 static void
61 targets_selection_received( GtkWidget *WXUNUSED(widget),
62 GtkSelectionData *selection_data,
63 wxClipboard *clipboard )
64 {
65 if (!wxTheClipboard) return;
66
67 if (selection_data->length <= 0) return;
68
69 // make sure we got the data in the correct form
70 if (selection_data->type != GDK_SELECTION_TYPE_ATOM) return;
71
72 // the atoms we received, holding a list of targets (= formats)
73 GdkAtom *atoms = (GdkAtom *)selection_data->data;
74
75 for (unsigned int i=0; i<selection_data->length/sizeof(GdkAtom); i++)
76 {
77 char *name = gdk_atom_name (atoms[i]);
78 if (name) printf( "Format available: %s.\n", name );
79
80 if (atoms[i] == clipboard->m_targetRequested)
81 {
82 clipboard->m_formatSupported = TRUE;
83 return;
84 }
85 }
86
87 return;
88 }
89
90 //-----------------------------------------------------------------------------
91 // "selection_received" for the actual data
92 //-----------------------------------------------------------------------------
93
94 static void
95 selection_received( GtkWidget *WXUNUSED(widget),
96 GtkSelectionData *selection_data,
97 wxClipboard *clipboard )
98 {
99 if (!wxTheClipboard) return;
100
101 wxDataObject *data_object = clipboard->m_receivedData;
102
103 if (!data_object) return;
104
105 if (selection_data->length <= 0) return;
106
107 // make sure we got the data in the correct format
108
109 if (data_object->GetFormat().GetAtom() != selection_data->target) return;
110
111 // make sure we got the data in the correct form (selection type).
112 // if so, copy data to target object
113
114 switch (data_object->GetFormat().GetType())
115 {
116 case wxDF_TEXT:
117 {
118 if (selection_data->type != GDK_SELECTION_TYPE_STRING) return;
119
120 wxTextDataObject *text_object = (wxTextDataObject *) data_object;
121
122 wxString text = (const char*) selection_data->data;
123
124 text_object->SetText( text );
125
126 break;
127 }
128
129 case wxDF_BITMAP:
130 {
131 if (selection_data->type != GDK_SELECTION_TYPE_BITMAP) return;
132
133 return;
134
135 break;
136 }
137
138 case wxDF_PRIVATE:
139 {
140 if (selection_data->type != GDK_SELECTION_TYPE_STRING) return;
141
142 wxPrivateDataObject *private_object = (wxPrivateDataObject *) data_object;
143
144 private_object->SetData( (const char*) selection_data->data, (size_t) selection_data->length );
145
146 break;
147 }
148
149 default:
150 {
151 return;
152 }
153 }
154
155 wxTheClipboard->m_formatSupported = TRUE;
156 }
157
158 //-----------------------------------------------------------------------------
159 // "selection_clear"
160 //-----------------------------------------------------------------------------
161
162 static gint
163 selection_clear_clip( GtkWidget *WXUNUSED(widget), GdkEventSelection *event )
164 {
165 if (!wxTheClipboard) return TRUE;
166
167 if (event->selection == GDK_SELECTION_PRIMARY)
168 {
169 wxTheClipboard->m_ownsPrimarySelection = FALSE;
170 }
171 else
172 if (event->selection == g_clipboardAtom)
173 {
174 wxTheClipboard->m_ownsClipboard = FALSE;
175 }
176 else
177 {
178 return FALSE;
179 }
180
181 if ((!wxTheClipboard->m_ownsPrimarySelection) &&
182 (!wxTheClipboard->m_ownsClipboard))
183 {
184 /* the clipboard is no longer in our hands. we can the clipboard data. */
185
186 if (wxTheClipboard->m_dataBroker)
187 {
188 delete wxTheClipboard->m_dataBroker;
189 wxTheClipboard->m_dataBroker = (wxDataBroker*) NULL;
190 }
191 }
192
193 return TRUE;
194 }
195
196 //-----------------------------------------------------------------------------
197 // selection handler for supplying data
198 //-----------------------------------------------------------------------------
199
200 static void
201 selection_handler( GtkWidget *WXUNUSED(widget), GtkSelectionData *selection_data, gpointer WXUNUSED(data) )
202 {
203 if (!wxTheClipboard) return;
204
205 if (!wxTheClipboard->m_dataBroker) return;
206
207 wxNode *node = wxTheClipboard->m_dataBroker->m_dataObjects.First();
208
209 while (node)
210 {
211 wxDataObject *data_object = (wxDataObject *)node->Data();
212
213 if (data_object->GetFormat().GetAtom() != selection_data->target)
214 {
215 node = node->Next();
216 break;
217 }
218
219 switch (data_object->GetFormat().GetType())
220 {
221 case wxDF_TEXT:
222 {
223 wxTextDataObject *text_object = (wxTextDataObject*) data_object;
224
225 wxString text = text_object->GetText();
226
227 char *s = WXSTRINGCAST text;
228 int len = (int) text.Length();
229
230 gtk_selection_data_set(
231 selection_data,
232 GDK_SELECTION_TYPE_STRING,
233 8*sizeof(gchar),
234 (unsigned char*) s,
235 len );
236
237 break;
238 }
239
240 case wxDF_BITMAP:
241 {
242 // wxBitmapDataObject *private_object = (wxBitmapDataObject*) data_object;
243
244 // how do we do that ?
245
246 break;
247 }
248
249 case wxDF_PRIVATE:
250 {
251 wxPrivateDataObject *private_object = (wxPrivateDataObject*) data_object;
252
253 if (private_object->GetSize() == 0) return;
254
255 gtk_selection_data_set(
256 selection_data,
257 GDK_SELECTION_TYPE_STRING,
258 8*sizeof(gchar),
259 (unsigned char*) private_object->GetData(),
260 (int) private_object->GetSize() );
261 }
262
263 default:
264 break;
265 }
266
267 node = node->Next();
268 }
269 }
270
271 //-----------------------------------------------------------------------------
272 // wxClipboard
273 //-----------------------------------------------------------------------------
274
275 IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
276
277 wxClipboard::wxClipboard()
278 {
279 m_open = FALSE;
280
281 m_ownsClipboard = FALSE;
282 m_ownsPrimarySelection = FALSE;
283
284 m_dataBroker = (wxDataBroker*) NULL;
285
286 m_receivedData = (wxDataObject*) NULL;
287
288 m_clipboardWidget = gtk_window_new( GTK_WINDOW_POPUP );
289 gtk_widget_realize( m_clipboardWidget );
290
291 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
292 "selection_clear_event",
293 GTK_SIGNAL_FUNC( selection_clear_clip ),
294 (gpointer) NULL );
295
296 if (!g_clipboardAtom) g_clipboardAtom = gdk_atom_intern( "CLIPBOARD", FALSE );
297 if (!g_targetsAtom) g_targetsAtom = gdk_atom_intern ("TARGETS", FALSE);
298
299 m_formatSupported = FALSE;
300 m_targetRequested = 0;
301 }
302
303 wxClipboard::~wxClipboard()
304 {
305 Clear();
306
307 if (m_clipboardWidget) gtk_widget_destroy( m_clipboardWidget );
308 }
309
310 void wxClipboard::Clear()
311 {
312 if (m_dataBroker)
313 {
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 */
316
317 if (gdk_selection_owner_get( g_clipboardAtom ) == m_clipboardWidget->window)
318 {
319 gtk_selection_owner_set( (GtkWidget*) NULL, g_clipboardAtom, GDK_CURRENT_TIME );
320 }
321
322 if (gdk_selection_owner_get( GDK_SELECTION_PRIMARY ) == m_clipboardWidget->window)
323 {
324 gtk_selection_owner_set( (GtkWidget*) NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME );
325 }
326
327 if (m_dataBroker)
328 {
329 delete m_dataBroker;
330 m_dataBroker = (wxDataBroker*) NULL;
331 }
332 }
333
334 m_targetRequested = 0;
335
336 m_formatSupported = FALSE;
337 }
338
339 bool wxClipboard::Open()
340 {
341 wxCHECK_MSG( !m_open, FALSE, "clipboard already open" );
342
343 m_open = TRUE;
344
345 return TRUE;
346 }
347
348 bool wxClipboard::SetData( wxDataObject *data )
349 {
350 wxCHECK_MSG( m_open, FALSE, "clipboard not open" );
351
352 wxCHECK_MSG( data, FALSE, "data is invalid" );
353
354 Clear();
355
356 return AddData( data );
357 }
358
359 bool wxClipboard::AddData( wxDataObject *data )
360 {
361 wxCHECK_MSG( m_open, FALSE, "clipboard not open" );
362
363 wxCHECK_MSG( data, FALSE, "data is invalid" );
364
365 /* if clipboard has been cleared before, create new data broker */
366
367 if (!m_dataBroker) m_dataBroker = new wxDataBroker();
368
369 /* add new data to list of offered data objects */
370
371 m_dataBroker->Add( data );
372
373 /* get native format id of new data object */
374
375 GdkAtom format = data->GetFormat().GetAtom();
376
377 wxCHECK_MSG( format, FALSE, "data has invalid format" );
378
379 /* This should happen automatically, but to be on the safe side */
380
381 m_ownsClipboard = FALSE;
382 m_ownsPrimarySelection = FALSE;
383
384 /* Add handlers if someone requests data */
385
386
387 #if (GTK_MINOR_VERSION > 0)
388
389 gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget),
390 GDK_SELECTION_PRIMARY,
391 format,
392 0 ); /* what is info ? */
393
394 gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget),
395 g_clipboardAtom,
396 format,
397 0 ); /* what is info ? */
398
399 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
400 "selection_get",
401 GTK_SIGNAL_FUNC(selection_handler),
402 (gpointer) NULL );
403
404 #else
405
406 gtk_selection_add_handler( m_clipboardWidget,
407 g_clipboardAtom,
408 format,
409 selection_handler,
410 (gpointer) NULL );
411
412 gtk_selection_add_handler( m_clipboardWidget,
413 GDK_SELECTION_PRIMARY,
414 format,
415 selection_handler,
416 (gpointer) NULL );
417 #endif
418
419 /* Tell the world we offer clipboard data */
420
421 if (!gtk_selection_owner_set( m_clipboardWidget,
422 g_clipboardAtom,
423 GDK_CURRENT_TIME ))
424 {
425 return FALSE;
426 }
427 m_ownsClipboard = TRUE;
428
429 if (!gtk_selection_owner_set( m_clipboardWidget,
430 GDK_SELECTION_PRIMARY,
431 GDK_CURRENT_TIME ))
432 {
433 return FALSE;
434 }
435 m_ownsPrimarySelection = TRUE;
436
437 return TRUE;
438 }
439
440 void wxClipboard::Close()
441 {
442 wxCHECK_RET( m_open, "clipboard not open" );
443
444 m_open = FALSE;
445 }
446
447 bool wxClipboard::IsSupported( wxDataFormat format )
448 {
449 wxCHECK_MSG( m_open, FALSE, "clipboard not open" );
450
451 /* store requested format to be asked for by callbacks */
452
453 m_targetRequested = format.GetAtom();
454
455 wxCHECK_MSG( m_targetRequested, FALSE, "invalid clipboard format" );
456
457 /* add handler for target (= format) query */
458
459 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
460 "selection_received",
461 GTK_SIGNAL_FUNC( targets_selection_received ),
462 (gpointer) this );
463
464 m_formatSupported = FALSE;
465
466 /* perform query. this will set m_formatSupported to
467 * TRUE if m_targetRequested is supported */
468
469 gtk_selection_convert( m_clipboardWidget,
470 g_clipboardAtom,
471 g_targetsAtom,
472 GDK_CURRENT_TIME );
473
474 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget),
475 GTK_SIGNAL_FUNC( targets_selection_received ),
476 (gpointer) this );
477
478 if (!m_formatSupported) return FALSE;
479
480 return TRUE;
481 }
482
483 bool wxClipboard::GetData( wxDataObject *data )
484 {
485 wxCHECK_MSG( m_open, FALSE, "clipboard not open" );
486
487 /* is data supported by clipboard ? */
488
489 if (!IsSupported( data->GetFormat() )) return FALSE;
490
491 /* store pointer to data object to be filled up by callbacks */
492
493 m_receivedData = data;
494
495 /* store requested format to be asked for by callbacks */
496
497 m_targetRequested = data->GetFormat().GetAtom();
498
499 wxCHECK_MSG( m_targetRequested, FALSE, "invalid clipboard format" );
500
501 /* start query */
502
503 m_formatSupported = FALSE;
504
505 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
506 "selection_received",
507 GTK_SIGNAL_FUNC( selection_received ),
508 (gpointer) this );
509
510 /* ask for clipboard contents */
511
512 gtk_selection_convert( m_clipboardWidget,
513 g_clipboardAtom,
514 m_targetRequested,
515 GDK_CURRENT_TIME );
516
517 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget),
518 GTK_SIGNAL_FUNC( selection_received ),
519 (gpointer) this );
520
521 /* this is a true error as we checked for the presence of such data before */
522
523 wxCHECK_MSG( m_formatSupported, FALSE, "error retrieving data from clipboard" );
524
525 return TRUE;
526 }
527
528 //-----------------------------------------------------------------------------
529 // wxClipboardModule
530 //-----------------------------------------------------------------------------
531
532 IMPLEMENT_DYNAMIC_CLASS(wxClipboardModule,wxModule)
533
534 bool wxClipboardModule::OnInit()
535 {
536 wxTheClipboard = new wxClipboard();
537
538 return TRUE;
539 }
540
541 void wxClipboardModule::OnExit()
542 {
543 if (wxTheClipboard) delete wxTheClipboard;
544 wxTheClipboard = (wxClipboard*) NULL;
545 }
546
547 #endif
548
549 // wxUSE_CLIPBOARD
550