xpra icon
Bug tracker and wiki

Opened 7 years ago

Closed 6 years ago

#272 closed enhancement (fixed)

fix/improve MS Windows clipboard handling

Reported by: Antoine Martin Owned by: alas
Priority: major Milestone: 0.9
Component: platforms Version:
Keywords: clipboard win32 Cc:

Description (last modified by Antoine Martin)

Split from #11. Please see wiki/Clipboard first.

  • it should be possible to keep track of the last "clipboard" ("primary", "secondary" or "clipboard") that the server claims to own and copy from that one when the client requests the clipboard contents (or when it requests the list of formats). Beware: there may be races here if we use a naive implementation... we could end up requesting data in a format which is not supported by the last clipboard token.

This should take of copy+paste from server to client.

  • client to server: we can simply claim that we own all three clipboards at once, when the server requests the contents we give it the only contents we have. (this direction is easier)

There may well be some cases where this causes problems, or where the user chooses to sync with a single clipboard, so we probably want to add a new UI and command line option (win32 clients only):

--clipboard-sync=primary|secondary|clipboard|all

"all" would be the new "auto" mode.

Attachments (1)

clipboard-tool.png (109.5 KB) - added by Antoine Martin 7 years ago.
screenshot of the new clipboard debugging tool

Download all attachments as: .zip

Change History (36)

comment:1 Changed 7 years ago by Antoine Martin

Description: modified (diff)
Status: newassigned

comment:2 Changed 7 years ago by Antoine Martin

Owner: changed from Antoine Martin to alas
Status: assignednew

mostly done in r2855, not done the UI since the default is probably better than what we had before.

Despite knowing very well that I needed to turn off VirtualBox's own clipboard synchronization, I forgot about it and thought the whole thing was broken... beware when testing!

comment:3 Changed 7 years ago by alas

With a Fedora 18 server with xpra 0.9.0 and a windows client with 0.8.7 I have found the following behaviors.

  1. Copying on the windows client loads the content into all three of the server clipboards (primary, secondary & clipboard). Pasting works consistently in this case.
  1. Copying in the xpra window loads the data into the primary clipboard and the clipboard clipboard, but not the secondary clipboard.
  1. The first such copy will produce correct results when pasting to the windows client. Copying a second (or subsequent) set of data will update the data in both the primary and clipboard clipboards, but attempts to paste into the windows client will result in pasting the first set of data repeatedly. (The pasting will behave correctly within the xpra window(s), meanwhile.)
  1. Highlighting and deleting data in the xpra window will copy that data to the primary clipboard (leading me to believe that it is used as an 'undo' storage location), while it will clear the secondary clipboard (if not already clear) and it will also (often, but somewhat erratically) clear the clipboard clipboard. --> At this point, however, pasting to the windows client will produce unpredictable results, often the pasting of some portion of the "deleted" text stored in the primary clipboard.
  1. Once the clipboard clipboard has thusly been cleared, whatever is next copied will be "transmitted" to the windows client clipboard and can be pasted. (And will likewise continue to be repasted and repasted again, until another such deletion resets the clipboard, or something is copied anew from the windows client, filling all three clipboards.)
  1. Sometimes, however, the clipboard clipboard won't be cleared. In that case, the windows clipboard will continue to "resist" updating with any new copied data.
  1. I also noticed that calls with xclip to output the contents of the secondary clipboard always produced a debugging message from the client indicating that it was being asked for clipboard data when it wasn't expecting to be so queried. I take that to mean that the secondary clipboard is intended to be used for data from outside of the local environment.
  1. Windows also seems to have an "undo" clipboard somewhere, which occasionally seems to confuse matters if clipboard contents don't "initialize" when an xpra session starts, in which case- despite having recently copied something from the windows client environment (before beginning the xpra session), an attempt to paste into the xpra will paste no data... and if one then tries to paste back into the windows environment something random will be pasted (which may or may not be drawn from the windows "undo" clipboard in much the same way that pasting sometimes results in pulling "deleted" data from the primary clipboard).

In general:

  1. If all three clipboards have data then most likely the last copy was from the client.
  1. If the primary and clipboard clipboards have data, then the last copy was from within the xpra environment.
  1. If only the primary clipboard has data, then most likely there was a recent deletion.
  1. If the data in the primary clipboard and the clipboard clipboard are different, the clipboard will generally have the latest "copy data" while the primary will have the "delete data".

Unfortunately, the behavior is just buggy enough to resist a clear understanding or predictability.

comment:4 in reply to:  3 Changed 7 years ago by Antoine Martin

Do you have any log samples for each one?

  1. Copying on the windows client loads the content into all three of the server clipboards (primary, secondary & clipboard). Pasting works consistently in this case.

OK

  1. Copying in the xpra window loads the data into the primary clipboard and the clipboard clipboard, but not the secondary clipboard.

Not exactly: some applications load into 'primary', some in 'clipboard' and some (very rare) in 'secondary'. (and some in more than one at the same time)
This is done by the application only and is totally beyond our control.
Generally speaking, simply selecting/highlighting some text places it in 'primary', without any need to 'copy' it (via Control-C or via a menu).
This is also why we really do not want to send clipboard data to the other end every time the clipboard contents change, but only when clipboard contents are requested by it. (imagine dragging the mouse over some large amount of text and the bandwidth hog this would generate)

  1. The first such copy will produce correct results when pasting to the windows client. Copying a second (or subsequent) set of data will update the data in both the primary and clipboard clipboards, but attempts to paste into the windows client will result in pasting the first set of data repeatedly. (The pasting will behave correctly within the xpra window(s), meanwhile.)

Confirmed. That's odd, sounds like something is owning the clipboard client side.
I may knock up a test application we can run on win32 to show clipboard events.
All the problems below may well be due to this one.

  1. Highlighting and deleting data in the xpra window will copy that data to the primary clipboard (leading me to believe that it is used as an 'undo' storage location), while it will clear the secondary clipboard (if not already clear) and it will also (often, but somewhat erratically) clear the clipboard clipboard. --> At this point, however, pasting to the windows client will produce unpredictable results, often the pasting of some portion of the "deleted" text stored in the primary clipboard.

I don't understand the 'undo' comments. And what do you mean by 'deleting data'?

  1. Once the clipboard clipboard has thusly been cleared, whatever is next copied will be "transmitted" to the windows client clipboard and can be pasted. (And will likewise continue to be repasted and repasted again, until another such deletion resets the clipboard, or something is copied anew from the windows client, filling all three clipboards.)

Due to (b), I'm not sure I understand.

  1. Sometimes, however, the clipboard clipboard won't be cleared. In that case, the windows clipboard will continue to "resist" updating with any new copied data.

Same. Why should it be cleared? Its contents are down to the application.

  1. I also noticed that calls with xclip to output the contents of the secondary clipboard always produced a debugging message from the client indicating that it was being asked for clipboard data when it wasn't expecting to be so queried. I take that to mean that the secondary clipboard is intended to be used for data from outside of the local environment.

Interesting, "secondary" is the only one that applications rarely ever touch.
So this one will be set when the windows client copies something, and should not be updated thereafter - this may well lead me to the source of the problems.
Could be a race since we set all three clipboards' ownership asynchronously.

  1. Windows also seems to have an "undo" clipboard somewhere, which occasionally seems to confuse matters if clipboard contents don't "initialize" when an xpra session starts, in which case- despite having recently copied something from the windows client environment (before beginning the xpra session), an attempt to paste into the xpra will paste no data... and if one then tries to paste back into the windows environment something random will be pasted (which may or may not be drawn from the windows "undo" clipboard in much the same way that pasting sometimes results in pulling "deleted" data from the primary clipboard).

Again, I don't know anything about this "undo" clipboard..
Initialization is tricky, who owns the clipboard at that point is not clear. IIRC, at the moment, the client should own it.

In general:

  1. If all three clipboards have data then most likely the last copy was from the client.

That would make sense since any copy events from the client sets all 3 clipboards as owned by the client.

  1. If the primary and clipboard clipboards have data, then the last copy was from within the xpra environment.

Also makes sense, X11 applications only interact with those two.

  1. If only the primary clipboard has data, then most likely there was a recent deletion.

What is a "deletion"?

  1. If the data in the primary clipboard and the clipboard clipboard are different, the clipboard will generally have the latest "copy data" while the primary will have the "delete data".

Hmmm, that I am not sure about at all.
Applications control the clipboards and they can place anything they like in there at any point.
We are only meant to grab all the updates and forward them to the client, so the client should always have the last clipboard update made.

Unfortunately, the behavior is just buggy enough to resist a clear understanding or predictability.

Indeed.

Let's see if fixing (2)a and/or (3) leads anywhere.
Have you tried any of those tests with a simple xterm instead of chrome to rule out application specific behaviour?

Changed 7 years ago by Antoine Martin

Attachment: clipboard-tool.png added

screenshot of the new clipboard debugging tool

comment:5 Changed 7 years ago by Antoine Martin

r2913 adds a clipboard debugging tool, and here is a screenshot:
http://xpra.org/trac/raw-attachment/ticket/272/clipboard-tool.png


Hopefully this can help figure out what is going wrong.
There is a new MS Windows beta package which includes this new tool (named GTK_Clipboard_Test.exe on win32)

Some initial notes and explanations

  • For each type of clipboard (CLIPBOARD, PRIMARY and SECONDARY), the top line is for retrieval and the bottom one for setting.
  • The Targets options for retrieval starts empty, you first need to Get Targets to obtain the list of available targets. Only then can you call Get Target. You should probably refresh it whenever the selection owner changes, as calling Get Target on an invalid target simply returns an empty value.
  • when using the Set String button, the data is copied from the editable field immediately, whatever text is in it at the time - changing the editable field afterwards does not have any effect until you use Set Target or Set String again. The only messages shown are:
    • Got string selection data.. (when using Get String), or:
    • Got selection data: ... (when using Get Target).
  • when using the Set Target button, nothing really happens yet and you can continue to type into the text field, everytime you click on Get Target or Get String, the value is requested and you should see a Answering selection request with value: .... The value retrieved should then be displayed. The same message is also displayed when we own the selection and an application requests the clipboard data from us.
  • The clear buttons have no other effect than to clear the fields (well, except when the text being cleared is already highlighted on Linux, as this text is automatically stored in PRIMARY.. so clearing it will also clear the selection)
  • running on win32 without xpra and with just a notepad++ instance, it seems to provide data as "UTF8_STRING" only and we can grab it without problems with both Get Target and Get String, however when we try to use Set Target notepad++ does not seem to be aware that we offer the selection (using STRING or UTF8_STRING makes no difference). Using Set String always works though.
  • on Linux, you may get extra "TARGETS", (like "TIMESTAMP") and the application tries to display the value it retrieves (it doesn't try too hard at present - this is just to test that we do get those values)
  • on Linux, all 3 clipboards work as expected, with one exception: setting the PRIMARY clipboard target causes it to be requested again and again (see screenshot for example). It may be a misbehaving application doing some polling, this needs testing with lighter/minimal DEs to confirm.
Last edited 7 years ago by Antoine Martin (previous) (diff)

comment:6 Changed 7 years ago by alas

By "undo" clipboard I was referring to a buffer that is used when you right-click and select the undo option from the resultant drop-down menu. Since the primary stores selected data, I presumed that it was being used for this drop-down menu option. I still can't really think of any other reason to store selected data, either- especially before it is copied.

I failed, though to divorce the selecting of the data from the deleting of it (I guess I never thought to try that), so any reference I make to "deleting" data should be understood as being an assumed part of any selecting that is not a precursor to copying. Hence, a reference to a "recent deletion" is in fact a reference to a recent selection (with an anecdotal deletion of said selected data to follow, inconsequentially).

I should note, however, that in one instance of my testing I did inadvertantly paste blank data over a selected portion of text, deleting it but storing it in the primary clipboard... after which I used the right-click undo button to "restore" the data, in the process of which the primary was in fact cleared. I didn't repeat the process however, so I can make no estimation of how consistently it does this.

I should also note that the client's local clipboard seems to be another entity entirely from the clipboards of the xpra server (which you probably realize, but it seems like it should be said). Many times what is pasted in the windows client bears no resemblance whatsoever to the current contents of any of the three clipboards within the server.

In any case, I'll see if these new tools help me pin things down any more.

comment:7 Changed 7 years ago by alas

Ok, still using a Fedora 18 server with xpra 0.9.0 but now with win client 0.8.8 I had some different results which might shed some light on... something.

  1. With 0.8.8 client, a copy only seems to save to primary. Unfortunately, pasting to the xpra chrome browser seems to only use the clipboard... so the 0.8.8 client can't copy and paste from the client to an xpra chrome browser.
  1. Xpra xterm windows, however, copy to and from the primary, so anything copied from a win client can be "pasted" (Shift-Inserted) into an xterm.
  1. Xpra chrome browser copy (of highlighted text) copies to both primary and clipboard. Highlighting copies to primary, whether or not a copy operation is performed. Anything highlighted thusly can be inserted into an xterm window.
  1. Oddly, whatever is "owned" by the windows clipboard seems to be loaded into the primary clipboard when an xpra session begins. The first change of the contents of primary seems to be pasteable to the win client, but later changes are (generally) not acknowledged by the client clipboard operations. Sometimes, however, only a portion of that first change will be "acknowledged" by the win client. One letter. Three letters. 17 letters. Sometimes different numbers of characters from the same string... and sometimes (very occasionally) it will change for no apparent reason. (Ownership issues? Some portion of primary clipboard data "wins a race" over ownership issues? I have no idea.)
  1. Changes to primary can be made from selecting in chrome or in xterm and are equally likely (or rather, unlikely) to be acknowledged by win client.
  1. For client clipboard copying to be pasteable to a chrome browser it needs to be picked up by clipboard. For xterm it needs to be picked up by primary. The loading of all three in 0.8.7 seemed to work well for client to server. (Perhaps I just needed to use the binding command.)
  1. At one point selecting text in xpra chrome browsers was copying to the primary, but then hitting backspace was clearing primary. I can only guess that something caused the clipboard to copy the "blank" as if it were "selected" to the primary. It behaved this way consistently, until I stopped that xpra session. The three subsequent xpra sessions however did not clear the primary with backspaces of highlighted text.
  1. While the primary was being cleared by backspaces, inserting into an xterm pasted in whatever was in the primary before the last selection which was deleted by the backspace. This consistently occurred, with xterm insertions pasting in data that was no longer contained in any of the three clipboards. (Perhaps xterm has yet another "insertion clipboard" that it turns to if the primary has recently been cleared? Perhaps my server picked the wrong morning to quit sniffing glue?) Once the backspacing ceased clearing primary this behavior also ceased.
  1. Whatever I did, I could not find any correlation between secondary or clipboard with anything that successfully pasted into the win client. primary had some success, but very limited. IIRC testing with 0.8.7, when copying from the win client was stored in all three clipboards, had the effect of "renewing" the ability for things copied in an xpra browser to be pasted into the win client. I'm not sure if it was a coincidence, but perhaps the updating of the secondary by a win client copy operation then caused a reaction to the next primary change "similar to that seen when an xpra session first begins" which allows for the next "change" in the primary to be passed to the client?? (I realize that makes little sense, but perhaps there is some ownership issue that the use of the secondary "toggles"... and, judging from the fact that I saw pastings with no change in clipboard, I suspect it is primary that has some success being "read" by a window client)

Hopefully this is some use.

comment:8 Changed 7 years ago by Antoine Martin

When testing with 0.8.x, the clipboard uses the old code which selects a single target for the data exchanges (PRIMARY by default - though this can be changed via the tray menu). This explains most of what is reported in comment:7.
(that and the bugs: (2)a and (3) from comment:3)

I don't think we will fix anything in the 0.8.x branch, it doesn't work great (and maybe the default remote clipboard should be CLIPBOARD instead of PRIMARY, this would make most people happier, except me an my xterms.. - but otherwise I think it works as was expected given the code that is in there) - 0.9.x is where it's at.

comment:9 Changed 7 years ago by Antoine Martin

  • Trying to understand (2)a:
    • on client connect, server gets all 3 tokens:
      got token, selection=CLIPBOARD
      got token, selection=PRIMARY
      got token, selection=SECONDARY
      
    • setting the contents of PRIMARY clipboard on the server end (using copy from somewhere, here I used set STRING target for CLIPBOARD selection from the clipboard tool, with a value of "123"), this showed on the server:
      do_selection_clear_event(.. GDK_SELECTION_CLEAR selection=CLIPBOARD, target=, property=>) selection=CLIPBOARD
      send clipboard token: CLIPBOARD
      process clipboard packet type=clipboard-request
      process clipboard request, request_id=0, selection=CLIPBOARD, local name=CLIPBOARD, target=UTF8_STRING
      get_contents(UTF8_STRING,<function got_contents at 0x7f2c1c85f500>) selection=CLIPBOARD
      unpack: <type 'NoneType'>, 0
      unpack(..) type=, format=0, data=<type 'NoneType'>:0
      got_contents(, 0, <type 'NoneType'>:0) str(data)=None..
      

So, we claim the CLIPBOARD selection, send the token to the client, the client then requests the contents as a 'UTF8_STRING' and we send back nothing...
The client showed:

got token, selection=CLIPBOARD
do_selection_request_event(... selection=CLIPBOARD ..)
target for CLIPBOARD: UTF8_STRING
get clipboard from remote
got clipboard contents None
remote selection fetch timed out or empty

Questions:

  • why did the win32 client immediately request the contents of the clipboard? what application? (how can we even find out?)
  • why didn't we find a value for the contents, since I set it to '123'..
  • reverse test: setting clipboard from win32
    • sends all the tokens to the server
    • requesting targets from the server correctly causes the client to call:
      get_contents(TARGETS, ..)
      
    • client returns an empty value??

This is giving me a headache! I'll try again tomorrow, but it looks like even the solution of going back to the one-to-one mapping may have the same issue..

comment:10 Changed 6 years ago by Antoine Martin

  • AFAICT win32 always requests the contents of the clipboard as soon as we set targets, so syncing with PRIMARY is out of the question. So we remove the merged clipboard code and we have to claim ownership (send the anti-token) of the clipboard everytime we get new data to ensure that the server will send the new data when something else is copied to the clipboard. (the code is not pretty, but this was easier than subclassing or adding new signals - probably)
  • Next problem was to do with targets, on *nix we were looking for atoms using the standard selection code, but this doesn't work on win32. Fortunately gtk has a nice function for getting targets already request_targets - unfortunately, that doesn't fit very well with the raw-to-wire and wire-to-raw methods.. so a lot of changes to accomodate that were needed too.
  • Third, we now sync with CLIPBOARD and not PRIMARY on win32 clients since that's what most people expect.. (never mind my xterms..)

Changes are in r3038


How to test (steps most likely to exercise the fixes):

  • copy text in application running via xpra
  • paste into native application
  • copy more text in application running via xpra
  • paste into native application again (verify the new text shows up)

Then as above but reversed (though that was not a problem for me before)


Rants and notes:

  • maybe we could use a flag (possibly named "crappy win32 platform"?) to tell the server to send the client something when the selection changes as we do seem to be getting an event when that occurs:
    do_owner_changed((<gtk.Clipboard object at 0x2a35b40 (GtkClipboard at 0x2a32820)>, \
        <gtk.gdk.Event at 0x29ad260: GDK_OWNER_CHANGE \
        reason=GDK_OWNER_CHANGE_NEW_OWNER, selection=CLIPBOARD>))
    

But this wouldn't save us much since the big waste (often transferring clipboard contents before they are needed) cannot be avoided on win32.

  • we should probably add a client capability so we can tell the server not to bother with PRIMARY and SECONDARY clipboards when only win32 clients are connected. (and save wasted CPU and bandwidth)

comment:11 Changed 6 years ago by Antoine Martin

r3039 removes the ability to select the "old" merged clipboard from the tray menu, the "merged" clipboard code no longer exists.

comment:12 Changed 6 years ago by alas

I rebuilt a fedora 0.9.0 xpra and installed it server-side (3/25/13, built from svn source, said it included 3039). I am using the 0.9.0 windows client from beta 3/22/13. Testing with gtk_view_clipboard on xterms and google-chrome browser in xpra session.

Results:

  • Test 1
    http://www.foiledcupcake.com (all 3 clipboards)
    (select text in xterm)
    (Primary: owner changed, reason: new owner, new owner = 0x80001b)
    --->clipboard clear (got string selection data: '')
    -->primary happy happy fu (Got string selection data: ' happy happy fu')
    --> secondary clear (Got string selection data: '')
    
    Paste in txt
     happy happy fu
    (straight from primary)
    
  • Test 2: Type & select new text in xterm
    Primary : Owner changed, reason: new owner, new owner=0x80001b
    
    ---> Clipboard clear (Got string selection data: '')
    --> Primary (Got string selection data: ' command not found') {Selected}
    --> Secondary : (Got string selection data: '')
    

This is as reproducible as a fecund teenager.

  • Test 3: Type virii into xterm & select.
    Primary : Owner changed, reason: new owner, new owner = 0x80001b
    Clipboard: (Got string selection data: '')
    Primary: (Got string slection data: ' virii')
    Secondary: (Got string selection data: '')
    Paste:  happy happy fu (old clipboard data)
    
  • Test 4:

Copy something client-side to reset clipboard. ('old clipboard data')
Select 'virii' from xterm. Paste (' virii')

Clipboard: (Got string selection data: '')
Primary: (Got string selection data: ' virii')
Secondary: (Got string selection data: '')

Paste into browser.
--nothing--
  • Test 5:

Type 'virii' into browser, select & copy.

"clipboard buffer contains blacklisted pattern 'virii' and has been dropped!"
Clipboard: (Got string selection data: 'virii')
Primary: (Got string selection data: 'virii')
Secondary: (Got string selection data: '')

Paste in txt: ('')
  • Test 6:

Type something else into browser & select & copy. Paste ('')
Copy something client side to reset clipboard, then select & copy browser text. ('unhappy camper')

--->Clipboard: (Got string selection data: 'unhappy camper')
--> Primary: (Got string selection data: 'unhappy camper')
--> Secondary: (Got string selection data: '')
  • Test 7:

Select something from xterm. Paste ('unhappy camper')

--->Clipboard: (Got string selection data: 'unhappy camper')
--> Primary: (Got string selection data: ' :ApplyCaretV')
--> Secondary: (Got string selection data: '')
  • Test 8:

Copy something client-side to reset clipboard.

---> Clipboard: Owner changed, reason: new owner, new owner=0x400020
--> Primary: Owner changed, reason: new owner, new owner=0x400021
--> Secondary: Owner changed, reason: new owner, new owner=0x400022

(All 3 clipboards set to client-side copy data)

  • Test 9:

Now select from xterm (Paste: 'nted reached')

--> Primary: Owner changed, reason: new owner, new owner=0x80001b
Paste again: 'nted reached'
--->Clipboard: Got string selection data: ''
--> Primary: Got string selection data: 'nted reached')
--> Secondary: Got string selection data: ''
Last edited 6 years ago by Antoine Martin (previous) (diff)

comment:13 Changed 6 years ago by alas

Status: newassigned

comment:14 Changed 6 years ago by Antoine Martin

I was finding it very hard to read, understand and respond to comment:13, so I have edited the text to try to make it easier to refer to it (adding numbering) - apologies if I've somehow misinterpreted anything. In the future, please try adding: expected: X, result: Y and copying easily identifiable strings rather than random bits of text (ie: is "foiledcupcake" relevant in any way? does it help us understand/identify what we are looking at or what is expected to happen)

  • First things first, what does the clipboard menu in the system tray show as options and which one is selected?


  • Test 1: Paste in txt - I assume this means pasting into a client side text editor, it looks like old xpra code as this should not be possible with current trunk - XPRA_CLIPBOARD_DEBUG=1 log samples (preferably from both sides) would help us confirm what is happening here.
  • Test 2: It seems that a number of these tests, at least this one AFAICT, are done using the clipboard tool and an application (xterm or chrome) with both running on the same side (server side), which is something that is not and never will be filtered in any way by xpra. Reproducible this should be, since this is the correct/expected X11 behaviour.
  • Test 3: Looks exactly as expected to me?
  • Test 4: Same issue "Test 1" above, the browser pastes from "clipboard" not "primary".
  • Test 5: the blacklisted contents get dropped... So we're testing both the filter and copy&paste issues at the same time (no wonder I was confused!).

r3045 should help in this case (and when copying an empty string) as we now always force claim the selection, no matter what the contents received are. This should prevent the need to "reset the clipboard" by copying something client side (by virtually "copying" something every time something is received).

  • Test 6: Apart from the "reset clipboard" issue above, I assume this works as intended?
  • Test 7: not sure what the strings are meant to be, I assume this works as intended?
  • Test 8: All 3 clipboards set to client-side copy data - how did you verify this? If true, this seems to do something that is simply impossible with the current clipboard code, and makes me think that the version tested is not the correct and up to date one, if not debug logging could shed a light on this. r3039 even removes the code from the tree to make sure - please verify with the latest from trunk. (please also see the "initial" question above too)
  • Test 9: not sure how where things are pasted or what is/isn't expected here.

comment:15 Changed 6 years ago by alas

Firstly, you are correct. The text I used was irrelevant, with the exception of "virii".

I just rebuilt xpra 0.9.0 for fedora (got notification of 3046 during the svn update) and I am using the 0.9.0 xpra beta for windows client (downloaded 3/26/13).

I just repeated test 1: and I am still able to copy from an xterm (opened as a start-child on the server command line) to a client side txt file.

The behavior is similar to any other xpra-session to window client copy & pasting. The second set of text I selected (xterm copy), when I attempted to paste it into a windows client txt file I instead re-pasted the text from the first copy (select). Once I do a (pointless) copy on the client side, however, then the next selection in an xterm is likewise pasteable.

Test 2. was a repetition of the test, and the test is still repeatable as far as I can tell.

Tests 3,4&5. Were tests of the clipboard filter. We can forget about them.

Test 6 was merely to show that a copy from a browser was copying to both primary & clipboard (which I suspected but wanted to see).

Test 7 was to show that copy (select) from an xterm was solely copying to primary (as we would expect). It did indeed change contents of primary and did indeed NOT change contents of clipboard.

Test 8 was a documentation of the change of owner of all three clipboards when a copy was made client-side (which I hadn't expected, but which doesn't surprise me). I verified it by looking at the contents of the gtk_view_clipboard data and comparing it with the output of a control-V in a client-side txt file. Repeating, I get the same results.

debugging log:

clipboard raw -> wire: ('UTF8_STRING', 8, 'skadoopie\x00') -> ('bytes', 'skadooopie\x00')
process clipboard packet type=clipboard-pending-requests

(Note, I tested this after the Test 9 logs were generated, so the 'skadoopie' mentioned is a reference back to the previous contents, presumably.)

Test 9 was to see what happens to clipboards server-side when a copy is made from an xterm after all three clipboards were changed by the client-side copy. I was surprised to see clipboard and secondary both cleared. I was expecting to see the change in primary.

With the latest (as far as I can tell) server-side fedora and client side windows install- I still seem to be able to copy from an xterm to a client-side txt file (or anything else, really).

The client-side XPRA_CLIPBOARD_DEBUG=1 is telling me the following:

get clipboard from remote handler id=1
local_to_remote(CLIPBOARD) current_remote_clipboard=PRIMARY
process clipboard packet type=clipboard-contents
process clipboard contents, selection=PRIMARY, type=UTF8_STRING, format=8
_munge_wire_selection_to_raw(bytes, UTF8_STRING, 8, (type 'str'):10:[' ', 's', 'k', 'a', 'd', 'o', 'o', 'p', 'i', 'e'])
wire selection to raw, encoding=bytes, type=UTF8_STRING, format=8, len(data0=10
clipboard wire -> raw: ('UTF8_STRING, 8, 'bytes', ' skadoopie') -> ' skadoopie'
got clipboard contents91)=10 (type=UTF8_STRING, format=8)
get clipboard from remote result(1)={'data': ' skadoopie', 'type': 'UTF8_STRING', 'format': 8}
do_selection_get((GtkSelectionData at 0x18ef2c),0,0) calling selection_data.set(UTF8_STRING, 8, (type 'str'):10)

I hope this clarifies something. I will try to go through the fedora server and look for any and all possible other instances of xpra that might be hiding high or low and confusing the yum localinstall when I get a chance, but I think I got them all already.

comment:16 Changed 6 years ago by Antoine Martin

The log messages you just posted confirm what I suspected all along:

local_to_remote(CLIPBOARD) current_remote_clipboard=PRIMARY

This message was part of the merged clipboard, which has been removed in r3039.


You can verify that this code is no longer present in the source tree:

$ grep -r current_remote_clipboard ./trunk/src | wc -l
0


You should be using your own build system to make new win32 installers as needed, otherwise you have to wait for me to upload new ones - like this one I built yesterday:

4cb7e3dbefc710d7860512d21bd768a5  Xpra_Setup_0.9.0.exe

comment:17 Changed 6 years ago by alas

Is this an update that was included on the client-side (the windows), rather than the server side? (fedora in this testing case)?

comment:18 Changed 6 years ago by Antoine Martin

Summary: allow MS Windows clients to interact with all 3 clipboards at the same timefix/improve MS Windows clipboard handling

The clipboard changes will generally affect both sides since both sides have a clipboard to manage. That said:

  • r3039 removes win32 client-side code only
  • r3038 and r3045 should only affect win32 clients

Unless I have really messed something up, checking the revision number should be enough to verify that those changes are included. (either via "xpra info" for the server, or via "about" for win32 clients)


(I've also just changed the ticket title to reflect what has been done in this ticket)

comment:19 Changed 6 years ago by alas

Well, the windows client that includes the updates seems to be doing the trick. Some preliminary tests show that the previous bugs (not being able to copy two things in a row from an xpra session and paste them into a windows client environment) are fixed.

I'll do some more tests and see if there's anything I'm overlooking, but I think these changes make a windows client clipboard work consistently.

comment:20 Changed 6 years ago by alas

I spoke too soon. Windows to xpra and xpra to windows copying and pasting now works consistently and, newly, repeatedly. Copying in an xpra browser and then pasting somewhere else in the xpra session, however, does not work with this new client.

Some tests.

Newest (3/30/13) xpra win client 0.9.0, fedora xpra server 0.9.0 (3/27/13)

Start- copy something from win client environment.
Clipboard: 	Got string selection data: {copied data - expected}
Primary:	Got string selection data: {copied data - not unexpected}
Secondary:	Got string selection data: '' {not unexpected}

Copy something in xpra browser.
Selecting causes: Primary:	Owner changed, reason: new owner, new owner=0xc00326
Control-c:	Clipboard:	Owner changed, reason: new owner, new owner=0xc00326
		Clipboard:	Owner changed, reason: new owner, new owner=0x400020

Clipboard:	Got string selection data: '' {unexpected, ought to have copied data}
Primary:	Got string selection data: {copied data - not unexpected}
Secondary: 	Got string selection data: '' {expected}

Paste back into browser. Nothing happens. ('', presumably)

Copy something else in browser.
Selecting: Causes the same owner change as above (in fact, causes a new line for each character selected.)
Control-c: Causes the same two owner changes as above.

Clipboard: 	Got string selection data: '' {same unexpected lack of data}
Primary:	Got string selection data: {copied data - expected - oddly the extra space copied has been filtered fromthe copied data string.}
Secondary:	Got string selection data: '' {expected}

Paste back into browser. Nothing happens again.

Copy something client side.

Clipboard:	Got string selection data: {copied data - expected}
Primary:	Got string selection data: '' {not particularly expected}
Secondary:	Got string selection data: '' {expected}

Paste into xpra browser. {copied data - expected}

Copy something in xpra browser.
Same owner changes as above.

Clipboard:	Got string selection data: '' {now expected}
Primary:	Got string selection data: {copied data - now expected}
Secondary:	Got string selection data: '' {now expected}

Paste into txt file client-side: {copied data - expected}

Copy second something in xpra browser.
All same as first copy.

Paste into txt file client-side: {copied data - unexpectedly pleasant change}

comment:21 Changed 6 years ago by Antoine Martin

Owner: changed from alas to Antoine Martin
Status: assignednew

Yes, that's sort of expected now since we make the client claim to own the clipboard selection... so that's not going to be enough (though probably enough for your particular use case)

comment:22 Changed 6 years ago by alas

It occurs to me that you may have misunderstood what I meant by not being able to copy in an xpra session and then paste back somewhere else in an xpra session.

I don't mean from one xpra session to another, or even from one xpra browser to another. I mean that you can't copy & paste even within the same tab within an xpra browser. For instance, if you open an email with an xpra browser and want to reply- you can't copy even a sentence from the email itself into the reply within the same tab.

While it may be unusual for there to be enough in an email that you want to use copy and then paste in order to copy a portion of an email in order to then respond, rather than just re-typing the "quote", I think most users will nevertheless expect that level of functionality and would rather not have to retype everything when a "simple" copy and paste would make the process much easier.

Just wanted to clarify, because I realized that Smo had misunderstood and thought I meant copying from one xpra browser to another wasn't working, rather than copying & pasting within a single tab wasn't working.

comment:23 Changed 6 years ago by Antoine Martin

Status: newassigned

Thanks for the clarification, I knew this was going to cause problems with local apps but I had forgotten that this would also interfere with cut&paste within the same app.

Since then, I've added some code to make it easier to test without having to run on win32 (to ease debugging): see r3048 and r3049.
You can now run the client with a single gdk clipboard with:

XPRA_CLIPBOARDS=clipboard xpra attach ...

Or use the win32 translated clipboard code (which now amounts to pretty much the same thing since the default clipboard is "clipboard") with:

XPRA_TRANSLATED_CLIPBOARD=1 xpra attach ...

Interestingly, using either one of these options, I've managed to reproduce the same annoying behaviour on Fedora 18 with cinnamon: some applications are pulling the clipboard contents every 0.5 seconds, causing unnecessary network traffic. Running the same setup on a plain Xvfb does not have this problem.
You can find a standalone test script in the tests/xpra tree as of r3050

The good thing about this is that it is now a hell of a lot easier to debug and test things.. but the bad thing is that I don't really know how to solve this.

comment:24 Changed 6 years ago by Antoine Martin

Owner: changed from Antoine Martin to alas
Status: assignednew

Can you please test r3051 to see if that helps?

(see also #307)

comment:25 Changed 6 years ago by alas

  • Ok r3051 does seem to help, but it is really odd. Copying & pasting within an xpra browser, or between xpra browsers works now-- but only up until the point when one copies something client-side (Windows, obviously).
  • Pasting anything copied in an xpra session to the client side doesn't work-- until a copy is first made of something client-side. Once that is done, one can copy and paste back and forth from xpra session to client-side as expected.
  • But-- once that client-side copy has occurred, one can no longer copy or paste from xpra session to xpra session (or even within the same xpra session).
  • Unless-- one goes to a new window (sometimes, especially when clicking a new youtube video, or sometimes facebook after an update), after which point one can copy & paste within and between xpra sessions again, until a copy is made client-side... at which point no copying within xpra sessions works. Again.

(I wanted to get this weirdness down while it was fresh. I will see about getting some debugging info as soon as I can.)

  • r3051 seems to fix an ubuntu client, so I assume likewise with other linux clients.

comment:26 Changed 6 years ago by Antoine Martin

  • (...) until a copy is first made of something client side:

r3068 prevents this race (server-side log message):

Traceback (most recent call last):
  File "/usr/lib/python2.6/site-packages/xpra/protocol.py", line 558, in do_read_parse_thread_loop
    self._process_packet_cb(self, packet)
  File "/usr/lib/python2.6/site-packages/xpra/server_base.py", line 1303, in process_packet
    assert ss.clipboard_enabled, "received a clipboard packet from a source which does not have clipboard enabled!"
AttributeError: 'NoneType' object has no attribute 'clipboard_enabled'

Which may have prevented the token from being received by the server initially. Weird, because I didn't see this error myself when I tested, only from other people's log extracts.. I think it was more likely to fire with ssh or password mode.

  • But-- once that client-side copy has occurred, one can no longer copy or paste from xpra session to xpra session

Confirmed, you will often find this message in the logs when this happens:

Our peer requested the contents of the clipboard, but *I* thought *they* had it... weird.

For reference, here's how I tested:

  • Fedora 18 server started with:
    XPRA_CLIPBOARD_DEBUG=1 xpra start :10 --bind-tcp=0.0.0.0:10000 --start-child=gnome-terminal
    
  • XP 32-bit client started with:
    set XPRA_CLIPBOARD_DEBUG=1
    xpra_cmd attach tcp:192.168.1.100:10000
    

  • Copy from server application:
    echo server-side-value1 | xclip -i -selection clipboard
    
  • Paste into server-side:
    xclip -o -selection clipboard
    

Does not work!

  • Paste client side (in notepad): works


This can be repeated with other values with the same results.


  • Copy from client application: select and copy "client-side-value1" from notepad.
  • Paste in notepad: works
  • Paste server side:
    xclip -o -selection clipboard
    

Works


More details on what happens when we copy from the server-side (full log):

553 do_selection_clear_event(<gtk.gdk.Event at 0x7f8d7db94760: GDK_SELECTION_CLEAR selection=CLIPBOARD, target=, property=>) selection=CLIPBOARD
554 send clipboard token: CLIPBOARD
554 do_owner_changed((<gtk.Clipboard object at 0x28f3230 (GtkClipboard at 0x2955030)>, <gtk.gdk.Event at 0x7f8d7db94760: GDK_OWNER_CHANGE reason=GDK_OWNER_CHANGE_NEW_OWNER, selection=CLIPBOARD>))
555 send clipboard token: CLIPBOARD
617 process clipboard packet type=clipboard-request
617 process clipboard request, request_id=3, selection=CLIPBOARD, local name=CLIPBOARD, target=UTF8_STRING
617 get_contents(UTF8_STRING,<function got_contents at 0x292acf8>) selection=CLIPBOARD
619 unpack: <type 'NoneType'>, 0
620 unpack(..) type=UTF8_STRING, format=8, data=<type 'str'>:19
620 got_contents(UTF8_STRING, 8, <type 'str'>:19) str(data)=server-side-value3
..
621 _do_munge_raw_selection_to_wire(UTF8_STRING, UTF8_STRING, 8, <type 'str'>:19)
621 clipboard raw -> wire: ('UTF8_STRING', 8, 'server-side-value3\n') -> ('bytes', 'server-side-value3\n')
628 process clipboard packet type=clipboard-request
630 process clipboard request, request_id=4, selection=CLIPBOARD, local name=CLIPBOARD, target=UTF8_STRING
630 get_contents(UTF8_STRING,<function got_contents at 0x292a7d0>) selection=CLIPBOARD
634 unpack: <type 'NoneType'>, 0
634 unpack(..) type=UTF8_STRING, format=8, data=<type 'str'>:19
634 got_contents(UTF8_STRING, 8, <type 'str'>:19) str(data)=server-side-value3
..
634 _do_munge_raw_selection_to_wire(UTF8_STRING, UTF8_STRING, 8, <type 'str'>:19)
634 clipboard raw -> wire: ('UTF8_STRING', 8, 'server-side-value3\n') -> ('bytes', 'server-side-value3\n')
674 process clipboard packet type=clipboard-token
675 process clipboard token selection=CLIPBOARD, local clipboard name=CLIPBOARD, proxy=ClipboardProxy(CLIPBOARD)
675 got token, selection=CLIPBOARD
676 process clipboard packet type=clipboard-token
676 process clipboard token selection=CLIPBOARD, local clipboard name=CLIPBOARD, proxy=ClipboardProxy(CLIPBOARD)
676 got token, selection=CLIPBOARD
677 do_owner_changed((<gtk.Clipboard object at 0x28f3230 (GtkClipboard at 0x2955030)>, <gtk.gdk.Event at 0x7f8d7db94760: GDK_OWNER_CHANGE reason=GDK_OWNER_CHANGE_NEW_OWNER, selection=CLIPBOARD>))
678 do_owner_changed((<gtk.Clipboard object at 0x28f3230 (GtkClipboard at 0x2955030)>, <gtk.gdk.Event at 0x7f8d7db94760: GDK_OWNER_CHANGE reason=GDK_OWNER_CHANGE_NEW_OWNER, selection=CLIPBOARD>))
680 do_selection_request_event(<gtk.gdk.Event at 0x7f8d7db94760: GDK_SELECTION_REQUEST selection=CLIPBOARD, target=TARGETS, property=GDK_SELECTION>)
680 target for CLIPBOARD: 'TARGETS'
680 do_selection_request_event(<gtk.gdk.Event at 0x7f8d7db94760: GDK_SELECTION_REQUEST selection=CLIPBOARD, target=TARGETS, property=GDK_SELECTION>) target=TARGETS, selection=CLIPBOARD
681 do_selection_get(<GtkSelectionData at 0x7fffbc70ba50>, 0, 48288958) selection=CLIPBOARD
681 get clipboard from remote handler id=12
683 do_selection_request_event(<gtk.gdk.Event at 0x2890288: GDK_SELECTION_REQUEST selection=CLIPBOARD, target=TARGETS, property=GDK_SELECTION>)
683 target for CLIPBOARD: 'TARGETS'
684 do_selection_request_event(<gtk.gdk.Event at 0x2890288: GDK_SELECTION_REQUEST selection=CLIPBOARD, target=TARGETS, property=GDK_SELECTION>) target=TARGETS, selection=CLIPBOARD
684 do_selection_get(<GtkSelectionData at 0x7fffbc709230>, 0, 48288961) selection=CLIPBOARD
684 get clipboard from remote handler id=13
855 process clipboard packet type=clipboard-contents
855 process clipboard contents, selection=CLIPBOARD, type=ATOM, format=32
855 _munge_wire_selection_to_raw(atoms, ATOM, 32, <type 'tuple'>:7:['TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING', 'UTF8_STRING', 'UTF8_STRING'])
855 _munge_wire_selection_to_raw(atoms, ATOM, 32, <type 'tuple'>:7)=[<GdkAtom 0x86 = 'TIMESTAMP'>, <GdkAtom 0x89 = 'TARGETS'>, <GdkAtom 0x88 = 'MULTIPLE'>, <GdkAtom 0x47 = 'UTF8_STRING'>, <GdkAtom 0x47 = 'UTF8_STRING'>, <GdkAtom 0x47 = 'UTF8_STRING'>, <GdkAtom 0x47 = 'UTF8_STRING'>]=[134L, 137L, 136L, 71L, 71L, 71L, 71L]=['\x86', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x89', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x88', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'G', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'G', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'G', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'G', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00']
855 clipboard wire -> raw: ('ATOM', 32, 'atoms', ('TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING', 'UTF8_STRING', 'UTF8_STRING')) -> '\x86\x00\x00\x00\x00\x00\x00\x00\x89\x00\x00\x00\x00\x00\x00\x00\x88\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00'
856 got clipboard contents(12)=56 (type=ATOM, format=32)
865 process clipboard packet type=clipboard-contents
866 process clipboard contents, selection=CLIPBOARD, type=ATOM, format=32
866 _munge_wire_selection_to_raw(atoms, ATOM, 32, <type 'tuple'>:7:['TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING', 'UTF8_STRING', 'UTF8_STRING'])
866 _munge_wire_selection_to_raw(atoms, ATOM, 32, <type 'tuple'>:7)=[<GdkAtom 0x86 = 'TIMESTAMP'>, <GdkAtom 0x89 = 'TARGETS'>, <GdkAtom 0x88 = 'MULTIPLE'>, <GdkAtom 0x47 = 'UTF8_STRING'>, <GdkAtom 0x47 = 'UTF8_STRING'>, <GdkAtom 0x47 = 'UTF8_STRING'>, <GdkAtom 0x47 = 'UTF8_STRING'>]=[134L, 137L, 136L, 71L, 71L, 71L, 71L]=['\x86', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x89', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x88', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'G', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'G', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'G', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'G', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00']
866 clipboard wire -> raw: ('ATOM', 32, 'atoms', ('TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING', 'UTF8_STRING', 'UTF8_STRING')) -> '\x86\x00\x00\x00\x00\x00\x00\x00\x89\x00\x00\x00\x00\x00\x00\x00\x88\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00'
866 got clipboard contents(13)=56 (type=ATOM, format=32)
866 get clipboard from remote result(13)={'data': '\x86\x00\x00\x00\x00\x00\x00\x00\x89\x00\x00\x00\x00\x00\x00\x00\x88\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00', 'type': 'ATOM', 'format': 32}
867 do_selection_get(<GtkSelectionData at 0x7fffbc709230>,0,48288961) calling selection_data.set(ATOM, 32, <type 'str'>:56)
867 get clipboard from remote result(12)={'data': '\x86\x00\x00\x00\x00\x00\x00\x00\x89\x00\x00\x00\x00\x00\x00\x00\x88\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00', 'type': 'ATOM', 'format': 32}
867 do_selection_get(<GtkSelectionData at 0x7fffbc70ba50>,0,48288958) calling selection_data.set(ATOM, 32, <type 'str'>:56)

Same log but edited:

554 send clipboard token: CLIPBOARD
555 send clipboard token: CLIPBOARD

617 process clipboard request, request_id=3, selection=CLIPBOARD, local name=CLIPBOARD, target=UTF8_STRING
617 get_contents(UTF8_STRING,<function got_contents at 0x292acf8>) selection=CLIPBOARD
620 got_contents(UTF8_STRING, 8, <type 'str'>:19) str(data)=server-side-value3

630 process clipboard request, request_id=4, selection=CLIPBOARD, local name=CLIPBOARD, target=UTF8_STRING
630 get_contents(UTF8_STRING,<function got_contents at 0x292a7d0>) selection=CLIPBOARD
634 got_contents(UTF8_STRING, 8, <type 'str'>:19) str(data)=server-side-value3

674 process clipboard packet type=clipboard-token
675 got token, selection=CLIPBOARD

676 process clipboard packet type=clipboard-token
676 got token, selection=CLIPBOARD

680 do_selection_request_event(<gtk.gdk.Event at 0x7f8d7db94760: GDK_SELECTION_REQUEST selection=CLIPBOARD, target=TARGETS, property=GDK_SELECTION>) target=TARGETS, selection=CLIPBOARD
681 get clipboard from remote handler id=12

684 do_selection_request_event(<gtk.gdk.Event at 0x2890288: GDK_SELECTION_REQUEST selection=CLIPBOARD, target=TARGETS, property=GDK_SELECTION>) target=TARGETS, selection=CLIPBOARD
684 get clipboard from remote handler id=13

855 process clipboard packet type=clipboard-contents
855 process clipboard contents, selection=CLIPBOARD, type=ATOM, format=32
855 _munge_wire_selection_to_raw(atoms, ATOM, 32, <type 'tuple'>:7:['TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING', 'UTF8_STRING', 'UTF8_STRING'])

865 process clipboard packet type=clipboard-contents
866 process clipboard contents, selection=CLIPBOARD, type=ATOM, format=32
866 _munge_wire_selection_to_raw(atoms, ATOM, 32, <type 'tuple'>:7:['TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING', 'UTF8_STRING', 'UTF8_STRING'])

867 do_selection_get(<GtkSelectionData at 0x7fffbc709230>,0,48288961) calling selection_data.set(ATOM, 32, <type 'str'>:56)
867 do_selection_get(<GtkSelectionData at 0x7fffbc70ba50>,0,48288958) calling selection_data.set(ATOM, 32, <type 'str'>:56)

So, as soon as we claim ownership of the clipboard, we get two requests (since we send 2 tokens) for the data within a few milliseconds, and shortly after the client claims the clipboard.

Now, the client log:

141 process clipboard packet type=clipboard-token
141 remote_to_local(CLIPBOARD) local_clipboard=CLIPBOARD, remote_clipboard=CLIPBOARD
141 process clipboard token selection=CLIPBOARD, local clipboard name=CLIPBOARD, proxy=ClipboardProxy(CLIPBOARD)
141 got token, selection=CLIPBOARD
151 do_owner_changed((<gtk.Clipboard object at 0xec1490 (GtkClipboard at 0x101f090)>, <gtk.gdk.Event at 00ED4D40: GDK_OWNER_CHANGE reason=GDK_OWNER_CHANGE_NEW_OWNER, selection=CLIPBOARD>))
151 do_selection_request_event(<gtk.gdk.Event at 00ED4D40: GDK_SELECTION_REQUEST selection=CLIPBOARD, target=UTF8_STRING, property=GDK_SELECTION>)
151 target for CLIPBOARD: 'UTF8_STRING'
151 do_selection_request_event(<gtk.gdk.Event at 00ED4D40: GDK_SELECTION_REQUEST selection=CLIPBOARD, target=UTF8_STRING, property=GDK_SELECTION>) target=UTF8_STRING, selection=CLIPBOARD
151 do_selection_get(<GtkSelectionData at 0x12f050>, 0, 0) selection=CLIPBOARD
151 get clipboard from remote handler id=0
151 local_to_remote(CLIPBOARD) local_clipboard=CLIPBOARD, remote_clipboard=CLIPBOARD
151 process clipboard packet type=clipboard-token
151 remote_to_local(CLIPBOARD) local_clipboard=CLIPBOARD, remote_clipboard=CLIPBOARD
151 process clipboard token selection=CLIPBOARD, local clipboard name=CLIPBOARD, proxy=ClipboardProxy(CLIPBOARD)
151 got token, selection=CLIPBOARD
151 do_owner_changed((<gtk.Clipboard object at 0xec1490 (GtkClipboard at 0x101f090)>, <gtk.gdk.Event at 00ED4AD0: GDK_OWNER_CHANGE reason=GDK_OWNER_CHANGE_NEW_OWNER, selection=CLIPBOARD>))
151 do_selection_request_event(<gtk.gdk.Event at 00ED4AD0: GDK_SELECTION_REQUEST selection=CLIPBOARD, target=UTF8_STRING, property=GDK_SELECTION>)
151 target for CLIPBOARD: 'UTF8_STRING'
151 do_selection_request_event(<gtk.gdk.Event at 00ED4AD0: GDK_SELECTION_REQUEST selection=CLIPBOARD, target=UTF8_STRING, property=GDK_SELECTION>) target=UTF8_STRING, selection=CLIPBOARD
151 do_selection_get(<GtkSelectionData at 0x12d668>, 0, 0) selection=CLIPBOARD
151 get clipboard from remote handler id=1
151 local_to_remote(CLIPBOARD) local_clipboard=CLIPBOARD, remote_clipboard=CLIPBOARD
180 process clipboard packet type=clipboard-contents
180 process clipboard contents, selection=CLIPBOARD, type=UTF8_STRING, format=8
180 _munge_wire_selection_to_raw(bytes, UTF8_STRING, 8, <type 'str'>:19:['s', 'e', 'r', 'v', 'e', 'r', '-', 's', 'i', 'd', 'e', '-', 'v', 'a', 'l', 'u', 'e', '3', '\n'])
180 wire selection to raw, encoding=bytes, type=UTF8_STRING, format=8, len(data)=19
180 clipboard wire -> raw: ('UTF8_STRING', 8, 'bytes', 'server-side-value3\n') -> 'server-side-value3\n'
180 got clipboard contents(0)=19 (type=UTF8_STRING, format=8)
180 process clipboard packet type=clipboard-contents
180 process clipboard contents, selection=CLIPBOARD, type=UTF8_STRING, format=8
180 _munge_wire_selection_to_raw(bytes, UTF8_STRING, 8, <type 'str'>:19:['s', 'e', 'r', 'v', 'e', 'r', '-', 's', 'i', 'd', 'e', '-', 'v', 'a', 'l', 'u', 'e', '3', '\n'])
180 wire selection to raw, encoding=bytes, type=UTF8_STRING, format=8, len(data)=19
180 clipboard wire -> raw: ('UTF8_STRING', 8, 'bytes', 'server-side-value3\n') -> 'server-side-value3\n'
180 got clipboard contents(1)=19 (type=UTF8_STRING, format=8)
180 get clipboard from remote result(1)={'data': 'server-side-value3\n', 'type': 'UTF8_STRING', 'format': 8}
190 do_selection_get(<GtkSelectionData at 0x12d668>,0,0) calling selection_data.set(UTF8_STRING, 8, <type 'str'>:19)
190 do_owner_changed((<gtk.Clipboard object at 0xec1490 (GtkClipboard at 0x101f090)>, <gtk.gdk.Event at 00ED4AD0: GDK_OWNER_CHANGE reason=GDK_OWNER_CHANGE_NEW_OWNER, selection=CLIPBOARD>))
190 send clipboard token: CLIPBOARD
190 local_to_remote(CLIPBOARD) local_clipboard=CLIPBOARD, remote_clipboard=CLIPBOARD
190 get clipboard from remote result(0)={'data': 'server-side-value3\n', 'type': 'UTF8_STRING', 'format': 8}
200 do_selection_get(<GtkSelectionData at 0x12f050>,0,0) calling selection_data.set(UTF8_STRING, 8, <type 'str'>:19)
200 do_owner_changed((<gtk.Clipboard object at 0xec1490 (GtkClipboard at 0x101f090)>, <gtk.gdk.Event at 00ED4D40: GDK_OWNER_CHANGE reason=GDK_OWNER_CHANGE_NEW_OWNER, selection=CLIPBOARD>))
200 send clipboard token: CLIPBOARD
200 local_to_remote(CLIPBOARD) local_clipboard=CLIPBOARD, remote_clipboard=CLIPBOARD
290 process clipboard packet type=clipboard-pending-requests
290 process clipboard packet type=clipboard-request
290 remote_to_local(CLIPBOARD) local_clipboard=CLIPBOARD, remote_clipboard=CLIPBOARD
290 process clipboard request, request_id=23, selection=CLIPBOARD, local name=CLIPBOARD, target=TARGETS
290 get_contents(TARGETS,<function got_contents at 0x00F31CB0>) selection=CLIPBOARD
290 got_targets(<gtk.Clipboard object at 0xec1490 (GtkClipboard at 0x101f090)>, ('TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING'), (None,))
290 got_contents(ATOM, 32, <type 'tuple'>:5) str(data)=('TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING')..
290 _filter_targets(('TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING'))=['TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING']
290 clipboard raw -> wire: ('ATOM', 32, ('TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING')) -> ('atoms', ['TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING'])
290 process clipboard packet type=clipboard-pending-requests
290 process clipboard packet type=clipboard-request
290 remote_to_local(CLIPBOARD) local_clipboard=CLIPBOARD, remote_clipboard=CLIPBOARD
290 process clipboard request, request_id=24, selection=CLIPBOARD, local name=CLIPBOARD, target=TARGETS
290 get_contents(TARGETS,<function got_contents at 0x00F31CB0>) selection=CLIPBOARD
290 got_targets(<gtk.Clipboard object at 0xec1490 (GtkClipboard at 0x101f090)>, ('TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING'), (None,))
290 got_contents(ATOM, 32, <type 'tuple'>:5) str(data)=('TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING')..
290 _filter_targets(('TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING'))=['TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING']
290 clipboard raw -> wire: ('ATOM', 32, ('TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING')) -> ('atoms', ['TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING'])
480 process clipboard packet type=clipboard-pending-requests
480 process clipboard packet type=clipboard-pending-requests

Now edited:

141 process clipboard packet type=clipboard-token

151 do_selection_request_event(<gtk.gdk.Event at 00ED4D40: GDK_SELECTION_REQUEST selection=CLIPBOARD, target=UTF8_STRING, property=GDK_SELECTION>) target=UTF8_STRING, selection=CLIPBOARD

151 process clipboard packet type=clipboard-token

151 do_selection_request_event(<gtk.gdk.Event at 00ED4AD0: GDK_SELECTION_REQUEST selection=CLIPBOARD, target=UTF8_STRING, property=GDK_SELECTION>) target=UTF8_STRING, selection=CLIPBOARD

180 get clipboard from remote result(1)={'data': 'server-side-value3\n', 'type': 'UTF8_STRING', 'format': 8}
190 do_owner_changed((<gtk.Clipboard object at 0xec1490 (GtkClipboard at 0x101f090)>, <gtk.gdk.Event at 00ED4AD0: GDK_OWNER_CHANGE reason=GDK_OWNER_CHANGE_NEW_OWNER, selection=CLIPBOARD>))
190 send clipboard token: CLIPBOARD

190 get clipboard from remote result(0)={'data': 'server-side-value3\n', 'type': 'UTF8_STRING', 'format': 8}
200 do_owner_changed((<gtk.Clipboard object at 0xec1490 (GtkClipboard at 0x101f090)>, <gtk.gdk.Event at 00ED4D40: GDK_OWNER_CHANGE reason=GDK_OWNER_CHANGE_NEW_OWNER, selection=CLIPBOARD>))
200 send clipboard token: CLIPBOARD

290 got_targets(<gtk.Clipboard object at 0xec1490 (GtkClipboard at 0x101f090)>, ('TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING'), (None,))
290 got_targets(<gtk.Clipboard object at 0xec1490 (GtkClipboard at 0x101f090)>, ('TIMESTAMP', 'TARGETS', 'MULTIPLE', 'UTF8_STRING', 'UTF8_STRING'), (None,))

480 process clipboard packet type=clipboard-pending-requests
480 process clipboard packet type=clipboard-pending-requests

Thoughts:

  • we send the clipboard token twice... once from do_selection_clear_event and once from do_owner_changed... Maybe we can drop the first one?
    --- src/xpra/platform/clipboard_base.py	(revision 3074)
    +++ src/xpra/platform/clipboard_base.py	(working copy)
    @@ -368,12 +368,15 @@
         def do_selection_clear_event(self, event):
             # Someone else on our side has the selection
             debug("do_selection_clear_event(%s) selection=%s", event, self._selection)
    +        #if send_on_owner_change, do_owner_changed will fire the token
    +        send = (not self._send_on_owner_change or self._have_token)
             self._have_token = False
     
             # Emit a signal -> send a note to the other side saying "hey its
             # ours now"
             # Send off the anti-token.
    -        self.emit("send-clipboard-token", self._selection)
    +        if send:
    +            self.emit("send-clipboard-token", self._selection)
             gtk.Invisible.do_selection_clear_event(self, event)
     
         def got_token(self):
    
  • as soon as we call selection_data.set, the client claims ownership of the clipboard (and therefore clears the value on the server). And we don't want that, the _send_on_owner_change is really a flag saying: the other may be stupid (ie: win32), send the token to force it to refresh, but the Linux servers are OK... here's a hacked patch:
    ### Eclipse Workspace Patch 1.0
    #P Xpra
    Index: src/xpra/platform/clipboard_base.py
    ===================================================================
    --- src/xpra/platform/clipboard_base.py	(revision 3074)
    +++ src/xpra/platform/clipboard_base.py	(working copy)
    @@ -278,7 +278,8 @@
             self._selection = selection
             self._clipboard = gtk.Clipboard(selection=selection)
             self._have_token = False
    -        self._send_on_owner_change = True
    +        import sys
    +        self._send_on_owner_change = not sys.platform.startswith("win")
             self._clipboard.connect("owner-change", self.do_owner_changed)
     
         def __str__(self):
    @@ -390,7 +394,9 @@
                          + "contents of remote clipboard")
             def reenable_send(*args):
                 self._send_on_owner_change = True
    -        gobject.idle_add(reenable_send)
    +        import sys
    +        if not sys.platform.startswith("win"):
    +            gobject.idle_add(reenable_send)
     
         # This function is called by the xpra core when the peer has requested the
         # contents of this clipboard:
    

With this patch we no longer clobber the server.

  • BUT even if this is all fixed.. (remains to be seen). I've had at least one crash due to this fugly code (#311)... Nested main loops and asynchronous calls don't mix well. Maybe we should just re-write it using plain X11 / native win32... (it's not like there is much gtk code left anyway?) PITA.

comment:27 Changed 6 years ago by alas

Some further notes.

Trying to use the clipboard control setter from the client tray icon.

*With the clipboard ownership set to the client - the above behavior is seen (the clipboard contents, upon a copy being made, are passed to the client clipboard & cleared from the server clipboard --> at which point those clipboard contents are no longer available on the server-side for pasting within an xpra browser).

*With the primary ownership set to the client - the server maintains the contents of the clipboard, and is thus able to paste the contents within the xpra browser --> but without those contents having been sent to the client, the contents can't be pasted client-side).

*With the primary ownership set to the client, however, a user loses the ability to select the contents of a browser address bar. Apparently the setting of the ownership to the client causes the server to try to pass the contents of the primary clipboard, as they are selected, to the client... in the process clearing the "selection" being highlighted. (This actually causes the xpra session to crash within minutes if the user tries determinedly to select the contents of the address bar.)

Some logs for that crash in case they help:

client-side

2013-04-15 12:09:35,490 Failed to load icon at C:\Program Files (x86)\Xpra\icons
\clipboard.ico: (6, 'LoadImage', 'The handle is invalid.')
2013-04-15 12:09:35,497 Failed to load icon at C:\Program Files (x86)\Xpra\icons
\clipboard.ico: (6, 'LoadImage', 'The handle is invalid.')
2013-04-15 12:09:35,505 Failed to load icon at C:\Program Files (x86)\Xpra\icons
\clipboard.ico: (6, 'LoadImage', 'The handle is invalid.')
2013-04-15 12:09:35,513 Failed to load icon at C:\Program Files (x86)\Xpra\icons
\xpra.ico: (6, 'LoadImage', 'The handle is invalid.')
pnc=: T

server-side

2013-04-15 12:09:35,782 Our peer requested the contents of the clipboard, but *I* thought *they* had it... 

weird.
2013-04-15 12:09:50,909 delayed_region_timeout: sending now - something is wrong!
2013-04-15 12:10:05,981 delayed_region_timeout: sending now - something is wrong!
2013-04-15 12:10:21,050 delayed_region_timeout: sending now - something is wrong!
2013-04-15 12:10:36,262 delayed_region_timeout: sending now - something is wrong!
2013-04-15 12:10:36,308 get_backlog found some damage acks that have been pending for too long, expiring 

them: [2667]
2013-04-15 12:10:38,970 Disconnecting existing client Protocol(SocketConnection(('10.0.32.196', 1200) - 

('10.0.11.10', 39790))), reason is: client ping timeout, - waited 60 seconds without a response
2013-04-15 12:10:38,972 connection closed after 19651 packets received (653047 bytes) and 45864 packets sent 

(76104883 bytes)
2013-04-15 12:10:38,978 xpra client disconnected.
2013-04-15 12:10:38,980 Connection lost
2013-04-15 12:10:38,987 Connection lost

*For some reason, this behavior of "pushing" the primary contents mid-selecting seems to only take place with address bar selections. (Maybe because I was using a chrome browser which was trying to process address bar contents more actively than other text?)

Perhaps, if contents of clipboard can be passed to the client without, in the process of doing so, clearing the server-side clipboard... those contents might be available both server and client side?

comment:28 Changed 6 years ago by Antoine Martin

without the patches from comment:26, the results from comment:27 aren't particularly useful, sorry.

comment:29 Changed 6 years ago by Antoine Martin

Fix committed in r3075.


Validation: with the same test setup described in comment:26 (Fedora 18 server, win32 client, gnome-terminal via xpra, notepad native win32):

  • Copy from server application:
    echo server-side-value1 | xclip -i -selection clipboard
    
  • Paste in notepad: works
  • Paste on server: works
    xclip -o -selection clipboard
    
  • (Paste in other server apps like gedit: works)


  • Copy new string from server:
    echo server-side-value2 | xclip -i -selection clipboard
    
  • Paste in all (notepad, server via xclip, gedit, ..): works


  • Copy from client application: select and copy "client-side-value1" from notepad.
  • Paste in all (notepad, server via xclip, gedit, ..): works

(bonus check: you should be able to see the tray icon showing the clipboard whilst the transfer is in progress - see #275)

  • Copy new string from client (say: "client-side-value2")
  • Paste in all again: works


  • Copy new strings from either client or server and repeat: works.

If you do find an application / test that makes this code misbehave, please try to report it in terms of reproducible "xclip" commands so we can debug it.

Testing which remote clipboard we sync to (as per comment:27) should not be a priority, and if there are issues with that let's move this to a new ticket (and we may even disable the feature) to prevent this from blocking the release.

See also #313

Last edited 6 years ago by Antoine Martin (previous) (diff)

comment:30 Changed 6 years ago by alas

Resolution: fixed
Status: newclosed

Ok, I can't find any way to make the clipboard misbehave between server-side xpra session browsers and the windows client (aside from some issues with our custom browser). I think this ticket is closed.

comment:31 Changed 6 years ago by Antoine Martin

Resolution: fixed
Status: closedreopened

This broke clipboard support on *nix... re-opening the ticket.

(odd because the changes were supposed to be limited to platforms that supply the "greedy" flag: win32 and osx only)

comment:32 Changed 6 years ago by Antoine Martin

Status: reopenednew

fixed in trunk in r3399 and 0.9.x branch in r3401

Please re-test to make sure this has not caused regressions, especially for win32 clients.

comment:33 Changed 6 years ago by Antoine Martin

Maybe the test should be:

send = (self._greedy_client and not self._block_owner_change) or (not self._greedy_client and self._have_token)

comment:34 Changed 6 years ago by alas

* Ignore this comment, it looks like the build scripts have changed in some way I can't find documented, so my build was an old 0.9.0 ... so it behaved as 0.9.0 behaves. (I'll open a ticket for that- and I'll leave you to decide whether to leave this warning for the unwary or just delete it for clarity.)


It looks like the clipboard has gone back to not capturing new copies to the clipboard within an xpra session.

Copy something in xpra client. Paste in xpra- works. Paste in client-works.

Copy something else in xpra client. Paste in xpra- works. Paste in client- pastes what was previously copied.

Copy something else again in xpra client. Paste in xpra- works. Paste in client- still pastes that same first copied data.

Copy something client-side. Paste client side- works (obviously). Paste in xpra- works.

Copy something new xpra client-side. Paste in xpra- works. Paste in client- works.

Copy something newer in xpra client-side. Paste in xpra- works. Paste in client- same new-ish (post client-copy, xpra-copy) data pastes.

As I recall, this is the behavior that takes place when the xpra copies are copied to primary and cliboard, but further copies within an xpra session only copy to primary (only to clipboard when it previously "belonged" to the client. Once it "belongs" to the xpra session then the copies are only stored in primary and the clipboard contents are unchanged from the state after that first "wrestling" of it from the client's ownership).

I'm assuming you remember that state of the clipboard behavior from previous iterations of this rabbit-hole. Let me know if you need me to do more comprehensive tests with gtk_view_clipboard and what have you (especially if you think that there might be something new in the behavior from that previous behavior).

(I should note though, that trying to build the fedora server from trunk is displaying as 0.9.0, though saying it included r3420 at the svn stage. Should the trunk be displaying as 0.9.0 or has my fedora build started pulling from some stray folder again?)

Last edited 6 years ago by alas (previous) (diff)

comment:35 Changed 6 years ago by Antoine Martin

Resolution: fixed
Status: newclosed

the build scripts have changed in some way I can't find documented

The build scripts are kept here: browser/xpra/trunk/scripts

As for the clipboard, I've just tested on win32 and cannot make it misbehave.
(but then again I was never very good at that)

Note: See TracTickets for help on using tickets.