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