deadpixi / sam

An updated version of the sam text editor.
Other
436 stars 47 forks source link

Performing <exch> two times in succession doesn't return your snarf buffer to sam #61

Closed siebenmann closed 6 years ago

siebenmann commented 7 years ago

Suppose that you snarf something that you plan to paste into another spot in sam, but then you absently or reflexively <exch> it. You would like to get your snarf buffer back, so you <exch> again. This doesn't work. Worse, it doesn't even keep the X selection you imported in the first place; you wind up with nothing in sam's snarf buffer.

As far as I can see, if you start with 'SAM' in sam's snarf buffer and 'X11' in the X selection, the results are:

  1. first <exch>: sam's snarf buffer becomes the X selection, the X selection becomes the snarf buffer. So sam's snarf buffer is 'X11' and the X selection is 'SAM'.
  2. second <exch>: sam's snarf buffer turns into the X selection (which means that the X selection returns to the original value of 'X11'), sam's snarf buffer is empty.
siebenmann commented 7 years ago

I believe I've identified the code flow issue that causes this (once one fixes issue #62): SelectSwap() in libXg/gwin.c reuses gw->gwin.selection as a signal from SelCallback() that it has acquired the selection, by nulling it before the selection swap process begins and then waiting for it to be non-null. When samterm itself owns the selection, this initial nulling destroys the value of the selection, so although SendSel() will be called through the magic of X events and callbacks, it will send out a empty string and then SelCallback() will receive this empty string back and set the snarf buffer to it.

I can see two solutions to this. The first is simply to somehow recognize when samterm is the holder of the selection and skip the whole process; simply directly swap gw->gwin.selection and the new selection value, returning the former and setting the latter as the new gw->gwin.selection. The second is to introduce an additional field in gw->gwin that SelCallback() uses to signal that it has been called, instead of reusing gw->gwin.selection for this. The latter is probably slightly simpler, because otherwise I think gwin.c would need to set up at least a lose_selection function for XtOwnSelection().

(I hacked together a version of the second option and it appears to work, although my specific implementation may have a memory leak somewhere.)