Search code examples
python-3.xcsvclipboardgdkgtk4

Gdk4 Clipboard union provider does not appear to make data available as expected


I have a python4/gtk4 application that i want to be able to output three types of data to the clipboard.

  1. A serialised object for internal application use
  2. A text/csv dump for copying into a spreadsheet
  3. a text/plain dump for any other application

I have what appears to be error free code conforming to what I understand of the API. I have tested the text/plain output with my own code in a seperate test app for pasting, and it works. However attempting to paste into any other application that is not of my own creation does not result in pasting anything. This includes gEdit 46.2, and LibreOffice Calc.

My copy code:


    # Access the default clipboard for the application
    clipboard = Gdk.Display.get_default().get_clipboard()

    # Generate CSV data for external use
    csv_data = self.get_csv_data_for_selected_cells()

    # Generate and serialize the selected cell list and sheet reference for internal clipboard use
    selection = {
        'sheet_name': self.model.sheets[self.model.current_sheet_index]['name'],
        'selected_cells': self._all_selected_cells
    }
    serialized_selection = pickle.dumps(selection)

    # Convert serialized data to GLib.Bytes for clipboard use
    gbytes_selection = GLib.Bytes.new(serialized_selection)
    gbytes_csv = GLib.Bytes.new(csv_data)

    # Create content providers for different formats
    selection_provider = Gdk.ContentProvider.new_for_bytes("application/x-tab-selection", gbytes_selection)
    csv_provider = Gdk.ContentProvider.new_for_bytes("text/csv", gbytes_csv)
    text_provider = Gdk.ContentProvider.new_for_bytes("text/plain", gbytes_csv)  # Optionally treat CSV as plain text

    # Combine content providers into a union provider that offers multiple formats
    union_provider = Gdk.ContentProvider.new_union([selection_provider, csv_provider, text_provider])

    # Output the supported formats for debugging purposes
    print(Gdk.ContentFormats.to_string(union_provider.ref_formats()))

    # Set the union provider to the clipboard
    clipboard.set_content(union_provider)

    # Verify clipboard content by retrieving it immediately
    clipboard.read_text_async(None, self.on_retrieve_clipboard_content)

    # Set focus back to the main view
    self.view.sourceview.grab_focus()
    self.view.scrolled_window.grab_focus()

    # Attempt to retrieve and verify clipboard content again (redundancy check in case this was a focus/persistancy issue)
    clipboard.read_text_async(None, self.on_retrieve_clipboard_content)

And my paste code in a separate test application:


    self.clipboard.read_text_async(None, self.on_paste_text)

    def on_retrieve_clipboard_content(self, clipboard, result):
        # Read the text from the clipboard and print it for verification
        retrieved_text = clipboard.read_text_finish(result)
        if retrieved_text:
            print(f"Retrieved clipboard content: {retrieved_text}")
        else:
            print("Failed to retrieve clipboard content.")

This is an example of what I see on copy:

application/x-tab-selection text/csv text/plain
<__gi__.GdkContentProviderUnion object at 0x7f0389561b80 (GdkContentProviderUnion at 0x555ac7a9ef90)>
Retrieved clipboard content: 42,99.0,12
56,,
,,
,4,88

Retrieved clipboard content: 42,99.0,12
56,,
,,
,4,88

When I go to paste into gEdit however, nothing pastes at all. Only when I access data through my own read_text_async calls can I get anything out of the clipboard.

I am obviously missing something fairly key, so any tips would be appreciated!


Solution

  • Instead of using text/plain as a mime type, I can use text/plain;charset=utf-8 and it solves the problem pasting across different applications.

    I also learnt through the tool that csv data is not useful clipboard material, and that tab delimited values are the standard for copy and pasting spreadsheet data.

    So now I have my internal application serialisation, and a single text/plain;charset=utf8 output generated as:

    tsv_writer = csv.writer(output, delimiter=‘\t’) # Use tab as the delimiter
    

    Thanks to gwillems on discourse.gnome.org for the advice (https://discourse.gnome.org/t/gdk4-clipboard-union-provider-does-not-appear-to-make-data-available-as-expected/22978).