]> git.saurik.com Git - wxWidgets.git/blame - src/x11/clipbrd.cpp
fix combobox dropdown position in RTL (patch 1623127)
[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
b6349b16
VZ
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)
542a26ba 38
9691c806
RR
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");
542a26ba 43
0b575029 44#endif // __WXDEBUG__
83df96d6 45
9691c806
RR
46//-----------------------------------------------------------------------------
47// reminder
48//-----------------------------------------------------------------------------
83df96d6 49
9691c806
RR
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)
83df96d6 58
9691c806 59struct _GtkSelectionData
83df96d6 60{
9691c806
RR
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
83df96d6 76
9691c806
RR
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 )
83df96d6 84{
9691c806 85 if ( wxTheClipboard && selection_data->length > 0 )
83df96d6 86 {
9691c806
RR
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") );
83df96d6 95
de6185e2 96 clipboard->m_waiting = false;
9691c806
RR
97 return;
98 }
99 }
83df96d6 100
9691c806
RR
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__
83df96d6 107
9691c806
RR
108 // the atoms we received, holding a list of targets (= formats)
109 GdkAtom *atoms = (GdkAtom *)selection_data->data;
83df96d6 110
9691c806
RR
111 for (unsigned int i=0; i<selection_data->length/sizeof(GdkAtom); i++)
112 {
113 wxDataFormat format( atoms[i] );
83df96d6 114
9691c806
RR
115 wxLogTrace( TRACE_CLIPBOARD,
116 wxT("selection received for targets, format %s"),
117 format.GetId().c_str() );
83df96d6 118
9691c806
RR
119 if (format == clipboard->m_targetRequested)
120 {
de6185e2 121 clipboard->m_waiting = false;
e4db172a 122 clipboard->m_formatSupported = true;
9691c806
RR
123 return;
124 }
125 }
126 }
83df96d6 127
de6185e2 128 clipboard->m_waiting = false;
9691c806 129}
83df96d6 130
9691c806
RR
131//-----------------------------------------------------------------------------
132// "selection_received" for the actual data
133//-----------------------------------------------------------------------------
83df96d6 134
9691c806
RR
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 {
de6185e2 145 clipboard->m_waiting = false;
9691c806
RR
146 return;
147 }
83df96d6 148
9691c806 149 wxDataObject *data_object = clipboard->m_receivedData;
83df96d6 150
9691c806
RR
151 if (!data_object)
152 {
de6185e2 153 clipboard->m_waiting = false;
9691c806
RR
154 return;
155 }
83df96d6 156
9691c806
RR
157 if (selection_data->length <= 0)
158 {
de6185e2 159 clipboard->m_waiting = false;
9691c806
RR
160 return;
161 }
83df96d6 162
9691c806 163 wxDataFormat format( selection_data->target );
83df96d6 164
9691c806
RR
165 /* make sure we got the data in the correct format */
166 if (!data_object->IsSupportedFormat( format ) )
167 {
de6185e2 168 clipboard->m_waiting = false;
9691c806
RR
169 return;
170 }
83df96d6 171
9691c806
RR
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 {
de6185e2 176 clipboard->m_waiting = false;
9691c806
RR
177 return;
178 }
83df96d6 179
9691c806 180 data_object->SetData( format, (size_t) selection_data->length, (const char*) selection_data->data );
83df96d6 181
e4db172a 182 wxTheClipboard->m_formatSupported = true;
de6185e2 183 clipboard->m_waiting = false;
83df96d6
JS
184}
185
9691c806
RR
186//-----------------------------------------------------------------------------
187// "selection_clear"
188//-----------------------------------------------------------------------------
83df96d6 189
9691c806
RR
190static gint
191selection_clear_clip( GtkWidget *WXUNUSED(widget), GdkEventSelection *event )
192{
193 if (!wxTheClipboard) return TRUE;
83df96d6 194
9691c806
RR
195 if (event->selection == GDK_SELECTION_PRIMARY)
196 {
de6185e2 197 wxTheClipboard->m_ownsPrimarySelection = false;
9691c806
RR
198 }
199 else
200 if (event->selection == g_clipboardAtom)
201 {
de6185e2 202 wxTheClipboard->m_ownsClipboard = false;
9691c806
RR
203 }
204 else
205 {
de6185e2 206 wxTheClipboard->m_waiting = false;
9691c806
RR
207 return FALSE;
208 }
83df96d6 209
9691c806
RR
210 if ((!wxTheClipboard->m_ownsPrimarySelection) &&
211 (!wxTheClipboard->m_ownsClipboard))
83df96d6 212 {
9691c806
RR
213 /* the clipboard is no longer in our hands. we can the delete clipboard data. */
214 if (wxTheClipboard->m_data)
83df96d6 215 {
9691c806
RR
216 wxLogTrace(TRACE_CLIPBOARD, wxT("wxClipboard will get cleared" ));
217
218 delete wxTheClipboard->m_data;
219 wxTheClipboard->m_data = (wxDataObject*) NULL;
220 }
83df96d6
JS
221 }
222
de6185e2 223 wxTheClipboard->m_waiting = false;
9691c806 224 return TRUE;
83df96d6
JS
225}
226
9691c806
RR
227//-----------------------------------------------------------------------------
228// selection handler for supplying data
229//-----------------------------------------------------------------------------
83df96d6 230
9691c806
RR
231static void
232selection_handler( GtkWidget *WXUNUSED(widget),
233 GtkSelectionData *selection_data,
234 guint WXUNUSED(info),
235 guint WXUNUSED(time),
236 gpointer WXUNUSED(data) )
83df96d6 237{
9691c806 238 if (!wxTheClipboard) return;
83df96d6 239
9691c806
RR
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
daad5a23 258 if ( format.GetType() == wxDF_TEXT || format.GetType() == wxDF_UNICODETEXT)
83df96d6 259 {
9691c806
RR
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;
83df96d6 268 }
9691c806
RR
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);
83df96d6
JS
279}
280
9691c806
RR
281#endif
282
83df96d6
JS
283//-----------------------------------------------------------------------------
284// wxClipboard
285//-----------------------------------------------------------------------------
286
287IMPLEMENT_DYNAMIC_CLASS(wxClipboard,wxObject)
288
289wxClipboard::wxClipboard()
290{
de6185e2 291 m_open = false;
9691c806 292
de6185e2
WS
293 m_ownsClipboard = false;
294 m_ownsPrimarySelection = false;
9691c806
RR
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 */
70b8ab77 302#if !wxUSE_NANOX
9691c806
RR
303 if (!g_clipboardAtom) g_clipboardAtom = XInternAtom( (Display*) wxGetDisplay(), "CLIPBOARD", False );
304 if (!g_targetsAtom) g_targetsAtom = XInternAtom( (Display*) wxGetDisplay(), "TARGETS", False );
70b8ab77 305#endif
e4db172a 306
de6185e2 307 m_formatSupported = false;
9691c806
RR
308 m_targetRequested = 0;
309
de6185e2 310 m_usePrimary = false;
83df96d6
JS
311}
312
313wxClipboard::~wxClipboard()
314{
9691c806
RR
315 Clear();
316
317// if (m_clipboardWidget) gtk_widget_destroy( m_clipboardWidget );
318// if (m_targetsWidget) gtk_widget_destroy( m_targetsWidget );
83df96d6
JS
319}
320
321void wxClipboard::Clear()
322{
9691c806 323 if (m_data)
83df96d6 324 {
9691c806
RR
325#if wxUSE_THREADS
326 /* disable GUI threads */
327#endif
328
329 /* As we have data we also own the clipboard. Once we no longer own
330 it, clear_selection is called which will set m_data to zero */
331#if 0
332 if (gdk_selection_owner_get( g_clipboardAtom ) == m_clipboardWidget->window)
333 {
e4db172a 334 m_waiting = true;
9691c806
RR
335
336 gtk_selection_owner_set( (GtkWidget*) NULL, g_clipboardAtom,
337 (guint32) GDK_CURRENT_TIME );
338
339 while (m_waiting) gtk_main_iteration();
340 }
341
342 if (gdk_selection_owner_get( GDK_SELECTION_PRIMARY ) == m_clipboardWidget->window)
343 {
e4db172a 344 m_waiting = true;
9691c806
RR
345
346 gtk_selection_owner_set( (GtkWidget*) NULL, GDK_SELECTION_PRIMARY,
347 (guint32) GDK_CURRENT_TIME );
348
349 while (m_waiting) gtk_main_iteration();
350 }
351#endif
352
353 if (m_data)
354 {
355 delete m_data;
356 m_data = (wxDataObject*) NULL;
357 }
358
359#if wxUSE_THREADS
360 /* re-enable GUI threads */
361#endif
83df96d6 362 }
9691c806
RR
363
364 m_targetRequested = 0;
e4db172a 365 m_formatSupported = false;
83df96d6
JS
366}
367
368bool wxClipboard::Open()
369{
e4db172a 370 wxCHECK_MSG( !m_open, false, wxT("clipboard already open") );
9691c806 371
e4db172a 372 m_open = true;
83df96d6 373
e4db172a 374 return true;
83df96d6
JS
375}
376
377bool wxClipboard::SetData( wxDataObject *data )
378{
de6185e2 379 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
9691c806 380
de6185e2 381 wxCHECK_MSG( data, false, wxT("data is invalid") );
83df96d6
JS
382
383 Clear();
384
385 return AddData( data );
386}
387
388bool wxClipboard::AddData( wxDataObject *data )
389{
70b8ab77 390#if wxUSE_NANOX
de6185e2 391 return false;
70b8ab77 392#else
de6185e2 393 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
9691c806 394
de6185e2 395 wxCHECK_MSG( data, false, wxT("data is invalid") );
9691c806
RR
396
397 /* we can only store one wxDataObject */
398 Clear();
399
400 m_data = data;
401
402 /* get formats from wxDataObjects */
403 wxDataFormat *array = new wxDataFormat[ m_data->GetFormatCount() ];
404 m_data->GetAllFormats( array );
83df96d6 405
cb78397f 406#if 0
9691c806
RR
407 /* primary selection or clipboard */
408 Atom clipboard = m_usePrimary ? (Atom) 1 // 1 = primary selection
409 : g_clipboardAtom;
cb78397f 410#endif // 0
9691c806
RR
411
412
413 for (size_t i = 0; i < m_data->GetFormatCount(); i++)
83df96d6 414 {
9691c806
RR
415 wxLogTrace( TRACE_CLIPBOARD,
416 wxT("wxClipboard now supports atom %s"),
417 array[i].GetId().c_str() );
418
83df96d6 419#if 0
9691c806
RR
420 gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget),
421 clipboard,
422 array[i],
423 0 ); /* what is info ? */
424#endif
83df96d6 425 }
9691c806
RR
426
427 delete[] array;
428
429#if 0
430 gtk_signal_connect( GTK_OBJECT(m_clipboardWidget),
431 "selection_get",
432 GTK_SIGNAL_FUNC(selection_handler),
433 (gpointer) NULL );
434#endif
435
436#if wxUSE_THREADS
437 /* disable GUI threads */
438#endif
439
de6185e2 440 bool res = false;
9691c806
RR
441#if 0
442 /* Tell the world we offer clipboard data */
443 res = (gtk_selection_owner_set( m_clipboardWidget,
444 clipboard,
445 (guint32) GDK_CURRENT_TIME ));
446#endif
447
448 if (m_usePrimary)
449 m_ownsPrimarySelection = res;
450 else
451 m_ownsClipboard = res;
452
453#if wxUSE_THREADS
454 /* re-enable GUI threads */
455#endif
456
457 return res;
70b8ab77 458#endif
83df96d6
JS
459}
460
461void wxClipboard::Close()
462{
9691c806
RR
463 wxCHECK_RET( m_open, wxT("clipboard not open") );
464
de6185e2 465 m_open = false;
83df96d6
JS
466}
467
9691c806 468bool wxClipboard::IsOpened() const
83df96d6 469{
9691c806 470 return m_open;
83df96d6
JS
471}
472
9691c806 473bool wxClipboard::IsSupported( const wxDataFormat& format )
83df96d6 474{
9691c806 475 /* reentrance problems */
e4db172a 476 if (m_waiting) return false;
9691c806
RR
477
478 /* store requested format to be asked for by callbacks */
479 m_targetRequested = format;
83df96d6
JS
480
481#if 0
9691c806
RR
482 wxLogTrace( TRACE_CLIPBOARD,
483 wxT("wxClipboard:IsSupported: requested format: %s"),
484 format.GetId().c_str() );
485#endif
83df96d6 486
e4db172a 487 wxCHECK_MSG( m_targetRequested, false, wxT("invalid clipboard format") );
83df96d6 488
e4db172a 489 m_formatSupported = false;
83df96d6 490
9691c806 491 /* perform query. this will set m_formatSupported to
e4db172a 492 true if m_targetRequested is supported.
9691c806
RR
493 also, we have to wait for the "answer" from the
494 clipboard owner which is an asynchronous process.
e4db172a 495 therefore we set m_waiting = true here and wait
9691c806 496 until the callback "targets_selection_received"
e4db172a 497 sets it to false */
83df96d6 498
e4db172a 499 m_waiting = true;
83df96d6 500
9691c806
RR
501#if 0
502 gtk_selection_convert( m_targetsWidget,
503 m_usePrimary ? (GdkAtom)GDK_SELECTION_PRIMARY
504 : g_clipboardAtom,
505 g_targetsAtom,
506 (guint32) GDK_CURRENT_TIME );
83df96d6 507
9691c806
RR
508 while (m_waiting) gtk_main_iteration();
509#endif
83df96d6 510
e4db172a 511 if (!m_formatSupported) return false;
83df96d6 512
e4db172a 513 return true;
83df96d6
JS
514}
515
9691c806 516bool wxClipboard::GetData( wxDataObject& data )
83df96d6 517{
e4db172a 518 wxCHECK_MSG( m_open, false, wxT("clipboard not open") );
83df96d6 519
9691c806
RR
520 /* get formats from wxDataObjects */
521 wxDataFormat *array = new wxDataFormat[ data.GetFormatCount() ];
522 data.GetAllFormats( array );
83df96d6 523
9691c806
RR
524 for (size_t i = 0; i < data.GetFormatCount(); i++)
525 {
526 wxDataFormat format( array[i] );
527
528 wxLogTrace( TRACE_CLIPBOARD,
529 wxT("wxClipboard::GetData: requested format: %s"),
530 format.GetId().c_str() );
531
532 /* is data supported by clipboard ? */
533
534 /* store requested format to be asked for by callbacks */
535 m_targetRequested = format;
536
e4db172a 537 wxCHECK_MSG( m_targetRequested, false, wxT("invalid clipboard format") );
9691c806 538
e4db172a 539 m_formatSupported = false;
9691c806
RR
540
541 /* perform query. this will set m_formatSupported to
e4db172a 542 true if m_targetRequested is supported.
9691c806
RR
543 also, we have to wait for the "answer" from the
544 clipboard owner which is an asynchronous process.
e4db172a 545 therefore we set m_waiting = true here and wait
9691c806 546 until the callback "targets_selection_received"
de6185e2 547 sets it to false */
9691c806 548
e4db172a 549 m_waiting = true;
9691c806
RR
550
551#if 0
552 gtk_selection_convert( m_targetsWidget,
553 m_usePrimary ? (GdkAtom)GDK_SELECTION_PRIMARY
554 : g_clipboardAtom,
555 g_targetsAtom,
556 (guint32) GDK_CURRENT_TIME );
557
558 while (m_waiting) gtk_main_iteration();
559#endif
560
561 if (!m_formatSupported) continue;
562
563 /* store pointer to data object to be filled up by callbacks */
564 m_receivedData = &data;
565
566 /* store requested format to be asked for by callbacks */
567 m_targetRequested = format;
568
e4db172a 569 wxCHECK_MSG( m_targetRequested, false, wxT("invalid clipboard format") );
9691c806
RR
570
571 /* start query */
e4db172a 572 m_formatSupported = false;
9691c806
RR
573
574 /* ask for clipboard contents. this will set
e4db172a 575 m_formatSupported to true if m_targetRequested
9691c806
RR
576 is supported.
577 also, we have to wait for the "answer" from the
578 clipboard owner which is an asynchronous process.
e4db172a 579 therefore we set m_waiting = true here and wait
9691c806 580 until the callback "targets_selection_received"
e4db172a 581 sets it to false */
9691c806 582
e4db172a 583 m_waiting = true;
9691c806
RR
584
585 wxLogTrace( TRACE_CLIPBOARD,
586 wxT("wxClipboard::GetData: format found, start convert") );
587
588#if 0
589 gtk_selection_convert( m_clipboardWidget,
590 m_usePrimary ? (GdkAtom)GDK_SELECTION_PRIMARY
591 : g_clipboardAtom,
592 m_targetRequested,
593 (guint32) GDK_CURRENT_TIME );
594
595 while (m_waiting) gtk_main_iteration();
596#endif
597
598 /* this is a true error as we checked for the presence of such data before */
de6185e2 599 wxCHECK_MSG( m_formatSupported, false, wxT("error retrieving data from clipboard") );
9691c806
RR
600
601 /* return success */
602 delete[] array;
e4db172a 603 return true;
83df96d6 604 }
9691c806
RR
605
606 wxLogTrace( TRACE_CLIPBOARD,
607 wxT("wxClipboard::GetData: format not found") );
608
609 /* return failure */
610 delete[] array;
e4db172a 611 return false;
83df96d6 612}
9691c806 613
83df96d6 614#endif
9691c806 615 // wxUSE_CLIPBOARD