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