configure and #ifdef wxUSE_XXX updates
[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 #ifdef 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 if (atoms[i] == clipboard->m_targetRequested)
79 {
80 clipboard->m_formatSupported = TRUE;
81 return;
82 }
83 }
84
85 return;
86 }
87
88 //-----------------------------------------------------------------------------
89 // "selection_received" for the actual data
90 //-----------------------------------------------------------------------------
91
92 static void
93 selection_received( GtkWidget *WXUNUSED(widget),
94 GtkSelectionData *selection_data,
95 wxClipboard *clipboard )
96 {
97 if (!wxTheClipboard) return;
98
99 wxDataObject *data_object = clipboard->m_receivedData;
100
101 if (!data_object) return;
102
103 if (selection_data->length <= 0) return;
104
105 // make sure we got the data in the correct format
106
107 if (data_object->m_formatAtom != selection_data->target) return;
108
109 // make sure we got the data in the correct form (selection type).
110 // if so, copy data to target object
111
112 switch (data_object->GetFormat())
113 {
114 case wxDF_TEXT:
115 {
116 if (selection_data->type != GDK_SELECTION_TYPE_STRING) return;
117
118 wxTextDataObject *text_object = (wxTextDataObject *) data_object;
119
120 wxString text = (const char*) selection_data->data;
121
122 text_object->SetText( text );
123
124 break;
125 }
126
127 case wxDF_BITMAP:
128 {
129 if (selection_data->type != GDK_SELECTION_TYPE_BITMAP) return;
130
131 return;
132
133 break;
134 }
135
136 case wxDF_PRIVATE:
137 {
138 if (selection_data->type != GDK_SELECTION_TYPE_STRING) return;
139
140 wxPrivateDataObject *private_object = (wxPrivateDataObject *) data_object;
141
142 private_object->SetData( (const char*) selection_data->data, (size_t) selection_data->length );
143
144 break;
145 }
146
147 default:
148 {
149 return;
150 }
151 }
152
153 wxTheClipboard->m_formatSupported = TRUE;
154 }
155
156 //-----------------------------------------------------------------------------
157 // "selection_clear"
158 //-----------------------------------------------------------------------------
159
160 static gint
161 selection_clear_clip( GtkWidget *WXUNUSED(widget), GdkEventSelection *event )
162 {
163 if (!wxTheClipboard) return TRUE;
164
165 if (event->selection == GDK_SELECTION_PRIMARY)
166 {
167 wxTheClipboard->m_ownsPrimarySelection = FALSE;
168 }
169 else
170 if (event->selection == g_clipboardAtom)
171 {
172 wxTheClipboard->m_ownsClipboard = FALSE;
173 }
174 else
175 {
176 return FALSE;
177 }
178
179 if ((!wxTheClipboard->m_ownsPrimarySelection) &&
180 (!wxTheClipboard->m_ownsClipboard))
181 {
182 // the clipboard is no longer in our hands. we can the
183 // clipboard data.
184
185 wxTheClipboard->m_dataObjects.Clear();
186 }
187
188 return TRUE;
189 }
190
191 //-----------------------------------------------------------------------------
192 // selection handler for supplying data
193 //-----------------------------------------------------------------------------
194
195 static void
196 selection_handler( GtkWidget *WXUNUSED(widget), GtkSelectionData *selection_data, gpointer WXUNUSED(data) )
197 {
198 if (!wxTheClipboard) return;
199
200 wxNode *node = wxTheClipboard->m_dataObjects.First();
201
202 while (node)
203 {
204 wxDataObject *data_object = (wxDataObject *)node->Data();
205
206 if (data_object->m_formatAtom != selection_data->target)
207 {
208 node = node->Next();
209 break;
210 }
211
212 switch (data_object->GetFormat())
213 {
214 case wxDF_TEXT:
215 {
216 wxTextDataObject *text_object = (wxTextDataObject*) data_object;
217
218 wxString text = text_object->GetText();
219
220 char *s = WXSTRINGCAST text;
221 int len = (int) text.Length();
222
223 gtk_selection_data_set(
224 selection_data,
225 GDK_SELECTION_TYPE_STRING,
226 8*sizeof(gchar),
227 (unsigned char*) s,
228 len );
229
230 break;
231 }
232
233 case wxDF_BITMAP:
234 {
235 // wxBitmapDataObject *private_object = (wxBitmapDataObject*) data_object;
236
237 // how do we do that ?
238
239 break;
240 }
241
242 case wxDF_PRIVATE:
243 {
244 wxPrivateDataObject *private_object = (wxPrivateDataObject*) data_object;
245
246 if (private_object->GetDataSize() == 0) return;
247
248 gtk_selection_data_set(
249 selection_data,
250 GDK_SELECTION_TYPE_STRING,
251 8*sizeof(gchar),
252 (unsigned char*) private_object->GetData(),
253 (int) private_object->GetDataSize() );
254 }
255
256 default:
257 break;
258 }
259
260 node = node->Next();
261 }
262 }
263
264 //-----------------------------------------------------------------------------
265 // wxClipboard
266 //-----------------------------------------------------------------------------
267
268 IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
269
270 wxClipboard::wxClipboard()
271 {
272 m_open = FALSE;
273
274 m_ownsClipboard = FALSE;
275 m_ownsPrimarySelection = FALSE;
276
277 m_dataObjects.DeleteContents( TRUE );
278
279 m_receivedData = (wxDataObject*) NULL;
280
281 m_clipboardWidget = gtk_window_new( GTK_WINDOW_POPUP );
282 gtk_widget_realize( m_clipboardWidget );
283
284 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
285 "selection_clear_event",
286 GTK_SIGNAL_FUNC( selection_clear_clip ),
287 (gpointer) NULL );
288
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);
292
293 m_formatSupported = FALSE;
294 m_targetRequested = 0;
295 }
296
297 wxClipboard::~wxClipboard()
298 {
299 Clear();
300
301 if (m_clipboardWidget) gtk_widget_destroy( m_clipboardWidget );
302 }
303
304 void wxClipboard::Clear()
305 {
306 if (m_dataObjects.GetCount())
307 {
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 */
310
311 if (gdk_selection_owner_get( g_clipboardAtom ) == m_clipboardWidget->window)
312 {
313 gtk_selection_owner_set( (GtkWidget*) NULL, g_clipboardAtom, GDK_CURRENT_TIME );
314 }
315
316 if (gdk_selection_owner_get( GDK_SELECTION_PRIMARY ) == m_clipboardWidget->window)
317 {
318 gtk_selection_owner_set( (GtkWidget*) NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME );
319 }
320
321 m_dataObjects.Clear();
322 }
323
324 m_targetRequested = 0;
325
326 m_formatSupported = FALSE;
327 }
328
329 bool wxClipboard::Open()
330 {
331 wxCHECK_MSG( !m_open, FALSE, "clipboard already open" );
332
333 m_open = TRUE;
334
335 return TRUE;
336 }
337
338 bool wxClipboard::SetData( wxDataObject *data )
339 {
340 wxCHECK_MSG( data, FALSE, "data is invalid" );
341
342 wxNode *node = m_dataObjects.First();
343
344 while (node)
345 {
346 wxDataObject *d = (wxDataObject*)node->Data();
347
348 if (d->GetFormat() == data->GetFormat())
349 {
350 m_dataObjects.DeleteNode( node );
351
352 break;
353 }
354
355 node = node->Next();
356 }
357
358 m_dataObjects.Append( data );
359
360 wxCHECK_MSG( m_open, FALSE, "clipboard not open" );
361
362 if (data->GetFormat() == wxDF_PRIVATE)
363 {
364 wxPrivateDataObject* pd = (wxPrivateDataObject*) data;
365
366 wxCHECK_MSG( !pd->GetId().IsEmpty(), FALSE, "private clipboard format requires ID string" );
367
368 data->m_formatAtom = GetTargetAtom( data->GetFormat(), pd->GetId() );
369 }
370 else
371 {
372 data->m_formatAtom = GetTargetAtom( data->GetFormat() );
373 }
374
375 // This should happen automatically
376
377 m_ownsClipboard = FALSE;
378 m_ownsPrimarySelection = FALSE;
379
380 // Add handlers if someone requests data
381
382 gtk_selection_add_handler( m_clipboardWidget,
383 g_clipboardAtom,
384 data->m_formatAtom,
385 selection_handler,
386 NULL );
387
388 gtk_selection_add_handler( m_clipboardWidget,
389 GDK_SELECTION_PRIMARY,
390 data->m_formatAtom,
391 selection_handler,
392 NULL );
393
394 // Tell the world we offer clipboard data
395
396 if (!gtk_selection_owner_set( m_clipboardWidget,
397 g_clipboardAtom,
398 GDK_CURRENT_TIME ))
399 {
400 return FALSE;
401 }
402 m_ownsClipboard = TRUE;
403
404 if (!gtk_selection_owner_set( m_clipboardWidget,
405 GDK_SELECTION_PRIMARY,
406 GDK_CURRENT_TIME ))
407 {
408 return FALSE;
409 }
410 m_ownsPrimarySelection = TRUE;
411
412 return TRUE;
413 }
414
415 void wxClipboard::Close()
416 {
417 wxCHECK_RET( m_open, "clipboard not open" );
418
419 m_open = FALSE;
420 }
421
422 bool wxClipboard::IsSupportedFormat( wxDataFormat format, const wxString &id )
423 {
424 m_targetRequested = GetTargetAtom( format, id );
425
426 if (m_targetRequested == 0) return FALSE;
427
428 // add handler for target (= format) query
429
430 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
431 "selection_received",
432 GTK_SIGNAL_FUNC( targets_selection_received ),
433 (gpointer) this );
434
435 m_formatSupported = FALSE;
436
437 // perform query. this will set m_formatSupported to
438 // TRUE if m_targetRequested is supported
439
440 gtk_selection_convert( m_clipboardWidget,
441 g_clipboardAtom,
442 g_targetsAtom,
443 GDK_CURRENT_TIME );
444
445 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget),
446 GTK_SIGNAL_FUNC( targets_selection_received ),
447 (gpointer) this );
448
449 if (!m_formatSupported) return FALSE;
450
451 return TRUE;
452 }
453
454 bool wxClipboard::GetData( wxDataObject *data )
455 {
456 wxCHECK_MSG( m_open, FALSE, "clipboard not open" );
457
458 m_receivedData = data;
459
460 wxCHECK_MSG( m_receivedData, FALSE, "invalid data object" );
461
462 if (m_receivedData->GetFormat() == wxDF_PRIVATE)
463 {
464 wxPrivateDataObject* pd = (wxPrivateDataObject*) m_receivedData;
465
466 wxCHECK_MSG( !pd->GetId().IsEmpty(), FALSE, "private clipboard format requires ID string" );
467
468 m_targetRequested = GetTargetAtom( m_receivedData->GetFormat(), pd->GetId() );
469 }
470 else
471 {
472 m_targetRequested = GetTargetAtom( m_receivedData->GetFormat() );
473 }
474
475 data->m_formatAtom = m_targetRequested;
476
477 wxCHECK_MSG( m_targetRequested, FALSE, "unsupported clipboard format" );
478
479 m_formatSupported = FALSE;
480
481 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
482 "selection_received",
483 GTK_SIGNAL_FUNC( selection_received ),
484 (gpointer) this );
485
486 gtk_selection_convert( m_clipboardWidget,
487 g_clipboardAtom,
488 m_targetRequested,
489 GDK_CURRENT_TIME );
490
491 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget),
492 GTK_SIGNAL_FUNC( selection_received ),
493 (gpointer) this );
494
495 wxCHECK_MSG( m_formatSupported, FALSE, "error retrieving data from clipboard" );
496
497 return TRUE;
498 }
499
500 GdkAtom wxClipboard::GetTargetAtom( wxDataFormat format, const wxString &id )
501 {
502 // What is X representation of that format?
503
504 switch (format)
505 {
506 case wxDF_TEXT:
507 {
508 return GDK_TARGET_STRING;
509 // g_textAtom
510 }
511
512 case wxDF_BITMAP:
513 {
514 return GDK_TARGET_BITMAP;
515 break;
516 }
517
518 case wxDF_PRIVATE:
519 {
520 // we create our own X representation
521
522 return gdk_atom_intern( WXSTRINGCAST( id ), FALSE );
523 }
524
525 default:
526 {
527 return (GdkAtom) 0;
528 }
529 }
530
531 return (GdkAtom) 0;
532 }
533
534 //-----------------------------------------------------------------------------
535 // wxClipboardModule
536 //-----------------------------------------------------------------------------
537
538 IMPLEMENT_DYNAMIC_CLASS(wxClipboardModule,wxModule)
539
540 bool wxClipboardModule::OnInit()
541 {
542 wxTheClipboard = new wxClipboard();
543
544 return TRUE;
545 }
546
547 void wxClipboardModule::OnExit()
548 {
549 if (wxTheClipboard) delete wxTheClipboard;
550 wxTheClipboard = (wxClipboard*) NULL;
551 }
552
553 #endif
554
555 // wxUSE_CLIPBOARD
556