wx.TheClipboard pasting different content on every second paste

Hi. I am using Fedora 32, wxPython 4.1.1 on Python3.8.9.

I encountered a weird behavior of the clipboard in RichTextCtrl. I need to be able to copy and paste a RichTextFieldTypeStandard but when I copy it (ctrl+c):
The first copy is pasted back normally but when I then go and copy and paste the same field again, a different text is pasted. It pastes whatever was in the clipboard before the new ctrl+c.
Here is a minimal example:
To reproduce the problem start the window.

  1. Drag your mouse to select the field.
  2. Ctrl+c
  3. Click below the existing field.
  4. Ctrl+v
  5. Repeat again from step 1.
    You will see that the next copy/paste will paste something different it will be whatever text you had in the clipboard before doing the first copy. If you then repeat again, it will go back to pasting the field and switch between pasting field and pasting previous text each time you try it.

Can someone please explain to me what the hell is going on here? :smiley:
It seems that wx.TheClipboard.GetData(text_data) (not shown in this example) returns False on every second paste attempt for some reason that is beyond my understanding.

Thanks.

import wx
import wx.richtext as rt

from wx.richtext import RichTextField, RichTextFieldTypeStandard


class RichTextFrame(wx.Frame):

    # Used for image differentiation.
    id = 1

    def __init__(self, *args, **kw):
        wx.Frame.__init__(self, *args, **kw)
        self.rtc = rt.RichTextCtrl(self, style=wx.VSCROLL | wx.HSCROLL | wx.NO_BORDER)
        self._main_sizer = wx.BoxSizer(wx.VERTICAL)

        # Required for copy paste to work and retain text attributes.
        rt.RichTextBuffer.AddHandler(rt.RichTextXMLHandler())

        self._main_sizer.Add(self.rtc, 1, flag=wx.EXPAND)
        self.SetSizer(self._main_sizer)

        self.rtc.GetBuffer().CleanUpFieldTypes()

    def write_field(self) -> None:
        """
        Write an image field into the text area.
        :return: None
        """
        new_field = self._register_field()
        self.rtc.WriteField(new_field.GetName(), rt.RichTextProperties())
        print(new_field.GetName())

    @staticmethod
    def _register_field():
        """
        Register a new custom image field.
        :return: None
        """
        # Create unique id for the image.
        RichTextFrame.id = RichTextFrame.id + 1

        # Create a sample image for the field.
        dc = wx.MemoryDC()
        font: wx.Font = dc.GetFont()
        font.SetPointSize(16)
        dc.SetFont(font)
        size = dc.GetTextExtent('Field: ' + str(RichTextFrame.id))
        bitmap = wx.Bitmap(width=size[0] + 10, height=size[1] + 10)
        dc.SelectObject(bitmap)
        dc.Clear()
        dc.SetTextForeground(wx.BLACK)
        dc.DrawText('Field: ' + str(RichTextFrame.id), 5, 5)

        field_type = ImageTextField(str(RichTextFrame.id), bitmap)
        rt.RichTextBuffer.AddFieldType(field_type)
        return field_type


class ImageTextField(RichTextFieldTypeStandard):
    """
    Custom RichTextFieldType class with an image.
    """

    def __init__(self, field_id: str, img: wx.Bitmap):
        """
        Constructor for a custom label for displaying images.
        """
        super().__init__(field_id, bitmap=img, displayStyle=RichTextFieldTypeStandard.RICHTEXT_FIELD_STYLE_RECTANGLE)

    def CanEditProperties(self, obj: RichTextField) -> bool:
        return False


class MyApp(wx.App):
    """
    Main class for running the gui.
    """
    def __init__(self):
        wx.App.__init__(self)
        self.frame = None

    def OnInit(self):
        self.frame = RichTextFrame(None, -1, "RichTextCtrl", size=(300, 300), style=wx.DEFAULT_FRAME_STYLE)
        self.SetTopWindow(self.frame)
        self.frame.Show()
        self.frame.write_field()
        return True


if __name__ == "__main__":
    app = MyApp()
    app.MainLoop()

1 Like

After studying the wxWidgets source code and noticing that I am not getting any error messages I found out that I am using the x11 clipboard. When I switched to wayland display server, the problem is gone.
There may be a bug in the X11 implementation of the GetData function.

But doing this prevents me from setting the frame position because that does not work under wayland.

See the docs for wxClipboard::UsePrimarySelection.

On X11 systems there is a secondary clipboard-like object present. It is automatically set whenever text is selected in a widget that supports it (all native widgets at least). So what may be happening in your case is that there is some confusion between whether the paste should pull from the selection or the clipboard. Iā€™m not sure about how RTC clipboard operations are implemented, but that would be the place to look for a possible cause to this issue if you are relying on its code for handling the clipboard. Maybe it needs to explicitly use UsePrimarySelection(false).

1 Like