we have the concept of doppelganger pointers, which track the movement of "real" pointers on the other window. (Doppelganger pointers are usually shown with black insides, and "real" pointers with white insides, as in the diagram above.) The position of the doppelganger is transmitted over RFB
in one direction, but since RFB sends this information only in that direction, the equivalent information in the other direction is sent over the xzibit control connection
However, there is a problem. In order to send the doppelganger information we have to track the movement of pointers, by receiving XMotionEvent
events. It turns out that XMotionEvent tracks the movement of doppelganger pointers as well as "real" ones.
This causes a feedback loop: the host user moves the pointer, the remote user sees their doppelganger, the remote user's doppelganger generates motion events, which moves the host user's doppelganger, which causes the remote user's doppelganger to move again, and so on for ever.
There are a few possible workarounds, but none seems very satisfactory.
We could stop using actual pointers for doppelgangers. Instead, we could use shaped windows and move them about
. That would stop them generating XMotionEvent. However, experimentation shows that this causes an unacceptable amount of flickering. So it looks as though we're stuck with using actual pointers.
We could also discount motion events derived from doppelgangers. This could be done by examining the event for some sort of flag (which doesn't seem to exist). A better solution is to remember where we put the doppelganger, and ignore any motion event from those coordinates. This is easily done for messages over the xzibit control connection. However, doing this for messages using the RFB PointerEvent mechanism poses a greater problem. We could:
- fork the gtk-vnc library and add a special case for doppelgangers. This is the most efficient answer. It is also a horrible bodge.
- ignore all RFB PointerEvents, and use the xzibit control connection in both ways, at the cost of sending all pointer events in one direction twice. This is the simplest answer, but is horribly inefficient.
- run a simple filter over the RFB stream as we receive it, which removes any RFB PointerEvent messages at the place where we last put the doppelganger. This is probably the cleanest solution, but is rather a hack. It's also difficult to implement, since RFB messages are of variable length and require knowledge of each type in order to know where each one ends. (A first approximation is simply to look for PointerEvent messages with the expected parameters anywhere in the stream, and hope that the five bytes we're looking for don't happen to occur embedded within another message. It's unlikely that they will, but again, it's not an elegant solution.)
I don't much like any of these. Tell me what you think.Update:
jojomojo points out xinput2's XIDeviceEvent which does have the mpx ID field. This is very useful, but now I have to make gtk-vnc be aware of it.