Subject: bug#25521: 26.0.50; After (make-frame '((name . "foo"))) (select-frame-by-name "foo") doesn't see the frame

From: [email-masked]
Date: Thu, 31 Aug 2017 23:13:50 -0400

tags 25521 + patch
quit

martin rudalics <[email-masked]> writes:

>> How about removing the delay from w32 as well, and implementing it in
> ...
>> +(add-hook 'after-make-frame-functions #'wait-until-frame-is-visible)
>
> Note that currently the w32 port waits only for frames that are meant to
> become visible and also waits every time a frame becomes visible and not
> only after it was created.

Hmm, I thought I could get away with using an existing hook.  But
looking at all the places where x_make_frame_visible is called, I'm
feeling reluctant to introduce lisp evaluation into them.  I think we
should go with Eli's idea, bring back the busy wait but add a timeout.

>From 3b8e60de58ae2b2f9fafd806e9f888e716a0f22b Mon Sep 17 00:00:00 2001
From: Noam Postavsky <[email-masked]>
Date: Wed, 30 Aug 2017 23:12:22 -0400
Subject: [PATCH v1] Bring back the busy wait after x_make_frame_visible
 (Bug#25521)

But limit the wait to a configurable timeout.  This mostly reverts
"Don't wait for frame to become visible".
* src/xterm.c (syms_of_xterm) [x-visible-frame-timeout]: New variable.
* src/xterm.c (x_make_frame_visible):
* src/w32term.c (x_make_frame_visible): Wait for frame to become
visible according to its value.
---
 src/w32term.c | 13 ++++++++----
 src/xterm.c   | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 74 insertions(+), 6 deletions(-)

diff --git a/src/w32term.c b/src/w32term.c
index 2785ae2b52..8b129ae029 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -6609,7 +6609,8 @@ w32_frame_raise_lower (struct frame *f, bool raise_flag)
 
 /* Change of visibility.  */
 
-/* This tries to wait until the frame is really visible.
+/* This tries to wait until the frame is really visible, depending on
+   the value of Vx_visible_frame_timeout.
    However, if the window manager asks the user where to position
    the frame, this will return before the user finishes doing that.
    The frame will not actually be visible at that time,
@@ -6668,12 +6669,16 @@ x_make_frame_visible (struct frame *f)
 		      : SW_SHOWNORMAL);
     }
 
+  if (!FLOATP (Vx_visible_frame_timeout))
+      return;
+
   /* Synchronize to ensure Emacs knows the frame is visible
      before we do anything else.  We do this loop with input not blocked
      so that incoming events are handled.  */
   {
     Lisp_Object frame;
-    int count;
+    double timeout = XFLOAT_DATA (Vx_visible_frame_timeout);
+    double start_time = XFLOAT_DATA (Ffloat_time (Qnil));
 
     /* This must come after we set COUNT.  */
     unblock_input ();
@@ -6683,8 +6688,8 @@ x_make_frame_visible (struct frame *f)
     /* Wait until the frame is visible.  Process X events until a
        MapNotify event has been seen, or until we think we won't get a
        MapNotify at all..  */
-    for (count = input_signal_count + 10;
-	 input_signal_count < count && !FRAME_VISIBLE_P (f);)
+    while (timeout > (XFLOAT_DATA (Ffloat_time (Qnil)) - start_time) &&
+           !FRAME_VISIBLE_P (f))
       {
 	/* Force processing of queued events.  */
         /* TODO: x_sync equivalent?  */
diff --git a/src/xterm.c b/src/xterm.c
index a7a52064a1..3ade688f1b 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -11373,8 +11373,13 @@ xembed_send_message (struct frame *f, Time t, enum xembed_message msg,
 
 /* Change of visibility.  */
 
-/* This function sends the request to make the frame visible, but may
-   return before it the frame's visibility is changed.  */
+/* This tries to wait until the frame is really visible, depending on
+   the value of Vx_visible_frame_timeout.
+   However, if the window manager asks the user where to position
+   the frame, this will return before the user finishes doing that.
+   The frame will not actually be visible at that time,
+   but it will become visible later when the window manager
+   finishes with it.  */
 
 void
 x_make_frame_visible (struct frame *f)
@@ -11445,11 +11450,14 @@ x_make_frame_visible (struct frame *f)
      before we do anything else.  We do this loop with input not blocked
      so that incoming events are handled.  */
   {
+    Lisp_Object frame;
     /* This must be before UNBLOCK_INPUT
        since events that arrive in response to the actions above
        will set it when they are handled.  */
     bool previously_visible = f->output_data.x->has_been_visible;
 
+    XSETFRAME (frame, f);
+
     int original_left = f->left_pos;
     int original_top = f->top_pos;
 
@@ -11496,6 +11504,48 @@ x_make_frame_visible (struct frame *f)
 
 	unblock_input ();
       }
+
+
+    if (!FLOATP (Vx_visible_frame_timeout))
+      return;
+
+    double timeout = XFLOAT_DATA (Vx_visible_frame_timeout);
+    double start_time = XFLOAT_DATA (Ffloat_time (Qnil));
+
+    /* Process X events until a MapNotify event has been seen.  */
+    while (timeout > (XFLOAT_DATA (Ffloat_time (Qnil)) - start_time) &&
+           !FRAME_VISIBLE_P (f))
+      {
+	/* Force processing of queued events.  */
+	x_sync (f);
+
+       /* This hack is still in use at least for Cygwin.  See
+	   http://lists.gnu.org/archive/html/emacs-devel/2013-12/msg00351.html.
+
+	   Machines that do polling rather than SIGIO have been
+	   observed to go into a busy-wait here.  So we'll fake an
+	   alarm signal to let the handler know that there's something
+	   to be read.  We used to raise a real alarm, but it seems
+	   that the handler isn't always enabled here.  This is
+	   probably a bug.  */
+	if (input_polling_used ())
+	  {
+	    /* It could be confusing if a real alarm arrives while
+	       processing the fake one.  Turn it off and let the
+	       handler reset it.  */
+	    int old_poll_suppress_count = poll_suppress_count;
+	    poll_suppress_count = 1;
+	    poll_for_input_1 ();
+	    poll_suppress_count = old_poll_suppress_count;
+	  }
+
+	if (XPending (FRAME_X_DISPLAY (f)))
+	  {
+	    XEvent xev;
+	    XNextEvent (FRAME_X_DISPLAY (f), &xev);
+	    x_dispatch_event (&xev, FRAME_X_DISPLAY (f));
+	  }
+      }
   }
 }
 
@@ -13291,6 +13341,19 @@ syms_of_xterm (void)
 keysyms.  The default is nil, which is the same as `super'.  */);
   Vx_super_keysym = Qnil;
 
+  DEFVAR_LISP ("x-visible-frame-timeout", Vx_visible_frame_timeout,
+    doc: /* How long to wait for a frame to become visible.
+Emacs will wait up to this many seconds after `make-frame-visible' is
+called until receiving notification from the windowing system that the
+frame has become visible.  Under some window managers this can take an
+indefinite amount of time, so it is important to limit the wait.
+
+If set to a non-float value, there will be no wait at all.  This
+should be fine unless your config contains some code that assumes
+frames will become visible immediately (e.g., calling
+`select-frame-by-name' directly after creating a named frame). */);
+  Vx_visible_frame_timeout = make_float (0.5);
+
   DEFVAR_LISP ("x-keysym-table", Vx_keysym_table,
     doc: /* Hash table of character codes indexed by X keysym codes.  */);
   Vx_keysym_table = make_hash_table (hashtest_eql, 900,
-- 
2.14.1