]> git.saurik.com Git - wxWidgets.git/blame - src/x11/clipbrd.cpp
fix crash in wxRadioBox creation due to its DoGetBestSize() now being called from...
[wxWidgets.git] / src / x11 / clipbrd.cpp
CommitLineData
83df96d6 1/////////////////////////////////////////////////////////////////////////////
e4db172a 2// Name: src/x11/clipbrd.cpp
83df96d6 3// Purpose: Clipboard functionality
9691c806 4// Author: Robert Roebling
e4db172a 5// Created:
83df96d6 6// RCS-ID: $Id$
9691c806 7// Copyright: (c) Robert Roebling
e4db172a 8// Licence: wxWindows licence
83df96d6
JS
9/////////////////////////////////////////////////////////////////////////////
10
e4db172a
WS
11// for compilers that support precompilation, includes "wx.h".
12#include "wx/wxprec.h"
83df96d6
JS
13
14#if wxUSE_CLIPBOARD
15
e4db172a
WS
16#include "wx/clipbrd.h"
17
18#ifndef WX_PRECOMP
19 #include "wx/log.h"
de6185e2 20 #include "wx/utils.h"
28f92d74 21 #include "wx/dataobj.h"
e4db172a
WS
22#endif
23
9691c806
RR
24#include "wx/x11/private.h"
25
26//-----------------------------------------------------------------------------
27// data
28//-----------------------------------------------------------------------------
29
70b8ab77 30#if !wxUSE_NANOX
9691c806
RR
31Atom g_clipboardAtom = 0;
32Atom g_targetsAtom = 0;
70b8ab77 33#endif
83df96d6 34
9691c806
RR
35// the trace mask we use with wxLogTrace() - call
36// wxLog::AddTraceMask(TRACE_CLIPBOARD) to enable the trace messages from here
37// (there will be a *lot* of them!)
38static const wxChar *TRACE_CLIPBOARD = _T("clipboard");
83df96d6 39
9691c806
RR
40//-----------------------------------------------------------------------------
41// reminder
42//-----------------------------------------------------------------------------
83df96d6 43
9691c806
RR
44/* The contents of a selection are returned in a GtkSelectionData
45 structure. selection/target identify the request.
46 type specifies the type of the return; if length < 0, and
47 the data should be ignored. This structure has object semantics -
48 no fields should be modified directly, they should not be created
49 directly, and pointers to them should not be stored beyond the duration of
50 a callback. (If the last is changed, we'll need to add reference
51 counting)
83df96d6 52
9691c806 53struct _GtkSelectionData
83df96d6 54{
9691c806
RR
55 GdkAtom selection;
56 GdkAtom target;
57 GdkAtom type;
58 gint format;
59 guchar *data;
60 gint length;
61};
62
63*/
64
65//-----------------------------------------------------------------------------
66// "selection_received" for targets
67//-----------------------------------------------------------------------------
68
69#if 0
83df96d6 70
9691c806
RR
71static void
72targets_selection_received( GtkWidget *WXUNUSED(widget),
73 GtkSelectionData *selection_data,
74#if (GTK_MINOR_VERSION > 0)
75 guint32 WXUNUSED(time),
76#endif
77 wxClipboard *clipboard )
83df96d6 78{
9691c806 79 if ( wxTheClipboard && selection_data->length > 0 )
83df96d6 80 {
9691c806
RR
81 /* make sure we got the data in the correct form */
82 GdkAtom type = selection_data->type;
83 if ( type != GDK_SELECTION_TYPE_ATOM )
84 {
85 if ( strcmp(gdk_atom_name(type), "TARGETS") )
86 {
87 wxLogTrace( TRACE_CLIPBOARD,
88 _T("got unsupported clipboard target") );
83df96d6 89
de6185e2 90 clipboard->m_waiting = false;
9691c806
RR
91 return;
92 }
93 }
83df96d6 94
9691c806
RR
95#ifdef __WXDEBUG__
96 wxDataFormat clip( selection_data->selection );
97 wxLogTrace( TRACE_CLIPBOARD,
98 wxT("selection received for targets, clipboard %s"),
99 clip.GetId().c_str() );
100#endif // __WXDEBUG__
83df96d6 101
9691c806
RR
102 // the atoms we received, holding a list of targets (= formats)
103 GdkAtom *atoms = (GdkAtom *)selection_data->data;
83df96d6 104
9691c806
RR
105 for (unsigned int i=0; i<selection_data->length/sizeof(GdkAtom); i++)
106 {
107 wxDataFormat format( atoms[i] );
83df96d6 108
9691c806
RR
109 wxLogTrace( TRACE_CLIPBOARD,
110 wxT("selection received for targets, format %s"),
111 format.GetId().c_str() );
83df96d6 112
9691c806
RR
113 if (format == clipboard->m_targetRequested)
114 {
de6185e2 115 clipboard->m_waiting = false;
e4db172a 116 clipboard->m_formatSupported = true;
9691c806
RR
117 return;
118 }
119 }
120 }
83df96d6 121
de6185e2 122 clipboard->m_waiting = false;
9691c806 123}
83df96d6 124
9691c806
RR
125//-----------------------------------------------------------------------------
126// "selection_received" for the actual data
127//-----------------------------------------------------------------------------
83df96d6 128
9691c806
RR
129static void
130selection_received( GtkWidget *WXUNUSED(widget),
131 GtkSelectionData *selection_data,
132#if (GTK_MINOR_VERSION > 0)
133 guint32 WXUNUSED(time),
134#endif
135 wxClipboard *clipboard )
136{
137 if (!wxTheClipboard)
138 {
de6185e2 139 clipboard->m_waiting = false;
9691c806
RR
140 return;
141 }
83df96d6 142
9691c806 143 wxDataObject *data_object = clipboard->m_receivedData;
83df96d6 144
9691c806
RR
145 if (!data_object)
146 {
de6185e2 147 clipboard->m_waiting = false;
9691c806
RR
148 return;
149 }
83df96d6 150
9691c806
RR
151 if (selection_data->length <= 0)
152 {
de6185e2 153 clipboard->m_waiting = false;
9691c806
RR
154 return;
155 }
83df96d6 156
9691c806 157 wxDataFormat format( selection_data->target );
83df96d6 158
9691c806
RR
159 /* make sure we got the data in the correct format */
160 if (!data_object->IsSupportedFormat( format ) )
161 {
de6185e2 162 clipboard->m_waiting = false;
9691c806
RR
163 return;
164 }
83df96d6 165
9691c806
RR
166 /* make sure we got the data in the correct form (selection type).
167 if so, copy data to target object */
168 if (selection_data->type != GDK_SELECTION_TYPE_STRING)
169 {
de6185e2 170 clipboard->m_waiting = false;
9691c806
RR
171 return;
172 }
83df96d6 173
9691c806 174 data_object->SetData( format, (size_t) selection_data->length, (const char*) selection_data->data );
83df96d6 175
e4db172a 176 wxTheClipboard->m_formatSupported = true;
de6185e2 177 clipboard->m_waiting = false;
83df96d6
JS
178}
179
9691c806
RR
180//-----------------------------------------------------------------------------
181// "selection_clear"
182//-----------------------------------------------------------------------------
83df96d6 183
9691c806
RR
184static gint
185selection_clear_clip( GtkWidget *WXUNUSED(widget), GdkEventSelection *event )
186{
187 if (!wxTheClipboard) return TRUE;
83df96d6 188
9691c806
RR
189 if (event->selection == GDK_SELECTION_PRIMARY)
190 {
de6185e2 191 wxTheClipboard->m_ownsPrimarySelection = false;
9691c806
RR
192 }
193 else
194 if (event->selection == g_clipboardAtom)
195 {
de6185e2 196 wxTheClipboard->m_ownsClipboard = false;
9691c806
RR
197 }
198 else
199 {
de6185e2 200 wxTheClipboard->m_waiting = false;
9691c806
RR
201 return FALSE;
202 }
83df96d6 203
9691c806
RR
204 if ((!wxTheClipboard->m_ownsPrimarySelection) &&
205 (!wxTheClipboard->m_ownsClipboard))
83df96d6 206 {
9691c806
RR
207 /* the clipboard is no longer in our hands. we can the delete clipboard data. */
208 if (wxTheClipboard->m_data)
83df96d6 209 {
9691c806
RR
210 wxLogTrace(TRACE_CLIPBOARD, wxT("wxClipboard will get cleared" ));
211
212 delete wxTheClipboard->m_data;
213 wxTheClipboard->m_data = (wxDataObject*) NULL;
214 }
83df96d6
JS
215 }
216
de6185e2 217 wxTheClipboard->m_waiting = false;
9691c806 218 return TRUE;
83df96d6
JS
219}
220
9691c806
RR
221//-----------------------------------------------------------------------------
222// selection handler for supplying data
223//-----------------------------------------------------------------------------
83df96d6 224
9691c806
RR
225static void
226selection_handler( GtkWidget *WXUNUSED(widget),
227 GtkSelectionData *selection_data,
228 guint WXUNUSED(info),
229 guint WXUNUSED(time),
230 gpointer WXUNUSED(data) )
83df96d6 231{
9691c806 232 if (!wxTheClipboard) return;
83df96d6 233
9691c806
RR
234 if (!wxTheClipboard->m_data) return;
235
236 wxDataObject *data = wxTheClipboard->m_data;
237
238 wxDataFormat format( selection_data->target );
239
240 if (!data->IsSupportedFormat( format )) return;
241
242 int size = data->GetDataSize( format );
243
244 if (size == 0) return;
245
246 void *d = malloc(size);
247
248 data->GetDataHere( selection_data->target, d );
249
250 // transform Unicode text into multibyte before putting it on clipboard
251#if wxUSE_UNICODE
daad5a23 252 if ( format.GetType() == wxDF_TEXT || format.GetType() == wxDF_UNICODETEXT)
83df96d6 253 {
9691c806
RR
254 const wchar_t *wstr = (const wchar_t *)d;
255 size_t len = wxConvCurrent->WC2MB(NULL, wstr, 0);
256 char *str = malloc(len + 1);
257 wxConvCurrent->WC2MB(str, wstr, len);
258 str[len] = '\0';
259
260 free(d);
261 d = str;
83df96d6 262 }
9691c806
RR
263#endif // wxUSE_UNICODE
264
265 gtk_selection_data_set(
266 selection_data,
267 GDK_SELECTION_TYPE_STRING,
268 8*sizeof(gchar),
269 (unsigned char*) d,
270 size );
271
272 free(d);
83df96d6
JS
273}
274
9691c806
RR
275#endif
276
83df96d6
JS
277//-----------------------------------------------------------------------------
278// wxClipboard
279//-----------------------------------------------------------------------------
280
281IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
282
283wxClipboard::wxClipboard()
284{
de6185e2 285 m_open = false;
9691c806 286
de6185e2
WS
287 m_ownsClipboard = false;
288 m_ownsPrimarySelection = false;
9691c806
RR
289
290 m_data = (wxDataObject*) NULL;
291 m_receivedData = (wxDataObject*) NULL;
292
293 /* we use m_targetsWidget to query what formats are available */
294
295 /* we use m_clipboardWidget to get and to offer data */
70b8ab77 296#if !wxUSE_NANOX
9691c806
RR
297 if (!g_clipboardAtom) g_clipboardAtom = XInternAtom( (Display*) wxGetDisplay(), "CLIPBOARD", False );
298 if (!g_targetsAtom) g_targetsAtom = XInternAtom( (Display*) wxGetDisplay(), "TARGETS", False );
70b8ab77 299#endif
e4db172a 300
de6185e2 301 m_formatSupported = false;
9691c806
RR
302 m_targetRequested = 0;
303
de6185e2 304 m_usePrimary = false;
83df96d6
JS
305}
306
307wxClipboard::~wxClipboard()
308{
9691c806
RR
309 Clear();
310
311// if (m_clipboardWidget) gtk_widget_destroy( m_clipboardWidget );
312// if (m_targetsWidget) gtk_widget_destroy( m_targetsWidget );
83df96d6
JS
313}
314
315void wxClipboard::Clear()
316{
9691c806 317 if (m_data)
83df96d6 318 {
9691c806
RR
319#if wxUSE_THREADS
320 /* disable GUI threads */
321#endif
322
323 /* As we have data we also own the clipboard. Once we no longer own
324 it, clear_selection is called which will set m_data to zero */
325#if 0
326 if (gdk_selection_owner_get( g_clipboardAtom ) == m_clipboardWidget->window)
327 {
e4db172a 328 m_waiting = true;
9691c806
RR
329
330 gtk_selection_owner_set( (GtkWidget*) NULL, g_clipboardAtom,
331 (guint32) GDK_CURRENT_TIME );
332
333 while (m_waiting) gtk_main_iteration();
334 }
335
336 if (gdk_selection_owner_get( GDK_SELECTION_PRIMARY ) == m_clipboardWidget->window)
337 {
e4db172a 338 m_waiting = true;
9691c806
RR
339
340 gtk_selection_owner_set( (GtkWidget*) NULL, GDK_SELECTION_PRIMARY,
341 (guint32) GDK_CURRENT_TIME );
342
343 while (m_waiting) gtk_main_iteration();
344 }
345#endif
346
347 if (m_data)
348 {
349 delete m_data;
350 m_data = (wxDataObject*) NULL;
351 }
352
353#if wxUSE_THREADS
354 /* re-enable GUI threads */
355#endif
83df96d6 356 }
9691c806
RR
357
358 m_targetRequested = 0;
e4db172a 359 m_formatSupported = false;
83df96d6
JS
360}
361
362bool wxClipboard::Open()
363{
e4db172a 364 wxCHECK_MSG( !m_open, false, wxT("clipboard already open") );
9691c806 365
e4db172a 366 m_open = true;
83df96d6 367
e4db172a 368 return true;
83df96d6
JS
369}
370
371bool wxClipboard::SetData( wxDataObject *data )
372{
de6185e2 373 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
9691c806 374
de6185e2 375 wxCHECK_MSG( data, false, wxT("data is invalid") );
83df96d6
JS
376
377 Clear();
378
379 return AddData( data );
380}
381
382bool wxClipboard::AddData( wxDataObject *data )
383{
70b8ab77 384#if wxUSE_NANOX
de6185e2 385 return false;
70b8ab77 386#else
de6185e2 387 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
9691c806 388
de6185e2 389 wxCHECK_MSG( data, false, wxT("data is invalid") );
9691c806
RR
390
391 /* we can only store one wxDataObject */
392 Clear();
393
394 m_data = data;
395
396 /* get formats from wxDataObjects */
397 wxDataFormat *array = new wxDataFormat[ m_data->GetFormatCount() ];
398 m_data->GetAllFormats( array );
83df96d6 399
cb78397f 400#if 0
9691c806
RR
401 /* primary selection or clipboard */
402 Atom clipboard = m_usePrimary ? (Atom) 1 // 1 = primary selection
403 : g_clipboardAtom;
cb78397f 404#endif // 0
9691c806
RR
405
406
407 for (size_t i = 0; i < m_data->GetFormatCount(); i++)
83df96d6 408 {
9691c806
RR
409 wxLogTrace( TRACE_CLIPBOARD,
410 wxT("wxClipboard now supports atom %s"),
411 array[i].GetId().c_str() );
412
83df96d6 413#if 0
9691c806
RR
414 gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget),
415 clipboard,
416 array[i],
417 0 ); /* what is info ? */
418#endif
83df96d6 419 }
9691c806
RR
420
421 delete[] array;
422
423#if 0
424 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
425 "selection_get",
426 GTK_SIGNAL_FUNC(selection_handler),
427 (gpointer) NULL );
428#endif
429
430#if wxUSE_THREADS
431 /* disable GUI threads */
432#endif
433
de6185e2 434 bool res = false;
9691c806
RR
435#if 0
436 /* Tell the world we offer clipboard data */
437 res = (gtk_selection_owner_set( m_clipboardWidget,
438 clipboard,
439 (guint32) GDK_CURRENT_TIME ));
440#endif
441
442 if (m_usePrimary)
443 m_ownsPrimarySelection = res;
444 else
445 m_ownsClipboard = res;
446
447#if wxUSE_THREADS
448 /* re-enable GUI threads */
449#endif
450
451 return res;
70b8ab77 452#endif
83df96d6
JS
453}
454
455void wxClipboard::Close()
456{
9691c806
RR
457 wxCHECK_RET( m_open, wxT("clipboard not open") );
458
de6185e2 459 m_open = false;
83df96d6
JS
460}
461
9691c806 462bool wxClipboard::IsOpened() const
83df96d6 463{
9691c806 464 return m_open;
83df96d6
JS
465}
466
9691c806 467bool wxClipboard::IsSupported( const wxDataFormat& format )
83df96d6 468{
9691c806 469 /* reentrance problems */
e4db172a 470 if (m_waiting) return false;
9691c806
RR
471
472 /* store requested format to be asked for by callbacks */
473 m_targetRequested = format;
83df96d6
JS
474
475#if 0
9691c806
RR
476 wxLogTrace( TRACE_CLIPBOARD,
477 wxT("wxClipboard:IsSupported: requested format: %s"),
478 format.GetId().c_str() );
479#endif
83df96d6 480
e4db172a 481 wxCHECK_MSG( m_targetRequested, false, wxT("invalid clipboard format") );
83df96d6 482
e4db172a 483 m_formatSupported = false;
83df96d6 484
9691c806 485 /* perform query. this will set m_formatSupported to
e4db172a 486 true if m_targetRequested is supported.
9691c806
RR
487 also, we have to wait for the "answer" from the
488 clipboard owner which is an asynchronous process.
e4db172a 489 therefore we set m_waiting = true here and wait
9691c806 490 until the callback "targets_selection_received"
e4db172a 491 sets it to false */
83df96d6 492
e4db172a 493 m_waiting = true;
83df96d6 494
9691c806
RR
495#if 0
496 gtk_selection_convert( m_targetsWidget,
497 m_usePrimary ? (GdkAtom)GDK_SELECTION_PRIMARY
498 : g_clipboardAtom,
499 g_targetsAtom,
500 (guint32) GDK_CURRENT_TIME );
83df96d6 501
9691c806
RR
502 while (m_waiting) gtk_main_iteration();
503#endif
83df96d6 504
e4db172a 505 if (!m_formatSupported) return false;
83df96d6 506
e4db172a 507 return true;
83df96d6
JS
508}
509
9691c806 510bool wxClipboard::GetData( wxDataObject& data )
83df96d6 511{
e4db172a 512 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
83df96d6 513
9691c806
RR
514 /* get formats from wxDataObjects */
515 wxDataFormat *array = new wxDataFormat[ data.GetFormatCount() ];
516 data.GetAllFormats( array );
83df96d6 517
9691c806
RR
518 for (size_t i = 0; i < data.GetFormatCount(); i++)
519 {
520 wxDataFormat format( array[i] );
521
522 wxLogTrace( TRACE_CLIPBOARD,
523 wxT("wxClipboard::GetData: requested format: %s"),
524 format.GetId().c_str() );
525
526 /* is data supported by clipboard ? */
527
528 /* store requested format to be asked for by callbacks */
529 m_targetRequested = format;
530
e4db172a 531 wxCHECK_MSG( m_targetRequested, false, wxT("invalid clipboard format") );
9691c806 532
e4db172a 533 m_formatSupported = false;
9691c806
RR
534
535 /* perform query. this will set m_formatSupported to
e4db172a 536 true if m_targetRequested is supported.
9691c806
RR
537 also, we have to wait for the "answer" from the
538 clipboard owner which is an asynchronous process.
e4db172a 539 therefore we set m_waiting = true here and wait
9691c806 540 until the callback "targets_selection_received"
de6185e2 541 sets it to false */
9691c806 542
e4db172a 543 m_waiting = true;
9691c806
RR
544
545#if 0
546 gtk_selection_convert( m_targetsWidget,
547 m_usePrimary ? (GdkAtom)GDK_SELECTION_PRIMARY
548 : g_clipboardAtom,
549 g_targetsAtom,
550 (guint32) GDK_CURRENT_TIME );
551
552 while (m_waiting) gtk_main_iteration();
553#endif
554
555 if (!m_formatSupported) continue;
556
557 /* store pointer to data object to be filled up by callbacks */
558 m_receivedData = &data;
559
560 /* store requested format to be asked for by callbacks */
561 m_targetRequested = format;
562
e4db172a 563 wxCHECK_MSG( m_targetRequested, false, wxT("invalid clipboard format") );
9691c806
RR
564
565 /* start query */
e4db172a 566 m_formatSupported = false;
9691c806
RR
567
568 /* ask for clipboard contents. this will set
e4db172a 569 m_formatSupported to true if m_targetRequested
9691c806
RR
570 is supported.
571 also, we have to wait for the "answer" from the
572 clipboard owner which is an asynchronous process.
e4db172a 573 therefore we set m_waiting = true here and wait
9691c806 574 until the callback "targets_selection_received"
e4db172a 575 sets it to false */
9691c806 576
e4db172a 577 m_waiting = true;
9691c806
RR
578
579 wxLogTrace( TRACE_CLIPBOARD,
580 wxT("wxClipboard::GetData: format found, start convert") );
581
582#if 0
583 gtk_selection_convert( m_clipboardWidget,
584 m_usePrimary ? (GdkAtom)GDK_SELECTION_PRIMARY
585 : g_clipboardAtom,
586 m_targetRequested,
587 (guint32) GDK_CURRENT_TIME );
588
589 while (m_waiting) gtk_main_iteration();
590#endif
591
592 /* this is a true error as we checked for the presence of such data before */
de6185e2 593 wxCHECK_MSG( m_formatSupported, false, wxT("error retrieving data from clipboard") );
9691c806
RR
594
595 /* return success */
596 delete[] array;
e4db172a 597 return true;
83df96d6 598 }
9691c806
RR
599
600 wxLogTrace( TRACE_CLIPBOARD,
601 wxT("wxClipboard::GetData: format not found") );
602
603 /* return failure */
604 delete[] array;
e4db172a 605 return false;
83df96d6 606}
9691c806 607
83df96d6 608#endif
9691c806 609 // wxUSE_CLIPBOARD