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