]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/clipbrd.cpp
1. the common helper functions are now in src/unix/utilsunx.cpp
[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
0d2a2b60 107 if (data_object->GetFormat().GetAtom() != selection_data->target) return;
8b53e5a2
RR
108
109 // make sure we got the data in the correct form (selection type).
110 // if so, copy data to target object
111
0d2a2b60 112 switch (data_object->GetFormat().GetType())
8b53e5a2
RR
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 {
0d2a2b60
RR
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 }
aeeb6a44 189 }
fd0eed64 190
8b53e5a2 191 return TRUE;
fd0eed64
RR
192}
193
194//-----------------------------------------------------------------------------
195// selection handler for supplying data
196//-----------------------------------------------------------------------------
197
198static void
199selection_handler( GtkWidget *WXUNUSED(widget), GtkSelectionData *selection_data, gpointer WXUNUSED(data) )
200{
8b53e5a2 201 if (!wxTheClipboard) return;
fd0eed64 202
0d2a2b60
RR
203 if (!wxTheClipboard->m_dataBroker) return;
204
205 wxNode *node = wxTheClipboard->m_dataBroker->m_dataObjects.First();
8b53e5a2
RR
206
207 while (node)
208 {
209 wxDataObject *data_object = (wxDataObject *)node->Data();
210
0d2a2b60 211 if (data_object->GetFormat().GetAtom() != selection_data->target)
8b53e5a2
RR
212 {
213 node = node->Next();
214 break;
215 }
216
0d2a2b60 217 switch (data_object->GetFormat().GetType())
8b53e5a2
RR
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
0d2a2b60 251 if (private_object->GetSize() == 0) return;
8b53e5a2
RR
252
253 gtk_selection_data_set(
254 selection_data,
255 GDK_SELECTION_TYPE_STRING,
256 8*sizeof(gchar),
257 (unsigned char*) private_object->GetData(),
0d2a2b60 258 (int) private_object->GetSize() );
8b53e5a2
RR
259 }
260
261 default:
262 break;
263 }
264
265 node = node->Next();
266 }
fd0eed64 267}
dc86cb34
RR
268
269//-----------------------------------------------------------------------------
270// wxClipboard
271//-----------------------------------------------------------------------------
272
273IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
274
275wxClipboard::wxClipboard()
276{
8b53e5a2
RR
277 m_open = FALSE;
278
aeeb6a44
RR
279 m_ownsClipboard = FALSE;
280 m_ownsPrimarySelection = FALSE;
281
0d2a2b60 282 m_dataBroker = (wxDataBroker*) NULL;
fd0eed64 283
8b53e5a2 284 m_receivedData = (wxDataObject*) NULL;
99c67c77 285
8b53e5a2
RR
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",
aeeb6a44 291 GTK_SIGNAL_FUNC( selection_clear_clip ),
8b53e5a2 292 (gpointer) NULL );
fd0eed64 293
8b53e5a2
RR
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;
dc86cb34
RR
300}
301
302wxClipboard::~wxClipboard()
b527aac5 303{
8b53e5a2 304 Clear();
b527aac5 305
8b53e5a2 306 if (m_clipboardWidget) gtk_widget_destroy( m_clipboardWidget );
b527aac5
RR
307}
308
309void wxClipboard::Clear()
dc86cb34 310{
0d2a2b60 311 if (m_dataBroker)
8b53e5a2
RR
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 */
fd0eed64 315
aeeb6a44 316 if (gdk_selection_owner_get( g_clipboardAtom ) == m_clipboardWidget->window)
8b53e5a2
RR
317 {
318 gtk_selection_owner_set( (GtkWidget*) NULL, g_clipboardAtom, GDK_CURRENT_TIME );
319 }
db1b4961 320
aeeb6a44
RR
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
0d2a2b60
RR
326 if (m_dataBroker)
327 {
328 delete m_dataBroker;
329 m_dataBroker = (wxDataBroker*) NULL;
330 }
8b53e5a2 331 }
b527aac5 332
8b53e5a2 333 m_targetRequested = 0;
b527aac5 334
8b53e5a2
RR
335 m_formatSupported = FALSE;
336}
337
338bool wxClipboard::Open()
339{
340 wxCHECK_MSG( !m_open, FALSE, "clipboard already open" );
b527aac5 341
8b53e5a2 342 m_open = TRUE;
b527aac5 343
8b53e5a2 344 return TRUE;
dc86cb34
RR
345}
346
75ce0581 347bool wxClipboard::SetData( wxDataObject *data )
dc86cb34 348{
75ce0581
RR
349 wxCHECK_MSG( m_open, FALSE, "clipboard not open" );
350
8b53e5a2 351 wxCHECK_MSG( data, FALSE, "data is invalid" );
db1b4961 352
0d2a2b60 353 Clear();
75ce0581
RR
354
355 return AddData( data );
356}
357
358bool wxClipboard::AddData( wxDataObject *data )
359{
360 wxCHECK_MSG( m_open, FALSE, "clipboard not open" );
0d2a2b60 361
75ce0581 362 wxCHECK_MSG( data, FALSE, "data is invalid" );
2830bf19 363
75ce0581 364 /* if clipboard has been cleared before, create new data broker */
8b53e5a2 365
75ce0581 366 if (!m_dataBroker) m_dataBroker = new wxDataBroker();
8b53e5a2 367
75ce0581
RR
368 /* add new data to list of offered data objects */
369
370 m_dataBroker->Add( data );
371
372 /* get native format id of new data object */
373
374 GdkAtom format = data->GetFormat().GetAtom();
8b53e5a2 375
75ce0581
RR
376 wxCHECK_MSG( format, FALSE, "data has invalid format" );
377
378 /* This should happen automatically, but to be on the safe side */
8b53e5a2 379
75ce0581
RR
380 m_ownsClipboard = FALSE;
381 m_ownsPrimarySelection = FALSE;
aeeb6a44 382
75ce0581 383 /* Add handlers if someone requests data */
8b53e5a2 384
75ce0581 385 gtk_selection_add_handler( m_clipboardWidget,
8b53e5a2 386 g_clipboardAtom,
0d2a2b60 387 format,
8b53e5a2 388 selection_handler,
0d2a2b60 389 (gpointer) NULL );
8b53e5a2 390
75ce0581 391 gtk_selection_add_handler( m_clipboardWidget,
aeeb6a44 392 GDK_SELECTION_PRIMARY,
0d2a2b60 393 format,
aeeb6a44 394 selection_handler,
0d2a2b60 395 (gpointer) NULL );
aeeb6a44 396
75ce0581 397 /* Tell the world we offer clipboard data */
8b53e5a2 398
75ce0581 399 if (!gtk_selection_owner_set( m_clipboardWidget,
8b53e5a2
RR
400 g_clipboardAtom,
401 GDK_CURRENT_TIME ))
75ce0581
RR
402 {
403 return FALSE;
404 }
405 m_ownsClipboard = TRUE;
aeeb6a44 406
75ce0581 407 if (!gtk_selection_owner_set( m_clipboardWidget,
aeeb6a44
RR
408 GDK_SELECTION_PRIMARY,
409 GDK_CURRENT_TIME ))
75ce0581
RR
410 {
411 return FALSE;
aeeb6a44 412 }
75ce0581
RR
413 m_ownsPrimarySelection = TRUE;
414
8b53e5a2
RR
415 return TRUE;
416}
db1b4961 417
8b53e5a2
RR
418void wxClipboard::Close()
419{
420 wxCHECK_RET( m_open, "clipboard not open" );
421
422 m_open = FALSE;
dc86cb34
RR
423}
424
5f699c22 425bool wxClipboard::IsSupported( wxDataFormat format )
b527aac5 426{
0d2a2b60
RR
427 wxCHECK_MSG( m_open, FALSE, "clipboard not open" );
428
75ce0581 429 /* store requested format to be asked for by callbacks */
0d2a2b60 430
5f699c22 431 m_targetRequested = format.GetAtom();
b527aac5 432
0d2a2b60
RR
433 wxCHECK_MSG( m_targetRequested, FALSE, "invalid clipboard format" );
434
0d2a2b60 435 /* add handler for target (= format) query */
b527aac5 436
8b53e5a2
RR
437 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
438 "selection_received",
439 GTK_SIGNAL_FUNC( targets_selection_received ),
440 (gpointer) this );
b527aac5 441
8b53e5a2 442 m_formatSupported = FALSE;
b527aac5 443
0d2a2b60
RR
444 /* perform query. this will set m_formatSupported to
445 * TRUE if m_targetRequested is supported */
8b53e5a2
RR
446
447 gtk_selection_convert( m_clipboardWidget,
448 g_clipboardAtom,
449 g_targetsAtom,
450 GDK_CURRENT_TIME );
b527aac5 451
8b53e5a2
RR
452 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget),
453 GTK_SIGNAL_FUNC( targets_selection_received ),
454 (gpointer) this );
b527aac5 455
8b53e5a2 456 if (!m_formatSupported) return FALSE;
75ce0581
RR
457
458 return TRUE;
459}
460
5f699c22 461bool wxClipboard::GetData( wxDataObject *data )
75ce0581
RR
462{
463 wxCHECK_MSG( m_open, FALSE, "clipboard not open" );
464
465 /* is data supported by clipboard ? */
466
5f699c22 467 if (!IsSupported( data->GetFormat() )) return FALSE;
75ce0581
RR
468
469 /* store pointer to data object to be filled up by callbacks */
470
5f699c22 471 m_receivedData = data;
75ce0581
RR
472
473 /* store requested format to be asked for by callbacks */
474
5f699c22 475 m_targetRequested = data->GetFormat().GetAtom();
b527aac5 476
75ce0581
RR
477 wxCHECK_MSG( m_targetRequested, FALSE, "invalid clipboard format" );
478
479 /* start query */
8b53e5a2 480
8b53e5a2 481 m_formatSupported = FALSE;
b527aac5 482
8b53e5a2
RR
483 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
484 "selection_received",
485 GTK_SIGNAL_FUNC( selection_received ),
486 (gpointer) this );
b527aac5 487
75ce0581
RR
488 /* ask for clipboard contents */
489
8b53e5a2
RR
490 gtk_selection_convert( m_clipboardWidget,
491 g_clipboardAtom,
492 m_targetRequested,
493 GDK_CURRENT_TIME );
b527aac5 494
8b53e5a2
RR
495 gtk_signal_disconnect_by_func( GTK_OBJECT(m_clipboardWidget),
496 GTK_SIGNAL_FUNC( selection_received ),
497 (gpointer) this );
b527aac5 498
0d2a2b60
RR
499 /* this is a true error as we checked for the presence of such data before */
500
8b53e5a2
RR
501 wxCHECK_MSG( m_formatSupported, FALSE, "error retrieving data from clipboard" );
502
503 return TRUE;
b527aac5
RR
504}
505
b527aac5
RR
506//-----------------------------------------------------------------------------
507// wxClipboardModule
508//-----------------------------------------------------------------------------
509
510IMPLEMENT_DYNAMIC_CLASS(wxClipboardModule,wxModule)
511
512bool wxClipboardModule::OnInit()
513{
8b53e5a2 514 wxTheClipboard = new wxClipboard();
b527aac5 515
8b53e5a2 516 return TRUE;
b527aac5
RR
517}
518
519void wxClipboardModule::OnExit()
dc86cb34 520{
8b53e5a2
RR
521 if (wxTheClipboard) delete wxTheClipboard;
522 wxTheClipboard = (wxClipboard*) NULL;
dc86cb34 523}
ac57418f
RR
524
525#endif
526
527 // wxUSE_CLIPBOARD
528