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