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