1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        gtk/clipbrd.cpp 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  11 #pragma implementation "clipbrd.h" 
  14 // For compilers that support precompilation, includes "wx.h". 
  15 #include "wx/wxprec.h" 
  17 #include "wx/clipbrd.h" 
  21 #include "wx/dataobj.h" 
  29 //----------------------------------------------------------------------------- 
  31 //----------------------------------------------------------------------------- 
  36 //----------------------------------------------------------------------------- 
  38 //----------------------------------------------------------------------------- 
  40 GdkAtom  g_clipboardAtom   
= 0; 
  41 GdkAtom  g_targetsAtom     
= 0; 
  43 #if defined(__WXGTK20__) && wxUSE_UNICODE 
  44 extern GdkAtom g_altTextAtom
; 
  47 // the trace mask we use with wxLogTrace() - call 
  48 // wxLog::AddTraceMask(TRACE_CLIPBOARD) to enable the trace messages from here 
  49 // (there will be a *lot* of them!) 
  50 static const wxChar 
*TRACE_CLIPBOARD 
= _T("clipboard"); 
  52 //----------------------------------------------------------------------------- 
  54 //----------------------------------------------------------------------------- 
  56 /* The contents of a selection are returned in a GtkSelectionData 
  57    structure. selection/target identify the request. 
  58    type specifies the type of the return; if length < 0, and 
  59    the data should be ignored. This structure has object semantics - 
  60    no fields should be modified directly, they should not be created 
  61    directly, and pointers to them should not be stored beyond the duration of 
  62    a callback. (If the last is changed, we'll need to add reference 
  65 struct _GtkSelectionData 
  77 //----------------------------------------------------------------------------- 
  78 // "selection_received" for targets 
  79 //----------------------------------------------------------------------------- 
  82 targets_selection_received( GtkWidget 
*WXUNUSED(widget
), 
  83                             GtkSelectionData 
*selection_data
, 
  84                             guint32 
WXUNUSED(time
), 
  85                             wxClipboard 
*clipboard 
) 
  87     if ( wxTheClipboard 
&& selection_data
->length 
> 0 ) 
  89         // make sure we got the data in the correct form 
  90         GdkAtom type 
= selection_data
->type
; 
  91         if ( type 
!= GDK_SELECTION_TYPE_ATOM 
) 
  93             if ( strcmp(gdk_atom_name(type
), "TARGETS") ) 
  95                 wxLogTrace( TRACE_CLIPBOARD
, 
  96                             _T("got unsupported clipboard target") ); 
  98                 clipboard
->m_waiting 
= FALSE
; 
 104         wxDataFormat 
clip( selection_data
->selection 
); 
 105         wxLogTrace( TRACE_CLIPBOARD
, 
 106                     wxT("selection received for targets, clipboard %s"), 
 107                     clip
.GetId().c_str() ); 
 108 #endif // __WXDEBUG__ 
 110         // the atoms we received, holding a list of targets (= formats) 
 111         GdkAtom 
*atoms 
= (GdkAtom 
*)selection_data
->data
; 
 113         for (unsigned int i
=0; i
<selection_data
->length
/sizeof(GdkAtom
); i
++) 
 115             wxDataFormat 
format( atoms
[i
] ); 
 117             wxLogTrace( TRACE_CLIPBOARD
, 
 118                         wxT("selection received for targets, format %s"), 
 119                         format
.GetId().c_str() ); 
 121 //            printf( "format %s requested %s\n",  
 122 //                    gdk_atom_name( atoms[i] ), 
 123 //                    gdk_atom_name( clipboard->m_targetRequested ) ); 
 125             if (format 
== clipboard
->m_targetRequested
) 
 127                 clipboard
->m_waiting 
= FALSE
; 
 128                 clipboard
->m_formatSupported 
= TRUE
; 
 134     clipboard
->m_waiting 
= FALSE
; 
 137 //----------------------------------------------------------------------------- 
 138 // "selection_received" for the actual data 
 139 //----------------------------------------------------------------------------- 
 142 selection_received( GtkWidget 
*WXUNUSED(widget
), 
 143                     GtkSelectionData 
*selection_data
, 
 144                     guint32 
WXUNUSED(time
), 
 145                     wxClipboard 
*clipboard 
) 
 149         clipboard
->m_waiting 
= FALSE
; 
 153     wxDataObject 
*data_object 
= clipboard
->m_receivedData
; 
 157         clipboard
->m_waiting 
= FALSE
; 
 161     if (selection_data
->length 
<= 0) 
 163         clipboard
->m_waiting 
= FALSE
; 
 167     wxDataFormat 
format( selection_data
->target 
); 
 169     // make sure we got the data in the correct format 
 170     if (!data_object
->IsSupportedFormat( format 
) ) 
 172         clipboard
->m_waiting 
= FALSE
; 
 177     This seems to cause problems somehow
 
 178     // make sure we got the data in the correct form (selection type). 
 179     // if so, copy data to target object 
 180     if (selection_data
->type 
!= GDK_SELECTION_TYPE_STRING
) 
 182         clipboard
->m_waiting 
= FALSE
; 
 187     data_object
->SetData( format
, (size_t) selection_data
->length
, (const char*) selection_data
->data 
); 
 189     wxTheClipboard
->m_formatSupported 
= TRUE
; 
 190     clipboard
->m_waiting 
= FALSE
; 
 193 //----------------------------------------------------------------------------- 
 195 //----------------------------------------------------------------------------- 
 198 selection_clear_clip( GtkWidget 
*WXUNUSED(widget
), GdkEventSelection 
*event 
) 
 200     if (!wxTheClipboard
) return TRUE
; 
 202     if (event
->selection 
== GDK_SELECTION_PRIMARY
) 
 204         wxTheClipboard
->m_ownsPrimarySelection 
= FALSE
; 
 207     if (event
->selection 
== g_clipboardAtom
) 
 209         wxTheClipboard
->m_ownsClipboard 
= FALSE
; 
 213         wxTheClipboard
->m_waiting 
= FALSE
; 
 217     if ((!wxTheClipboard
->m_ownsPrimarySelection
) && 
 218         (!wxTheClipboard
->m_ownsClipboard
)) 
 220         /* the clipboard is no longer in our hands. we can the delete clipboard data. */ 
 221         if (wxTheClipboard
->m_data
) 
 223             wxLogTrace(TRACE_CLIPBOARD
, wxT("wxClipboard will get cleared" )); 
 225             delete wxTheClipboard
->m_data
; 
 226             wxTheClipboard
->m_data 
= (wxDataObject
*) NULL
; 
 230     wxTheClipboard
->m_waiting 
= FALSE
; 
 234 //----------------------------------------------------------------------------- 
 235 // selection handler for supplying data 
 236 //----------------------------------------------------------------------------- 
 239 selection_handler( GtkWidget 
*WXUNUSED(widget
), 
 240                    GtkSelectionData 
*selection_data
, 
 241                    guint 
WXUNUSED(info
), 
 242                    guint 
WXUNUSED(time
), 
 243                    gpointer 
WXUNUSED(data
) ) 
 245     if (!wxTheClipboard
) return; 
 247     if (!wxTheClipboard
->m_data
) return; 
 249     wxDataObject 
*data 
= wxTheClipboard
->m_data
; 
 251     wxDataFormat 
format( selection_data
->target 
); 
 253     if (!data
->IsSupportedFormat( format 
)) return; 
 255     int size 
= data
->GetDataSize( format 
); 
 257     if (size 
== 0) return; 
 259     void *d 
= malloc(size
); 
 261     // Text data will be in UTF8 in Unicode mode. 
 262     data
->GetDataHere( selection_data
->target
, d 
); 
 264     gtk_selection_data_set( 
 266         GDK_SELECTION_TYPE_STRING
, 
 274 //----------------------------------------------------------------------------- 
 276 //----------------------------------------------------------------------------- 
 278 IMPLEMENT_DYNAMIC_CLASS(wxClipboard
,wxObject
) 
 280 wxClipboard::wxClipboard() 
 285     m_ownsClipboard 
= FALSE
; 
 286     m_ownsPrimarySelection 
= FALSE
; 
 288     m_data 
= (wxDataObject
*) NULL
; 
 289     m_receivedData 
= (wxDataObject
*) NULL
; 
 291     /* we use m_targetsWidget to query what formats are available */ 
 293     m_targetsWidget 
= gtk_window_new( GTK_WINDOW_POPUP 
); 
 294     gtk_widget_realize( m_targetsWidget 
); 
 296     gtk_signal_connect( GTK_OBJECT(m_targetsWidget
), 
 297                         "selection_received", 
 298                         GTK_SIGNAL_FUNC( targets_selection_received 
), 
 301     /* we use m_clipboardWidget to get and to offer data */ 
 303     m_clipboardWidget 
= gtk_window_new( GTK_WINDOW_POPUP 
); 
 304     gtk_widget_realize( m_clipboardWidget 
); 
 306     gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
), 
 307                         "selection_received", 
 308                         GTK_SIGNAL_FUNC( selection_received 
), 
 311     gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
), 
 312                         "selection_clear_event", 
 313                         GTK_SIGNAL_FUNC( selection_clear_clip 
), 
 316     if (!g_clipboardAtom
) g_clipboardAtom 
= gdk_atom_intern( "CLIPBOARD", FALSE 
); 
 317     if (!g_targetsAtom
) g_targetsAtom 
= gdk_atom_intern ("TARGETS", FALSE
); 
 319     m_formatSupported 
= FALSE
; 
 320     m_targetRequested 
= 0; 
 322     m_usePrimary 
= FALSE
; 
 325 wxClipboard::~wxClipboard() 
 329     if (m_clipboardWidget
) gtk_widget_destroy( m_clipboardWidget 
); 
 330     if (m_targetsWidget
) gtk_widget_destroy( m_targetsWidget 
); 
 333 void wxClipboard::Clear() 
 338         /* disable GUI threads */ 
 341         //  As we have data we also own the clipboard. Once we no longer own 
 342         //  it, clear_selection is called which will set m_data to zero 
 343         if (gdk_selection_owner_get( g_clipboardAtom 
) == m_clipboardWidget
->window
) 
 347             gtk_selection_owner_set( (GtkWidget
*) NULL
, g_clipboardAtom
, 
 348                                      (guint32
) GDK_CURRENT_TIME 
); 
 350             while (m_waiting
) gtk_main_iteration(); 
 353         if (gdk_selection_owner_get( GDK_SELECTION_PRIMARY 
) == m_clipboardWidget
->window
) 
 357             gtk_selection_owner_set( (GtkWidget
*) NULL
, GDK_SELECTION_PRIMARY
, 
 358                                      (guint32
) GDK_CURRENT_TIME 
); 
 360             while (m_waiting
) gtk_main_iteration(); 
 366             m_data 
= (wxDataObject
*) NULL
; 
 370         /* re-enable GUI threads */ 
 374     m_targetRequested 
= 0; 
 375     m_formatSupported 
= FALSE
; 
 378 bool wxClipboard::Open() 
 380     wxCHECK_MSG( !m_open
, FALSE
, wxT("clipboard already open") ); 
 387 bool wxClipboard::SetData( wxDataObject 
*data 
) 
 389     wxCHECK_MSG( m_open
, FALSE
, wxT("clipboard not open") ); 
 391     wxCHECK_MSG( data
, FALSE
, wxT("data is invalid") ); 
 395     return AddData( data 
); 
 398 bool wxClipboard::AddData( wxDataObject 
*data 
) 
 400     wxCHECK_MSG( m_open
, FALSE
, wxT("clipboard not open") ); 
 402     wxCHECK_MSG( data
, FALSE
, wxT("data is invalid") ); 
 404     // we can only store one wxDataObject 
 409     // get formats from wxDataObjects 
 410     wxDataFormat 
*array 
= new wxDataFormat
[ m_data
->GetFormatCount() ]; 
 411     m_data
->GetAllFormats( array 
); 
 413     // primary selection or clipboard 
 414     GdkAtom clipboard 
= m_usePrimary 
? (GdkAtom
)GDK_SELECTION_PRIMARY
 
 418     for (size_t i 
= 0; i 
< m_data
->GetFormatCount(); i
++) 
 420         wxLogTrace( TRACE_CLIPBOARD
, 
 421                     wxT("wxClipboard now supports atom %s"), 
 422                     array
[i
].GetId().c_str() ); 
 424 //        printf( "added %s\n",  
 425 //                    gdk_atom_name( array[i].GetFormatId() ) ); 
 427         gtk_selection_add_target( GTK_WIDGET(m_clipboardWidget
), 
 430                                   0 );  /* what is info ? */ 
 435     gtk_signal_connect( GTK_OBJECT(m_clipboardWidget
), 
 437                         GTK_SIGNAL_FUNC(selection_handler
), 
 441     /* disable GUI threads */ 
 444     /* Tell the world we offer clipboard data */ 
 445     bool res 
= (gtk_selection_owner_set( m_clipboardWidget
, 
 447                                          (guint32
) GDK_CURRENT_TIME 
)); 
 450         m_ownsPrimarySelection 
= res
; 
 452         m_ownsClipboard 
= res
; 
 455     /* re-enable GUI threads */ 
 461 void wxClipboard::Close() 
 463     wxCHECK_RET( m_open
, wxT("clipboard not open") ); 
 468 bool wxClipboard::IsOpened() const 
 473 bool wxClipboard::IsSupported( const wxDataFormat
& format 
) 
 475     /* reentrance problems */ 
 476     if (m_waiting
) return FALSE
; 
 478     /* store requested format to be asked for by callbacks */ 
 479     m_targetRequested 
= format
; 
 482     wxLogTrace( TRACE_CLIPBOARD
, 
 483                 wxT("wxClipboard:IsSupported: requested format: %s"), 
 484                 format
.GetId().c_str() ); 
 487     wxCHECK_MSG( m_targetRequested
, FALSE
, wxT("invalid clipboard format") ); 
 489     m_formatSupported 
= FALSE
; 
 491     /* perform query. this will set m_formatSupported to 
 492        TRUE if m_targetRequested is supported. 
 493        also, we have to wait for the "answer" from the 
 494        clipboard owner which is an asynchronous process. 
 495        therefore we set m_waiting = TRUE here and wait 
 496        until the callback "targets_selection_received" 
 501     gtk_selection_convert( m_targetsWidget
, 
 502                            m_usePrimary 
? (GdkAtom
)GDK_SELECTION_PRIMARY
 
 505                            (guint32
) GDK_CURRENT_TIME 
); 
 507     while (m_waiting
) gtk_main_iteration(); 
 509 #if defined(__WXGTK20__) && wxUSE_UNICODE 
 510     if (!m_formatSupported 
&& format 
== wxDataFormat(wxDF_UNICODETEXT
)) 
 512         // Another try with plain STRING format 
 513         extern GdkAtom g_altTextAtom
; 
 514         return IsSupported(g_altTextAtom
); 
 518     if (!m_formatSupported
) return FALSE
; 
 523 bool wxClipboard::GetData( wxDataObject
& data 
) 
 525     wxCHECK_MSG( m_open
, FALSE
, wxT("clipboard not open") ); 
 527     /* get formats from wxDataObjects */ 
 528     wxDataFormat 
*array 
= new wxDataFormat
[ data
.GetFormatCount() ]; 
 529     data
.GetAllFormats( array 
); 
 531     for (size_t i 
= 0; i 
< data
.GetFormatCount(); i
++) 
 533         wxDataFormat 
format( array
[i
] ); 
 535         wxLogTrace( TRACE_CLIPBOARD
, 
 536                     wxT("wxClipboard::GetData: requested format: %s"), 
 537                     format
.GetId().c_str() ); 
 539         /* is data supported by clipboard ? */ 
 541         /* store requested format to be asked for by callbacks */ 
 542         m_targetRequested 
= format
; 
 544         wxCHECK_MSG( m_targetRequested
, FALSE
, wxT("invalid clipboard format") ); 
 546         m_formatSupported 
= FALSE
; 
 548        /* perform query. this will set m_formatSupported to 
 549           TRUE if m_targetRequested is supported. 
 550           also, we have to wait for the "answer" from the 
 551           clipboard owner which is an asynchronous process. 
 552           therefore we set m_waiting = TRUE here and wait 
 553           until the callback "targets_selection_received" 
 558         gtk_selection_convert( m_targetsWidget
, 
 559                            m_usePrimary 
? (GdkAtom
)GDK_SELECTION_PRIMARY
 
 562                            (guint32
) GDK_CURRENT_TIME 
); 
 564         while (m_waiting
) gtk_main_iteration(); 
 566         if (!m_formatSupported
) continue; 
 568         /* store pointer to data object to be filled up by callbacks */ 
 569         m_receivedData 
= &data
; 
 571         /* store requested format to be asked for by callbacks */ 
 572         m_targetRequested 
= format
; 
 574         wxCHECK_MSG( m_targetRequested
, FALSE
, wxT("invalid clipboard format") ); 
 577         m_formatSupported 
= FALSE
; 
 579         /* ask for clipboard contents.  this will set 
 580            m_formatSupported to TRUE if m_targetRequested 
 582            also, we have to wait for the "answer" from the 
 583            clipboard owner which is an asynchronous process. 
 584            therefore we set m_waiting = TRUE here and wait 
 585            until the callback "targets_selection_received" 
 590         wxLogTrace( TRACE_CLIPBOARD
, 
 591                     wxT("wxClipboard::GetData: format found, start convert") ); 
 593         gtk_selection_convert( m_clipboardWidget
, 
 594                                m_usePrimary 
? (GdkAtom
)GDK_SELECTION_PRIMARY
 
 597                                (guint32
) GDK_CURRENT_TIME 
); 
 599         while (m_waiting
) gtk_main_iteration(); 
 601         /* this is a true error as we checked for the presence of such data before */ 
 602         wxCHECK_MSG( m_formatSupported
, FALSE
, wxT("error retrieving data from clipboard") ); 
 609     wxLogTrace( TRACE_CLIPBOARD
, 
 610                 wxT("wxClipboard::GetData: format not found") );