]> git.saurik.com Git - wxWidgets.git/blame - src/x11/clipbrd.cpp
[wxGTK2] Make the affirmative button the default in native wxDirDialog implementation...
[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"
e4db172a
WS
21#endif
22
83df96d6
JS
23#include "wx/dataobj.h"
24
9691c806
RR
25#include "wx/x11/private.h"
26
27//-----------------------------------------------------------------------------
28// data
29//-----------------------------------------------------------------------------
30
70b8ab77 31#if !wxUSE_NANOX
9691c806
RR
32Atom g_clipboardAtom = 0;
33Atom g_targetsAtom = 0;
70b8ab77 34#endif
83df96d6 35
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");
83df96d6 40
9691c806
RR
41//-----------------------------------------------------------------------------
42// reminder
43//-----------------------------------------------------------------------------
83df96d6 44
9691c806
RR
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)
83df96d6 53
9691c806 54struct _GtkSelectionData
83df96d6 55{
9691c806
RR
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
83df96d6 71
9691c806
RR
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 )
83df96d6 79{
9691c806 80 if ( wxTheClipboard && selection_data->length > 0 )
83df96d6 81 {
9691c806
RR
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") );
83df96d6 90
de6185e2 91 clipboard->m_waiting = false;
9691c806
RR
92 return;
93 }
94 }
83df96d6 95
9691c806
RR
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__
83df96d6 102
9691c806
RR
103 // the atoms we received, holding a list of targets (= formats)
104 GdkAtom *atoms = (GdkAtom *)selection_data->data;
83df96d6 105
9691c806
RR
106 for (unsigned int i=0; i<selection_data->length/sizeof(GdkAtom); i++)
107 {
108 wxDataFormat format( atoms[i] );
83df96d6 109
9691c806
RR
110 wxLogTrace( TRACE_CLIPBOARD,
111 wxT("selection received for targets, format %s"),
112 format.GetId().c_str() );
83df96d6 113
9691c806
RR
114 if (format == clipboard->m_targetRequested)
115 {
de6185e2 116 clipboard->m_waiting = false;
e4db172a 117 clipboard->m_formatSupported = true;
9691c806
RR
118 return;
119 }
120 }
121 }
83df96d6 122
de6185e2 123 clipboard->m_waiting = false;
9691c806 124}
83df96d6 125
9691c806
RR
126//-----------------------------------------------------------------------------
127// "selection_received" for the actual data
128//-----------------------------------------------------------------------------
83df96d6 129
9691c806
RR
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 {
de6185e2 140 clipboard->m_waiting = false;
9691c806
RR
141 return;
142 }
83df96d6 143
9691c806 144 wxDataObject *data_object = clipboard->m_receivedData;
83df96d6 145
9691c806
RR
146 if (!data_object)
147 {
de6185e2 148 clipboard->m_waiting = false;
9691c806
RR
149 return;
150 }
83df96d6 151
9691c806
RR
152 if (selection_data->length <= 0)
153 {
de6185e2 154 clipboard->m_waiting = false;
9691c806
RR
155 return;
156 }
83df96d6 157
9691c806 158 wxDataFormat format( selection_data->target );
83df96d6 159
9691c806
RR
160 /* make sure we got the data in the correct format */
161 if (!data_object->IsSupportedFormat( format ) )
162 {
de6185e2 163 clipboard->m_waiting = false;
9691c806
RR
164 return;
165 }
83df96d6 166
9691c806
RR
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 {
de6185e2 171 clipboard->m_waiting = false;
9691c806
RR
172 return;
173 }
83df96d6 174
9691c806 175 data_object->SetData( format, (size_t) selection_data->length, (const char*) selection_data->data );
83df96d6 176
e4db172a 177 wxTheClipboard->m_formatSupported = true;
de6185e2 178 clipboard->m_waiting = false;
83df96d6
JS
179}
180
9691c806
RR
181//-----------------------------------------------------------------------------
182// "selection_clear"
183//-----------------------------------------------------------------------------
83df96d6 184
9691c806
RR
185static gint
186selection_clear_clip( GtkWidget *WXUNUSED(widget), GdkEventSelection *event )
187{
188 if (!wxTheClipboard) return TRUE;
83df96d6 189
9691c806
RR
190 if (event->selection == GDK_SELECTION_PRIMARY)
191 {
de6185e2 192 wxTheClipboard->m_ownsPrimarySelection = false;
9691c806
RR
193 }
194 else
195 if (event->selection == g_clipboardAtom)
196 {
de6185e2 197 wxTheClipboard->m_ownsClipboard = false;
9691c806
RR
198 }
199 else
200 {
de6185e2 201 wxTheClipboard->m_waiting = false;
9691c806
RR
202 return FALSE;
203 }
83df96d6 204
9691c806
RR
205 if ((!wxTheClipboard->m_ownsPrimarySelection) &&
206 (!wxTheClipboard->m_ownsClipboard))
83df96d6 207 {
9691c806
RR
208 /* the clipboard is no longer in our hands. we can the delete clipboard data. */
209 if (wxTheClipboard->m_data)
83df96d6 210 {
9691c806
RR
211 wxLogTrace(TRACE_CLIPBOARD, wxT("wxClipboard will get cleared" ));
212
213 delete wxTheClipboard->m_data;
214 wxTheClipboard->m_data = (wxDataObject*) NULL;
215 }
83df96d6
JS
216 }
217
de6185e2 218 wxTheClipboard->m_waiting = false;
9691c806 219 return TRUE;
83df96d6
JS
220}
221
9691c806
RR
222//-----------------------------------------------------------------------------
223// selection handler for supplying data
224//-----------------------------------------------------------------------------
83df96d6 225
9691c806
RR
226static void
227selection_handler( GtkWidget *WXUNUSED(widget),
228 GtkSelectionData *selection_data,
229 guint WXUNUSED(info),
230 guint WXUNUSED(time),
231 gpointer WXUNUSED(data) )
83df96d6 232{
9691c806 233 if (!wxTheClipboard) return;
83df96d6 234
9691c806
RR
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 )
83df96d6 254 {
9691c806
RR
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;
83df96d6 263 }
9691c806
RR
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);
83df96d6
JS
274}
275
9691c806
RR
276#endif
277
83df96d6
JS
278//-----------------------------------------------------------------------------
279// wxClipboard
280//-----------------------------------------------------------------------------
281
282IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
283
284wxClipboard::wxClipboard()
285{
de6185e2 286 m_open = false;
9691c806 287
de6185e2
WS
288 m_ownsClipboard = false;
289 m_ownsPrimarySelection = false;
9691c806
RR
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 */
70b8ab77 297#if !wxUSE_NANOX
9691c806
RR
298 if (!g_clipboardAtom) g_clipboardAtom = XInternAtom( (Display*) wxGetDisplay(), "CLIPBOARD", False );
299 if (!g_targetsAtom) g_targetsAtom = XInternAtom( (Display*) wxGetDisplay(), "TARGETS", False );
70b8ab77 300#endif
e4db172a 301
de6185e2 302 m_formatSupported = false;
9691c806
RR
303 m_targetRequested = 0;
304
de6185e2 305 m_usePrimary = false;
83df96d6
JS
306}
307
308wxClipboard::~wxClipboard()
309{
9691c806
RR
310 Clear();
311
312// if (m_clipboardWidget) gtk_widget_destroy( m_clipboardWidget );
313// if (m_targetsWidget) gtk_widget_destroy( m_targetsWidget );
83df96d6
JS
314}
315
316void wxClipboard::Clear()
317{
9691c806 318 if (m_data)
83df96d6 319 {
9691c806
RR
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 {
e4db172a 329 m_waiting = true;
9691c806
RR
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 {
e4db172a 339 m_waiting = true;
9691c806
RR
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
83df96d6 357 }
9691c806
RR
358
359 m_targetRequested = 0;
e4db172a 360 m_formatSupported = false;
83df96d6
JS
361}
362
363bool wxClipboard::Open()
364{
e4db172a 365 wxCHECK_MSG( !m_open, false, wxT("clipboard already open") );
9691c806 366
e4db172a 367 m_open = true;
83df96d6 368
e4db172a 369 return true;
83df96d6
JS
370}
371
372bool wxClipboard::SetData( wxDataObject *data )
373{
de6185e2 374 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
9691c806 375
de6185e2 376 wxCHECK_MSG( data, false, wxT("data is invalid") );
83df96d6
JS
377
378 Clear();
379
380 return AddData( data );
381}
382
383bool wxClipboard::AddData( wxDataObject *data )
384{
70b8ab77 385#if wxUSE_NANOX
de6185e2 386 return false;
70b8ab77 387#else
de6185e2 388 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
9691c806 389
de6185e2 390 wxCHECK_MSG( data, false, wxT("data is invalid") );
9691c806
RR
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 );
83df96d6 400
cb78397f 401#if 0
9691c806
RR
402 /* primary selection or clipboard */
403 Atom clipboard = m_usePrimary ? (Atom) 1 // 1 = primary selection
404 : g_clipboardAtom;
cb78397f 405#endif // 0
9691c806
RR
406
407
408 for (size_t i = 0; i < m_data->GetFormatCount(); i++)
83df96d6 409 {
9691c806
RR
410 wxLogTrace( TRACE_CLIPBOARD,
411 wxT("wxClipboard now supports atom %s"),
412 array[i].GetId().c_str() );
413
83df96d6 414#if 0
9691c806
RR
415 gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget),
416 clipboard,
417 array[i],
418 0 ); /* what is info ? */
419#endif
83df96d6 420 }
9691c806
RR
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
de6185e2 435 bool res = false;
9691c806
RR
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;
70b8ab77 453#endif
83df96d6
JS
454}
455
456void wxClipboard::Close()
457{
9691c806
RR
458 wxCHECK_RET( m_open, wxT("clipboard not open") );
459
de6185e2 460 m_open = false;
83df96d6
JS
461}
462
9691c806 463bool wxClipboard::IsOpened() const
83df96d6 464{
9691c806 465 return m_open;
83df96d6
JS
466}
467
9691c806 468bool wxClipboard::IsSupported( const wxDataFormat& format )
83df96d6 469{
9691c806 470 /* reentrance problems */
e4db172a 471 if (m_waiting) return false;
9691c806
RR
472
473 /* store requested format to be asked for by callbacks */
474 m_targetRequested = format;
83df96d6
JS
475
476#if 0
9691c806
RR
477 wxLogTrace( TRACE_CLIPBOARD,
478 wxT("wxClipboard:IsSupported: requested format: %s"),
479 format.GetId().c_str() );
480#endif
83df96d6 481
e4db172a 482 wxCHECK_MSG( m_targetRequested, false, wxT("invalid clipboard format") );
83df96d6 483
e4db172a 484 m_formatSupported = false;
83df96d6 485
9691c806 486 /* perform query. this will set m_formatSupported to
e4db172a 487 true if m_targetRequested is supported.
9691c806
RR
488 also, we have to wait for the "answer" from the
489 clipboard owner which is an asynchronous process.
e4db172a 490 therefore we set m_waiting = true here and wait
9691c806 491 until the callback "targets_selection_received"
e4db172a 492 sets it to false */
83df96d6 493
e4db172a 494 m_waiting = true;
83df96d6 495
9691c806
RR
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 );
83df96d6 502
9691c806
RR
503 while (m_waiting) gtk_main_iteration();
504#endif
83df96d6 505
e4db172a 506 if (!m_formatSupported) return false;
83df96d6 507
e4db172a 508 return true;
83df96d6
JS
509}
510
9691c806 511bool wxClipboard::GetData( wxDataObject& data )
83df96d6 512{
e4db172a 513 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
83df96d6 514
9691c806
RR
515 /* get formats from wxDataObjects */
516 wxDataFormat *array = new wxDataFormat[ data.GetFormatCount() ];
517 data.GetAllFormats( array );
83df96d6 518
9691c806
RR
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
e4db172a 532 wxCHECK_MSG( m_targetRequested, false, wxT("invalid clipboard format") );
9691c806 533
e4db172a 534 m_formatSupported = false;
9691c806
RR
535
536 /* perform query. this will set m_formatSupported to
e4db172a 537 true if m_targetRequested is supported.
9691c806
RR
538 also, we have to wait for the "answer" from the
539 clipboard owner which is an asynchronous process.
e4db172a 540 therefore we set m_waiting = true here and wait
9691c806 541 until the callback "targets_selection_received"
de6185e2 542 sets it to false */
9691c806 543
e4db172a 544 m_waiting = true;
9691c806
RR
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
e4db172a 564 wxCHECK_MSG( m_targetRequested, false, wxT("invalid clipboard format") );
9691c806
RR
565
566 /* start query */
e4db172a 567 m_formatSupported = false;
9691c806
RR
568
569 /* ask for clipboard contents. this will set
e4db172a 570 m_formatSupported to true if m_targetRequested
9691c806
RR
571 is supported.
572 also, we have to wait for the "answer" from the
573 clipboard owner which is an asynchronous process.
e4db172a 574 therefore we set m_waiting = true here and wait
9691c806 575 until the callback "targets_selection_received"
e4db172a 576 sets it to false */
9691c806 577
e4db172a 578 m_waiting = true;
9691c806
RR
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 */
de6185e2 594 wxCHECK_MSG( m_formatSupported, false, wxT("error retrieving data from clipboard") );
9691c806
RR
595
596 /* return success */
597 delete[] array;
e4db172a 598 return true;
83df96d6 599 }
9691c806
RR
600
601 wxLogTrace( TRACE_CLIPBOARD,
602 wxT("wxClipboard::GetData: format not found") );
603
604 /* return failure */
605 delete[] array;
e4db172a 606 return false;
83df96d6 607}
9691c806 608
83df96d6 609#endif
9691c806 610 // wxUSE_CLIPBOARD