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