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