]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/clipbrd.cpp
Now even wxRadioButton works
[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
b527aac5 155selection_clear( GtkWidget *WXUNUSED(widget), GdkEventSelection *WXUNUSED(event) )
fd0eed64 156{
8b53e5a2 157 if (!wxTheClipboard) return TRUE;
fd0eed64 158
8b53e5a2
RR
159 // the clipboard is no longer in our hands. we have to delete the
160 // clipboard data.
b527aac5 161
8b53e5a2 162 wxTheClipboard->m_dataObjects.Clear();
fd0eed64 163
8b53e5a2 164 return TRUE;
fd0eed64
RR
165}
166
167//-----------------------------------------------------------------------------
168// selection handler for supplying data
169//-----------------------------------------------------------------------------
170
171static void
172selection_handler( GtkWidget *WXUNUSED(widget), GtkSelectionData *selection_data, gpointer WXUNUSED(data) )
173{
8b53e5a2 174 if (!wxTheClipboard) return;
fd0eed64 175
8b53e5a2
RR
176 wxNode *node = wxTheClipboard->m_dataObjects.First();
177
178 while (node)
179 {
180 wxDataObject *data_object = (wxDataObject *)node->Data();
181
182 if (data_object->m_formatAtom != selection_data->target)
183 {
184 node = node->Next();
185 break;
186 }
187
188 switch (data_object->GetFormat())
189 {
190 case wxDF_TEXT:
191 {
192 wxTextDataObject *text_object = (wxTextDataObject*) data_object;
193
194 wxString text = text_object->GetText();
195
196 char *s = WXSTRINGCAST text;
197 int len = (int) text.Length();
198
199 gtk_selection_data_set(
200 selection_data,
201 GDK_SELECTION_TYPE_STRING,
202 8*sizeof(gchar),
203 (unsigned char*) s,
204 len );
205
206 break;
207 }
208
209 case wxDF_BITMAP:
210 {
211 // wxBitmapDataObject *private_object = (wxBitmapDataObject*) data_object;
212
213 // how do we do that ?
214
215 break;
216 }
217
218 case wxDF_PRIVATE:
219 {
220 wxPrivateDataObject *private_object = (wxPrivateDataObject*) data_object;
221
222 if (private_object->GetDataSize() == 0) return;
223
224 gtk_selection_data_set(
225 selection_data,
226 GDK_SELECTION_TYPE_STRING,
227 8*sizeof(gchar),
228 (unsigned char*) private_object->GetData(),
229 (int) private_object->GetDataSize() );
230 }
231
232 default:
233 break;
234 }
235
236 node = node->Next();
237 }
fd0eed64 238}
dc86cb34
RR
239
240//-----------------------------------------------------------------------------
241// wxClipboard
242//-----------------------------------------------------------------------------
243
244IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
245
246wxClipboard::wxClipboard()
247{
8b53e5a2
RR
248 m_open = FALSE;
249
250 m_dataObjects.DeleteContents( TRUE );
fd0eed64 251
8b53e5a2 252 m_receivedData = (wxDataObject*) NULL;
99c67c77 253
8b53e5a2
RR
254 m_clipboardWidget = gtk_window_new( GTK_WINDOW_POPUP );
255 gtk_widget_realize( m_clipboardWidget );
256
257 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
258 "selection_clear_event",
259 GTK_SIGNAL_FUNC( selection_clear ),
260 (gpointer) NULL );
fd0eed64 261
8b53e5a2
RR
262 if (!g_clipboardAtom) g_clipboardAtom = gdk_atom_intern( "CLIPBOARD", FALSE );
263 if (!g_textAtom) g_textAtom = gdk_atom_intern( "TEXT", FALSE );
264 if (!g_targetsAtom) g_targetsAtom = gdk_atom_intern ("TARGETS", FALSE);
265
266 m_formatSupported = FALSE;
267 m_targetRequested = 0;
dc86cb34
RR
268}
269
270wxClipboard::~wxClipboard()
b527aac5 271{
8b53e5a2 272 Clear();
b527aac5 273
8b53e5a2 274 if (m_clipboardWidget) gtk_widget_destroy( m_clipboardWidget );
b527aac5
RR
275}
276
277void wxClipboard::Clear()
dc86cb34 278{
8b53e5a2
RR
279 if (m_dataObjects.GetCount())
280 {
281 /* As we have data we also own the clipboard. Once we no longer own
282 it, clear_selection is called which will set m_data to zero */
fd0eed64 283
8b53e5a2
RR
284 if (gdk_selection_owner_get( g_clipboardAtom) == m_clipboardWidget->window)
285 {
286 gtk_selection_owner_set( (GtkWidget*) NULL, g_clipboardAtom, GDK_CURRENT_TIME );
287 }
db1b4961 288
8b53e5a2
RR
289 m_dataObjects.Clear();
290 }
b527aac5 291
8b53e5a2 292 m_targetRequested = 0;
b527aac5 293
8b53e5a2
RR
294 m_formatSupported = FALSE;
295}
296
297bool wxClipboard::Open()
298{
299 wxCHECK_MSG( !m_open, FALSE, "clipboard already open" );
b527aac5 300
8b53e5a2 301 m_open = TRUE;
b527aac5 302
8b53e5a2 303 return TRUE;
dc86cb34
RR
304}
305
8b53e5a2 306bool wxClipboard::SetData( wxDataObject *data )
dc86cb34 307{
8b53e5a2 308 wxCHECK_MSG( data, FALSE, "data is invalid" );
db1b4961 309
8b53e5a2
RR
310 m_dataObjects.Append( data );
311
312 wxCHECK_MSG( m_open, FALSE, "clipboard not open" );
313
314 if (data->GetFormat() == wxDF_PRIVATE)
315 {
316 wxPrivateDataObject* pd = (wxPrivateDataObject*) data;
317
318 wxCHECK_MSG( !pd->GetId().IsEmpty(), FALSE, "private clipboard format requires ID string" );
319
320 data->m_formatAtom = GetTargetAtom( data->GetFormat(), pd->GetId() );
321 }
322 else
323 {
324 data->m_formatAtom = GetTargetAtom( data->GetFormat() );
325 }
326
327 // Add handlers if someone requests data
328
329 gtk_selection_add_handler( m_clipboardWidget,
330 g_clipboardAtom,
331 data->m_formatAtom,
332 selection_handler,
333 NULL );
334
335 // Tell the world we offer clipboard data
336
337 if (!gtk_selection_owner_set( m_clipboardWidget,
338 g_clipboardAtom,
339 GDK_CURRENT_TIME ))
340 {
341 return FALSE;
342 }
343
344 return TRUE;
345}
db1b4961 346
8b53e5a2
RR
347void wxClipboard::Close()
348{
349 wxCHECK_RET( m_open, "clipboard not open" );
350
351 m_open = FALSE;
dc86cb34
RR
352}
353
8b53e5a2 354bool wxClipboard::IsSupportedFormat( wxDataFormat format, const wxString &id )
b527aac5 355{
8b53e5a2 356 m_targetRequested = GetTargetAtom( format, id );
b527aac5 357
8b53e5a2
RR
358 if (m_targetRequested == 0) return FALSE;
359
360 // add handler for target (= format) query
b527aac5 361
8b53e5a2
RR
362 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
363 "selection_received",
364 GTK_SIGNAL_FUNC( targets_selection_received ),
365 (gpointer) this );
b527aac5 366
8b53e5a2 367 m_formatSupported = FALSE;
b527aac5 368
8b53e5a2
RR
369 // perform query. this will set m_formatSupported to
370 // TRUE if m_targetRequested is supported
371
372 gtk_selection_convert( m_clipboardWidget,
373 g_clipboardAtom,
374 g_targetsAtom,
375 GDK_CURRENT_TIME );
b527aac5 376
8b53e5a2
RR
377 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget),
378 GTK_SIGNAL_FUNC( targets_selection_received ),
379 (gpointer) this );
b527aac5 380
8b53e5a2 381 if (!m_formatSupported) return FALSE;
b527aac5 382
8b53e5a2 383 return TRUE;
b527aac5
RR
384}
385
8b53e5a2 386bool wxClipboard::GetData( wxDataObject *data )
dc86cb34 387{
8b53e5a2
RR
388 wxCHECK_MSG( m_open, FALSE, "clipboard not open" );
389
390 m_receivedData = data;
391
392 wxCHECK_MSG( m_receivedData, FALSE, "invalid data object" );
393
394 if (m_receivedData->GetFormat() == wxDF_PRIVATE)
395 {
396 wxPrivateDataObject* pd = (wxPrivateDataObject*) m_receivedData;
397
398 wxCHECK_MSG( !pd->GetId().IsEmpty(), FALSE, "private clipboard format requires ID string" );
399
400 m_targetRequested = GetTargetAtom( m_receivedData->GetFormat(), pd->GetId() );
401 }
402 else
403 {
404 m_targetRequested = GetTargetAtom( m_receivedData->GetFormat() );
405 }
406
407 data->m_formatAtom = m_targetRequested;
b527aac5 408
8b53e5a2 409 wxCHECK_MSG( m_targetRequested, FALSE, "unsupported clipboard format" );
b527aac5 410
8b53e5a2 411 m_formatSupported = FALSE;
b527aac5 412
8b53e5a2
RR
413 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
414 "selection_received",
415 GTK_SIGNAL_FUNC( selection_received ),
416 (gpointer) this );
b527aac5 417
8b53e5a2
RR
418 gtk_selection_convert( m_clipboardWidget,
419 g_clipboardAtom,
420 m_targetRequested,
421 GDK_CURRENT_TIME );
b527aac5 422
8b53e5a2
RR
423 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget),
424 GTK_SIGNAL_FUNC( selection_received ),
425 (gpointer) this );
b527aac5 426
8b53e5a2
RR
427 wxCHECK_MSG( m_formatSupported, FALSE, "error retrieving data from clipboard" );
428
429 return TRUE;
b527aac5
RR
430}
431
8b53e5a2 432GdkAtom wxClipboard::GetTargetAtom( wxDataFormat format, const wxString &id )
b527aac5 433{
8b53e5a2
RR
434 // What is X representation of that format?
435
436 switch (format)
437 {
438 case wxDF_TEXT:
439 {
440 return GDK_TARGET_STRING;
441 // g_textAtom
442 }
443
444 case wxDF_BITMAP:
445 {
446 return GDK_TARGET_BITMAP;
447 break;
448 }
449
450 case wxDF_PRIVATE:
451 {
452 // we create our own X representation
453
454 return gdk_atom_intern( WXSTRINGCAST( id ), FALSE );
455 }
456
457 default:
458 {
459 return (GdkAtom) 0;
460 }
461 }
462
463 return (GdkAtom) 0;
dc86cb34
RR
464}
465
b527aac5
RR
466//-----------------------------------------------------------------------------
467// wxClipboardModule
468//-----------------------------------------------------------------------------
469
470IMPLEMENT_DYNAMIC_CLASS(wxClipboardModule,wxModule)
471
472bool wxClipboardModule::OnInit()
473{
8b53e5a2 474 wxTheClipboard = new wxClipboard();
b527aac5 475
8b53e5a2 476 return TRUE;
b527aac5
RR
477}
478
479void wxClipboardModule::OnExit()
dc86cb34 480{
8b53e5a2
RR
481 if (wxTheClipboard) delete wxTheClipboard;
482 wxTheClipboard = (wxClipboard*) NULL;
dc86cb34 483}