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