]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/clipbrd.cpp
added an error message if a bitmap can't be addedto the image list
[wxWidgets.git] / src / gtk1 / clipbrd.cpp
CommitLineData
dc86cb34
RR
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
06cfab17 16#if wxUSE_CLIPBOARD
ac57418f 17
83624f79
RR
18#include "glib.h"
19#include "gdk/gdk.h"
20#include "gtk/gtk.h"
21
dc86cb34
RR
22//-----------------------------------------------------------------------------
23// data
24//-----------------------------------------------------------------------------
25
26wxClipboard *wxTheClipboard = (wxClipboard*) NULL;
27
fd0eed64
RR
28GdkAtom g_textAtom = 0;
29GdkAtom g_clipboardAtom = 0;
b527aac5 30GdkAtom g_targetsAtom = 0;
fd0eed64 31
dc86cb34 32//-----------------------------------------------------------------------------
b527aac5 33// reminder
dc86cb34
RR
34//-----------------------------------------------------------------------------
35
b527aac5
RR
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
45struct _GtkSelectionData
dc86cb34 46{
b527aac5
RR
47 GdkAtom selection;
48 GdkAtom target;
49 GdkAtom type;
50 gint format;
51 guchar *data;
52 gint length;
53};
54
55*/
dc86cb34 56
b527aac5
RR
57//-----------------------------------------------------------------------------
58// "selection_received" for targets
59//-----------------------------------------------------------------------------
60
61static void
62targets_selection_received( GtkWidget *WXUNUSED(widget),
63 GtkSelectionData *selection_data,
64 wxClipboard *clipboard )
dc86cb34 65{
8b53e5a2 66 if (!wxTheClipboard) return;
b527aac5 67
8b53e5a2 68 if (selection_data->length <= 0) return;
b527aac5 69
8b53e5a2
RR
70 // make sure we got the data in the correct form
71 if (selection_data->type != GDK_SELECTION_TYPE_ATOM) return;
b527aac5 72
8b53e5a2
RR
73 // the atoms we received, holding a list of targets (= formats)
74 GdkAtom *atoms = (GdkAtom *)selection_data->data;
b527aac5 75
8b53e5a2
RR
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 }
b527aac5 84
8b53e5a2 85 return;
dc86cb34
RR
86}
87
88//-----------------------------------------------------------------------------
b527aac5 89// "selection_received" for the actual data
dc86cb34
RR
90//-----------------------------------------------------------------------------
91
fd0eed64 92static void
b527aac5
RR
93selection_received( GtkWidget *WXUNUSED(widget),
94 GtkSelectionData *selection_data,
95 wxClipboard *clipboard )
dc86cb34 96{
8b53e5a2 97 if (!wxTheClipboard) return;
b527aac5 98
8b53e5a2
RR
99 wxDataObject *data_object = clipboard->m_receivedData;
100
101 if (!data_object) return;
102
103 if (selection_data->length <= 0) return;
b527aac5 104
8b53e5a2
RR
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;
dc86cb34 154}
fd0eed64
RR
155
156//-----------------------------------------------------------------------------
157// "selection_clear"
158//-----------------------------------------------------------------------------
159
160static gint
aeeb6a44 161selection_clear_clip( GtkWidget *WXUNUSED(widget), GdkEventSelection *event )
fd0eed64 162{
8b53e5a2 163 if (!wxTheClipboard) return TRUE;
2830bf19 164
aeeb6a44
RR
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.
b527aac5 184
aeeb6a44
RR
185 wxTheClipboard->m_dataObjects.Clear();
186 }
fd0eed64 187
8b53e5a2 188 return TRUE;
fd0eed64
RR
189}
190
191//-----------------------------------------------------------------------------
192// selection handler for supplying data
193//-----------------------------------------------------------------------------
194
195static void
196selection_handler( GtkWidget *WXUNUSED(widget), GtkSelectionData *selection_data, gpointer WXUNUSED(data) )
197{
8b53e5a2 198 if (!wxTheClipboard) return;
fd0eed64 199
8b53e5a2
RR
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 }
fd0eed64 262}
dc86cb34
RR
263
264//-----------------------------------------------------------------------------
265// wxClipboard
266//-----------------------------------------------------------------------------
267
268IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
269
270wxClipboard::wxClipboard()
271{
8b53e5a2
RR
272 m_open = FALSE;
273
aeeb6a44
RR
274 m_ownsClipboard = FALSE;
275 m_ownsPrimarySelection = FALSE;
276
8b53e5a2 277 m_dataObjects.DeleteContents( TRUE );
fd0eed64 278
8b53e5a2 279 m_receivedData = (wxDataObject*) NULL;
99c67c77 280
8b53e5a2
RR
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",
aeeb6a44 286 GTK_SIGNAL_FUNC( selection_clear_clip ),
8b53e5a2 287 (gpointer) NULL );
fd0eed64 288
8b53e5a2
RR
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;
dc86cb34
RR
295}
296
297wxClipboard::~wxClipboard()
b527aac5 298{
8b53e5a2 299 Clear();
b527aac5 300
8b53e5a2 301 if (m_clipboardWidget) gtk_widget_destroy( m_clipboardWidget );
b527aac5
RR
302}
303
304void wxClipboard::Clear()
dc86cb34 305{
8b53e5a2
RR
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 */
fd0eed64 310
aeeb6a44 311 if (gdk_selection_owner_get( g_clipboardAtom ) == m_clipboardWidget->window)
8b53e5a2
RR
312 {
313 gtk_selection_owner_set( (GtkWidget*) NULL, g_clipboardAtom, GDK_CURRENT_TIME );
314 }
db1b4961 315
aeeb6a44
RR
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
8b53e5a2
RR
321 m_dataObjects.Clear();
322 }
b527aac5 323
8b53e5a2 324 m_targetRequested = 0;
b527aac5 325
8b53e5a2
RR
326 m_formatSupported = FALSE;
327}
328
329bool wxClipboard::Open()
330{
331 wxCHECK_MSG( !m_open, FALSE, "clipboard already open" );
b527aac5 332
8b53e5a2 333 m_open = TRUE;
b527aac5 334
8b53e5a2 335 return TRUE;
dc86cb34
RR
336}
337
8b53e5a2 338bool wxClipboard::SetData( wxDataObject *data )
dc86cb34 339{
8b53e5a2 340 wxCHECK_MSG( data, FALSE, "data is invalid" );
db1b4961 341
2830bf19
RR
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
8b53e5a2
RR
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 }
aeeb6a44
RR
374
375 // This should happen automatically
8b53e5a2 376
aeeb6a44
RR
377 m_ownsClipboard = FALSE;
378 m_ownsPrimarySelection = FALSE;
379
8b53e5a2
RR
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
aeeb6a44
RR
388 gtk_selection_add_handler( m_clipboardWidget,
389 GDK_SELECTION_PRIMARY,
390 data->m_formatAtom,
391 selection_handler,
392 NULL );
393
8b53e5a2
RR
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 }
aeeb6a44
RR
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;
8b53e5a2
RR
411
412 return TRUE;
413}
db1b4961 414
8b53e5a2
RR
415void wxClipboard::Close()
416{
417 wxCHECK_RET( m_open, "clipboard not open" );
418
419 m_open = FALSE;
dc86cb34
RR
420}
421
8b53e5a2 422bool wxClipboard::IsSupportedFormat( wxDataFormat format, const wxString &id )
b527aac5 423{
8b53e5a2 424 m_targetRequested = GetTargetAtom( format, id );
b527aac5 425
8b53e5a2
RR
426 if (m_targetRequested == 0) return FALSE;
427
428 // add handler for target (= format) query
b527aac5 429
8b53e5a2
RR
430 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
431 "selection_received",
432 GTK_SIGNAL_FUNC( targets_selection_received ),
433 (gpointer) this );
b527aac5 434
8b53e5a2 435 m_formatSupported = FALSE;
b527aac5 436
8b53e5a2
RR
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 );
b527aac5 444
8b53e5a2
RR
445 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget),
446 GTK_SIGNAL_FUNC( targets_selection_received ),
447 (gpointer) this );
b527aac5 448
8b53e5a2 449 if (!m_formatSupported) return FALSE;
b527aac5 450
8b53e5a2 451 return TRUE;
b527aac5
RR
452}
453
8b53e5a2 454bool wxClipboard::GetData( wxDataObject *data )
dc86cb34 455{
8b53e5a2
RR
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;
b527aac5 476
8b53e5a2 477 wxCHECK_MSG( m_targetRequested, FALSE, "unsupported clipboard format" );
b527aac5 478
8b53e5a2 479 m_formatSupported = FALSE;
b527aac5 480
8b53e5a2
RR
481 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
482 "selection_received",
483 GTK_SIGNAL_FUNC( selection_received ),
484 (gpointer) this );
b527aac5 485
8b53e5a2
RR
486 gtk_selection_convert( m_clipboardWidget,
487 g_clipboardAtom,
488 m_targetRequested,
489 GDK_CURRENT_TIME );
b527aac5 490
8b53e5a2
RR
491 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget),
492 GTK_SIGNAL_FUNC( selection_received ),
493 (gpointer) this );
b527aac5 494
8b53e5a2
RR
495 wxCHECK_MSG( m_formatSupported, FALSE, "error retrieving data from clipboard" );
496
497 return TRUE;
b527aac5
RR
498}
499
8b53e5a2 500GdkAtom wxClipboard::GetTargetAtom( wxDataFormat format, const wxString &id )
b527aac5 501{
8b53e5a2
RR
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;
dc86cb34
RR
532}
533
b527aac5
RR
534//-----------------------------------------------------------------------------
535// wxClipboardModule
536//-----------------------------------------------------------------------------
537
538IMPLEMENT_DYNAMIC_CLASS(wxClipboardModule,wxModule)
539
540bool wxClipboardModule::OnInit()
541{
8b53e5a2 542 wxTheClipboard = new wxClipboard();
b527aac5 543
8b53e5a2 544 return TRUE;
b527aac5
RR
545}
546
547void wxClipboardModule::OnExit()
dc86cb34 548{
8b53e5a2
RR
549 if (wxTheClipboard) delete wxTheClipboard;
550 wxTheClipboard = (wxClipboard*) NULL;
dc86cb34 551}
ac57418f
RR
552
553#endif
554
555 // wxUSE_CLIPBOARD
556