]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/clipbrd.cpp
supporting PopUp on osx cocoa as well, see #10361
[wxWidgets.git] / src / gtk / clipbrd.cpp
index 649b4424d8264fbe481952218594ae27fb96f485..15ffd8be44b703f29bcbc00688f0697544092cff 100644 (file)
@@ -80,7 +80,7 @@ public:
 
     // this method must be called by GTK+ callbacks to indicate that we got the
     // result for our clipboard operation
-    static void OnDone(wxClipboard *clipboard)
+    static void OnDone(wxClipboard * WXUNUSED_UNLESS_DEBUG(clipboard))
     {
         wxASSERT_MSG( clipboard == ms_clipboard,
                         _T("got notification for alien clipboard") );
@@ -108,7 +108,7 @@ private:
 wxClipboard *wxClipboardSync::ms_clipboard = NULL;
 
 // ============================================================================
-// clipboard ca;backs implementation
+// clipboard callbacks implementation
 // ============================================================================
 
 //-----------------------------------------------------------------------------
@@ -291,37 +291,39 @@ selection_handler( GtkWidget *WXUNUSED(widget),
                wxString::FromAscii(wxGtkString(gdk_atom_name(selection_data->selection))).c_str(),
                GPOINTER_TO_UINT( signal_data )
                );
-#endif
+#endif // __WXDEBUG__
 
-    if (!data->IsSupportedFormat( format )) return;
+    if ( !data->IsSupportedFormat( format ) )
+        return;
 
     int size = data->GetDataSize( format );
+    if ( !size )
+        return;
 
-    if (size == 0) return;
-
-    void *d = malloc(size);
-    wxON_BLOCK_EXIT1(free, d);
+    wxCharBuffer buf(size - 1); // it adds 1 internally (for NUL)
 
-    // Text data will be in UTF8 in Unicode mode.
-    data->GetDataHere( selection_data->target, d );
+    // text data must be returned in UTF8 if format is wxDF_UNICODETEXT
+    if ( !data->GetDataHere(format, buf.data()) )
+        return;
 
-    // NB: GTK+ requires special treatment of UTF8_STRING data, the text
-    //     would show as UTF-8 data interpreted as latin1 (?) in other
-    //     GTK+ apps if we used gtk_selection_data_set()
+    // use UTF8_STRING format if requested in Unicode build but just plain
+    // STRING one in ANSI or if explicitly asked in Unicode
+#if wxUSE_UNICODE
     if (format == wxDataFormat(wxDF_UNICODETEXT))
     {
         gtk_selection_data_set_text(
             selection_data,
-            (const gchar*)d,
+            (const gchar*)buf.data(),
             size );
     }
     else
+#endif // wxUSE_UNICODE
     {
         gtk_selection_data_set(
             selection_data,
             GDK_SELECTION_TYPE_STRING,
             8*sizeof(gchar),
-            (unsigned char*) d,
+            (const guchar*)buf.data(),
             size );
     }
 }
@@ -342,6 +344,73 @@ void wxClipboard::GTKOnSelectionReceived(const GtkSelectionData& sel)
     m_formatSupported = true;
 }
 
+//-----------------------------------------------------------------------------
+// asynchronous "selection_received" for targets
+//-----------------------------------------------------------------------------
+
+extern "C" {
+static void
+async_targets_selection_received( GtkWidget *WXUNUSED(widget),
+                            GtkSelectionData *selection_data,
+                            guint32 WXUNUSED(time),
+                            wxClipboard *clipboard )
+{
+    if ( !clipboard ) // Assert?
+        return;
+
+    if (!clipboard->m_sink)
+        return;
+        
+    wxClipboardEvent *event = new wxClipboardEvent(wxEVT_CLIPBOARD_CHANGED);
+    event->SetEventObject( clipboard );
+    
+    if ( !selection_data || selection_data->length <= 0 )
+    {
+        clipboard->m_sink->QueueEvent( event );
+        clipboard->m_sink.Release();
+        return;
+    }
+
+    // make sure we got the data in the correct form
+    GdkAtom type = selection_data->type;
+    if ( type != GDK_SELECTION_TYPE_ATOM )
+    {
+        if ( strcmp(wxGtkString(gdk_atom_name(type)), "TARGETS") != 0 )
+        {
+            wxLogTrace( TRACE_CLIPBOARD,
+                        _T("got unsupported clipboard target") );
+
+            clipboard->m_sink->QueueEvent( event );
+            clipboard->m_sink.Release();
+            return;
+        }
+    }
+
+#ifdef __WXDEBUG__
+    // it's not really a format, of course, but we can reuse its GetId() method
+    // to format this atom as string
+    wxDataFormat clip(selection_data->selection);
+    wxLogTrace( TRACE_CLIPBOARD,
+                wxT("Received available formats for clipboard %s"),
+                clip.GetId().c_str() );
+#endif // __WXDEBUG__
+
+    // the atoms we received, holding a list of targets (= formats)
+    const GdkAtom * const atoms = (GdkAtom *)selection_data->data;
+    for ( size_t i = 0; i < selection_data->length/sizeof(GdkAtom); i++ )
+    {
+        const wxDataFormat format(atoms[i]);
+
+        wxLogTrace(TRACE_CLIPBOARD, wxT("\t%s"), format.GetId().c_str());
+
+        event->AddFormat( format );
+    }
+    
+    clipboard->m_sink->QueueEvent( event );
+    clipboard->m_sink.Release();
+}
+}
+
 // ============================================================================
 // wxClipboard implementation
 // ============================================================================
@@ -370,6 +439,13 @@ wxClipboard::wxClipboard()
     g_signal_connect (m_targetsWidget, "selection_received",
                       G_CALLBACK (targets_selection_received), this);
 
+    // we use m_targetsWidgetAsync to query what formats asynchronously
+    m_targetsWidgetAsync = gtk_window_new( GTK_WINDOW_POPUP );
+    gtk_widget_realize( m_targetsWidgetAsync );
+
+    g_signal_connect (m_targetsWidgetAsync, "selection_received",
+                      G_CALLBACK (async_targets_selection_received), this);
+
     // we use m_clipboardWidget to get and to offer data
     m_clipboardWidget = gtk_window_new( GTK_WINDOW_POPUP );
     gtk_widget_realize( m_clipboardWidget );
@@ -446,6 +522,22 @@ void wxClipboard::AddSupportedTarget(GdkAtom atom)
     );
 }
 
+bool wxClipboard::IsSupportedAsync(wxEvtHandler *sink)
+{
+    if (m_sink.get())
+        return false;  // currently busy, come back later
+        
+    wxCHECK_MSG( sink, false, wxT("no sink given") );
+      
+    m_sink = sink;
+    gtk_selection_convert( m_targetsWidgetAsync,
+                           GTKGetClipboardAtom(),
+                           g_targetsAtom,
+                           (guint32) GDK_CURRENT_TIME );
+                           
+    return true;
+}
+
 bool wxClipboard::DoIsSupported(const wxDataFormat& format)
 {
     wxCHECK_MSG( format, false, wxT("invalid clipboard format") );