Glfw: Add support for incremental transfer of selections

Created on 15 Apr 2014  ·  5Comments  ·  Source: glfw/glfw

You can repro this with clipboard app from tests folder, here's a junk file of 262146 bytes, copy all of it and paste into window, you'll get:

Error: X11: Failed to convert selection to string
Clipboard does not contain a string
X11 bug verified

Most helpful comment

I've been looking into this myself but I haven't been able to complete the implementation of it. Hopefully some of the experience in trying to implement it might be of use to someone else trying to do the same. In a nutshell, here is what happens and what ICCCM expects us to do to handle this INCR atom:

Below, when calling _glfwPlatformGetClipboardString is where X11 becomes very sad:

if (_glfwGetWindowPropertyX11(event.xselection.requestor,
                              event.xselection.property,
                              event.xselection.target,
                              (unsigned char**) &data))
    _glfw.x11.clipboardString = strdup(data);

And the reason is because we are requesting event.xselection.target of type UTF8_STRING, which will work most of the time, except when we have passed the selection owner's maximum allowed single-batch transfer size (262146 bytes in this case). The selection owner will instead give us an actualType of INCR which is not the same as the requested type UTF8_STRING. The owner wants to send data incrementally, i.e. in chunks of several XGetWindowPropertys containing UTF8_STRINGs.

To solve this we need to follow the ICCCM recommendation "INCR Properties". But in a nutshell:

  1. Get a handle to the INCR-atom with XInternAtom e.g. with the name INCR_STRING.
  2. See in _glfwGetWindowPropertyX11 if we received actualType of INCR_STRING, if so:
    a) Fetch INCR_STRING using XGetWindowProperty, it contains a lower transfer bound.
    b) Delete this INCR_STRING property so the owner can start sending us the good stuff.
    c) Wait for a PropertyNotify event, signaling arrival of a chunk of the full data.
    d) Retrieve chunk data using XGetWindowProperty, append it to a buffer.
    e) Delete the property, signaling owner to send additional chunks.
    f) Check if the size of the data is zero, if not loop back to c.
    g) Transfer complete, you now have the entire data!

If you are interested, here is a half-done implementation gist of incremental selections that I wrote.
Here are a couple of links that I found useful when looking into the issue:

Hopefully this is to some use to somebody, I wasn't able to figure it out myself unfortunately.

All 5 comments

GLFW doesn't support incremental clipboard data transfer yet.

Note to self: UTF8_STRING

I've been looking into this myself but I haven't been able to complete the implementation of it. Hopefully some of the experience in trying to implement it might be of use to someone else trying to do the same. In a nutshell, here is what happens and what ICCCM expects us to do to handle this INCR atom:

Below, when calling _glfwPlatformGetClipboardString is where X11 becomes very sad:

if (_glfwGetWindowPropertyX11(event.xselection.requestor,
                              event.xselection.property,
                              event.xselection.target,
                              (unsigned char**) &data))
    _glfw.x11.clipboardString = strdup(data);

And the reason is because we are requesting event.xselection.target of type UTF8_STRING, which will work most of the time, except when we have passed the selection owner's maximum allowed single-batch transfer size (262146 bytes in this case). The selection owner will instead give us an actualType of INCR which is not the same as the requested type UTF8_STRING. The owner wants to send data incrementally, i.e. in chunks of several XGetWindowPropertys containing UTF8_STRINGs.

To solve this we need to follow the ICCCM recommendation "INCR Properties". But in a nutshell:

  1. Get a handle to the INCR-atom with XInternAtom e.g. with the name INCR_STRING.
  2. See in _glfwGetWindowPropertyX11 if we received actualType of INCR_STRING, if so:
    a) Fetch INCR_STRING using XGetWindowProperty, it contains a lower transfer bound.
    b) Delete this INCR_STRING property so the owner can start sending us the good stuff.
    c) Wait for a PropertyNotify event, signaling arrival of a chunk of the full data.
    d) Retrieve chunk data using XGetWindowProperty, append it to a buffer.
    e) Delete the property, signaling owner to send additional chunks.
    f) Check if the size of the data is zero, if not loop back to c.
    g) Transfer complete, you now have the entire data!

If you are interested, here is a half-done implementation gist of incremental selections that I wrote.
Here are a couple of links that I found useful when looking into the issue:

Hopefully this is to some use to somebody, I wasn't able to figure it out myself unfortunately.

Thank you, that's an an excellent description! It's a little absurd what clients need to do to accomplish things that are a couple of function calls on other platforms.

I started implementing INCR two days ago. I have reading working, as well as conversion from STRING / Latin-1, but had a brief moment of despair when I realized that INCR, MULTIPLE and STRING can combine for writing. Some restructuring is in order before that can be implemented cleanly.

Pushed it just now to the selection-fixes branch if anyone wants a peek.

I need to focus on pull request reviews for a while. I've kept a lot of fine code waiting for a shameful a amount of time. If anyone wants to continue working on this in the meantime, based on code above or not, please do.

Was this page helpful?
0 / 5 - 0 ratings