]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/clipbrd.cpp
Made wxGTK dataobj.cpp compile; removed flashing from wxGLCanvas samples;
[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 #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 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->GetFormat().GetAtom() != 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().GetType())
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 clipboard data. */
183
184 if (wxTheClipboard->m_dataBroker)
185 {
186 delete wxTheClipboard->m_dataBroker;
187 wxTheClipboard->m_dataBroker = (wxDataBroker*) NULL;
188 }
189 }
190
191 return TRUE;
192 }
193
194 //-----------------------------------------------------------------------------
195 // selection handler for supplying data
196 //-----------------------------------------------------------------------------
197
198 static void
199 selection_handler( GtkWidget *WXUNUSED(widget), GtkSelectionData *selection_data, gpointer WXUNUSED(data) )
200 {
201 if (!wxTheClipboard) return;
202
203 if (!wxTheClipboard->m_dataBroker) return;
204
205 wxNode *node = wxTheClipboard->m_dataBroker->m_dataObjects.First();
206
207 while (node)
208 {
209 wxDataObject *data_object = (wxDataObject *)node->Data();
210
211 if (data_object->GetFormat().GetAtom() != selection_data->target)
212 {
213 node = node->Next();
214 break;
215 }
216
217 switch (data_object->GetFormat().GetType())
218 {
219 case wxDF_TEXT:
220 {
221 wxTextDataObject *text_object = (wxTextDataObject*) data_object;
222
223 wxString text = text_object->GetText();
224
225 char *s = WXSTRINGCAST text;
226 int len = (int) text.Length();
227
228 gtk_selection_data_set(
229 selection_data,
230 GDK_SELECTION_TYPE_STRING,
231 8*sizeof(gchar),
232 (unsigned char*) s,
233 len );
234
235 break;
236 }
237
238 case wxDF_BITMAP:
239 {
240 // wxBitmapDataObject *private_object = (wxBitmapDataObject*) data_object;
241
242 // how do we do that ?
243
244 break;
245 }
246
247 case wxDF_PRIVATE:
248 {
249 wxPrivateDataObject *private_object = (wxPrivateDataObject*) data_object;
250
251 if (private_object->GetSize() == 0) return;
252
253 gtk_selection_data_set(
254 selection_data,
255 GDK_SELECTION_TYPE_STRING,
256 8*sizeof(gchar),
257 (unsigned char*) private_object->GetData(),
258 (int) private_object->GetSize() );
259 }
260
261 default:
262 break;
263 }
264
265 node = node->Next();
266 }
267 }
268
269 //-----------------------------------------------------------------------------
270 // wxClipboard
271 //-----------------------------------------------------------------------------
272
273 IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
274
275 wxClipboard::wxClipboard()
276 {
277 m_open = FALSE;
278
279 m_ownsClipboard = FALSE;
280 m_ownsPrimarySelection = FALSE;
281
282 m_dataBroker = (wxDataBroker*) NULL;
283
284 m_receivedData = (wxDataObject*) NULL;
285
286 m_clipboardWidget = gtk_window_new( GTK_WINDOW_POPUP );
287 gtk_widget_realize( m_clipboardWidget );
288
289 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
290 "selection_clear_event",
291 GTK_SIGNAL_FUNC( selection_clear_clip ),
292 (gpointer) NULL );
293
294 if (!g_clipboardAtom) g_clipboardAtom = gdk_atom_intern( "CLIPBOARD", FALSE );
295 if (!g_textAtom) g_textAtom = gdk_atom_intern( "TEXT", FALSE );
296 if (!g_targetsAtom) g_targetsAtom = gdk_atom_intern ("TARGETS", FALSE);
297
298 m_formatSupported = FALSE;
299 m_targetRequested = 0;
300 }
301
302 wxClipboard::~wxClipboard()
303 {
304 Clear();
305
306 if (m_clipboardWidget) gtk_widget_destroy( m_clipboardWidget );
307 }
308
309 void wxClipboard::Clear()
310 {
311 if (m_dataBroker)
312 {
313 /* As we have data we also own the clipboard. Once we no longer own
314 it, clear_selection is called which will set m_data to zero */
315
316 if (gdk_selection_owner_get( g_clipboardAtom ) == m_clipboardWidget->window)
317 {
318 gtk_selection_owner_set( (GtkWidget*) NULL, g_clipboardAtom, GDK_CURRENT_TIME );
319 }
320
321 if (gdk_selection_owner_get( GDK_SELECTION_PRIMARY ) == m_clipboardWidget->window)
322 {
323 gtk_selection_owner_set( (GtkWidget*) NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME );
324 }
325
326 if (m_dataBroker)
327 {
328 delete m_dataBroker;
329 m_dataBroker = (wxDataBroker*) NULL;
330 }
331 }
332
333 m_targetRequested = 0;
334
335 m_formatSupported = FALSE;
336 }
337
338 bool wxClipboard::Open()
339 {
340 wxCHECK_MSG( !m_open, FALSE, "clipboard already open" );
341
342 m_open = TRUE;
343
344 return TRUE;
345 }
346
347 bool wxClipboard::SetData( wxDataBroker *data )
348 {
349 wxCHECK_MSG( data, FALSE, "data is invalid" );
350
351 Clear();
352
353 m_dataBroker = data;
354
355 if (!m_dataBroker) return FALSE;
356
357 wxCHECK_MSG( m_open, FALSE, "clipboard not open" );
358
359 wxNode *node = m_dataBroker->m_dataObjects.First();
360 while (node)
361 {
362 wxDataObject *dobj = (wxDataObject*)node->Data();
363
364 GdkAtom format = dobj->GetFormat().GetAtom();
365
366 if (format != (GdkAtom) 0)
367 {
368 /* This should happen automatically */
369
370 m_ownsClipboard = FALSE;
371 m_ownsPrimarySelection = FALSE;
372
373 /* Add handlers if someone requests data */
374
375 gtk_selection_add_handler( m_clipboardWidget,
376 g_clipboardAtom,
377 format,
378 selection_handler,
379 (gpointer) NULL );
380
381 gtk_selection_add_handler( m_clipboardWidget,
382 GDK_SELECTION_PRIMARY,
383 format,
384 selection_handler,
385 (gpointer) NULL );
386
387 /* Tell the world we offer clipboard data */
388
389 if (!gtk_selection_owner_set( m_clipboardWidget,
390 g_clipboardAtom,
391 GDK_CURRENT_TIME ))
392 {
393 return FALSE;
394 }
395 m_ownsClipboard = TRUE;
396
397 if (!gtk_selection_owner_set( m_clipboardWidget,
398 GDK_SELECTION_PRIMARY,
399 GDK_CURRENT_TIME ))
400 {
401 return FALSE;
402 }
403 m_ownsPrimarySelection = TRUE;
404 }
405
406 node = node->Next();
407 }
408
409 return TRUE;
410 }
411
412 void wxClipboard::Close()
413 {
414 wxCHECK_RET( m_open, "clipboard not open" );
415
416 m_open = FALSE;
417 }
418
419 bool wxClipboard::GetData( wxDataObject *data )
420 {
421 wxCHECK_MSG( m_open, FALSE, "clipboard not open" );
422
423 m_receivedData = data;
424
425 wxCHECK_MSG( m_receivedData, FALSE, "invalid data object" );
426
427 /* STEP ONE: check if there is such data in the clipboard */
428
429 m_targetRequested = data->GetFormat().GetAtom();
430
431 wxCHECK_MSG( m_targetRequested, FALSE, "invalid clipboard format" );
432
433 if (m_targetRequested == 0) return FALSE;
434
435 /* add handler for target (= format) query */
436
437 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
438 "selection_received",
439 GTK_SIGNAL_FUNC( targets_selection_received ),
440 (gpointer) this );
441
442 m_formatSupported = FALSE;
443
444 /* perform query. this will set m_formatSupported to
445 * TRUE if m_targetRequested is supported */
446
447 gtk_selection_convert( m_clipboardWidget,
448 g_clipboardAtom,
449 g_targetsAtom,
450 GDK_CURRENT_TIME );
451
452 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget),
453 GTK_SIGNAL_FUNC( targets_selection_received ),
454 (gpointer) this );
455
456 if (!m_formatSupported) return FALSE;
457
458 /* STEP TWO: get the data from the clipboard */
459
460 m_formatSupported = FALSE;
461
462 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
463 "selection_received",
464 GTK_SIGNAL_FUNC( selection_received ),
465 (gpointer) this );
466
467 gtk_selection_convert( m_clipboardWidget,
468 g_clipboardAtom,
469 m_targetRequested,
470 GDK_CURRENT_TIME );
471
472 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget),
473 GTK_SIGNAL_FUNC( selection_received ),
474 (gpointer) this );
475
476 /* this is a true error as we checked for the presence of such data before */
477
478 wxCHECK_MSG( m_formatSupported, FALSE, "error retrieving data from clipboard" );
479
480 return TRUE;
481 }
482
483 //-----------------------------------------------------------------------------
484 // wxClipboardModule
485 //-----------------------------------------------------------------------------
486
487 IMPLEMENT_DYNAMIC_CLASS(wxClipboardModule,wxModule)
488
489 bool wxClipboardModule::OnInit()
490 {
491 wxTheClipboard = new wxClipboard();
492
493 return TRUE;
494 }
495
496 void wxClipboardModule::OnExit()
497 {
498 if (wxTheClipboard) delete wxTheClipboard;
499 wxTheClipboard = (wxClipboard*) NULL;
500 }
501
502 #endif
503
504 // wxUSE_CLIPBOARD
505