Subject: Re: bug#8869: Unjustified selection time-out

From: Chong Yidong <[email-masked]>
Date: Sun, 19 Jun 2011 15:59:26 -0400

Jan Djärv <[email-masked]> writes:

> 1) Emacs sends SAVE_TARGET and starts to wait for SelectionNotify.
> 2) The clipboard manager tries to get the CLIPBOARD selection with a
>    SelectionRequest.
> 3) Emacs receives this but does not reply to it, as it is only intereted in
>    SelectionNotify.
> 4) If an input event, such as mouse move, occurs, the loop is broken and all
>    queued X Events are handeled, including SelectionRequest.
> 5) The clipboard manager has gotten the clipboard from Emacs and only now
>    sends SelectionNotify.
>
> Thus, if there isn't any input in 4), the exit will time out.
> Emacs must handle SelectionRequest in 3) to work correctly.

Ah, thanks for this observation; now I can reproduce the problem, by
deleting the selection-owning frame using the mouse instead of a
keystroke.

The behavior of wait_reading_process_output is indeed problematic, but
perhaps it's better to work around it in x_get_foreign_selection,
instead of changing wait_reading_process_output itself.  The following
patch, for example, changes x_get_foreign_selection to loop calling
wait_reading_process_output with 1ms intervals.  That allows the
selection events be handled even if no keyboard input is supplied.
WDYT?

*** src/xselect.c       2011-06-06 19:43:39 +0000
--- src/xselect.c       2011-06-19 19:49:23 +0000
***************
*** 1207,1213 ****
    Atom type_atom = (CONSP (target_type)
             ? symbol_to_x_atom (dpyinfo, XCAR (target_type))
                   : symbol_to_x_atom (dpyinfo, target_type));
-   int secs, usecs;
  
    if (!FRAME_LIVE_P (f))
      return Qnil;
--- 1207,1212 ----
***************
*** 1243,1253 ****
    UNBLOCK_INPUT;
  
    /* This allows quits.  Also, don't wait forever.  */
-   secs = x_selection_timeout / 1000;
-   usecs = (x_selection_timeout % 1000) * 1000;
    TRACE1 ("  Start waiting %d secs for SelectionNotify", secs);
!   wait_reading_process_output (secs, usecs, 0, 0,
!                                             reading_selection_reply,
NULL, 0);
    TRACE1 ("  Got event = %d", !NILP (XCAR (reading_selection_reply)));
  
    if (NILP (XCAR (reading_selection_reply)))
--- 1242,1258 ----
    UNBLOCK_INPUT;
  
    /* This allows quits.  Also, don't wait forever.  */
    TRACE1 ("  Start waiting %d secs for SelectionNotify", secs);
!   {
!     int j, periods = max (1, x_selection_timeout);
!     for (j = 0; j < periods; j++)
!       {
!       wait_reading_process_output (0, 1000, 0, 0,
!
    reading_selection_reply, NULL, 0);
!   if (!NILP (XCAR (reading_selection_reply)))
!     break;
!       }
!   }
    TRACE1 ("  Got event = %d", !NILP (XCAR (reading_selection_reply)));
  
    if (NILP (XCAR (reading_selection_reply)))