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