]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/x11/clipbrd.cpp
Misc XRC format docs corrections.
[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// Copyright: (c) Robert Roebling
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// for compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
13#if wxUSE_CLIPBOARD
14
15#include "wx/clipbrd.h"
16
17#ifndef WX_PRECOMP
18 #include "wx/log.h"
19 #include "wx/utils.h"
20 #include "wx/dataobj.h"
21#endif
22
23#include "wx/x11/private.h"
24
25//-----------------------------------------------------------------------------
26// data
27//-----------------------------------------------------------------------------
28
29#if !wxUSE_NANOX
30Atom g_clipboardAtom = 0;
31Atom g_targetsAtom = 0;
32#endif
33
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)
37
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!)
41static const wxChar *TRACE_CLIPBOARD = wxT("clipboard");
42
43#endif // __WXDEBUG__
44
45//-----------------------------------------------------------------------------
46// reminder
47//-----------------------------------------------------------------------------
48
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)
57
58struct _GtkSelectionData
59{
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
75
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 )
83{
84 if ( wxTheClipboard && selection_data->length > 0 )
85 {
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,
93 wxT("got unsupported clipboard target") );
94
95 clipboard->m_waiting = false;
96 return;
97 }
98 }
99
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__
106
107 // the atoms we received, holding a list of targets (= formats)
108 GdkAtom *atoms = (GdkAtom *)selection_data->data;
109
110 for (unsigned int i=0; i<selection_data->length/sizeof(GdkAtom); i++)
111 {
112 wxDataFormat format( atoms[i] );
113
114 wxLogTrace( TRACE_CLIPBOARD,
115 wxT("selection received for targets, format %s"),
116 format.GetId().c_str() );
117
118 if (format == clipboard->m_targetRequested)
119 {
120 clipboard->m_waiting = false;
121 clipboard->m_formatSupported = true;
122 return;
123 }
124 }
125 }
126
127 clipboard->m_waiting = false;
128}
129
130//-----------------------------------------------------------------------------
131// "selection_received" for the actual data
132//-----------------------------------------------------------------------------
133
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 {
144 clipboard->m_waiting = false;
145 return;
146 }
147
148 wxDataObject *data_object = clipboard->m_receivedData;
149
150 if (!data_object)
151 {
152 clipboard->m_waiting = false;
153 return;
154 }
155
156 if (selection_data->length <= 0)
157 {
158 clipboard->m_waiting = false;
159 return;
160 }
161
162 wxDataFormat format( selection_data->target );
163
164 /* make sure we got the data in the correct format */
165 if (!data_object->IsSupportedFormat( format ) )
166 {
167 clipboard->m_waiting = false;
168 return;
169 }
170
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 {
175 clipboard->m_waiting = false;
176 return;
177 }
178
179 data_object->SetData( format, (size_t) selection_data->length, (const char*) selection_data->data );
180
181 wxTheClipboard->m_formatSupported = true;
182 clipboard->m_waiting = false;
183}
184
185//-----------------------------------------------------------------------------
186// "selection_clear"
187//-----------------------------------------------------------------------------
188
189static gint
190selection_clear_clip( GtkWidget *WXUNUSED(widget), GdkEventSelection *event )
191{
192 if (!wxTheClipboard) return TRUE;
193
194 if (event->selection == GDK_SELECTION_PRIMARY)
195 {
196 wxTheClipboard->m_ownsPrimarySelection = false;
197 }
198 else
199 if (event->selection == g_clipboardAtom)
200 {
201 wxTheClipboard->m_ownsClipboard = false;
202 }
203 else
204 {
205 wxTheClipboard->m_waiting = false;
206 return FALSE;
207 }
208
209 if ((!wxTheClipboard->m_ownsPrimarySelection) &&
210 (!wxTheClipboard->m_ownsClipboard))
211 {
212 /* the clipboard is no longer in our hands. we can the delete clipboard data. */
213 if (wxTheClipboard->m_data)
214 {
215 wxLogTrace(TRACE_CLIPBOARD, wxT("wxClipboard will get cleared" ));
216
217 wxDELETE(wxTheClipboard->m_data);
218 }
219 }
220
221 wxTheClipboard->m_waiting = false;
222 return TRUE;
223}
224
225//-----------------------------------------------------------------------------
226// selection handler for supplying data
227//-----------------------------------------------------------------------------
228
229static void
230selection_handler( GtkWidget *WXUNUSED(widget),
231 GtkSelectionData *selection_data,
232 guint WXUNUSED(info),
233 guint WXUNUSED(time),
234 gpointer WXUNUSED(data) )
235{
236 if (!wxTheClipboard) return;
237
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
256 if ( format.GetType() == wxDF_TEXT || format.GetType() == wxDF_UNICODETEXT)
257 {
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;
266 }
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);
277}
278
279#endif
280
281//-----------------------------------------------------------------------------
282// wxClipboard
283//-----------------------------------------------------------------------------
284
285IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
286
287wxClipboard::wxClipboard()
288{
289 m_open = false;
290
291 m_ownsClipboard = false;
292 m_ownsPrimarySelection = false;
293
294 m_data = NULL;
295 m_receivedData = NULL;
296
297 /* we use m_targetsWidget to query what formats are available */
298
299 /* we use m_clipboardWidget to get and to offer data */
300#if !wxUSE_NANOX
301 if (!g_clipboardAtom) g_clipboardAtom = XInternAtom( (Display*) wxGetDisplay(), "CLIPBOARD", False );
302 if (!g_targetsAtom) g_targetsAtom = XInternAtom( (Display*) wxGetDisplay(), "TARGETS", False );
303#endif
304
305 m_formatSupported = false;
306 m_targetRequested = 0;
307}
308
309wxClipboard::~wxClipboard()
310{
311 Clear();
312
313// if (m_clipboardWidget) gtk_widget_destroy( m_clipboardWidget );
314// if (m_targetsWidget) gtk_widget_destroy( m_targetsWidget );
315}
316
317void wxClipboard::Clear()
318{
319 if (m_data)
320 {
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 {
330 m_waiting = true;
331
332 gtk_selection_owner_set( 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 {
340 m_waiting = true;
341
342 gtk_selection_owner_set( NULL, GDK_SELECTION_PRIMARY,
343 (guint32) GDK_CURRENT_TIME );
344
345 while (m_waiting) gtk_main_iteration();
346 }
347#endif
348
349 wxDELETE(m_data);
350
351#if wxUSE_THREADS
352 /* re-enable GUI threads */
353#endif
354 }
355
356 m_targetRequested = 0;
357 m_formatSupported = false;
358}
359
360bool wxClipboard::Open()
361{
362 wxCHECK_MSG( !m_open, false, wxT("clipboard already open") );
363
364 m_open = true;
365
366 return true;
367}
368
369bool wxClipboard::SetData( wxDataObject *data )
370{
371 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
372
373 wxCHECK_MSG( data, false, wxT("data is invalid") );
374
375 Clear();
376
377 return AddData( data );
378}
379
380bool wxClipboard::AddData( wxDataObject *data )
381{
382#if wxUSE_NANOX
383 return false;
384#else
385 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
386
387 wxCHECK_MSG( data, false, wxT("data is invalid") );
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 );
397
398#if 0
399 /* primary selection or clipboard */
400 Atom clipboard = m_usePrimary ? (Atom) 1 // 1 = primary selection
401 : g_clipboardAtom;
402#endif // 0
403
404
405 for (size_t i = 0; i < m_data->GetFormatCount(); i++)
406 {
407 wxLogTrace( TRACE_CLIPBOARD,
408 wxT("wxClipboard now supports atom %s"),
409 array[i].GetId().c_str() );
410
411#if 0
412 gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget),
413 clipboard,
414 array[i],
415 0 ); /* what is info ? */
416#endif
417 }
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
432 bool res = false;
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;
450#endif
451}
452
453void wxClipboard::Close()
454{
455 wxCHECK_RET( m_open, wxT("clipboard not open") );
456
457 m_open = false;
458}
459
460bool wxClipboard::IsOpened() const
461{
462 return m_open;
463}
464
465bool wxClipboard::IsSupported( const wxDataFormat& format )
466{
467 /* reentrance problems */
468 if (m_waiting) return false;
469
470 /* store requested format to be asked for by callbacks */
471 m_targetRequested = format;
472
473#if 0
474 wxLogTrace( TRACE_CLIPBOARD,
475 wxT("wxClipboard:IsSupported: requested format: %s"),
476 format.GetId().c_str() );
477#endif
478
479 wxCHECK_MSG( m_targetRequested, false, wxT("invalid clipboard format") );
480
481 m_formatSupported = false;
482
483 /* perform query. this will set m_formatSupported to
484 true if m_targetRequested is supported.
485 also, we have to wait for the "answer" from the
486 clipboard owner which is an asynchronous process.
487 therefore we set m_waiting = true here and wait
488 until the callback "targets_selection_received"
489 sets it to false */
490
491 m_waiting = true;
492
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 );
499
500 while (m_waiting) gtk_main_iteration();
501#endif
502
503 if (!m_formatSupported) return false;
504
505 return true;
506}
507
508bool wxClipboard::GetData( wxDataObject& data )
509{
510 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
511
512 /* get formats from wxDataObjects */
513 wxDataFormat *array = new wxDataFormat[ data.GetFormatCount() ];
514 data.GetAllFormats( array );
515
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
529 wxCHECK_MSG( m_targetRequested, false, wxT("invalid clipboard format") );
530
531 m_formatSupported = false;
532
533 /* perform query. this will set m_formatSupported to
534 true if m_targetRequested is supported.
535 also, we have to wait for the "answer" from the
536 clipboard owner which is an asynchronous process.
537 therefore we set m_waiting = true here and wait
538 until the callback "targets_selection_received"
539 sets it to false */
540
541 m_waiting = true;
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
561 wxCHECK_MSG( m_targetRequested, false, wxT("invalid clipboard format") );
562
563 /* start query */
564 m_formatSupported = false;
565
566 /* ask for clipboard contents. this will set
567 m_formatSupported to true if m_targetRequested
568 is supported.
569 also, we have to wait for the "answer" from the
570 clipboard owner which is an asynchronous process.
571 therefore we set m_waiting = true here and wait
572 until the callback "targets_selection_received"
573 sets it to false */
574
575 m_waiting = true;
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 */
591 wxCHECK_MSG( m_formatSupported, false, wxT("error retrieving data from clipboard") );
592
593 /* return success */
594 delete[] array;
595 return true;
596 }
597
598 wxLogTrace( TRACE_CLIPBOARD,
599 wxT("wxClipboard::GetData: format not found") );
600
601 /* return failure */
602 delete[] array;
603 return false;
604}
605
606#endif
607 // wxUSE_CLIPBOARD